1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34 package info.magnolia.security.app.dialog.field;
35
36 import info.magnolia.icons.MagnoliaIcons;
37
38 import java.util.ArrayList;
39 import java.util.List;
40 import java.util.Map;
41
42 import com.vaadin.ui.Button;
43 import com.vaadin.ui.Component;
44 import com.vaadin.v7.data.Property;
45 import com.vaadin.v7.data.Validator;
46 import com.vaadin.v7.data.util.ObjectProperty;
47 import com.vaadin.v7.ui.AbstractField;
48 import com.vaadin.v7.ui.CustomField;
49 import com.vaadin.v7.ui.Field;
50 import com.vaadin.v7.ui.HorizontalLayout;
51 import com.vaadin.v7.ui.Label;
52 import com.vaadin.v7.ui.VerticalLayout;
53
54
55
56
57
58
59
60 public class AccessControlListField extends CustomField<AccessControlList> {
61 private final Map<Long, String> permissions;
62 private final NewEntryHandler newEntryHandler;
63
64 private VerticalLayout layout;
65 private List<Field<AccessControlList.Entry>> entryFields = new ArrayList<>();
66 private ValueChangeListener valueChangeListener;
67
68 private String addButtonCaption = "Add";
69 private String removeButtonCaption = "Remove";
70 private String emptyPlaceholderCaption = "No access";
71 private EntryFieldFactory entryFieldFactory;
72
73
74
75
76
77
78
79 public AccessControlListField(Map<Long, String> permissions, NewEntryHandler newEntryHandler) {
80 this.permissions = permissions;
81 this.newEntryHandler = newEntryHandler;
82 }
83
84 @Override
85 protected Component initContent() {
86 layout = new VerticalLayout();
87 layout.setSpacing(false);
88 layout.addStyleName("access-control-list-field");
89
90 AccessControlList<AccessControlList.Entry> acl = getValue();
91 List<Component> entryRows = buildEntryRows(acl);
92 layout.addComponents(entryRows.toArray(new Component[0]));
93
94 if (acl.getEntries().isEmpty()) {
95 layout.addComponent(new Label(emptyPlaceholderCaption));
96 }
97
98 if (newEntryHandler != null) {
99 final Button addButton = new Button(addButtonCaption);
100 addButton.addClickListener(new Button.ClickListener() {
101 @Override
102 public void buttonClick(Button.ClickEvent event) {
103 AccessControlList.Entry entry = newEntryHandler.createEntry();
104 AccessControlList<AccessControlList.Entry> value = getValue();
105 if (value == null) {
106 value = new AccessControlList<>();
107 setValue(value);
108 }
109 value.addEntry(entry);
110
111 Field<AccessControlList.Entry> entryField = getEntryFieldFactory().createField(entry);
112
113 if (entryField instanceof AbstractField) {
114 ((AbstractField) entryField).setValidationVisible(isValidationVisible());
115 }
116
117
118 entryFields.add(entryField);
119 layout.addComponent(buildEntryRow(entryField), layout.getComponentCount() - 1);
120 if (layout.getComponent(0) instanceof Label) {
121 layout.removeComponent(layout.getComponent(0));
122 }
123 }
124 });
125 layout.addComponent(addButton);
126 }
127 return layout;
128 }
129
130 protected List<Component> buildEntryRows(AccessControlList<AccessControlList.Entry> acl) {
131 List<Component> entryRows = new ArrayList<>();
132 if (acl != null) {
133 for (final AccessControlList.Entry entry : acl.getEntries()) {
134 Field<AccessControlList.Entry> entryField = getEntryFieldFactory().createField(entry);
135
136 if (entryField instanceof AbstractField) {
137 ((AbstractField) entryField).setValidationVisible(isValidationVisible());
138 }
139
140 entryFields.add(entryField);
141 entryRows.add(buildEntryRow(entryField));
142 }
143 }
144 return entryRows;
145 }
146
147 protected Component buildEntryRow(final Field<AccessControlList.Entry> entryField) {
148 final HorizontalLayout entryRow = new HorizontalLayout();
149 entryRow.setSpacing(true);
150 entryRow.setWidth("100%");
151
152 Button deleteButton = new Button(MagnoliaIcons.TRASH);
153 deleteButton.addStyleName("v-button-icon icon-button");
154 deleteButton.setDescription(removeButtonCaption);
155 deleteButton.addClickListener(new Button.ClickListener() {
156
157 @Override
158 public void buttonClick(Button.ClickEvent event) {
159 AccessControlList<AccessControlList.Entry> acl = getValue();
160 acl.removeEntry(entryField.getValue());
161 entryFields.remove(entryField);
162 if (isValidationVisible()) {
163
164 fireValueChange(false);
165 }
166
167
168 layout.removeComponent(entryRow);
169 if (acl.getEntries().size() == 0) {
170 layout.addComponentAsFirst(new Label(emptyPlaceholderCaption));
171 }
172 }
173 });
174
175 entryRow.addComponents(entryField, deleteButton);
176 entryRow.setExpandRatio(entryField, 1f);
177 return entryRow;
178 }
179
180 public String getAddButtonCaption() {
181 return addButtonCaption;
182 }
183
184 public void setAddButtonCaption(String addButtonCaption) {
185 this.addButtonCaption = addButtonCaption;
186 }
187
188 public String getRemoveButtonCaption() {
189 return removeButtonCaption;
190 }
191
192 public void setRemoveButtonCaption(String removeButtonCaption) {
193 this.removeButtonCaption = removeButtonCaption;
194 }
195
196 public String getEmptyPlaceholderCaption() {
197 return emptyPlaceholderCaption;
198 }
199
200 public void setEmptyPlaceholderCaption(String emptyPlaceholderCaption) {
201 this.emptyPlaceholderCaption = emptyPlaceholderCaption;
202 }
203
204 @Override
205 public Class<AccessControlList> getType() {
206 return AccessControlList.class;
207 }
208
209 @Override
210 public AccessControlList<AccessControlList.Entry> getValue() {
211 return super.getValue();
212 }
213
214 @Override
215 protected void validate(AccessControlList fieldValue) throws Validator.InvalidValueException {
216 List<Validator.InvalidValueException> causes = new ArrayList<>();
217
218 try {
219 super.validate(fieldValue);
220 } catch (Validator.InvalidValueException e) {
221 causes.add(e);
222 }
223
224
225 for (Field<AccessControlList.Entry> entryField : entryFields) {
226 try {
227 entryField.validate();
228 } catch (Validator.InvalidValueException e) {
229 causes.add(e);
230 }
231 }
232
233 if (!causes.isEmpty()) {
234
235
236 throw new Validator.InvalidValueException(null, causes.toArray(new Validator.InvalidValueException[0]));
237 }
238 }
239
240
241
242
243
244 @Override
245 public void setValidationVisible(boolean validateAutomatically) {
246 super.setValidationVisible(validateAutomatically);
247 for (Field<?> entryField : entryFields) {
248 if (entryField instanceof AbstractField) {
249 ((AbstractField) entryField).setValidationVisible(isValidationVisible());
250 }
251 }
252
253 if (validateAutomatically && valueChangeListener == null) {
254 valueChangeListener = new ValueChangeListener() {
255 @Override
256 public void valueChange(Property.ValueChangeEvent event) {
257 fireValueChange(false);
258 }
259 };
260 for (Field<?> entryField : entryFields) {
261 entryField.addValueChangeListener(valueChangeListener);
262 }
263 } else if (!validateAutomatically && valueChangeListener != null) {
264 for (Field<?> entryField : entryFields) {
265 entryField.removeValueChangeListener(valueChangeListener);
266 }
267 valueChangeListener = null;
268 }
269 }
270
271 public EntryFieldFactory getEntryFieldFactory() {
272 if (entryFieldFactory == null) {
273 this.entryFieldFactory = new DefaultEntryFieldFactory();
274 }
275 return entryFieldFactory;
276 }
277
278 public void setEntryFieldFactory(EntryFieldFactory entryFieldFactory) {
279 this.entryFieldFactory = entryFieldFactory;
280 }
281
282
283
284
285 public interface NewEntryHandler {
286
287
288
289 AccessControlList.Entry createEntry();
290 }
291
292
293
294
295 public interface EntryFieldFactory {
296
297
298
299 Field<AccessControlList.Entry> createField(AccessControlList.Entry entry);
300 }
301
302
303
304
305 public class DefaultEntryFieldFactory implements EntryFieldFactory {
306 @Override
307 public Field<AccessControlList.Entry> createField(AccessControlList.Entry entry) {
308 AccessControlFieldd/AccessControlField.html#AccessControlField">AccessControlField entryField = new AccessControlField(permissions);
309 entryField.setPropertyDataSource(new ObjectProperty<>(entry));
310 return entryField;
311 }
312 }
313 }