/** * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.brixcms.plugin.site.picker.reference; import java.io.Serializable; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Optional; import org.apache.wicket.Component; import org.apache.wicket.ajax.AjaxRequestTarget; import org.apache.wicket.ajax.markup.html.AjaxLink; import org.apache.wicket.ajax.markup.html.form.AjaxButton; import org.apache.wicket.markup.html.WebMarkupContainer; import org.apache.wicket.markup.html.form.Form; import org.apache.wicket.markup.html.form.FormComponent; import org.apache.wicket.markup.html.form.TextField; import org.apache.wicket.markup.html.panel.FeedbackPanel; import org.apache.wicket.markup.html.panel.Panel; import org.apache.wicket.model.CompoundPropertyModel; import org.apache.wicket.model.IModel; import org.apache.wicket.model.Model; import org.apache.wicket.model.PropertyModel; import org.apache.wicket.model.ResourceModel; import org.apache.wicket.util.lang.Objects; import org.brixcms.web.BrixFeedbackPanel; import org.brixcms.web.generic.BrixGenericPanel; import org.brixcms.web.nodepage.BrixPageParameters; import org.brixcms.web.util.DisabledClassAppender; import com.inmethod.grid.IDataSource; import com.inmethod.grid.IGridColumn; import com.inmethod.grid.SizeUnit; import com.inmethod.grid.column.AbstractColumn; import com.inmethod.grid.column.CheckBoxColumn; import com.inmethod.grid.column.editable.EditablePropertyColumn; import com.inmethod.grid.column.editable.SubmitCancelColumn; import com.inmethod.grid.datagrid.DataGrid; public abstract class IndexedParametersTab extends Panel { private AjaxLink<?> removeSelected; private Entry newEntry = new Entry(); private final DataSource dataSource = new DataSource(); public IndexedParametersTab(String id) { super(id); setOutputMarkupId(true); final FeedbackPanel feedback = new BrixFeedbackPanel("feedback"); feedback.setOutputMarkupId(true); add(feedback); Form<Entry> newForm = new Form<Entry>("newForm", new CompoundPropertyModel<Entry>(new PropertyModel<Entry>(this, "newEntry"))); add(newForm); newForm.add(new TextField<String>("value").setRequired(true)); newForm.add(new AjaxButton("add") { @Override protected void onSubmit(AjaxRequestTarget target) { dataSource.addEntry(newEntry); dataSource.storeToPageParameters(); target.add(IndexedParametersTab.this); newEntry = new Entry(); } @Override protected void onError(AjaxRequestTarget target) { target.add(feedback); } }); List<IGridColumn> columns = new ArrayList<IGridColumn>(); columns.add(new CheckBoxColumn("checkbox")); columns.add(new EditablePropertyColumn(new ResourceModel("value"), "value") { @Override protected void addValidators(FormComponent component) { component.setRequired(true); } }); columns.add(new SubmitCancelColumn("submitCancel", new ResourceModel("edit")) { @Override protected void onSubmitted(AjaxRequestTarget target, IModel rowModel, WebMarkupContainer rowComponent) { dataSource.storeToPageParameters(); super.onSubmitted(target, rowModel, rowComponent); target.add(feedback); } @Override protected void onError(AjaxRequestTarget target, IModel rowModel, WebMarkupContainer rowComponent) { target.add(feedback); } }); columns.add(new AbstractColumn("move", new ResourceModel("move")) { @Override public Component newCell(WebMarkupContainer parent, String componentId, IModel rowModel) { final AbstractColumn column = this; return new MovePanel(componentId, rowModel) { @Override protected DataGrid getGrid() { return (DataGrid) column.getGrid(); } }; } }.setInitialSize(5).setSizeUnit(SizeUnit.EM).setResizable(false)); final DataGrid grid = new DataGrid("grid", dataSource, columns) { @Override public void onItemSelectionChanged(IModel item, boolean newValue) { Optional<AjaxRequestTarget> target = getRequestCycle().find(AjaxRequestTarget.class); if (target.isPresent()) { target.get().add(removeSelected); } super.onItemSelectionChanged(item, newValue); } }; grid.setRowsPerPage(Integer.MAX_VALUE); grid.setAllowSelectMultiple(true); grid.setContentHeight(14, SizeUnit.EM); grid.setSelectToEdit(false); add(grid); add(removeSelected = new AjaxLink<Void>("removeSelected") { @Override public void onClick(AjaxRequestTarget target) { Collection<IModel> items = grid.getSelectedItems(); if (items.size() > 0) { for (IModel model : items) { Entry entry = (Entry) model.getObject(); dataSource.removeEntry(entry); } grid.resetSelectedItems(); dataSource.storeToPageParameters(); grid.markAllItemsDirty(); grid.update(); } else { target.appendJavaScript("alert('" + getString("noItemsSelected") + "');"); } } @Override public boolean isEnabled() { return !grid.getSelectedItems().isEmpty(); } }); removeSelected.add(new DisabledClassAppender()); } protected abstract BrixPageParameters getPageParameters(); private abstract class MovePanel extends BrixGenericPanel<Entry> { public MovePanel(String id, IModel<Entry> model) { super(id, model); add(new AjaxLink<Void>("up") { @Override public boolean isEnabled() { return dataSource.canMoveUp(getEntry()); } @Override public void onClick(AjaxRequestTarget target) { dataSource.moveUp(getEntry()); getGrid().markAllItemsDirty(); getGrid().update(); } }.add(new DisabledClassAppender())); add(new AjaxLink<Void>("down") { @Override public boolean isEnabled() { return dataSource.canMoveDown(getEntry()); } @Override public void onClick(AjaxRequestTarget target) { dataSource.moveDown(getEntry()); getGrid().markAllItemsDirty(); getGrid().update(); } }.add(new DisabledClassAppender())); } private Entry getEntry() { return getModelObject(); } protected abstract DataGrid getGrid(); } private class DataSource implements IDataSource { public void detach() { } public IModel model(Object object) { // FIXME: Code duplication return new Model<Serializable>((Serializable) object) { @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj instanceof Model == false) { return false; } Model that = (Model) obj; return Objects.equal(getObject(), that.getObject()); } @Override public int hashCode() { return getObject().hashCode(); } }; } public void query(IQuery query, IQueryResult result) { result.setTotalCount(getEntries().size()); result.setItems(getEntries().iterator()); } private List<Entry> getEntries() { if (entries == null) { entries = new ArrayList<Entry>(); for (int i = 0; i < getPageParameters().getIndexedCount(); ++i) { Entry entry = new Entry(); entry.value = getPageParameters().get(i).toString(); entries.add(entry); } } return entries; } private void storeToPageParameters() { if (entries != null) { getPageParameters().clearIndexed(); int index = 0; for (Entry entry : entries) { getPageParameters().set(index, entry.value); ++index; } } } private void addEntry(Entry entry) { entries.add(entry); } private void removeEntry(Entry entry) { entries.remove(entry); } private boolean canMoveUp(Entry entry) { return getEntries().indexOf(entry) > 0; } private void moveUp(Entry entry) { int index = getEntries().indexOf(entry); if (index > 0) { getEntries().remove(index); getEntries().add(index - 1, entry); } } private boolean canMoveDown(Entry entry) { int index = getEntries().indexOf(entry); return index >= 0 && index < getEntries().size() - 1; } private void moveDown(Entry entry) { int index = getEntries().indexOf(entry); if (index >= 0 && index < getEntries().size() - 1) { getEntries().remove(index); getEntries().add(index + 1, entry); } } private List<Entry> entries = null; } private class Entry implements Serializable { private String value; } ; }