CCM NG: Form etc for editing FlexLayoutComponent and some other things

git-svn-id: https://svn.libreccm.org/ccm/ccm_ng@5357 8810af33-2d31-482b-a856-94f89814c4df
ccm-docs
jensp 2018-03-23 19:19:52 +00:00
parent dc266c10a0
commit 811ecf6a93
26 changed files with 1610 additions and 302 deletions

View File

@ -32,6 +32,8 @@ import com.arsdigita.globalization.GlobalizedMessage;
import com.arsdigita.ui.admin.pagemodels.AbstractComponentModelForm; import com.arsdigita.ui.admin.pagemodels.AbstractComponentModelForm;
import com.arsdigita.ui.admin.pagemodels.PageModelsTab; import com.arsdigita.ui.admin.pagemodels.PageModelsTab;
import org.libreccm.cdi.utils.CdiUtil;
import org.libreccm.pagemodel.ComponentModelRepository;
import org.librecms.CmsConstants; import org.librecms.CmsConstants;
import org.librecms.pagemodel.ItemListComponent; import org.librecms.pagemodel.ItemListComponent;
@ -133,8 +135,7 @@ public class ItemListComponentForm
} }
@Override @Override
public void init(final FormSectionEvent event) public void init(final FormSectionEvent event) throws FormProcessException {
throws FormProcessException {
super.init(event); super.init(event);
@ -144,7 +145,7 @@ public class ItemListComponentForm
if (component == null) { if (component == null) {
pageSizeField.setValue(state, "30"); pageSizeField.setValue(state, "30");
}else { } else {
final Object[] descendingValue; final Object[] descendingValue;
if (component.isDescending()) { if (component.isDescending()) {
descendingValue = new Object[]{DESCENDING}; descendingValue = new Object[]{DESCENDING};
@ -163,6 +164,21 @@ public class ItemListComponentForm
} }
} }
@Override
protected ItemListComponent loadSelectedComponent(final long componentId) {
final CdiUtil cdiUtil = CdiUtil.createCdiUtil();
final ComponentModelRepository componentModelRepo = cdiUtil
.findBean(ComponentModelRepository.class);
return componentModelRepo.findById(componentId,
ItemListComponent.class,
new String[]{"listOrder"})
.orElseThrow(() -> new IllegalArgumentException(String
.format("No ComponentModel with ID %d in the database.",
componentId)));
}
@Override @Override
public void validate(final FormSectionEvent event) public void validate(final FormSectionEvent event)
throws FormProcessException { throws FormProcessException {

View File

@ -39,24 +39,23 @@ import com.arsdigita.bebop.util.BebopConstants;
import com.arsdigita.xml.Element; import com.arsdigita.xml.Element;
/** /**
* A <code>List</code>, similar to a <code>javax.swing.JList</code>, that * A <code>List</code>, similar to a <code>javax.swing.JList</code>, that keeps
* keeps track of a sequence of items and selections of one or more of * track of a sequence of items and selections of one or more of these items. A
* these items. A separate model, {@link ListModel}, is used to represent * separate model, {@link ListModel}, is used to represent the items in the
* the items in the list. * list.
* *
* @see ListModel * @see ListModel
* @see ListModelBuilder * @see ListModelBuilder
* @see com.arsdigita.bebop.list.ListCellRenderer * @see com.arsdigita.bebop.list.ListCellRenderer
* @author David Lutterkort * @author David Lutterkort
* @version $Id: List.java 287 2005-02-22 00:29:02Z sskracic $ * @version $Id: List.java 287 2005-02-22 00:29:02Z sskracic $
*/ */
public class List extends SimpleComponent implements BebopConstants { public class List extends SimpleComponent implements BebopConstants {
/** /**
* The name of the StringParameter that the list uses to keep track of * The name of the StringParameter that the list uses to keep track of which
* which item is selected. * item is selected.
*/ */
public static final String SELECTED = "sel"; public static final String SELECTED = "sel";
@ -67,8 +66,9 @@ public class List extends SimpleComponent implements BebopConstants {
public static final String SELECT_EVENT = "s"; public static final String SELECT_EVENT = "s";
/** /**
* The model builder for this list. Is used to produce a new model for * The model builder for this list. Is used to produce a new model for each
* each request served by this <code>List</code>. * request served by this <code>List</code>.
*
* @see #setListModelBuilder * @see #setListModelBuilder
* @see ArrayListModelBuilder * @see ArrayListModelBuilder
* @see MapListModelBuilder * @see MapListModelBuilder
@ -79,6 +79,7 @@ public class List extends SimpleComponent implements BebopConstants {
/** /**
* The renderer used to format list items. * The renderer used to format list items.
*
* @see DefaultListCellRenderer * @see DefaultListCellRenderer
*/ */
private ListCellRenderer m_renderer; private ListCellRenderer m_renderer;
@ -93,27 +94,28 @@ public class List extends SimpleComponent implements BebopConstants {
private boolean m_stateParamsAreRegistered; private boolean m_stateParamsAreRegistered;
/** /**
* <p>Vertical List layout.</p> * <p>
**/ * Vertical List layout.</p>
*
*/
public static final int VERTICAL = 0; public static final int VERTICAL = 0;
/** /**
* <p>Horizontal List layout.</p> * <p>
**/ * Horizontal List layout.</p>
*
*/
public static final int HORIZONTAL = 1; public static final int HORIZONTAL = 1;
private int m_layout = VERTICAL; private int m_layout = VERTICAL;
/** /**
* Creates a new <code>List</code> that uses the specified * Creates a new <code>List</code> that uses the specified list model
* list model builder to generate * builder to generate per-request {@link ListModel ListModels}.
* per-request {@link ListModel ListModels}.
* *
* @param b the model builder used for this list * @param b the model builder used for this list
*
* @pre b != null * @pre b != null
*/ */
public List(ListModelBuilder b) { public List(ListModelBuilder b) {
@ -128,8 +130,8 @@ public class List extends SimpleComponent implements BebopConstants {
public List() { public List() {
// Force the use of the 'right' constructor // Force the use of the 'right' constructor
this((SingleSelectionModel) null); this((SingleSelectionModel) null);
m_selection = m_selection = new ParameterSingleSelectionModel(new StringParameter(
new ParameterSingleSelectionModel(new StringParameter(SELECTED)); SELECTED));
} }
/** /**
@ -150,14 +152,14 @@ public class List extends SimpleComponent implements BebopConstants {
/** /**
* Creates a new <code>List</code> from an array of objects. Uses an * Creates a new <code>List</code> from an array of objects. Uses an
* internal {@link ListModelBuilder}. Each {@link ListModel} that is * internal {@link ListModelBuilder}. Each {@link ListModel} that is built
* built will * will iterate through the entries of the object, returning the objects
* iterate through the entries of the object, returning the objects from * from calls to {@link ListModel#getElement} and the corresponding index,
* calls to {@link ListModel#getElement} and the corresponding index,
* which is converted to a <code>String</code> from calls to {@link * which is converted to a <code>String</code> from calls to {@link
* ListModel#getKey}. * ListModel#getKey}.
* *
* @param values an array of items * @param values an array of items
*
* @pre values != null * @pre values != null
* @see #setListData(Object[] v) * @see #setListData(Object[] v)
*/ */
@ -173,10 +175,11 @@ public class List extends SimpleComponent implements BebopConstants {
* returned by <code>map.entrySet().iterator()</code>. Calls to {@link * returned by <code>map.entrySet().iterator()</code>. Calls to {@link
* ListModel#getElement} return one value in <code>map</code>. Calls to * ListModel#getElement} return one value in <code>map</code>. Calls to
* {@link ListModel#getElement} return the corresponding key, which is * {@link ListModel#getElement} return the corresponding key, which is
* converted * converted to a <code>String</code> by calling <code>toString()</code> on
* to a <code>String</code> by calling <code>toString()</code> on the key. * the key.
* *
* @param map a key-value mapping for the list items * @param map a key-value mapping for the list items
*
* @pre map != null * @pre map != null
*/ */
public List(Map map) { public List(Map map) {
@ -189,12 +192,13 @@ public class List extends SimpleComponent implements BebopConstants {
* specified page. * specified page.
* *
* @param p the page this list is contained in * @param p the page this list is contained in
*
* @pre p != null * @pre p != null
* @pre ! isLocked() * @pre ! isLocked()
*/ */
public void register(Page p) { public void register(Page p) {
Assert.isUnlocked(this); Assert.isUnlocked(this);
if ( m_selection.getStateParameter() != null ) { if (m_selection.getStateParameter() != null) {
p.addComponentStateParam(this, m_selection.getStateParameter()); p.addComponentStateParam(this, m_selection.getStateParameter());
} }
} }
@ -204,11 +208,13 @@ public class List extends SimpleComponent implements BebopConstants {
* component. Calls to this method should only be made through links * component. Calls to this method should only be made through links
* generated by this list. * generated by this list.
* *
* <p>Determines the new selected element and fires a {@link * <p>
* Determines the new selected element and fires a {@link
* ChangeEvent} if it has changed. After that, fires an {@link * ChangeEvent} if it has changed. After that, fires an {@link
* ActionEvent}. * ActionEvent}.
* *
* @param state the state of the current request * @param state the state of the current request
*
* @throws ServletException if the control event is unknown. * @throws ServletException if the control event is unknown.
* @pre state != null * @pre state != null
* @see #fireStateChanged fireStateChanged * @see #fireStateChanged fireStateChanged
@ -217,7 +223,7 @@ public class List extends SimpleComponent implements BebopConstants {
public void respond(PageState state) throws ServletException { public void respond(PageState state) throws ServletException {
String event = state.getControlEventName(); String event = state.getControlEventName();
if ( SELECT_EVENT.equals(event) ) { if (SELECT_EVENT.equals(event)) {
setSelectedKey(state, state.getControlEventValue()); setSelectedKey(state, state.getControlEventValue());
} else { } else {
throw new ServletException("Unknown event '" + event + "'"); throw new ServletException("Unknown event '" + event + "'");
@ -226,11 +232,33 @@ public class List extends SimpleComponent implements BebopConstants {
} }
/** /**
* Generates XML representing the items in the list. The items are * Allow subclasses to override how the layout is determined.
* formatted using a {@link ListCellRenderer}. <code>generateXML</code>
* is called on each component returned by the renderer.
* *
* <p> The XML that is generated has the following form: * @param list
*/
protected void exportLayoutAttribute(final Element list) {
if (m_layout == VERTICAL) {
list.addAttribute("layout", "vertical");
} else {
list.addAttribute("layout", "horizontal");
}
}
protected String getTagName() {
return BEBOP_LIST;
}
protected String getTagXMLNS() {
return BEBOP_XML_NS;
}
/**
* Generates XML representing the items in the list. The items are formatted
* using a {@link ListCellRenderer}. <code>generateXML</code> is called on
* each component returned by the renderer.
*
* <p>
* The XML that is generated has the following form:
* <pre> * <pre>
* &lt;bebop:list mode="single" %bebopAttr;> * &lt;bebop:list mode="single" %bebopAttr;>
* &lt;bebop:cell [selected="selected"] key="itemKey"> * &lt;bebop:cell [selected="selected"] key="itemKey">
@ -239,43 +267,43 @@ public class List extends SimpleComponent implements BebopConstants {
* ... more &lt;bebop:cell> elements, one for each list item ... * ... more &lt;bebop:cell> elements, one for each list item ...
* &lt;/bebop:list></pre> * &lt;/bebop:list></pre>
* *
* @param state the state of the current request * @param state the state of the current request
* @param parent the element into which XML is generated * @param parent the element into which XML is generated
*
* @pre state != null * @pre state != null
* @pre parent != null * @pre parent != null
* @see com.arsdigita.bebop.list.ListCellRenderer * @see com.arsdigita.bebop.list.ListCellRenderer
*/ */
public void generateXML(PageState state, Element parent) { public void generateXML(PageState state, Element parent) {
if ( ! isVisible(state) ) { if (!isVisible(state)) {
return; return;
} }
ListModel m = getModel(state); ListModel m = getModel(state);
// Check if there are items in the list // Check if there are items in the list
if(m.next()) { if (m.next()) {
// The list has items // The list has items
Element list = parent.newChildElement(getTagName(), getTagXMLNS());
Element list = parent.newChildElement(BEBOP_LIST, BEBOP_XML_NS);
exportAttributes(list); exportAttributes(list);
if (m_layout == VERTICAL) { // if (m_layout == VERTICAL) {
list.addAttribute("layout", "vertical"); // list.addAttribute("layout", "vertical");
} else { // } else {
list.addAttribute("layout", "horizontal"); // list.addAttribute("layout", "horizontal");
} // }
exportLayoutAttribute(list);
Component c; Component c;
Object selKey; Object selKey;
if(getStateParamsAreRegistered()) if (getStateParamsAreRegistered()) {
{ selKey = getSelectedKey(state);
selKey = getSelectedKey(state); } else {
}
else
selKey = null; selKey = null;
}
int i = 0; int i = 0;
do { do {
@ -286,24 +314,25 @@ public class List extends SimpleComponent implements BebopConstants {
// Converting both keys to String for comparison // Converting both keys to String for comparison
// since ListModel.getKey returns a String // since ListModel.getKey returns a String
boolean selected = (selKey != null) && boolean selected = (selKey != null) && key.equals(selKey
key.equals(selKey.toString()); .toString());
item.addAttribute("key", key); item.addAttribute("key", key);
if ( selected ) { if (selected) {
item.addAttribute("selected", "selected"); item.addAttribute("selected", "selected");
} }
if(getStateParamsAreRegistered()) if (getStateParamsAreRegistered()) {
state.setControlEvent(this, SELECT_EVENT, key); state.setControlEvent(this, SELECT_EVENT, key);
}
c = getCellRenderer().getComponent(this, state, m.getElement(), c = getCellRenderer().getComponent(this, state, m.getElement(),
key, i, selected); key, i, selected);
c.generateXML(state, item); c.generateXML(state, item);
i += 1; i += 1;
} while (m.next()); } while (m.next());
} else { } else {
// The list has no items // The list has no items
if(m_emptyView != null) { if (m_emptyView != null) {
// Display the empty view // Display the empty view
m_emptyView.generateXML(state, parent); m_emptyView.generateXML(state, parent);
} else { } else {
@ -317,42 +346,42 @@ public class List extends SimpleComponent implements BebopConstants {
state.clearControlEvent(); state.clearControlEvent();
} }
/** /**
* <p>Retrieve the current List layout.</p> * <p>
* Retrieve the current List layout.</p>
* *
* @return List.VERTICAL or List.HORIZONTAL * @return List.VERTICAL or List.HORIZONTAL
**/ *
*/
public int getLayout() { public int getLayout() {
return m_layout; return m_layout;
} }
/** /**
* <p>Set the current List layout.</p> * <p>
* Set the current List layout.</p>
* *
* @param layout New layout value, must be List.VERTICAL or List.HORIZONTAL * @param layout New layout value, must be List.VERTICAL or List.HORIZONTAL
**/ *
*/
public void setLayout(int layout) { public void setLayout(int layout) {
Assert.isUnlocked(this); Assert.isUnlocked(this);
Assert.isTrue((layout == VERTICAL) || (layout == HORIZONTAL), Assert.isTrue((layout == VERTICAL) || (layout == HORIZONTAL),
"Invalid layout code passed to setLayout"); "Invalid layout code passed to setLayout");
m_layout = layout; m_layout = layout;
} }
/** /**
* This method is part of a mechanism to freakishly allow * This method is part of a mechanism to freakishly allow List's to be used
* List's to be used as parent classes for components * as parent classes for components that do not have their state params
* that do not have their state params registered with the * registered with the page. An example of a situation like this is Form
* page. An example of a situation like this is Form ErrorDisplay * ErrorDisplay being used in a Metaform
* being used in a Metaform
*/ */
public void setStateParamsAreRegistered(boolean val) public void setStateParamsAreRegistered(boolean val) {
{
m_stateParamsAreRegistered = val; m_stateParamsAreRegistered = val;
} }
public boolean getStateParamsAreRegistered() public boolean getStateParamsAreRegistered() {
{
return m_stateParamsAreRegistered; return m_stateParamsAreRegistered;
} }
@ -360,6 +389,7 @@ public class List extends SimpleComponent implements BebopConstants {
* Returns the renderer currently used for rendering list items. * Returns the renderer currently used for rendering list items.
* *
* @return the current list cell renderer. * @return the current list cell renderer.
*
* @see #setCellRenderer setCellRenderer * @see #setCellRenderer setCellRenderer
* @see com.arsdigita.bebop.list.ListCellRenderer * @see com.arsdigita.bebop.list.ListCellRenderer
*/ */
@ -368,10 +398,11 @@ public class List extends SimpleComponent implements BebopConstants {
} }
/** /**
* Sets the cell renderer to be used when generating output with * Sets the cell renderer to be used when generating output with or
* or {@link #generateXML generateXML}. * {@link #generateXML generateXML}.
* *
* @param r a <code>ListCellRenderer</code> value * @param r a <code>ListCellRenderer</code> value
*
* @pre r != null * @pre r != null
* @pre ! isLocked() * @pre ! isLocked()
* @see com.arsdigita.bebop.list.ListCellRenderer * @see com.arsdigita.bebop.list.ListCellRenderer
@ -386,6 +417,7 @@ public class List extends SimpleComponent implements BebopConstants {
* {@link ListModel}. * {@link ListModel}.
* *
* @return a <code>ListModelBuilder</code> value. * @return a <code>ListModelBuilder</code> value.
*
* @see #setModelBuilder setModelBuilder * @see #setModelBuilder setModelBuilder
* @see ListModelBuilder * @see ListModelBuilder
*/ */
@ -398,6 +430,7 @@ public class List extends SimpleComponent implements BebopConstants {
* {@link ListModel}. * {@link ListModel}.
* *
* @param b a <code>ListModelBuilder</code> value * @param b a <code>ListModelBuilder</code> value
*
* @pre ! isLocked() * @pre ! isLocked()
* @see ListModelBuilder * @see ListModelBuilder
*/ */
@ -407,9 +440,9 @@ public class List extends SimpleComponent implements BebopConstants {
} }
/** /**
* Sets the empty view component, which is * Sets the empty view component, which is shown if there are no items in
* shown if there are no items in the list. This component must * the list. This component must be stateless. For example, it could be an
* be stateless. For example, it could be an Image or a Label. * Image or a Label.
* *
* @param c the new empty view component * @param c the new empty view component
*/ */
@ -419,25 +452,27 @@ public class List extends SimpleComponent implements BebopConstants {
} }
/** /**
* Gets the empty view component. The empty view component is * Gets the empty view component. The empty view component is shown if there
* shown if there are no items in the list. * are no items in the list.
*
* @return the empty view component. * @return the empty view component.
*/ */
public final Component getEmptyView() { public final Component getEmptyView() {
return m_emptyView; return m_emptyView;
} }
/** /**
* Initialize the private <code>m_model</code> variable. The initial * Initialize the private <code>m_model</code> variable. The initial value
* value is what the model builder returns for the state. * is what the model builder returns for the state.
*/ */
private void initListModel() { private void initListModel() {
m_model = new RequestLocal() { m_model = new RequestLocal() {
protected Object initialValue(PageState s) {
return getModelBuilder().makeModel(List.this, s); protected Object initialValue(PageState s) {
} return getModelBuilder().makeModel(List.this, s);
}; }
};
} }
/** /**
@ -445,8 +480,9 @@ public class List extends SimpleComponent implements BebopConstants {
* <code>state</code>. * <code>state</code>.
* *
* @param state the state of the current request * @param state the state of the current request
*
* @return the list model used in processing the request represented by * @return the list model used in processing the request represented by
* <code>state</code>. * <code>state</code>.
*/ */
public ListModel getModel(PageState state) { public ListModel getModel(PageState state) {
return (ListModel) m_model.get(state); return (ListModel) m_model.get(state);
@ -455,11 +491,12 @@ public class List extends SimpleComponent implements BebopConstants {
/** /**
* Sets the list to use for the values in <code>values</code>. Each {@link * Sets the list to use for the values in <code>values</code>. Each {@link
* ListModel} that is built will iterate through the entries of the object, * ListModel} that is built will iterate through the entries of the object,
* returning the objects from calls to {@link ListModel#getElement} and * returning the objects from calls to {@link ListModel#getElement} and the
* the corresponding index, which is converted to a <code>String</code> * corresponding index, which is converted to a <code>String</code> from
* from calls to {@link ListModel#getKey}. * calls to {@link ListModel#getKey}.
* *
* @param values an array of items * @param values an array of items
*
* @pre values != null * @pre values != null
* @pre ! isLocked() * @pre ! isLocked()
*/ */
@ -475,9 +512,11 @@ public class List extends SimpleComponent implements BebopConstants {
* <code>map.entrySet().iterator()</code>. Calls to {@link * <code>map.entrySet().iterator()</code>. Calls to {@link
* ListModel#getElement} return one value in <code>map</code>. Calls to * ListModel#getElement} return one value in <code>map</code>. Calls to
* {@link ListModel#getElement} return the corresponding key, which is * {@link ListModel#getElement} return the corresponding key, which is
* converted to a <code>String</code> by calling <code>toString()</code> * converted to a <code>String</code> by calling <code>toString()</code> on
* on the key. * the key.
*
* @param map a key-value mapping for the list items * @param map a key-value mapping for the list items
*
* @pre map != null * @pre map != null
* @pre ! isLocked() * @pre ! isLocked()
*/ */
@ -492,7 +531,7 @@ public class List extends SimpleComponent implements BebopConstants {
* programmatically. * programmatically.
* *
* @return the model used by the list to keep track of the selected list * @return the model used by the list to keep track of the selected list
* item. * item.
*/ */
public final SingleSelectionModel getSelectionModel() { public final SingleSelectionModel getSelectionModel() {
return m_selection; return m_selection;
@ -503,12 +542,13 @@ public class List extends SimpleComponent implements BebopConstants {
* currently selected list item. * currently selected list item.
* *
* @param m the new selection model * @param m the new selection model
*
* @pre m != null * @pre m != null
* @pre ! isLocked() * @pre ! isLocked()
*/ */
public final void setSelectionModel(SingleSelectionModel m) { public final void setSelectionModel(SingleSelectionModel m) {
Assert.isUnlocked(this); Assert.isUnlocked(this);
if ( m_changeListener != null ) { if (m_changeListener != null) {
// Transfer the change listener // Transfer the change listener
m_selection.removeChangeListener(m_changeListener); m_selection.removeChangeListener(m_changeListener);
m.addChangeListener(m_changeListener); m.addChangeListener(m_changeListener);
@ -517,12 +557,13 @@ public class List extends SimpleComponent implements BebopConstants {
} }
/** /**
* Gets the key for the selected list item. This will only * Gets the key for the selected list item. This will only be a valid key if
* be a valid key * {@link #isSelected isSelected} is <code>true</code>.
* if {@link #isSelected isSelected} is <code>true</code>.
* *
* @param state the state of the current request * @param state the state of the current request
*
* @return the key for the selected list item. * @return the key for the selected list item.
*
* @pre isSelected(state) * @pre isSelected(state)
*/ */
public Object getSelectedKey(PageState state) { public Object getSelectedKey(PageState state) {
@ -530,12 +571,13 @@ public class List extends SimpleComponent implements BebopConstants {
} }
/** /**
* Sets the selection to the one with the specified key. If * Sets the selection to the one with the specified key. If <code>key</code>
* <code>key</code> was not already selected, fires the {@link * was not already selected, fires the {@link
* ChangeEvent}. * ChangeEvent}.
* *
* @param state the state of the current request * @param state the state of the current request
* @param key the key for the selected list item * @param key the key for the selected list item
*
* @see #fireStateChanged fireStateChanged * @see #fireStateChanged fireStateChanged
*/ */
public void setSelectedKey(PageState state, String key) { public void setSelectedKey(PageState state, String key) {
@ -546,8 +588,9 @@ public class List extends SimpleComponent implements BebopConstants {
* Returns <code>true</code> if one of the list items is currently selected. * Returns <code>true</code> if one of the list items is currently selected.
* *
* @param state the state of the current request * @param state the state of the current request
*
* @return <code>true</code> if one of the list items is selected * @return <code>true</code> if one of the list items is selected
* <code>false</code> otherwise. * <code>false</code> otherwise.
*/ */
public boolean isSelected(PageState state) { public boolean isSelected(PageState state) {
return m_selection.isSelected(state); return m_selection.isSelected(state);
@ -557,6 +600,7 @@ public class List extends SimpleComponent implements BebopConstants {
* Clears the selection in the request represented by <code>state</code>. * Clears the selection in the request represented by <code>state</code>.
* *
* @param state the state of the current request * @param state the state of the current request
*
* @post ! isSelected(state) * @post ! isSelected(state)
*/ */
public void clearSelection(PageState state) { public void clearSelection(PageState state) {
@ -565,19 +609,20 @@ public class List extends SimpleComponent implements BebopConstants {
/** /**
* Creates the change listener that is used for forwarding change events * Creates the change listener that is used for forwarding change events
* fired by * fired by the selection model to change listeners registered with the
* the selection model to change listeners registered with the list. The * list. The returned change listener refires the event with the list,
* returned change listener refires the event with the list,
* rather than the selection model, as source. * rather than the selection model, as source.
* *
* @return the change listener used internally by the list. * @return the change listener used internally by the list.
*/ */
protected ChangeListener createChangeListener() { protected ChangeListener createChangeListener() {
return new ChangeListener() { return new ChangeListener() {
public void stateChanged(ChangeEvent e) {
fireStateChanged(e.getPageState()); public void stateChanged(ChangeEvent e) {
} fireStateChanged(e.getPageState());
}; }
};
} }
/** /**
@ -585,13 +630,14 @@ public class List extends SimpleComponent implements BebopConstants {
* list item changes during the processing of a request. The change event * list item changes during the processing of a request. The change event
* that listeners receive names the list as the source. * that listeners receive names the list as the source.
* *
* @param l the change listener to run when the selected item changes in * @param l the change listener to run when the selected item changes in a
* a request * request
*
* @pre ! isLocked() * @pre ! isLocked()
*/ */
public void addChangeListener(ChangeListener l) { public void addChangeListener(ChangeListener l) {
Assert.isUnlocked(this); Assert.isUnlocked(this);
if ( m_changeListener == null ) { if (m_changeListener == null) {
m_changeListener = createChangeListener(); m_changeListener = createChangeListener();
m_selection.addChangeListener(m_changeListener); m_selection.addChangeListener(m_changeListener);
} }
@ -599,10 +645,9 @@ public class List extends SimpleComponent implements BebopConstants {
} }
/** /**
* Removes a change listener. The listener should have been previously * Removes a change listener. The listener should have been previously added
* added with {@link #addChangeListener addChangeListener}, although no * with {@link #addChangeListener addChangeListener}, although no error is
* error is signalled if the change listener is not found among the * signalled if the change listener is not found among the list's listeners.
* list's listeners.
* *
* @param l the change listener to remove from the list * @param l the change listener to remove from the list
*/ */
@ -612,19 +657,18 @@ public class List extends SimpleComponent implements BebopConstants {
} }
/** /**
* Fires a change event to signal that the selected list item has changed * Fires a change event to signal that the selected list item has changed in
* in the request represented by <code>state</code>. The source of the * the request represented by <code>state</code>. The source of the event is
* event is the list. * the list.
* *
* @param state the state of the current request * @param state the state of the current request
*/ */
protected void fireStateChanged(PageState state) { protected void fireStateChanged(PageState state) {
Iterator Iterator i = m_listeners.getListenerIterator(ChangeListener.class);
i=m_listeners.getListenerIterator(ChangeListener.class);
ChangeEvent e = null; ChangeEvent e = null;
while (i.hasNext()) { while (i.hasNext()) {
if ( e == null ) { if (e == null) {
e = new ChangeEvent(this, state); e = new ChangeEvent(this, state);
} }
((ChangeListener) i.next()).stateChanged(e); ((ChangeListener) i.next()).stateChanged(e);
@ -633,9 +677,10 @@ public class List extends SimpleComponent implements BebopConstants {
// Action events // Action events
/** /**
* Adds an action listener. This method is run whenever {@link #respond respond} is * Adds an action listener. This method is run whenever
* called on the list. This gives clients a way to track mouse clicks * {@link #respond respond} is called on the list. This gives clients a way
* received by the list. * to track mouse clicks received by the list.
*
* @param 1 the action listener to add * @param 1 the action listener to add
* *
* @pre l != null * @pre l != null
@ -649,6 +694,7 @@ public class List extends SimpleComponent implements BebopConstants {
/** /**
* Removes a previously added action listener. * Removes a previously added action listener.
*
* @param 1 the action listener to remove * @param 1 the action listener to remove
* *
* @see #addActionListener addActionListener * @see #addActionListener addActionListener
@ -660,20 +706,20 @@ public class List extends SimpleComponent implements BebopConstants {
/** /**
* Fires an action event signalling that the list received the request * Fires an action event signalling that the list received the request
* submission. All registered action listeners are run. The source of * submission. All registered action listeners are run. The source of the
* the event is the list. * event is the list.
*
* @param state the state of the current request * @param state the state of the current request
* *
* @pre state != null * @pre state != null
* @see #respond respond * @see #respond respond
*/ */
protected void fireActionEvent(PageState state) { protected void fireActionEvent(PageState state) {
Iterator Iterator i = m_listeners.getListenerIterator(ActionListener.class);
i=m_listeners.getListenerIterator(ActionListener.class);
ActionEvent e = null; ActionEvent e = null;
while (i.hasNext()) { while (i.hasNext()) {
if ( e == null ) { if (e == null) {
e = new ActionEvent(this, state); e = new ActionEvent(this, state);
} }
((ActionListener) i.next()).actionPerformed(e); ((ActionListener) i.next()).actionPerformed(e);
@ -681,7 +727,6 @@ public class List extends SimpleComponent implements BebopConstants {
} }
// ListModelBuilder for maps // ListModelBuilder for maps
/** /**
* Build list models from a map. The list models use the result of * Build list models from a map. The list models use the result of
* <code>toString()</code> called on the key of the map entries as their * <code>toString()</code> called on the key of the map entries as their
@ -689,6 +734,7 @@ public class List extends SimpleComponent implements BebopConstants {
* the list model iterates over. * the list model iterates over.
*/ */
private static class MapListModelBuilder implements ListModelBuilder { private static class MapListModelBuilder implements ListModelBuilder {
private Map m_map; private Map m_map;
private boolean m_locked; private boolean m_locked;
@ -702,36 +748,38 @@ public class List extends SimpleComponent implements BebopConstants {
public ListModel makeModel(List l, PageState state) { public ListModel makeModel(List l, PageState state) {
return new ListModel() { return new ListModel() {
private Iterator i = m_map.entrySet().iterator();
private Map.Entry e = null;
public boolean next() { private Iterator i = m_map.entrySet().iterator();
if ( ! i.hasNext() ) { private Map.Entry e = null;
e = null;
return false; public boolean next() {
} if (!i.hasNext()) {
e = (Map.Entry) i.next(); e = null;
return true; return false;
} }
e = (Map.Entry) i.next();
return true;
}
public Object getElement() { public Object getElement() {
checkState(); checkState();
return e.getValue(); return e.getValue();
}
public String getKey() {
checkState();
return e.getKey().toString();
}
private void checkState() {
if (e == null) {
throw new IllegalStateException(
"No valid current item. "
+ "Model is either before first item or after last item");
} }
}
public String getKey() { };
checkState();
return e.getKey().toString();
}
private void checkState() {
if ( e == null ) {
throw new IllegalStateException("No valid current item. "
+ "Model is either before first item or after last item");
}
}
};
} }
public void lock() { public void lock() {
@ -741,16 +789,17 @@ public class List extends SimpleComponent implements BebopConstants {
public final boolean isLocked() { public final boolean isLocked() {
return m_locked; return m_locked;
} }
} }
// ListModelBuilder for arrays // ListModelBuilder for arrays
/** /**
* Build list models from an array of values. The list models use the * Build list models from an array of values. The list models use the index
* index of the array entries, converted to a <code>String</code>, as the * of the array entries, converted to a <code>String</code>, as the key for
* key for the list items and the array values as their elements. * the list items and the array values as their elements.
*/ */
private static class ArrayListModelBuilder implements ListModelBuilder { private static class ArrayListModelBuilder implements ListModelBuilder {
private Object[] m_values; private Object[] m_values;
private boolean m_locked; private boolean m_locked;
@ -764,33 +813,36 @@ public class List extends SimpleComponent implements BebopConstants {
public ListModel makeModel(List l, PageState state) { public ListModel makeModel(List l, PageState state) {
return new ListModel() { return new ListModel() {
private int i = -1;
public boolean next() { private int i = -1;
i += 1;
return ( i < m_values.length );
}
public Object getElement() { public boolean next() {
checkState(); i += 1;
return m_values[i]; return (i < m_values.length);
} }
public String getKey() { public Object getElement() {
checkState(); checkState();
return String.valueOf(i); return m_values[i];
} }
private void checkState() { public String getKey() {
if ( i < 0 ) { checkState();
throw new IllegalStateException return String.valueOf(i);
("Before first item. Call next() first."); }
}
if ( i >= m_values.length ) { private void checkState() {
throw new IllegalStateException("After last item. Model exhausted."); if (i < 0) {
} throw new IllegalStateException(
"Before first item. Call next() first.");
} }
}; if (i >= m_values.length) {
throw new IllegalStateException(
"After last item. Model exhausted.");
}
}
};
} }
public void lock() { public void lock() {
@ -800,22 +852,26 @@ public class List extends SimpleComponent implements BebopConstants {
public final boolean isLocked() { public final boolean isLocked() {
return m_locked; return m_locked;
} }
} }
/** /**
* A {@link ListModel} that has no rows. * A {@link ListModel} that has no rows.
*/ */
public static final ListModel EMPTY_MODEL = new ListModel() { public static final ListModel EMPTY_MODEL = new ListModel() {
public boolean next() {
return false;
}
public String getKey() { public boolean next() {
throw new IllegalStateException("ListModel is empty"); return false;
} }
public String getKey() {
throw new IllegalStateException("ListModel is empty");
}
public Object getElement() {
throw new IllegalStateException("ListModel is empty");
}
};
public Object getElement() {
throw new IllegalStateException("ListModel is empty");
}
};
} }

View File

@ -26,26 +26,29 @@ import com.arsdigita.xml.Element;
/** /**
* A container that outputs its components in a &lt;list&gt;. Each child is * A container that outputs its components in a &lt;list&gt;. Each child is
* printed in its own list item. The components are put into the list * printed in its own list item. The components are put into the list in the
* in the order in which they were added to the * order in which they were added to the <code>ListPanel</code>, progressing
* <code>ListPanel</code>, progressing from top to bottom. * from top to bottom.
* *
* <p> ListPanels can be ordered or unordered.</p> * <p>
* ListPanels can be ordered or unordered.</p>
* *
* @author Christian Brechb&uuml;hler (christian@arsdigita.com) * @author Christian Brechb&uuml;hler (christian@arsdigita.com)
* *
* @version $Id$ * @version $Id$
* */ *
public class ListPanel extends SimpleContainer { */
public class ListPanel extends SimpleContainer {
public static final boolean ORDERED = true ; public static final boolean ORDERED = true;
public static final boolean UNORDERED = false; public static final boolean UNORDERED = false;
private boolean m_ordered; private boolean m_ordered;
/** /**
* Creates a simple list. * Creates a simple list.
*
* @param ordered <code>true</code> is an ordered (numbered) list; * @param ordered <code>true</code> is an ordered (numbered) list;
* <code>false</code> is an unordered (bulleted) list * <code>false</code> is an unordered (bulleted) list
* *
*/ */
public ListPanel(boolean ordered) { public ListPanel(boolean ordered) {
@ -54,32 +57,36 @@ public class ListPanel extends SimpleContainer {
/** /**
* Adds child components as a subtree under list-item nodes. * Adds child components as a subtree under list-item nodes.
* <p>Generates a DOM fragment: * <p>
* <p><pre> * Generates a DOM fragment:
* <p>
* <pre>
* &lt;bebop:listPanel> * &lt;bebop:listPanel>
* &lt;bebop:cell> ... cell contents &lt;/bebop:cell> * &lt;bebop:cell> ... cell contents &lt;/bebop:cell>
* &lt;bebop:cell> ... cell contents &lt;/bebop:cell> * &lt;bebop:cell> ... cell contents &lt;/bebop:cell>
* ... * ...
* &lt;/bebop:list></pre></p> * &lt;/bebop:list></pre></p>
* @param state the state of the current request *
* @param state the state of the current request
* @param parent the node under which this subtree will be added * @param parent the node under which this subtree will be added
*/ */
public void generateXML(PageState state, Element parent) { public void generateXML(PageState state, Element parent) {
if ( ! isVisible(state) ) { if (isVisible(state)) {
return;
}
Element list = parent.newChildElement("bebop:listPanel", BEBOP_XML_NS); Element list = parent.newChildElement("bebop:listPanel",
list.addAttribute("ordered", String.valueOf(m_ordered)); BEBOP_XML_NS);
exportAttributes(list); list.addAttribute("ordered", String.valueOf(m_ordered));
exportAttributes(list);
// generate XML for children // generate XML for children
for (Iterator i = children(); i.hasNext(); ) { for (Iterator i = children(); i.hasNext();) {
Component c = (Component) i.next(); Component c = (Component) i.next();
Element item = list.newChildElement("bebop:cell", BEBOP_XML_NS); Element item = list.newChildElement("bebop:cell", BEBOP_XML_NS);
c.generateXML(state, item); c.generateXML(state, item);
}
} }
} }
} }

View File

@ -1,71 +0,0 @@
/*
* Copyright (C) 2018 LibreCCM Foundation.
*
* 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., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
package com.arsdigita.pagemodel.layout.ui;
import com.arsdigita.bebop.BoxPanel;
import com.arsdigita.bebop.FormData;
import com.arsdigita.bebop.PageState;
import com.arsdigita.bebop.ParameterSingleSelectionModel;
import com.arsdigita.ui.admin.pagemodels.AbstractComponentModelForm;
import com.arsdigita.ui.admin.pagemodels.PageModelsTab;
import org.libreccm.pagemodel.layout.FlexLayout;
/**
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
public class FlexLayoutComponentForm
extends AbstractComponentModelForm<FlexLayout> {
public FlexLayoutComponentForm(
final PageModelsTab pageModelsTab,
final ParameterSingleSelectionModel<String> selectedModelId,
final ParameterSingleSelectionModel<String> selectedComponentId) {
super("FlexLayoutComponentForm",
pageModelsTab,
selectedModelId,
selectedComponentId);
}
@Override
protected void addWidgets() {
final BoxPanel horizontalPanel = new BoxPanel(BoxPanel.HORIZONTAL);
add(horizontalPanel);
}
@Override
protected FlexLayout createComponentModel() {
return new FlexLayout();
}
@Override
protected void updateComponentModel(final FlexLayout componentModel,
final PageState state,
final FormData data) {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
}

View File

@ -29,6 +29,7 @@ import com.arsdigita.bebop.event.FormProcessListener;
import com.arsdigita.bebop.event.FormSectionEvent; import com.arsdigita.bebop.event.FormSectionEvent;
import com.arsdigita.bebop.event.FormValidationListener; import com.arsdigita.bebop.event.FormValidationListener;
import com.arsdigita.bebop.form.TextField; import com.arsdigita.bebop.form.TextField;
import com.arsdigita.bebop.parameters.LongParameter;
import com.arsdigita.globalization.GlobalizedMessage; import com.arsdigita.globalization.GlobalizedMessage;
import com.arsdigita.ui.admin.AdminUiConstants; import com.arsdigita.ui.admin.AdminUiConstants;
@ -239,6 +240,7 @@ public abstract class AbstractComponentModelForm<T extends ComponentModel>
* @throws FormProcessException * @throws FormProcessException
*/ */
@Override @Override
@SuppressWarnings("unchecked")
public void init(final FormSectionEvent event) throws FormProcessException { public void init(final FormSectionEvent event) throws FormProcessException {
final PageState state = event.getPageState(); final PageState state = event.getPageState();
@ -248,18 +250,26 @@ public abstract class AbstractComponentModelForm<T extends ComponentModel>
if (selectedComponentIdStr != null if (selectedComponentIdStr != null
&& !selectedComponentIdStr.isEmpty()) { && !selectedComponentIdStr.isEmpty()) {
final CdiUtil cdiUtil = CdiUtil.createCdiUtil();
componentModel = loadSelectedComponent(
Long.parseLong(selectedComponentIdStr));
keyField.setValue(state, componentModel.getKey());
}
}
@SuppressWarnings("unchecked")
protected T loadSelectedComponent(final long componentId) {
final CdiUtil cdiUtil = CdiUtil.createCdiUtil();
final ComponentModelRepository componentModelRepo = cdiUtil final ComponentModelRepository componentModelRepo = cdiUtil
.findBean(ComponentModelRepository.class); .findBean(ComponentModelRepository.class);
final ComponentModel model = componentModelRepo return (T) componentModelRepo
.findById(Long.parseLong(selectedComponentIdStr)) .findById(componentId)
.orElseThrow(() -> new IllegalArgumentException(String .orElseThrow(() -> new IllegalArgumentException(String
.format("No ComponentModel with ID %s in the database.", .format("No ComponentModel with ID %d in the database.",
selectedComponentIdStr))); componentId)));
keyField.setValue(state, model.getKey());
}
} }
/** /**

View File

@ -0,0 +1,411 @@
/*
* Copyright (C) 2018 LibreCCM Foundation.
*
* 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., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
package com.arsdigita.ui.admin.pagemodels.layout;
import com.arsdigita.bebop.BoxPanel;
import com.arsdigita.bebop.Component;
import com.arsdigita.bebop.FormData;
import com.arsdigita.bebop.FormProcessException;
import com.arsdigita.bebop.Label;
import com.arsdigita.bebop.List;
import com.arsdigita.bebop.PageState;
import com.arsdigita.bebop.ParameterSingleSelectionModel;
import com.arsdigita.bebop.PropertySheet;
import com.arsdigita.bebop.PropertySheetModel;
import com.arsdigita.bebop.PropertySheetModelBuilder;
import com.arsdigita.bebop.event.FormSectionEvent;
import com.arsdigita.bebop.form.Option;
import com.arsdigita.bebop.form.SingleSelect;
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.ui.admin.AdminUiConstants;
import com.arsdigita.ui.admin.pagemodels.AbstractComponentModelForm;
import com.arsdigita.ui.admin.pagemodels.PageModelsTab;
import com.arsdigita.util.LockableImpl;
import com.arsdigita.xml.Element;
import org.libreccm.cdi.utils.CdiUtil;
import org.libreccm.core.UnexpectedErrorException;
import org.libreccm.pagemodel.ComponentModelRepository;
import org.libreccm.pagemodel.layout.FlexBox;
import org.libreccm.pagemodel.layout.FlexDirection;
import org.libreccm.pagemodel.layout.FlexLayout;
import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator;
import java.util.Objects;
/**
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
public class FlexLayoutComponentForm
extends AbstractComponentModelForm<FlexLayout> {
private final ParameterSingleSelectionModel<String> selectedComponentId;
private SingleSelect directionSelect;
// private FlexBoxesPanel boxesPanel;
private List boxesList;
public FlexLayoutComponentForm(
final PageModelsTab pageModelsTab,
final ParameterSingleSelectionModel<String> selectedModelId,
final ParameterSingleSelectionModel<String> selectedComponentId) {
super("FlexLayoutComponentForm",
pageModelsTab,
selectedModelId,
selectedComponentId);
Objects.requireNonNull(pageModelsTab);
Objects.requireNonNull(selectedModelId);
Objects.requireNonNull(selectedComponentId);
this.selectedComponentId = selectedComponentId;
}
@Override
protected void addWidgets() {
directionSelect = new SingleSelect("directionSelect");
directionSelect.setLabel(new GlobalizedMessage(
AdminUiConstants.ADMIN_BUNDLE,
"ui.admin.pagelayout.flexlayout.direction.label"));
directionSelect
.addOption(new Option(
FlexDirection.HORIZONTAL.toString(),
new Label(new GlobalizedMessage(
AdminUiConstants.ADMIN_BUNDLE,
"ui.admin.pagelayout.flexlayout.direction"
+ ".option.horizontal"))));
directionSelect
.addOption(new Option(
FlexDirection.VERTICAL.toString(),
new Label(new GlobalizedMessage(
AdminUiConstants.ADMIN_BUNDLE,
"ui.admin.pagelayout.flexlayout.direction"
+ ".option.vertical"))));
add(directionSelect);
// boxesPanel = new FlexBoxesPanel();
// add(boxesPanel);
boxesList
= new BoxesList(new BoxesListModelBuilder(selectedComponentId));
boxesList.setCellRenderer(new BoxesListCellRenderer());
boxesList.setEmptyView(new Label(new GlobalizedMessage(
"ui.admin.pagelayout.flexlayout.no_boxes",
AdminUiConstants.ADMIN_BUNDLE)));
add(boxesList);
}
@Override
protected FlexLayout createComponentModel() {
return new FlexLayout();
}
@Override
protected void updateComponentModel(final FlexLayout componentModel,
final PageState state,
final FormData data) {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
@Override
public void init(final FormSectionEvent event) throws FormProcessException {
super.init(event);
final PageState state = event.getPageState();
final FlexLayout layout = getComponentModel();
if (layout == null) {
directionSelect.setValue(state, FlexDirection.VERTICAL.toString());
} else {
directionSelect.setValue(state, layout.getDirection().toString());
}
}
// private class FlexBoxesPanel extends SimpleContainer {
//
// private FlexDirection direction;
//
// public FlexBoxesPanel() {
// super("flexLayout", "bebop");
//
// direction = FlexDirection.VERTICAL;
// }
//
// public FlexDirection getDirection() {
// return direction;
// }
//
// public void setFlexDirection(final FlexDirection direction) {
// this.direction = direction;
// }
//
// @Override
// protected Element generateParent(final Element parent) {
//
// final Element element = super.generateParent(parent);
// element.addAttribute("direction", direction
// .toString()
// .toLowerCase());
// return element;
// }
//
// }
private class FlexBoxPanel extends BoxPanel {
private final FlexBox box;
public FlexBoxPanel(final FlexBox box) {
super(BoxPanel.VERTICAL);
this.box = box;
final PropertySheet propertySheet = new PropertySheet(
new FlexBoxPropertySheetModelBuilder(box));
super.add(propertySheet);
}
}
private class FlexBoxPropertySheetModelBuilder
extends LockableImpl
implements PropertySheetModelBuilder {
private final FlexBox box;
public FlexBoxPropertySheetModelBuilder(final FlexBox box) {
this.box = box;
}
@Override
public PropertySheetModel makeModel(final PropertySheet sheet,
final PageState state) {
return new FlexBoxPropertySheetModel(box);
}
}
private class FlexBoxPropertySheetModel implements PropertySheetModel {
private final FlexBox box;
private final Iterator<FlexBoxProperty> propertyIterator;
private FlexBoxProperty currentProperty;
public FlexBoxPropertySheetModel(final FlexBox box) {
this.box = box;
propertyIterator = Arrays
.asList(FlexBoxProperty.values())
.iterator();
}
@Override
public boolean nextRow() {
if (box == null) {
return false;
}
if (propertyIterator.hasNext()) {
currentProperty = propertyIterator.next();
return true;
} else {
return false;
}
}
@Override
public String getLabel() {
return currentProperty.toString();
}
@Override
public GlobalizedMessage getGlobalizedLabel() {
final String key = String
.format("ui.admin.pagemodels.flexlayout.box.properties.%s",
currentProperty.toString().toLowerCase());
return new GlobalizedMessage(key, AdminUiConstants.ADMIN_BUNDLE);
}
@Override
public String getValue() {
switch (currentProperty) {
case ORDER:
return Integer.toString(box.getOrder());
case SIZE:
return Integer.toString(box.getSize());
case COMPONENT:
if (box.getComponent() == null) {
return "";
} else {
return box.getComponent().getClass().getName();
}
default:
throw new UnexpectedErrorException(String
.format("Invalid \"%s\" for property of FlexBox.",
currentProperty.toString()));
}
}
}
private static enum FlexBoxProperty {
ORDER,
SIZE,
COMPONENT
}
private class BoxesList extends List {
private FlexLayout flexLayout;
public BoxesList(final ListModelBuilder listModelBuilder) {
super(listModelBuilder);
}
public FlexLayout getFlexLayout() {
return flexLayout;
}
public void setFlexLayout(final FlexLayout flexLayout) {
this.flexLayout = flexLayout;
}
@Override
protected String getTagName() {
return "flexLayoutBoxesList";
}
@Override
protected void exportLayoutAttribute(final Element list) {
if (flexLayout.getDirection() == FlexDirection.HORIZONTAL) {
list.addAttribute("layout", "horizontal");
} else {
list.addAttribute("layout", "vertical");
}
}
}
private class BoxesListModelBuilder
extends LockableImpl
implements ListModelBuilder {
private final ParameterSingleSelectionModel<String> selectedComponentId;
public BoxesListModelBuilder(
final ParameterSingleSelectionModel<String> selectedComponentId) {
super();
Objects.requireNonNull(selectedComponentId);
this.selectedComponentId = selectedComponentId;
}
@Override
public ListModel makeModel(final List list,
final PageState state) {
if (selectedComponentId.isSelected(state)) {
final CdiUtil cdiUtil = CdiUtil.createCdiUtil();
final ComponentModelRepository componentModelRepo = cdiUtil
.findBean(ComponentModelRepository.class);
final String componentModelId = selectedComponentId
.getSelectedKey(state);
final FlexLayout flexLayout = (FlexLayout) componentModelRepo
.findById(Long.parseLong(componentModelId))
.orElseThrow(() -> new IllegalArgumentException(String
.format("No ComponentModel with ID %s in the database",
componentModelId)));
return new BoxesListModel(flexLayout.getBoxes());
} else {
return new BoxesListModel(Collections.emptyList());
}
}
}
private class BoxesListModel implements ListModel {
private final Iterator<FlexBox> iterator;
private FlexBox currentBox;
public BoxesListModel(final java.util.List<FlexBox> boxes) {
this.iterator = boxes.iterator();
}
@Override
public boolean next() {
if (iterator.hasNext()) {
currentBox = iterator.next();
return true;
} else {
return false;
}
}
@Override
public Object getElement() {
return currentBox;
}
@Override
public String getKey() {
return Long.toString(currentBox.getBoxId());
}
}
private class BoxesListCellRenderer implements ListCellRenderer {
@Override
public Component getComponent(final List list,
final PageState state,
final Object value,
final String key,
final int index,
final boolean isSelected) {
final FlexBox box = (FlexBox) value;
return new FlexBoxPanel(box);
}
}
}

View File

@ -188,7 +188,7 @@ public abstract class AbstractEntityRepository<K, E> implements Serializable {
/** /**
* Finds an entity by its ID and does fetch joins for the provided * Finds an entity by its ID and does fetch joins for the provided
* attributes. Be careful with this method. Do not a too many attributes to * attributes. Be careful with this method. Do not a too many attributes to
* the fetch joins, only does which you really need. Otherwise there can be * the fetch joins, only those which you really need. Otherwise there can be
* a serious performance impact. * a serious performance impact.
* *
* @param entityId The ID of the entity to retrieve. * @param entityId The ID of the entity to retrieve.

View File

@ -18,7 +18,7 @@
*/ */
package org.libreccm.core; package org.libreccm.core;
import com.arsdigita.pagemodel.layout.ui.FlexLayoutComponentForm; import com.arsdigita.ui.admin.pagemodels.layout.FlexLayoutComponentForm;
import com.arsdigita.ui.admin.AdminServlet; import com.arsdigita.ui.admin.AdminServlet;
import com.arsdigita.ui.admin.AdminUiConstants; import com.arsdigita.ui.admin.AdminUiConstants;
import com.arsdigita.ui.admin.applications.AdminApplicationCreator; import com.arsdigita.ui.admin.applications.AdminApplicationCreator;

View File

@ -23,10 +23,23 @@ import org.libreccm.core.CoreConstants;
import org.libreccm.security.AuthorizationRequired; import org.libreccm.security.AuthorizationRequired;
import org.libreccm.security.RequiresPrivilege; import org.libreccm.security.RequiresPrivilege;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import javax.enterprise.context.RequestScoped; import javax.enterprise.context.RequestScoped;
import javax.transaction.Transactional; import javax.transaction.Transactional;
import java.util.UUID; import java.util.UUID;
import javax.persistence.EntityGraph;
import javax.persistence.NoResultException;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Root;
/** /**
* Repository class for managing {@link ComponentModel} entities. * Repository class for managing {@link ComponentModel} entities.
* *
@ -47,7 +60,7 @@ public class ComponentModelRepository
public String getIdAttributeName() { public String getIdAttributeName() {
return "componentModelId"; return "componentModelId";
} }
@Override @Override
public Long getIdOfEntity(final ComponentModel entity) { public Long getIdOfEntity(final ComponentModel entity) {
return entity.getComponentModelId(); return entity.getComponentModelId();
@ -83,4 +96,69 @@ public class ComponentModelRepository
} }
} }
@Transactional(Transactional.TxType.REQUIRED)
public <M extends ComponentModel> Optional<M> findById(final long modelId,
final Class<M> modelClass) {
return Optional.ofNullable(getEntityManager().find(modelClass,
modelId));
}
@Transactional(Transactional.TxType.REQUIRED)
public <M extends ComponentModel> Optional<M> findById(
final long modelId,
final Class<M> modelClass,
final String entityGraphName) {
return Optional.ofNullable(getEntityManager().find(modelClass,
modelId));
}
@Transactional(Transactional.TxType.REQUIRED)
public <M extends ComponentModel> Optional<M> findById(
final long entityId,
final Class<M> modelClass,
final EntityGraph<M> entityGraph) {
Objects.requireNonNull(entityId);
Objects.requireNonNull(entityGraph);
final Map<String, Object> hints = new HashMap<>();
hints.put(FETCH_GRAPH_HINT_KEY, entityGraph);
return Optional.ofNullable(getEntityManager().find(modelClass,
entityId,
hints));
}
@Transactional(Transactional.TxType.REQUIRED)
public <M extends ComponentModel> Optional<M> findById(
final long entityId,
final Class<M> modelClass,
final String... fetchJoins) {
Objects.requireNonNull(entityId);
final CriteriaBuilder builder = getEntityManager()
.getCriteriaBuilder();
final CriteriaQuery<M> criteriaQuery = builder
.createQuery(modelClass);
final Root<M> from = criteriaQuery.from(modelClass);
criteriaQuery.from(getEntityClass());
criteriaQuery.select(from);
for (final String fetchJoin : fetchJoins) {
from.fetch(fetchJoin);
}
criteriaQuery
.where(builder.equal(from.get(getIdAttributeName()), entityId));
final TypedQuery<M> query = getEntityManager()
.createQuery(criteriaQuery);
try {
return Optional.of(query.getSingleResult());
} catch (NoResultException ex) {
return Optional.empty();
}
}
} }

View File

@ -56,6 +56,7 @@ public class FlexBox implements Serializable {
private long boxId; private long boxId;
@ManyToOne @ManyToOne
@JoinColumn(name = "LAYOUT_ID")
private FlexLayout layout; private FlexLayout layout;
@Column(name = "BOX_ORDER") @Column(name = "BOX_ORDER")

View File

@ -46,7 +46,7 @@ import javax.persistence.Table;
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a> * @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/ */
@Entity @Entity
@Table(name = "HORIZONTAL_LAYOUT_COMPONENTS", schema = CoreConstants.DB_SCHEMA) @Table(name = "FLEX_LAYOUT_COMPONENTS", schema = CoreConstants.DB_SCHEMA)
public class FlexLayout extends ComponentModel { public class FlexLayout extends ComponentModel {
private static final long serialVersionUID = 1977244351125227610L; private static final long serialVersionUID = 1977244351125227610L;
@ -65,7 +65,6 @@ public class FlexLayout extends ComponentModel {
*/ */
@OneToMany(mappedBy = "layout") @OneToMany(mappedBy = "layout")
@OrderBy(value = "order") @OrderBy(value = "order")
@JoinColumn(name = "LAYOUT_ID")
private List<FlexBox> boxes; private List<FlexBox> boxes;
public FlexLayout() { public FlexLayout() {

View File

@ -59,7 +59,7 @@ public class FlexLayoutRenderer implements ComponentRenderer<FlexLayout> {
componentModel componentModel
.getBoxes() .getBoxes()
.stream() .stream()
.map(this::renderBox) .map(box -> renderBox(box, parameters))
.collect(Collectors.toList())); .collect(Collectors.toList()));
return result; return result;

View File

@ -40,7 +40,7 @@ import javax.ws.rs.core.Response;
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a> * @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/ */
@RequestScoped @RequestScoped
@Path("/{theme}") @Path("/files/{theme}")
public class ThemeFiles { public class ThemeFiles {
@Inject @Inject

View File

@ -0,0 +1,106 @@
/*
* Copyright (C) 2018 LibreCCM Foundation.
*
* 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., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
package org.libreccm.theming;
import org.libreccm.webdav.methods.PROPFIND;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;
import javax.ws.rs.GET;
import javax.ws.rs.NotFoundException;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
/**
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
@RequestScoped
@Path("/dav/{theme}")
public class ThemeFilesDav {
@Inject
private Themes themes;
@GET
@Path("/{path}")
public Response getFile(@PathParam("theme") final String theme,
@PathParam("path") final String path) {
final ThemeInfo info = themes
.getTheme(theme, ThemeVersion.LIVE)
.orElseThrow(() -> new NotFoundException(String
.format("Theme \"%s\" does not exist.", theme)));
final InputStream inputStream = themes
.getFileFromTheme(info, path)
.orElseThrow(() -> new NotFoundException(String
.format("The file \"%s\" does exist in the theme \"%s\".",
path,
theme)));
final MediaType mediaType = getMediaTypeFromPath(path);
final BufferedReader reader = new BufferedReader(
new InputStreamReader(inputStream));
final ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
try {
int value = reader.read();
while (value != -1) {
outputStream.write(value);
value = reader.read();
}
} catch (IOException ex) {
throw new WebApplicationException(ex);
}
final byte[] data = outputStream.toByteArray();
return Response.ok(data, mediaType).build();
}
@PROPFIND
@Path("/{path}")
public Response propfind(@PathParam("theme") final String theme,
@PathParam("path") final String path) {
throw new UnsupportedOperationException();
}
private MediaType getMediaTypeFromPath(final String path) {
if (path.endsWith(".css")) {
return new MediaType("text", "css");
} else {
return MediaType.WILDCARD_TYPE;
}
}
}

View File

@ -36,6 +36,7 @@ public class ThemesService extends Application {
final Set<Class<?>> classes = new HashSet<>(); final Set<Class<?>> classes = new HashSet<>();
classes.add(ThemeFiles.class); classes.add(ThemeFiles.class);
classes.add(ThemeFilesDav.class);
return classes; return classes;
} }

View File

@ -0,0 +1,179 @@
/*
* Copyright (C) 2018 LibreCCM Foundation.
*
* 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., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
package org.libreccm.webdav;
/**
* WebDAV Headers.
*
* The class is based on a class/interface from java.net WebDAV Project:
*
* <a href="https://gitlab.com/headcrashing/webdav-jaxrs/blob/master/src/main/java/net/java/dev/webdav/jaxrs/Headers.java">https://gitlab.com/headcrashing/webdav-jaxrs/blob/master/src/main/java/net/java/dev/webdav/jaxrs/Headers.java</a>
*
*
* @author <a href="mailto:karg@java.net">Markus KARG</a>
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*
* @see
* <a href="http://www.webdav.org/specs/rfc4918.html#http.headers.for.distributed.authoring">
* Chapter 10 "HTTP Headers for Distributed Authoring" of RFC 4918 "HTTP
* Extensions for Web Distributed Authoring and Versioning (WebDAV)"
* </a>
*/
public final class Headers {
/**
* WebDAV DAV Header
*
* @see
* <a href="http://www.webdav.org/specs/rfc4918.html#HEADER_DAV">Chapter
* 10.1 "DAV Header" of RFC 4918 "HTTP Extensions for Web Distributed
* Authoring and Versioning (WebDAV)"</a>
*/
public static final String DAV = "DAV";
/**
* WebDAV Depth Header
*
* @see
* <a href="http://www.webdav.org/specs/rfc4918.html#HEADER_Depth">Chapter
* 10.2 "Depth Header" of RFC 4918 "HTTP Extensions for Web Distributed
* Authoring and Versioning (WebDAV)"</a>
*/
public static final String DEPTH = "Depth";
/**
* WebDAV Depth Header Value "0"
*
* @see
* <a href="http://www.webdav.org/specs/rfc4918.html#HEADER_Depth">Chapter
* 10.2 "Depth Header" of RFC 4918 "HTTP Extensions for Web Distributed
* Authoring and Versioning (WebDAV)"</a>
*/
public static final String DEPTH_0 = "0";
/**
* WebDAV Depth Header Value "1"
*
* @see
* <a href="http://www.webdav.org/specs/rfc4918.html#HEADER_Depth">Chapter
* 10.2 "Depth Header" of RFC 4918 "HTTP Extensions for Web Distributed
* Authoring and Versioning (WebDAV)"</a>
*/
public static final String DEPTH_1 = "1";
/**
* WebDAV Depth Header Value "infinity"
*
* @see
* <a href="http://www.webdav.org/specs/rfc4918.html#HEADER_Depth">Chapter
* 10.2 "Depth Header" of RFC 4918 "HTTP Extensions for Web Distributed
* Authoring and Versioning (WebDAV)"</a>
*/
public static final String DEPTH_INFINITY = "infinity";
/**
* WebDAV Destination Header
*
* @see
* <a href="http://www.webdav.org/specs/rfc4918.html#HEADER_Destination">Chapter
* 10.3 "Destination Header" of RFC 4918 "HTTP Extensions for Web
* Distributed Authoring and Versioning (WebDAV)"</a>
*/
public static final String DESTINATION = "Destination";
/**
* WebDAV If Header
*
* @see <a href="http://www.webdav.org/specs/rfc4918.html#HEADER_If">Chapter
* 10.4 "If Header" of RFC 4918 "HTTP Extensions for Web Distributed
* Authoring and Versioning (WebDAV)"</a>
*/
public static final String IF = "If";
/**
* WebDAV Lock-Token Header
*
* @see
* <a href="http://www.webdav.org/specs/rfc4918.html#HEADER_Lock-Token">Chapter
* 10.5 "Lock-Token Header" of RFC 4918 "HTTP Extensions for Web Distributed
* Authoring and Versioning (WebDAV)"</a>
*/
public static final String LOCK_TOKEN = "Lock-Token";
/**
* WebDAV Overwrite Header
*
* @see
* <a href="http://www.webdav.org/specs/rfc4918.html#HEADER_Overwrite">Chapter
* 10.6 "Overwrite Header" of RFC 4918 "HTTP Extensions for Web Distributed
* Authoring and Versioning (WebDAV)"</a>
*/
public static final String OVERWRITE = "Overwrite";
/**
* WebDAV Overwrite Header Value "T"
*
* @see
* <a href="http://www.webdav.org/specs/rfc4918.html#HEADER_Overwrite">Chapter
* 10.6 "Overwrite Header" of RFC 4918 "HTTP Extensions for Web Distributed
* Authoring and Versioning (WebDAV)"</a>
*/
public static final String OVERWRITE_TRUE = "T";
/**
* WebDAV Overwrite Header Value "F"
*
* @see
* <a href="http://www.webdav.org/specs/rfc4918.html#HEADER_Overwrite">Chapter
* 10.6 "Overwrite Header" of RFC 4918 "HTTP Extensions for Web Distributed
* Authoring and Versioning (WebDAV)"</a>
*/
public static final String OVERWRITE_FALSE = "F";
/**
* WebDAV Timeout Header
*
* @see
* <a href="http://www.webdav.org/specs/rfc4918.html#HEADER_Timeout">Chapter
* 10.7 "Timeout Request Header" of RFC 4918 "HTTP Extensions for Web
* Distributed Authoring and Versioning (WebDAV)"</a>
*/
public static final String TIMEOUT = "Timeout";
/**
* WebDAV Timeout Header Value "Second-"
*
* @see
* <a href="http://www.webdav.org/specs/rfc4918.html#HEADER_Timeout">Chapter
* 10.7 "Timeout Request Header" of RFC 4918 "HTTP Extensions for Web
* Distributed Authoring and Versioning (WebDAV)"</a>
*/
public static final String TIMEOUT_SECOND = "Second-";
/**
* WebDAV Timeout Header Value "Infinite"
*
* @see
* <a href="http://www.webdav.org/specs/rfc4918.html#HEADER_Timeout">Chapter
* 10.7 "Timeout Request Header" of RFC 4918 "HTTP Extensions for Web
* Distributed Authoring and Versioning (WebDAV)"</a>
*/
public static final String TIMEOUT_INFINITE = "Infinite";
}

View File

@ -0,0 +1,131 @@
/*
* Copyright (C) 2018 LibreCCM Foundation.
*
* 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., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
package org.libreccm.webdav;
import javax.ws.rs.core.Response;
import static javax.ws.rs.core.Response.Status.Family.*;
/**
* Commonly used status codes defined by WebDAV.
*
* The enum is based on an enum from the java.net WebDAV project:
*
* <a href="https://gitlab.com/headcrashing/webdav-jaxrs/blob/master/src/main/java/net/java/dev/webdav/jaxrs/ResponseStatus.java">https://gitlab.com/headcrashing/webdav-jaxrs/blob/master/src/main/java/net/java/dev/webdav/jaxrs/ResponseStatus.java</a>
*
* @author <a href="mailto:mkarg@java.net">Markus KARG</a>
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*
* @see
* <a href="http://www.webdav.org/specs/rfc4918.html#status.code.extensions.to.http11">Chapter
* 11 "Status Code Extensions to HTTP/1.1" of RFC 4918 "HTTP Extensions for Web
* Distributed Authoring and Versioning (WebDAV)"</a>
*/
public enum ResponseStatus implements Response.StatusType {
/**
* 207 Multi-Status
*
* @see
* <a href="http://www.webdav.org/specs/rfc4918.html#STATUS_207">Chapter
* 11.1 "207 Multi-Status" of RFC 4918 "HTTP Extensions for Web Distributed
* Authoring and Versioning (WebDAV)"</a>
*/
MULTI_STATUS(207, "Multi-Status"),
/**
* 422 Unprocessable Entity
*
* @see
* <a href="http://www.webdav.org/specs/rfc4918.html#STATUS_422">Chapter
* 11.2 "422 Unprocessable Entity" of RFC 4918 "HTTP Extensions for Web
* Distributed Authoring and Versioning (WebDAV)"</a>
*/
UNPROCESSABLE_ENTITY(422, "Unprocessable Entity"),
/**
* 423 Locked
*
* @see
* <a href="http://www.webdav.org/specs/rfc4918.html#STATUS_423">Chapter
* 11.3 "423 Locked" of RFC 4918 "HTTP Extensions for Web Distributed
* Authoring and Versioning (WebDAV)"</a>
*/
LOCKED(423, "Locked"),
/**
* 424 Failed Dependency
*
* @see
* <a href="http://www.webdav.org/specs/rfc4918.html#STATUS_424">Chapter
* 11.4 "424 Failed Dependency" of RFC 4918 "HTTP Extensions for Web
* Distributed Authoring and Versioning (WebDAV)"</a>
*/
FAILED_DEPENDENCY(424, "Failed Dependency"),
/**
* 507 Insufficient Storage
*
* @see
* <a href="http://www.webdav.org/specs/rfc4918.html#STATUS_507">Chapter
* 11.5 "507 Insufficient Storage" of RFC 4918 "HTTP Extensions for Web
* Distributed Authoring and Versioning (WebDAV)"</a>
*/
INSUFFICIENT_STORAGE(507, "Insufficient Storage");
private final int statusCode;
private final String reasonPhrase;
private ResponseStatus(final int statusCode, final String reasonPhrase) {
this.statusCode = statusCode;
this.reasonPhrase = reasonPhrase;
}
@Override
public int getStatusCode() {
return statusCode;
}
@Override
public Response.Status.Family getFamily() {
switch (this.statusCode / 100) {
case 1:
return INFORMATIONAL;
case 2:
return SUCCESSFUL;
case 3:
return REDIRECTION;
case 4:
return CLIENT_ERROR;
case 5:
return SERVER_ERROR;
default:
return OTHER;
}
}
@Override
public String getReasonPhrase() {
return reasonPhrase;
}
@Override
public String toString() {
return reasonPhrase;
}
}

View File

@ -0,0 +1,49 @@
/*
* #%L
* WebDAV Support for JAX-RS
* %%
* Copyright (C) 2008 - 2018 The java.net WebDAV Project
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program. If not, see
* <http://www.gnu.org/licenses/gpl-3.0.html>.
* #L%
*/
package org.libreccm.webdav.methods;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import javax.ws.rs.HttpMethod;
import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.*;
/**
* Indicates that the annotated method responds to WebDAV COPY requests.
*
* Adopted from
* <a href="https://gitlab.com/headcrashing/webdav-jaxrs/blob/master/src/main/java/net/java/dev/webdav/jaxrs/methods/COPY.java">https://gitlab.com/headcrashing/webdav-jaxrs/blob/master/src/main/java/net/java/dev/webdav/jaxrs/methods/COPY.java</a>
*
* @author Markus KARG (mkarg@java.net)
*
* @see <a href="http://www.webdav.org/specs/rfc4918.html#METHOD_COPY">Chapter
* 9.8 "COPY Method" of RFC 4918 "HTTP Extensions for Web Distributed Authoring
* and Versioning (WebDAV)"</a>
*/
@Target(METHOD)
@Retention(RUNTIME)
@HttpMethod("COPY")
public @interface COPY {
// Has no members.
}

View File

@ -0,0 +1,49 @@
/*
* #%L
* WebDAV Support for JAX-RS
* %%
* Copyright (C) 2008 - 2018 The java.net WebDAV Project
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program. If not, see
* <http://www.gnu.org/licenses/gpl-3.0.html>.
* #L%
*/
package org.libreccm.webdav.methods;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import javax.ws.rs.HttpMethod;
import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.*;
/**
* Indicates that the annotated method responds to WebDAV LOCK requests.
*
* Adopted from
* <a href="https://gitlab.com/headcrashing/webdav-jaxrs/blob/master/src/main/java/net/java/dev/webdav/jaxrs/methods/LOCK.java">https://gitlab.com/headcrashing/webdav-jaxrs/blob/master/src/main/java/net/java/dev/webdav/jaxrs/methods/LOCK.java</a>
*
* @author Markus KARG (mkarg@java.net)
*
* @see <a href="http://www.webdav.org/specs/rfc4918.html#METHOD_LOCK">Chapter
* 9.10 "LOCK Method" of RFC 4918 "HTTP Extensions for Web Distributed Authoring
* and Versioning (WebDAV)"</a>
*/
@Target(METHOD)
@Retention(RUNTIME)
@HttpMethod("LOCK")
public @interface LOCK {
// Has no members.
}

View File

@ -0,0 +1,47 @@
/*
* #%L
* WebDAV Support for JAX-RS
* %%
* Copyright (C) 2008 - 2018 The java.net WebDAV Project
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program. If not, see
* <http://www.gnu.org/licenses/gpl-3.0.html>.
* #L%
*/
package org.libreccm.webdav.methods;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import javax.ws.rs.HttpMethod;
import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.*;
/**
* Indicates that the annotated method responds to WebDAV MKCOL requests.
*
* Adopted from <a href="https://gitlab.com/headcrashing/webdav-jaxrs/blob/master/src/main/java/net/java/dev/webdav/jaxrs/methods/MKCOL.java">https://gitlab.com/headcrashing/webdav-jaxrs/blob/master/src/main/java/net/java/dev/webdav/jaxrs/methods/MKCOL.java</a>
*
* @author Markus KARG (mkarg@java.net)
*
* @see <a href="http://www.webdav.org/specs/rfc4918.html#METHOD_MKCOL">Chapter 9.3 "MKCOL Method" of RFC 4918
* "HTTP Extensions for Web Distributed Authoring and Versioning (WebDAV)"</a>
*/
@Target(METHOD)
@Retention(RUNTIME)
@HttpMethod("MKCOL")
public @interface MKCOL {
// Has no members.
}

View File

@ -0,0 +1,47 @@
/*
* #%L
* WebDAV Support for JAX-RS
* %%
* Copyright (C) 2008 - 2018 The java.net WebDAV Project
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program. If not, see
* <http://www.gnu.org/licenses/gpl-3.0.html>.
* #L%
*/
package org.libreccm.webdav.methods;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import javax.ws.rs.HttpMethod;
import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.*;
/**
* Indicates that the annotated method responds to WebDAV MOVE requests.
*
* Adopted from <a href="https://gitlab.com/headcrashing/webdav-jaxrs/blob/master/src/main/java/net/java/dev/webdav/jaxrs/methods/MOVE.java">https://gitlab.com/headcrashing/webdav-jaxrs/blob/master/src/main/java/net/java/dev/webdav/jaxrs/methods/MOVE.java</a>
*
* @author Markus KARG (mkarg@java.net)
*
* @see <a href="http://www.webdav.org/specs/rfc4918.html#METHOD_MOVE">Chapter 9.9 "COPY Method" of RFC 4918
* "HTTP Extensions for Web Distributed Authoring and Versioning (WebDAV)"</a>
*/
@Target(METHOD)
@Retention(RUNTIME)
@HttpMethod("MOVE")
public @interface MOVE {
// Has no members.
}

View File

@ -0,0 +1,47 @@
/*
* #%L
* WebDAV Support for JAX-RS
* %%
* Copyright (C) 2008 - 2018 The java.net WebDAV Project
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program. If not, see
* <http://www.gnu.org/licenses/gpl-3.0.html>.
* #L%
*/
package org.libreccm.webdav.methods;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import javax.ws.rs.HttpMethod;
import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.*;
/**
* Indicates that the annotated method responds to WebDAV PROPFIND requests.
*
* Adopted from <a href="https://gitlab.com/headcrashing/webdav-jaxrs/blob/master/src/main/java/net/java/dev/webdav/jaxrs/methods/PROPFIND.java">https://gitlab.com/headcrashing/webdav-jaxrs/blob/master/src/main/java/net/java/dev/webdav/jaxrs/methods/PROPFIND.java</a>
*
* @author Markus KARG (mkarg@java.net)
*
* @see <a href="http://www.webdav.org/specs/rfc4918.html#METHOD_PROPFIND">Chapter 9.1 "PROPFIND Method" of RFC 4918
* "HTTP Extensions for Web Distributed Authoring and Versioning (WebDAV)"</a>
*/
@Target(METHOD)
@Retention(RUNTIME)
@HttpMethod("PROPFIND")
public @interface PROPFIND {
// Has no members.
}

View File

@ -0,0 +1,47 @@
/*
* #%L
* WebDAV Support for JAX-RS
* %%
* Copyright (C) 2008 - 2018 The java.net WebDAV Project
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program. If not, see
* <http://www.gnu.org/licenses/gpl-3.0.html>.
* #L%
*/
package org.libreccm.webdav.methods;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import javax.ws.rs.HttpMethod;
import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.*;
/**
* Indicates that the annotated method responds to WebDAV PROPPATCH requests.
*
* Adopted from <a href="https://gitlab.com/headcrashing/webdav-jaxrs/blob/master/src/main/java/net/java/dev/webdav/jaxrs/methods/PROPPATCH.java">https://gitlab.com/headcrashing/webdav-jaxrs/blob/master/src/main/java/net/java/dev/webdav/jaxrs/methods/PROPPATCH.java</a>
*
* @author Markus KARG (mkarg@java.net)
*
* @see <a href="http://www.webdav.org/specs/rfc4918.html#METHOD_PROPPATCH">Chapter 9.2 "PROPPATCH Method" of RFC 4918
* "HTTP Extensions for Web Distributed Authoring and Versioning (WebDAV)"</a>
*/
@Target(METHOD)
@Retention(RUNTIME)
@HttpMethod("PROPPATCH")
public @interface PROPPATCH {
// Has no members.
}

View File

@ -0,0 +1,47 @@
/*
* #%L
* WebDAV Support for JAX-RS
* %%
* Copyright (C) 2008 - 2018 The java.net WebDAV Project
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program. If not, see
* <http://www.gnu.org/licenses/gpl-3.0.html>.
* #L%
*/
package org.libreccm.webdav.methods;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import javax.ws.rs.HttpMethod;
import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.*;
/**
* Indicates that the annotated method responds to WebDAV UNLOCK requests.
*
* Adopted from <a href="https://gitlab.com/headcrashing/webdav-jaxrs/blob/master/src/main/java/net/java/dev/webdav/jaxrs/methods/UNLOCK.java">https://gitlab.com/headcrashing/webdav-jaxrs/blob/master/src/main/java/net/java/dev/webdav/jaxrs/methods/UNLOCK.java</a>
*
* @author Markus KARG (mkarg@java.net)
*
* @see <a href="http://www.webdav.org/specs/rfc4918.html#METHOD_UNLOCK">Chapter 9.11 "UNLOCK Method" of RFC 4918
* "HTTP Extensions for Web Distributed Authoring and Versioning (WebDAV)"</a>
*/
@Target(METHOD)
@Retention(RUNTIME)
@HttpMethod("UNLOCK")
public @interface UNLOCK {
// Has no members.
}

View File

@ -0,0 +1,22 @@
/*
* Copyright (C) 2018 LibreCCM Foundation.
*
* 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., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
/**
* Annotations for the WebDAV HTTP methods.
*/
package org.libreccm.webdav.methods;

View File

@ -0,0 +1,29 @@
/*
* Copyright (C) 2018 LibreCCM Foundation.
*
* 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., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
/**
* Annotations and classes for exposing resources via WebDAV using JAX-RS.
* The classes in these packages are based on classes originally created for
* JAX-RS. This project was hosted on the now defunct dev.java.net site. The
* sources now be found at {@link https://gitlab.com/headcrashing/webdav-jaxrs}.
* Unfortunately the project is not maintained anymore and has not been updated
* for JAX-RS 2. Therefore we used the classes only as foundation for our
* implementation. The classes have been edited to match our coding standards
* and to be compatible with new versions of JAX-RS and other libraries.
*/
package org.libreccm.webdav;