16
16
import java.util.ArrayList;
17
17
import java.util.Collection;
18
18
import java.util.Collections;
19
import java.util.HashMap;
20
import java.util.HashSet;
19
21
import java.util.Iterator;
20
22
import java.util.List;
24
import java.util.Map.Entry;
21
25
import java.util.Objects;
22
26
import java.util.Optional;
23
27
import java.util.function.BiConsumer;
28
import java.util.function.Function;
29
import java.util.stream.Collectors;
25
31
import org.apache.commons.collections4.list.UnmodifiableList;
26
32
import org.apache.commons.lang3.tuple.Pair;
33
import org.apache.logging.log4j.Level;
27
34
import org.apache.logging.log4j.LogManager;
28
35
import org.apache.logging.log4j.Logger;
29
36
import org.kitodo.api.Metadata;
171
178
private void createMetadataTable() {
172
179
// the existing metadata is passed to the rule set, which sorts it
173
List<MetadataViewWithValuesInterface> tableData = null;
180
Collection<Metadata> entered = addLabels(new HashSet<>(metadata));
174
181
if (Objects.nonNull(treeNode) && !treeNode.getChildren().isEmpty()) {
176
tableData = metadataView.getSortedVisibleMetadata(
177
DataEditorService.getExistingMetadataRows(treeNode.getChildren()),
178
additionallySelectedFields);
183
entered.addAll(DataEditorService.getExistingMetadataRows(treeNode.getChildren()));
179
184
} catch (InvalidMetadataValueException e) {
180
185
logger.error(e.getLocalizedMessage());
183
tableData = metadataView
184
.getSortedVisibleMetadata(addLabels(metadata), additionallySelectedFields);
188
List<MetadataViewWithValuesInterface> tableData = metadataView.getSortedVisibleMetadata(entered, additionallySelectedFields);
186
189
treeNode.getChildren().clear();
187
190
hiddenMetadata = Collections.emptyList();
188
191
for (MetadataViewWithValuesInterface rowData : tableData) {
193
196
if (metadataView.isComplex()) {
194
197
createMetadataGroupPanel((ComplexMetadataViewInterface) metadataView, values);
196
createMetadataEntryEdit((SimpleMetadataViewInterface) metadataView, values);
199
if (!createMetadataEntryEdit((SimpleMetadataViewInterface) metadataView, values)) {
201
* If a conditional metadata was set automatically,
202
* start over. This is necessary to update dependent
203
* fields above or below.
205
logger.debug("Metadata was changed. Restarting.");
206
createMetadataTable();
199
211
hiddenMetadata = values;
294
306
* the value(s) to be displayed
307
* @return whether the input field could be generated. If an automatic
308
* preset has been added to the metadata, false is returned. In that
309
* case, the rule set must be invoked again to update the options
310
* for dependent fields.
296
public void createMetadataEntryEdit(SimpleMetadataViewInterface simpleMetadataView,
312
public boolean createMetadataEntryEdit(SimpleMetadataViewInterface simpleMetadataView,
297
313
Collection<Metadata> values) {
299
315
ProcessDetail data;
304
320
case MULTIPLE_SELECTION:
305
321
case MULTI_LINE_SINGLE_SELECTION:
306
322
case ONE_LINE_SINGLE_SELECTION:
307
data = new ProcessSelectMetadata(this, simpleMetadataView, simpleValues(values));
323
List<Map<MetadataEntry, Boolean>> leadingFields = getListForLeadingMetadataFields();
324
Map<String, String> options = simpleMetadataView.getSelectItems(leadingFields);
325
boolean dependent = leadingFields.parallelStream().flatMap(map -> map.entrySet().parallelStream())
326
.anyMatch(entry -> Boolean.TRUE.equals(entry.getValue()));
327
if (dependent && !options.isEmpty() && addAutoPresetForConditionalMetadata(simpleMetadataView, options, values)) {
330
data = new ProcessSelectMetadata(this, simpleMetadataView, simpleValues(values), dependent);
310
333
data = new ProcessBooleanMetadata(this, simpleMetadataView, oneValue(values, MetadataEntry.class));
323
346
new DefaultTreeNode(data, treeNode).setExpanded(true);
324
347
} catch (IllegalStateException e) {
348
logger.catching(Level.WARN, e);
325
349
ProcessFieldedMetadata metadata = new ProcessFieldedMetadata(this, oneValue(values, MetadataGroup.class));
326
350
metadata.treeNode = new DefaultTreeNode(metadata, treeNode);
327
351
metadata.createUndefinedMetadataTable();
328
352
metadata.treeNode.setExpanded(true);
358
* A value must be set for conditional metadata, as there is no no-selection
359
* option. In this case, the first possible value is already displayed as
360
* selected, even if it is not yet reflected in the metadata before saving.
361
* In this case, no options are offered in selection fields that depend on
362
* this field, because their options are based on the metadata. Therefore,
363
* in this case, the metadata must be set explicitly. Then, a termination
364
* must take place and the rule set must be invoked again in order to
365
* correctly populate the dependent fields with options.
368
* view that gives the access the select items
369
* @param metadataForInput
370
* list of metadata, to which a preset will be added if necessary
371
* @return true, if the current tree building process must be restarted,
372
* because the metadata was changed
374
private boolean addAutoPresetForConditionalMetadata(SimpleMetadataViewInterface view, Map<String, String> options,
375
Collection<Metadata> metadataForInput) {
377
if (metadataForInput.isEmpty()) {
378
MetadataEntry autoPreset = new MetadataEntry();
379
autoPreset.setKey(view.getId());
380
if (Objects.isNull(container)) {
381
autoPreset.setDomain(DOMAIN_TO_MDSEC.get(view.getDomain().orElse(Domain.DESCRIPTION)));
383
autoPreset.setValue(options.entrySet().iterator().next().getKey());
384
metadata.add(autoPreset);
386
logger.debug("Added metadata {} to {}", autoPreset, metadataKey);
443
511
return "dataTable";
514
List<Map<MetadataEntry, Boolean>> getListForLeadingMetadataFields() {
515
List<Map<MetadataEntry, Boolean>> result = Objects.isNull(container) ? new ArrayList<>()
516
: container.getListForLeadingMetadataFields();
517
Map<String, MetadataEntry> metadataEntryMap = new HashMap<>();
518
treeNode.getChildren().stream().map(TreeNode::getData).filter(ProcessSimpleMetadata.class::isInstance)
519
.map(ProcessSimpleMetadata.class::cast).map(ProcessDetail::getMetadataID).forEachOrdered(key -> {
520
MetadataEntry metadataEntry = new MetadataEntry();
521
metadataEntry.setKey(key);
522
metadataEntryMap.put(key, metadataEntry);
524
metadata.stream().filter(MetadataEntry.class::isInstance).map(MetadataEntry.class::cast)
525
.forEachOrdered(key -> metadataEntryMap.put(key.getKey(), key));
526
result.add(metadataEntryMap.entrySet().stream()
527
.collect(Collectors.toMap(Entry::getValue, all -> Boolean.FALSE)));
447
532
* Returns the metadata of a metadata group, when used recursively.
613
void markLeadingMetadataFields(List<Map<MetadataEntry, Boolean>> leadingMetadataFields) {
614
int lastIndex = leadingMetadataFields.size() - 1;
616
container.markLeadingMetadataFields(leadingMetadataFields.subList(0, lastIndex));
618
final List<String> leadingMetadataKeys = leadingMetadataFields.get(lastIndex).entrySet().parallelStream()
619
.filter(entry -> Boolean.TRUE.equals(entry.getValue())).map(entry -> entry.getKey().getKey())
620
.collect(Collectors.toList());
621
treeNode.getChildren().parallelStream().map(TreeNode::getData).map(ProcessDetail.class::cast)
622
.filter(processDetail -> leadingMetadataKeys.contains(processDetail.getMetadataID()))
623
.forEach(ProcessDetail::setLeading);
529
627
* Reads the contents of the processMetadata and stores the values in the
530
628
* appropriate place. If the line is used to edit a field of the METS