View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.syncope.client.ui.commons.markup.html.form;
20  
21  import java.util.List;
22  import org.apache.syncope.client.ui.commons.Constants;
23  import org.apache.syncope.client.ui.commons.ajax.markup.html.IndicatorAjaxSubmitLink;
24  import org.apache.syncope.client.ui.commons.pages.BaseWebPage;
25  import org.apache.wicket.ajax.AjaxRequestTarget;
26  import org.apache.wicket.markup.html.WebMarkupContainer;
27  import org.apache.wicket.markup.html.basic.Label;
28  import org.apache.wicket.markup.html.form.Form;
29  import org.apache.wicket.markup.html.list.ListItem;
30  import org.apache.wicket.markup.html.list.ListView;
31  import org.apache.wicket.markup.html.panel.Fragment;
32  import org.apache.wicket.markup.html.panel.Panel;
33  import org.apache.wicket.model.IModel;
34  import org.apache.wicket.model.ResourceModel;
35  import org.springframework.util.CollectionUtils;
36  
37  public abstract class AbstractMultiPanel<INNER> extends AbstractFieldPanel<List<INNER>> {
38  
39      private static final long serialVersionUID = -6322397761456513324L;
40  
41      private final ListView<INNER> view;
42  
43      private final WebMarkupContainer container;
44  
45      private final Form<?> form;
46  
47      public AbstractMultiPanel(
48              final String id,
49              final String name,
50              final IModel<List<INNER>> model) {
51  
52          super(id, name, model);
53  
54          // -----------------------
55          // Object container definition
56          // -----------------------
57          container = new WebMarkupContainer("multiValueContainer");
58          container.setOutputMarkupId(true);
59          add(container);
60  
61          form = new Form<>("innerForm");
62          form.setDefaultButton(null);
63          container.add(form);
64          // -----------------------
65  
66          view = new InnerView("view", name, model);
67  
68          if (CollectionUtils.isEmpty(model.getObject())) {
69              form.addOrReplace(getNoDataFragment(model, name));
70          } else {
71              form.addOrReplace(getDataFragment());
72          }
73      }
74  
75      // SYNCOPE-1476
76      public AbstractMultiPanel<INNER> setFormAsMultipart(final boolean multipart) {
77          form.setMultiPart(multipart);
78          return this;
79      }
80  
81      private Fragment getNoDataFragment(final IModel<List<INNER>> model, final String label) {
82          Fragment fragment = new Fragment("content", "noDataFragment", AbstractMultiPanel.this);
83          fragment.add(new Label("field-label", new ResourceModel(label, label)));
84          fragment.add(getPlusFragment(model));
85          return fragment;
86      }
87  
88      private Fragment getDataFragment() {
89          Fragment contentFragment = new Fragment("content", "dataFragment", AbstractMultiPanel.this);
90          contentFragment.add(view.setOutputMarkupId(true));
91          return contentFragment;
92      }
93  
94      private Fragment getPlusFragment(final IModel<List<INNER>> model) {
95          IndicatorAjaxSubmitLink plus = new IndicatorAjaxSubmitLink("add") {
96  
97              private static final long serialVersionUID = -7978723352517770644L;
98  
99              @Override
100             protected void onSubmit(final AjaxRequestTarget target) {
101                 //Add current component
102                 model.getObject().add(newModelObject());
103 
104                 if (model.getObject().size() == 1) {
105                     form.addOrReplace(getDataFragment());
106                 }
107 
108                 target.add(container);
109             }
110 
111             @Override
112             protected void onError(final AjaxRequestTarget target) {
113                 sendError(getString(Constants.OPERATION_ERROR));
114                 super.onError(target);
115                 ((BaseWebPage) getPage()).getNotificationPanel().refresh(target);
116             }
117 
118         };
119 
120         Fragment fragment = new Fragment("panelPlus", "fragmentPlus", AbstractMultiPanel.this);
121         fragment.addOrReplace(plus);
122         fragment.setRenderBodyOnly(true);
123 
124         return fragment;
125     }
126 
127     public ListView<INNER> getView() {
128         return view;
129     }
130 
131     @Override
132     public AbstractMultiPanel<INNER> setModelObject(final List<INNER> object) {
133         view.setModelObject(object);
134         return this;
135     }
136 
137     protected abstract INNER newModelObject();
138 
139     protected abstract void sendError(String message);
140 
141     private final class InnerView extends ListView<INNER> {
142 
143         private static final long serialVersionUID = -9180479401817023838L;
144 
145         private final String label;
146 
147         private final IModel<List<INNER>> model;
148 
149         private InnerView(final String id, final String label, final IModel<List<INNER>> model) {
150             super(id, model);
151             this.label = label;
152             this.model = model;
153         }
154 
155         @Override
156         protected void populateItem(final ListItem<INNER> item) {
157             Panel panel = getItemPanel(item);
158 
159             item.add(panel.setRenderBodyOnly(true));
160 
161             IndicatorAjaxSubmitLink minus = new IndicatorAjaxSubmitLink("drop") {
162 
163                 private static final long serialVersionUID = -7978723352517770644L;
164 
165                 @Override
166                 protected void onSubmit(final AjaxRequestTarget target) {
167                     //Drop current component
168                     model.getObject().remove(item.getModelObject());
169                     clearInput(panel);
170 
171                     if (model.getObject().isEmpty()) {
172                         form.addOrReplace(getNoDataFragment(model, label));
173                     }
174 
175                     target.add(container);
176                 }
177 
178                 @Override
179                 protected void onError(final AjaxRequestTarget target) {
180                     onSubmit(target);
181                 }
182             };
183 
184             item.add(minus);
185 
186             Fragment fragment = item.getIndex() == model.getObject().size() - 1
187                     ? getPlusFragment(model)
188                     : new Fragment("panelPlus", "emptyFragment", AbstractMultiPanel.this);
189 
190             item.add(fragment.setRenderBodyOnly(true));
191         }
192     }
193 
194     protected abstract Panel getItemPanel(ListItem<INNER> item);
195 
196     protected void clearInput(final Panel panel) {
197         // do nothing by default
198     }
199 
200     @Override
201     public AbstractFieldPanel<List<INNER>> setReadOnly(final boolean readOnly) {
202         container.setEnabled(!readOnly);
203         return this;
204     }
205 
206     public AbstractFieldPanel<List<INNER>> setFormReadOnly(final boolean readOnly) {
207         form.setEnabled(!readOnly);
208         return this;
209     }
210 }