source: VirtualCollectionRegistry/trunk/VirtualCollectionRegistry/src/main/java/eu/clarin/cmdi/virtualcollectionregistry/gui/wizard/CreateVirtualCollectionWizard.java @ 5448

Last change on this file since 5448 was 5448, checked in by Twan Goosen, 10 years ago

Fixed adding and editing of resources to collections

  • Property svn:eol-style set to native
File size: 26.6 KB
Line 
1package eu.clarin.cmdi.virtualcollectionregistry.gui.wizard;
2
3import eu.clarin.cmdi.virtualcollectionregistry.gui.VolatileEntityModel;
4import java.util.Arrays;
5import java.util.Iterator;
6import java.util.List;
7
8import org.apache.wicket.Component;
9import org.apache.wicket.ajax.AjaxRequestTarget;
10import org.apache.wicket.ajax.markup.html.AjaxLink;
11import org.apache.wicket.extensions.ajax.markup.html.repeater.data.table.AjaxFallbackDefaultDataTable;
12import org.apache.wicket.extensions.markup.html.repeater.data.grid.ICellPopulator;
13import org.apache.wicket.extensions.markup.html.repeater.data.table.AbstractColumn;
14import org.apache.wicket.extensions.markup.html.repeater.data.table.DataTable;
15import org.apache.wicket.extensions.markup.html.repeater.data.table.HeaderlessColumn;
16import org.apache.wicket.extensions.markup.html.repeater.data.table.IColumn;
17import org.apache.wicket.extensions.markup.html.repeater.data.table.PropertyColumn;
18import org.apache.wicket.extensions.markup.html.repeater.util.SortableDataProvider;
19import org.apache.wicket.extensions.wizard.dynamic.DynamicWizardModel;
20import org.apache.wicket.extensions.wizard.dynamic.DynamicWizardStep;
21import org.apache.wicket.extensions.wizard.dynamic.IDynamicWizardStep;
22import org.apache.wicket.markup.ComponentTag;
23import org.apache.wicket.markup.html.WebMarkupContainer;
24import org.apache.wicket.markup.html.basic.Label;
25import org.apache.wicket.markup.html.form.DropDownChoice;
26import org.apache.wicket.markup.html.form.EnumChoiceRenderer;
27import org.apache.wicket.markup.html.form.Form;
28import org.apache.wicket.markup.html.form.FormComponent;
29import org.apache.wicket.markup.html.form.RequiredTextField;
30import org.apache.wicket.markup.html.form.TextArea;
31import org.apache.wicket.markup.html.form.TextField;
32import org.apache.wicket.markup.html.form.validation.AbstractFormValidator;
33import org.apache.wicket.markup.html.list.ListItem;
34import org.apache.wicket.markup.html.list.ListView;
35import org.apache.wicket.markup.html.list.OddEvenListItem;
36import org.apache.wicket.markup.html.panel.Panel;
37import org.apache.wicket.markup.repeater.Item;
38import org.apache.wicket.model.CompoundPropertyModel;
39import org.apache.wicket.model.IModel;
40import org.apache.wicket.model.Model;
41import org.apache.wicket.model.StringResourceModel;
42import org.apache.wicket.validation.validator.StringValidator;
43import org.apache.wicket.validation.validator.UrlValidator;
44
45import eu.clarin.cmdi.virtualcollectionregistry.gui.dialog.ConfirmationDialog;
46import eu.clarin.cmdi.virtualcollectionregistry.model.Creator;
47import eu.clarin.cmdi.virtualcollectionregistry.model.Resource;
48import eu.clarin.cmdi.virtualcollectionregistry.model.VirtualCollection;
49
50@SuppressWarnings("serial")
51public abstract class CreateVirtualCollectionWizard extends WizardBase {
52
53    private final class GeneralStep extends DynamicWizardStep {
54
55        private final class DeleteKeywordDialog extends ConfirmationDialog {
56
57            private String keyword;
58
59            public DeleteKeywordDialog(String id,
60                    final Component updateComponent) {
61                super(id, updateComponent);
62            }
63
64            @Override
65            public void onConfirm(AjaxRequestTarget target) {
66                vc.getObject().getKeywords().remove(keyword);
67            }
68
69            public void show(AjaxRequestTarget target, String keyword) {
70                this.keyword = keyword;
71                super.show(target, new StringResourceModel("keywords.deleteconfirm", null, new Object[]{keyword}));
72            }
73        } // class CreateVirtualCollectionWizard.GeneralStep.DeleteKeywordDialog
74
75        private final class KeywordsList extends WebMarkupContainer {
76
77            private final ListView<String> itemsView;
78
79            public KeywordsList(String id, final List<String> items) {
80                super(id);
81                setOutputMarkupId(true);
82
83                itemsView = new ListView<String>("keywords", items) {
84                    @Override
85                    protected void populateItem(final ListItem<String> item) {
86                        final IModel<String> model = item.getModel();
87                        item.add(new Label("itemText", model.getObject()));
88                        item.add(new AjaxLink<String>("itemRemove") {
89                            @Override
90                            public void onClick(AjaxRequestTarget target) {
91                                deleteKeywordDialog.show(target,
92                                        model.getObject());
93                            }
94                        });
95                    }
96
97                    @Override
98                    protected ListItem<String> newItem(int index) {
99                        final IModel<String> model
100                                = getListItemModel(getModel(), index);
101                        return new OddEvenListItem<String>(index, model) {
102                            @Override
103                            protected void onComponentTag(ComponentTag tag) {
104                                super.onComponentTag(tag);
105                                if (getIndex() == 0) {
106                                    tag.append("class", "first", " ");
107                                }
108                            }
109                        };
110                    }
111                };
112                add(itemsView);
113            }
114        } // class CreateVirtualCollectionWizard.GeneralStep.KeywordsList
115
116        private final AddKeywordDialog addKeywordDialog;
117        private final DeleteKeywordDialog deleteKeywordDialog;
118
119        public GeneralStep() {
120            super(null, "General", null, vc);
121            setDefaultModel(new CompoundPropertyModel<VirtualCollection>(vc));
122            final TextField<String> nameField
123                    = new RequiredTextField<String>("name");
124            nameField.add(new StringValidator.MaximumLengthValidator(255));
125            add(nameField);
126            final DropDownChoice<VirtualCollection.Type> typeChoice
127                    = new DropDownChoice<VirtualCollection.Type>("type",
128                            Arrays.asList(VirtualCollection.Type.values()),
129                            new EnumChoiceRenderer<VirtualCollection.Type>(this));
130            typeChoice.setRequired(true);
131            add(typeChoice);
132            add(new TextArea<String>("description"));
133            final DropDownChoice<VirtualCollection.Purpose> purposeChoice
134                    = new DropDownChoice<VirtualCollection.Purpose>("purpose",
135                            Arrays.asList(VirtualCollection.Purpose.values()),
136                            new EnumChoiceRenderer<VirtualCollection.Purpose>(this));
137            add(purposeChoice);
138            final DropDownChoice<VirtualCollection.Reproducibility> reproducibilityChoice
139                    = new DropDownChoice<VirtualCollection.Reproducibility>("reproducibility",
140                            Arrays.asList(VirtualCollection.Reproducibility.values()),
141                            new EnumChoiceRenderer<VirtualCollection.Reproducibility>(this));
142            add(reproducibilityChoice);
143            final TextArea<String> reproducibilityNoticeArea
144                    = new TextArea<String>("reproducibilityNotice");
145            add(reproducibilityNoticeArea);
146
147            final KeywordsList keywordList
148                    = new KeywordsList("keywordsList", vc.getObject().getKeywords());
149            add(keywordList);
150            add(new AjaxLink<String>("keywordsAdd") {
151                @Override
152                public void onClick(AjaxRequestTarget target) {
153                    addKeywordDialog.show(target);
154                }
155            });
156
157            addKeywordDialog = new AddKeywordDialog("addKeywordDialog") {
158                @Override
159                public void onSubmit(AjaxRequestTarget target, String keyword) {
160                    if (!vc.getObject().getKeywords().contains(keyword)) {
161                        vc.getObject().getKeywords().add(keyword);
162                    }
163                    target.addComponent(keywordList);
164                }
165            };
166            add(addKeywordDialog);
167
168            deleteKeywordDialog =
169                new DeleteKeywordDialog("deleteKeywordDialog", keywordList);
170            add(deleteKeywordDialog);
171        }
172
173        @Override
174        public boolean isLastStep() {
175            return false;
176        }
177
178        @Override
179        public IDynamicWizardStep next() {
180            return new CreatorsStep(this);
181        }
182
183        @Override
184        public void applyState() {
185            super.applyState();
186            switch (vc.getObject().getType()) {
187                case EXTENSIONAL:
188                    vc.getObject().setGeneratedBy(null);
189                    break;
190                case INTENSIONAL:
191                    vc.getObject().getResources().clear();
192                    break;
193            }
194        }
195    } // class CreateVirtualCollectionWizard.GeneralStep
196
197    private final class CreatorsStep extends DynamicWizardStep {
198        private final class ActionsPanel extends Panel {
199            public ActionsPanel(String id, final IModel<Creator> model) {
200                super(id, model);
201                setRenderBodyOnly(true);
202                final AjaxLink<Creator> editLink =
203                    new AjaxLink<Creator>("edit") {
204                            @Override
205                            public void onClick(AjaxRequestTarget target) {
206                                editCreatorDialog.show(target, model);
207                            }
208                        };
209                add(editLink);
210                final AjaxLink<Creator> deleteLink =
211                    new AjaxLink<Creator>("delete") {
212                            @Override
213                            public void onClick(AjaxRequestTarget target) {
214                                deleteCreatorDialog.showCreator(target, model);
215                            }
216                        };
217                add(deleteLink);
218            }
219        } // class CreateVirtualCollectionWizard.CreatorsStep.ActionsPanel
220
221        private final class DeleteCreatorDialog extends ConfirmationDialog {
222            private IModel<Creator> creator;
223
224            public DeleteCreatorDialog(String id,
225                    final Component updateComponent) {
226                super(id, updateComponent);
227                setInitialWidth(400);
228            }
229
230            @Override
231            public void onConfirm(AjaxRequestTarget target) {
232                if (creator != null) {
233                    vc.getObject().getCreators().remove(creator.getObject());
234                }
235            }
236
237            public void showCreator(AjaxRequestTarget target, IModel<Creator> creator) {
238                this.creator = creator;
239                super.show(target,
240                        new StringResourceModel("creators.deleteconfirm",
241                                creator));
242            }
243        } // class CreateVirtualCollectionWizard.CreatorsStep.DeleteCreatorDialog
244
245        private final EditCreatorDialog editCreatorDialog;
246        private final DeleteCreatorDialog deleteCreatorDialog;
247
248        public CreatorsStep(IDynamicWizardStep previousStep) {
249            super(previousStep, "Creators", null, vc);
250            final DataTable<Creator> creatorsTable
251                    = new AjaxFallbackDefaultDataTable<Creator>("creatorsTable",
252                            createColumns(),
253                            new SortableDataProvider<Creator>() {
254                                @Override
255                                public Iterator<? extends Creator>
256                                iterator(int first, int count) {
257                                    return vc.getObject().getCreators().listIterator(first);
258                                }
259
260                                @Override
261                                public IModel<Creator> model(Creator creator) {
262                                    return new VolatileEntityModel<Creator>(creator);
263                                }
264                                @Override
265                                public int size() {
266                                    return vc.getObject().getCreators().size();
267                                }
268                            },
269                            8);
270            creatorsTable.setOutputMarkupId(true);
271            add(creatorsTable);
272
273            editCreatorDialog = new EditCreatorDialog("editCreatorDialog") {
274                @Override
275                public void onSubmit(AjaxRequestTarget target, Creator creator) {
276                    // create a copy first because retrieving the creators may
277                    // reset the state of the object
278                    final Creator copy = creator.getCopy();
279                    final List<Creator> creators = vc.getObject().getCreators();
280                    if (creators.contains(creator)) {
281                        // update existig creator (needed since we're dealing with a volatile instance)
282                        creator.setValuesFrom(copy);
283                    } else {
284                        // new entry, add
285                        creators.add(creator);
286                    }
287                    target.addComponent(creatorsTable);
288                }
289            };
290            add(editCreatorDialog);
291
292            deleteCreatorDialog
293                    = new DeleteCreatorDialog("deleteCreatorDialog", creatorsTable);
294            add(deleteCreatorDialog);
295
296            add(new AjaxLink<Object>("add") {
297                @Override
298                public void onClick(AjaxRequestTarget target) {
299                    editCreatorDialog.show(target);
300                }
301            });
302        }
303
304        @Override
305        public boolean isLastStep() {
306            return false;
307        }
308
309        @Override
310        public IDynamicWizardStep next() {
311            switch (vc.getObject().getType()) {
312                case EXTENSIONAL:
313                    return new ResourcesStep(this);
314                case INTENSIONAL:
315                    return new GeneratedByStep(this);
316                default:
317                    throw new InternalError("bad vc type");
318            } // switch
319        }
320
321        @SuppressWarnings("unchecked")
322        private IColumn<Creator>[] createColumns() {
323            final IColumn<?>[] columns = new IColumn<?>[]{
324                new PropertyColumn<Creator>(new Model<String>("Person"),
325                "person"),
326                new PropertyColumn<Creator>(new Model<String>("EMail"),
327                "email"),
328                new PropertyColumn<Creator>(new Model<String>(
329                "Organisation"), "organisation"),
330                new HeaderlessColumn<Creator>() {
331                    @Override
332                    public void populateItem(
333                            Item<ICellPopulator<Creator>> item,
334                            String compontentId, IModel<Creator> model) {
335                        item.add(new ActionsPanel(compontentId, model));
336                    }
337
338                    @Override
339                    public String getCssClass() {
340                        return "action";
341                    }
342                }
343            };
344            return (IColumn<Creator>[]) columns;
345        }
346    } // class CreateVirtualCollectionWizard.CreatorsStep
347
348    private final class ResourcesStep extends DynamicWizardStep {
349        private final class ActionsPanel extends Panel {
350            public ActionsPanel(String id, final IModel<Resource> model) {
351                super(id, model);
352                setRenderBodyOnly(true);
353                final AjaxLink<Resource> editLink =
354                    new AjaxLink<Resource>("edit") {
355                            @Override
356                            public void onClick(AjaxRequestTarget target) {
357                                editResourceDialog.show(target, model);
358                            }
359                        };
360                add(editLink);
361                final AjaxLink<Resource> deleteLink =
362                    new AjaxLink<Resource>("delete") {
363                            @Override
364                            public void onClick(AjaxRequestTarget target) {
365                                deleteResourceDialog.showResource(target, model);
366                            }
367                        };
368                add(deleteLink);
369            }
370        } // class CreateVirtualCollectionWizard.ResourcesStep.ActionsPanel
371
372        private final class DeleteResourceDialog extends ConfirmationDialog {
373            private IModel<Resource> resource;
374
375            public DeleteResourceDialog(String id,
376                    final Component updateComponenet) {
377                super(id, updateComponenet);
378                setInitialWidth(400);
379            }
380
381            @Override
382            public void onConfirm(AjaxRequestTarget target) {
383                if (resource != null) {
384                    vc.getObject().getResources().remove(resource.getObject());
385                }
386            }
387
388            public void showResource(AjaxRequestTarget target, IModel<Resource> resource) {
389                this.resource = resource;
390                super.show(target,
391                        new StringResourceModel("resources.deleteconfirm",
392                                resource));
393            }
394        } // class CreateVirtualCollectionWizard.CreatorsStep.DeleteResourceDialog
395
396        private final EditResourceDialog editResourceDialog;
397        private final DeleteResourceDialog deleteResourceDialog;
398
399        public ResourcesStep(IDynamicWizardStep previousStep) {
400            super(previousStep, "Resources", null, vc);
401            final DataTable<Resource> resourcesTable =
402                new AjaxFallbackDefaultDataTable<Resource>("resourcesTable",
403                            createColumns(),
404                            new SortableDataProvider<Resource>() {
405                                @Override
406                                public Iterator<? extends Resource>
407                                iterator(int first, int count) {
408                                    return vc.getObject().getResources().listIterator(first);
409                                }
410
411                                @Override
412                                public IModel<Resource> model(Resource resource) {
413                                    return new VolatileEntityModel<Resource>(resource);
414                                }
415
416                                @Override
417                                public int size() {
418                                    return vc.getObject().getResources().size();
419                                }
420                            },
421                            64);
422            resourcesTable.setOutputMarkupId(true);
423            add(resourcesTable);
424
425            editResourceDialog = new EditResourceDialog("editResourceDialog") {
426                @Override
427                public void onSubmit(AjaxRequestTarget target,
428                        Resource resource) {
429                    // create a copy first because retrieving the resources may
430                    // reset the state of the object
431                    final Resource copy = resource.getCopy();
432                    final List<Resource> resources = vc.getObject().getResources();
433                    if (resources.contains(resource)) {
434                        // update existig resource (needed since we're dealing with a volatile instance)
435                        resource.valuesFrom(copy);
436                    } else {
437                        // new entry, add
438                        resources.add(resource);
439                    }
440                    target.addComponent(resourcesTable);
441                }
442            };
443            add(editResourceDialog);
444
445            deleteResourceDialog = new DeleteResourceDialog(
446                    "deleteResourceDialog", resourcesTable);
447            add(deleteResourceDialog);
448
449            final AddResourcesDialog addResourcesDialog =
450                new AddResourcesDialog("addResourcesDialog") {
451                        @Override
452                        public void onSubmit(AjaxRequestTarget target,
453                                Resource[] resources) {
454                            for (Resource resource : resources) {
455                                if (!vc.getObject().getResources().contains(resource)) {
456                                    vc.getObject().getResources().add(resource);
457                                }
458                            }
459                            target.addComponent(resourcesTable);
460                        }
461
462                    };
463            add(addResourcesDialog);
464
465            add(new AjaxLink<Object>("add") {
466                @Override
467                public void onClick(AjaxRequestTarget target) {
468                    editResourceDialog.show(target);
469                }
470            });
471
472            add(new AjaxLink<Object>("addMore") {
473                @Override
474                public void onClick(AjaxRequestTarget target) {
475                    addResourcesDialog.show(target);
476                }
477            });
478
479            add(new AbstractFormValidator() {
480                @Override
481                public FormComponent<?>[] getDependentFormComponents() {
482                    return null;
483                }
484
485                @Override
486                public void validate(Form<?> form) {
487                    if (vc.getObject().getResources().isEmpty()) {
488                        form.error("An extensional collection requires at "
489                                + "least one resource.");
490                    }
491                }
492            });
493        }
494
495        @Override
496        public boolean isLastStep() {
497            return true;
498        }
499
500        @Override
501        public IDynamicWizardStep next() {
502            return null;
503        }
504
505        @SuppressWarnings("unchecked")
506        private IColumn<Resource>[] createColumns() {
507            final IColumn<?>[] columns = new IColumn<?>[]{
508                new AbstractColumn<Resource>(new Model<String>("Type")) {
509                    @Override
510                    public void populateItem(
511                            Item<ICellPopulator<Resource>> item,
512                            String componentId, IModel<Resource> model) {
513                        switch (model.getObject().getType()) {
514                            case METADATA:
515                                item.add(new Label(componentId, "Metadata"));
516                                break;
517                            case RESOURCE:
518                                item.add(new Label(componentId, "Resource"));
519                                break;
520                        }
521                    }
522
523                    @Override
524                    public String getCssClass() {
525                        return "type";
526                    }
527                },
528                new PropertyColumn<Resource>(
529                new Model<String>("Reference"), "ref"),
530                new HeaderlessColumn<Resource>() {
531                    @Override
532                    public void populateItem(
533                            Item<ICellPopulator<Resource>> item,
534                            String compontentId, IModel<Resource> model) {
535                        item.add(new ActionsPanel(compontentId, model));
536                    }
537
538                    @Override
539                    public String getCssClass() {
540                        return "action";
541                    }
542                }
543            };
544            return (IColumn<Resource>[]) columns;
545        }
546    } // class CreateVirtualCollectionWizard.ResourcesStep
547
548    private final class GeneratedByStep extends DynamicWizardStep {
549        public GeneratedByStep(IDynamicWizardStep previousStep) {
550            super(previousStep, "Intensional Collection Query", null, vc);
551            setDefaultModel(new CompoundPropertyModel<VirtualCollection>(vc));
552            final TextArea<String> descriptionArea =
553                new TextArea<String>("generatedBy.description");
554            descriptionArea.setRequired(true);
555            add(descriptionArea);
556            final TextField<String> uriField =
557                new TextField<String>("generatedBy.uri");
558            uriField.add(new StringValidator.MaximumLengthValidator(255));
559            uriField.add(new UrlValidator(UrlValidator.NO_FRAGMENTS));
560            add(uriField);
561            final TextField<String> queryProfileField =
562                new TextField<String>("generatedBy.query.profile");
563            add(queryProfileField);
564            final TextArea<String> queryValueArea =
565                new TextArea<String>("generatedBy.query.value");
566            add(queryValueArea);
567
568            add(new AbstractFormValidator() {
569                @Override
570                public FormComponent<?>[] getDependentFormComponents() {
571                    return new FormComponent[]{queryProfileField,
572                        queryValueArea};
573                }
574
575                @Override
576                public void validate(Form<?> form) {
577                    final String profile = queryProfileField.getInput();
578                    final String value = queryValueArea.getInput();
579                    if (profile.isEmpty() && !value.isEmpty()) {
580                        form.error("profile is required with value");
581                        queryProfileField.invalid();
582                    }
583                    if (!profile.isEmpty() && value.isEmpty()) {
584                        form.error("value is required with profile");
585                        queryValueArea.invalid();
586                    }
587                    if (profile.isEmpty() && value.isEmpty()) {
588                        /*
589                         * XXX: clear Query object as side-effect. This is
590                         * more a hack than a clean solution.
591                         */
592                        if (vc.getObject().getGeneratedBy() != null) {
593                            vc.getObject().getGeneratedBy().setQuery(null);
594                        }
595                    }
596                }
597            });
598        }
599
600        @Override
601        public boolean isLastStep() {
602            return true;
603        }
604
605        @Override
606        public IDynamicWizardStep next() {
607            return null;
608        }
609    } // class CreateVirtualCollectionWizard.GeneratedByStep
610
611    private final IModel<VirtualCollection> vc;
612
613    public CreateVirtualCollectionWizard(String id, IModel<VirtualCollection> vc) {
614        super(id);
615        if (vc == null) {
616            throw new IllegalArgumentException("vc == null");
617        }
618        this.vc = vc;
619        setDefaultModel(new CompoundPropertyModel<VirtualCollection>(this));
620        init(new DynamicWizardModel(new GeneralStep()));
621    }
622
623    @Override
624    public final void onCancel() {
625        onCancelWizard();
626    }
627
628    @Override
629    public final void onFinish() {
630        onFinishWizard(vc);
631    }
632
633    protected abstract void onCancelWizard();
634
635    protected abstract void onFinishWizard(IModel<VirtualCollection> vc);
636
637} // class CreateVirtualCollectionWizard
Note: See TracBrowser for help on using the repository browser.