Project

General

Profile

« Previous | Next » 

Revision 4512ae1c

Added by Katja Luther over 2 years ago

ref #9772: code cleaning

View differences:

eu.etaxonomy.taxeditor.editor/src/main/java/eu/etaxonomy/taxeditor/editor/descriptiveDataSet/matrix/CharacterMatrix.java
221 221
        toolbar = new CharacterMatrixToolbar(this, SWT.NONE);
222 222
    }
223 223

  
224
    @SuppressWarnings("unused")
225
    private void createBottomToolbar() {
226
        new CharacterMatrixBottomToolbar(this, SWT.NONE);
227
    }
224
//    @SuppressWarnings("unused")
225
//    private void createBottomToolbar() {
226
//        new CharacterMatrixBottomToolbar(this, SWT.NONE);
227
//    }
228 228

  
229 229

  
230 230
    private void applyStyles(){
eu.etaxonomy.taxeditor.editor/src/main/java/eu/etaxonomy/taxeditor/editor/descriptiveDataSet/matrix/CharacterMatrixBottomToolbar.java
1
/**
2
* Copyright (C) 2018 EDIT
3
* European Distributed Institute of Taxonomy
4
* http://www.e-taxonomy.eu
5
*
6
* The contents of this file are subject to the Mozilla Public License Version 1.1
7
* See LICENSE.TXT at the top of this package for the full license terms.
8
*/
9
package eu.etaxonomy.taxeditor.editor.descriptiveDataSet.matrix;
10

  
11
import java.util.Collection;
12
import java.util.List;
13
import java.util.Set;
14
import java.util.UUID;
15
import java.util.stream.Collectors;
16

  
17
import org.eclipse.core.runtime.ICoreRunnable;
18
import org.eclipse.core.runtime.IProgressMonitor;
19
import org.eclipse.core.runtime.SubMonitor;
20
import org.eclipse.core.runtime.jobs.IJobChangeEvent;
21
import org.eclipse.core.runtime.jobs.Job;
22
import org.eclipse.core.runtime.jobs.JobChangeAdapter;
23
import org.eclipse.jface.layout.GridDataFactory;
24
import org.eclipse.jface.viewers.IStructuredSelection;
25
import org.eclipse.jface.window.Window;
26
import org.eclipse.jface.wizard.WizardDialog;
27
import org.eclipse.swt.SWT;
28
import org.eclipse.swt.events.SelectionAdapter;
29
import org.eclipse.swt.events.SelectionEvent;
30
import org.eclipse.swt.layout.RowLayout;
31
import org.eclipse.swt.widgets.Button;
32
import org.eclipse.swt.widgets.Composite;
33

  
34
import eu.etaxonomy.cdm.api.application.CdmApplicationState;
35
import eu.etaxonomy.cdm.api.service.IDescriptiveDataSetService;
36
import eu.etaxonomy.cdm.api.service.ITaxonNodeService;
37
import eu.etaxonomy.cdm.api.service.UpdateResult;
38
import eu.etaxonomy.cdm.api.service.description.AggregationMode;
39
import eu.etaxonomy.cdm.api.service.description.StructuredDescriptionAggregationConfiguration;
40
import eu.etaxonomy.cdm.api.service.dto.SpecimenRowWrapperDTO;
41
import eu.etaxonomy.cdm.common.monitor.IRemotingProgressMonitor;
42
import eu.etaxonomy.cdm.filter.TaxonNodeFilter;
43
import eu.etaxonomy.cdm.model.description.DescriptiveDataSet;
44
import eu.etaxonomy.cdm.model.taxon.Taxon;
45
import eu.etaxonomy.cdm.persistence.dto.DescriptiveDataSetBaseDto;
46
import eu.etaxonomy.cdm.persistence.dto.TaxonNodeDto;
47
import eu.etaxonomy.cdm.persistence.dto.TermDto;
48
import eu.etaxonomy.taxeditor.editor.internal.TaxeditorEditorPlugin;
49
import eu.etaxonomy.taxeditor.editor.l10n.Messages;
50
import eu.etaxonomy.taxeditor.model.AbstractUtility;
51
import eu.etaxonomy.taxeditor.model.MessagingUtils;
52
import eu.etaxonomy.taxeditor.operation.IFeedbackGenerator;
53
import eu.etaxonomy.taxeditor.store.CdmStore;
54
import eu.etaxonomy.taxeditor.store.StoreUtil;
55
import eu.etaxonomy.taxeditor.ui.dialog.configurator.StructuredAggregationConfigurationWizard;
56
import eu.etaxonomy.taxeditor.ui.dialog.selection.TaxonSelectionDialog;
57

  
58
/**
59
 * @author pplitzner
60
 * @since Jul 9, 2018
61
 */
62
public class CharacterMatrixBottomToolbar extends Composite{
63

  
64
    private CharacterMatrix matrix;
65

  
66
    public CharacterMatrixBottomToolbar(CharacterMatrix matrix, int style) {
67
        super(matrix, style);
68
        this.matrix = matrix;
69

  
70
        init();
71
    }
72

  
73
    private void init() {
74

  
75
        setLayout(new RowLayout());
76
        GridDataFactory.fillDefaults().grab(true, false).applyTo(this);
77

  
78
//        /**
79
//         * Add description button
80
//         */
81
//        Button btnAddDescription = new Button(this, SWT.PUSH);
82
//        btnAddDescription.setImage(ImageResources.getImage(ImageResources.ADD_ICON_GREEN));
83
//        btnAddDescription.addSelectionListener(new SelectionAdapter() {
84
//            @Override
85
//            public void widgetSelected(SelectionEvent e) {
86
//                if(StoreUtil.promptCheckIsDirty(matrix.getPart())){
87
//                    return;
88
//                }
89
//                SpecimenSelectionDialog dialog = new SpecimenSelectionDialog(matrix.getShell(), matrix, null);
90
//                if(dialog.open()==Window.OK){
91
//                    Collection<SpecimenNodeWrapper> wrappers = dialog.getSpecimen();
92
//                    if(wrappers.stream().anyMatch(wrapper->wrapper.getTaxonDescriptionUuid()==null)
93
//                            && !MessagingUtils.confirmDialog(
94
//                                    "Create Taxon Association",
95
//                                    "Some specimens are not linked with taxon via IndividualsAssociation yet.\n"
96
//                                    + "Do you want to create this association?")){
97
//                        return;
98
//                    }
99
//                    addRowsToMatrix(wrappers, matrix.getDescriptiveDataSet().getUuid());
100
//                    wrappers.forEach(wrapper->matrix.getSpecimenCache().remove(wrapper));
101
//                }
102
//            }
103
//        });
104
        /**
105
         * Remove description button
106
         */
107
//        Button btnRemoveDescription = new Button(this, SWT.PUSH);
108
//        btnRemoveDescription.setImage(ImageResources.getImage(ImageResources.ACTIVE_DELETE_ICON));
109
//        btnRemoveDescription.addSelectionListener(new SelectionAdapter() {
110
//            @Override
111
//            public void widgetSelected(SelectionEvent e) {
112
//                if(StoreUtil.promptCheckIsDirty(matrix.getPart())){
113
//                    return;
114
//                }
115
//                if(!MessagingUtils.confirmDialog(Messages.CharacterMatrixBottomToolbar_CONFIRM_DELETE_TITLE, Messages.CharacterMatrixBottomToolbar_CONFIRM_DELETE_MESSAGE)){
116
//                    return;
117
//                }
118
//                int[] fullySelectedRowPositions = matrix.getBodyLayer().getSelectionLayer().getFullySelectedRowPositions();
119
//                List<RowWrapperDTO> toRemove = new ArrayList<>();
120
//                for (int i : fullySelectedRowPositions) {
121
//                    Object rowObject = matrix.getBodyDataProvider().getRowObject(i);
122
//                    if(rowObject instanceof RowWrapperDTO){
123
//                        toRemove.add((RowWrapperDTO) rowObject);
124
//                    }
125
//                }
126
//                toRemove.forEach(rowToRemove -> {
127
//                    matrix.putDescriptionToDelete(rowToRemove.getDescription().getUuid());
128
//                    matrix.getDescriptions().remove(rowToRemove);
129
//                    matrix.setDirty();
130
////                    CdmStore.getService(IDescriptiveDataSetService.class).removeDescription(
131
////                            rowToRemove.getDescription().getUuid(), matrix.getDescriptiveDataSet().getUuid());
132
//                });
133
//            }
134
//        });
135
        /**
136
         * Aggregate button
137
         */
138
        Button btnAggregate = new Button(this, SWT.PUSH);
139
        btnAggregate.setText(Messages.CharacterMatrixBottomToolbar_AGGREGATE);
140
        btnAggregate.addSelectionListener(new SelectionAdapter() {
141
            @Override
142
            public void widgetSelected(SelectionEvent e) {
143
                if(StoreUtil.promptCheckIsDirty(matrix.getPart())){
144
                    return;
145
                }
146
                aggregatDescriptiveDataSet(matrix.getDescriptiveDataSet().getUuid());
147
            }
148
        });
149
        /**
150
         * Key generation button
151
         */
152
        Button btnGenerateKey = new Button(this, SWT.PUSH);
153
        btnGenerateKey.setText("Generate Polytomous Key");
154
        btnGenerateKey.addSelectionListener(new SelectionAdapter() {
155
            @Override
156
            public void widgetSelected(SelectionEvent e) {
157
                if(StoreUtil.promptCheckIsDirty(matrix.getPart())){
158
                    return;
159
                }
160
                Set<TaxonNodeDto> nodeDtos = matrix.getDescriptiveDataSet().getSubTreeFilter();
161
                TaxonNodeDto parentDto = CdmStore.getService(ITaxonNodeService.class).findCommonParentDto(nodeDtos);
162
                UUID taxonUuid = parentDto.getTaxonUuid();
163
                int response = MessagingUtils.confirmDialog(
164
                        "Choose taxonomic scope",
165
                        String.format("The common parent taxon of this dataset is :\n%s\n\n"
166
                                + "Do you want to use this as the taxonomic scope for the polytomous key?"
167
                                , parentDto.getTaxonTitleCache()), "Yes", "Choose different taxon", "Cancel");
168
                if(response==2){
169
                    return;
170
                }
171
                else if(response==1){
172
                    Taxon taxon = TaxonSelectionDialog.selectTaxon(getShell(), null);
173
                    if(taxon==null){
174
                        return;
175
                    }
176
                    taxonUuid = taxon.getUuid();
177
                }
178
                generateKey(matrix.getDescriptiveDataSet().getUuid(), taxonUuid);
179
            }
180

  
181
        });
182
    }
183

  
184
    private void aggregatDescriptiveDataSet(UUID descriptiveDataSetUuid){
185

  
186
        StructuredDescriptionAggregationConfiguration config = StructuredDescriptionAggregationConfiguration.NewInstance(
187
                null, null);
188
        IStructuredSelection sel = matrix.getSelection();
189
        Object o = sel.getFirstElement();
190
        TaxonNodeFilter filter = TaxonNodeFilter.NewRankInstance(matrix.getDescriptiveDataSet().getMinRank().getUuid(),
191
                matrix.getDescriptiveDataSet().getMaxRank().getUuid());
192
        for (TermDto namedArea : matrix.getDescriptiveDataSet().getGeoFilter()) {
193
            filter = filter.orArea(namedArea.getUuid());
194
        }
195
//        for (TaxonNode taxonNode : matrix.getDescriptiveDataSet().getTaxonSubtreeFilter()) {
196
//            filter = filter.orSubtree(taxonNode);
197
//        }
198

  
199
        if (o instanceof TaxonNodeDto){
200
            filter = filter.orSubtree(CdmStore.getService(ITaxonNodeService.class).load(((TaxonNodeDto)o).getUuid()));
201
        }else{
202
            for (TaxonNodeDto taxonNode : matrix.getDescriptiveDataSet().getSubTreeFilter()) {
203
                filter = filter.orSubtree(taxonNode.getUuid());
204
            }
205
        }
206
        config.setTaxonNodeFilter(filter);
207

  
208
        config.setDatasetUuid(matrix.getDescriptiveDataSet().getUuid());
209
        config.setAggregationMode(AggregationMode.byWithinTaxonAndToParent());
210
        config.setAdaptBatchSize(false);
211
        StructuredAggregationConfigurationWizard aggregationWizard = new StructuredAggregationConfigurationWizard(config, this.matrix.getDescriptiveDataSet(), null);
212
        WizardDialog dialog = new WizardDialog(AbstractUtility.getShell(),
213
                aggregationWizard);
214

  
215
        int open = dialog.open();
216
        if (open != Window.OK){
217
            return;
218
        }
219
        UUID monitorUuid =  CdmApplicationState.getLongRunningTasksService().invoke(config);
220

  
221
        String jobLabel = "Aggregate Descriptive Dataset";
222
        Job job = Job.create(jobLabel, (ICoreRunnable) monitor -> {
223
            SubMonitor subMonitor = SubMonitor.convert(monitor);
224
            subMonitor.beginTask(jobLabel, IProgressMonitor.UNKNOWN);
225
            IRemotingProgressMonitor remotingMonitor;
226
            try {
227
                remotingMonitor = CdmStore.getProgressMonitorClientManager()
228
                        .pollMonitor(jobLabel,
229
                                monitorUuid,
230
                                50,
231
                                null,
232
                                (List<IFeedbackGenerator>)null,
233
                                subMonitor);
234
                Object resultObject = remotingMonitor.getResult();
235
                if(resultObject instanceof Exception){
236
                    MessagingUtils.errorDialog("Aggregation failed", this, "Aggregation was not successfull", TaxeditorEditorPlugin.PLUGIN_ID, (Exception)resultObject, true, true);
237
                }
238
                else if(resultObject instanceof UpdateResult){
239
                    DescriptiveDataSet dataSet = (DescriptiveDataSet) ((UpdateResult) resultObject).getCdmEntity();
240
//                    dataSet = matrix.getCdmEntitiySession().load(dataSet, true);
241

  
242
                    DescriptiveDataSetBaseDto dto = CdmStore.getService(IDescriptiveDataSetService.class).getDescriptiveDataSetDtoByUuid(dataSet.getUuid());
243
                    // update local dataset
244
                    matrix.setDescriptiveDataSet(dto);
245
                    matrix.loadDescriptions(false, false);
246
                }
247
            } catch (InterruptedException e) {
248
                return;
249
            }
250
            monitor.done();
251
        });
252
        job.addJobChangeListener(new JobChangeAdapter(){
253
            @Override
254
            public void done(IJobChangeEvent event) {
255
                CharacterMatrixBottomToolbar.this.getDisplay().asyncExec(()->{
256
                    matrix.redraw();
257
                });
258
            }
259
        });
260
        job.schedule();
261
    }
262

  
263
    private void addRowsToMatrix(Collection<SpecimenRowWrapperDTO> wrappers, UUID descriptiveDataSetUuid){
264
        UUID monitorUuid =  CdmApplicationState.getLongRunningTasksService().addRowWrapperToDataset(wrappers, descriptiveDataSetUuid);
265

  
266
        String jobLabel = "Add specimens to matrix";
267
        Job job = Job.create(jobLabel, (ICoreRunnable) monitor -> {
268
            SubMonitor subMonitor = SubMonitor.convert(monitor);
269
            subMonitor.beginTask(jobLabel, IProgressMonitor.UNKNOWN);
270
            IRemotingProgressMonitor remotingMonitor;
271
            try {
272
                remotingMonitor = CdmStore.getProgressMonitorClientManager()
273
                        .pollMonitor(jobLabel,
274
                                monitorUuid,
275
                                50,
276
                                null,
277
                                (List)null,
278
                                subMonitor);
279
                Object resultObject = remotingMonitor.getResult();
280
                if(resultObject instanceof Exception){
281
                    MessagingUtils.errorDialog("Adding specimens failed", this, "Adding specimens was not successfull", TaxeditorEditorPlugin.PLUGIN_ID, (Exception)resultObject, true, true);
282
                }
283
                else if(resultObject instanceof UpdateResult){
284
                    UpdateResult result = (UpdateResult)resultObject;
285
                    if(!result.getExceptions().isEmpty()){
286
                        MessagingUtils.warningDialog(Messages.CharacterMatrixBottomToolbar_ERROR_ROW_CREATION_TITLE, this,
287
                                String.format(Messages.CharacterMatrixBottomToolbar_ERROR_ROW_CREATION_MESSAGE, result.getExceptions()
288
                                        .stream().map(ex->ex.toString())
289
                                        .collect(Collectors.joining("\n"))));
290
                    }
291
                    DescriptiveDataSet dataSet = (DescriptiveDataSet) result.getCdmEntity();
292
//                    dataSet = matrix.getCdmEntitiySession().load(dataSet, true);
293
                    // update local dataset
294
                    DescriptiveDataSetBaseDto dto = CdmStore.getService(IDescriptiveDataSetService.class).getDescriptiveDataSetDtoByUuid(dataSet.getUuid());
295
                    // update local dataset
296
                    matrix.setDescriptiveDataSet(dto);
297
//                    matrix.setDescriptiveDataSet(dataSet);
298
                    matrix.loadDescriptions(false, false);
299
                }
300
            } catch (InterruptedException e) {
301
                return;
302
            }
303
            monitor.done();
304
        });
305
        job.addJobChangeListener(new JobChangeAdapter(){
306
            @Override
307
            public void done(IJobChangeEvent event) {
308
                CharacterMatrixBottomToolbar.this.getDisplay().asyncExec(()->{
309
                    matrix.redraw();
310
                });
311
            }
312
        });
313
        job.schedule();
314
    }
315

  
316
    private void generateKey(UUID datasetUuid, UUID taxonUuid) {
317

  
318
        UUID monitorUuid =  CdmApplicationState.getLongRunningTasksService().generatePolytomousKey(datasetUuid, taxonUuid);
319

  
320
        String jobLabel = "Generate polytomous key";
321
        Job job = Job.create(jobLabel, (ICoreRunnable) monitor -> {
322
            SubMonitor subMonitor = SubMonitor.convert(monitor);
323
            subMonitor.beginTask(jobLabel, IProgressMonitor.UNKNOWN);
324
            IRemotingProgressMonitor remotingMonitor;
325
            try {
326
                remotingMonitor = CdmStore.getProgressMonitorClientManager()
327
                        .pollMonitor(jobLabel,
328
                                monitorUuid,
329
                                50,
330
                                null,
331
                                (List)null,
332
                                subMonitor);
333
                Object resultObject = remotingMonitor.getResult();
334
                if(resultObject instanceof Exception){
335
                    MessagingUtils.errorDialog("Key generation failed", this, "Generating the polytomous key was not successfull", TaxeditorEditorPlugin.PLUGIN_ID, (Exception)resultObject, true, true);
336
                }
337
            } catch (InterruptedException e) {
338
                return;
339
            }
340
            monitor.done();
341
        });
342
        job.schedule();
343

  
344
    }
345

  
346
}
eu.etaxonomy.taxeditor.editor/src/main/java/eu/etaxonomy/taxeditor/editor/descriptiveDataSet/matrix/handler/CreateTaxonDescriptionHandler.java
46 46
                .createTaxonDescription(descriptiveDataSet.getUuid(), node.getUuid(), getDescriptionType());
47 47
        matrixPart.getMatrix().getCdmEntitiySession().load(taxonRowWrapperDTO.getDescription(), true);
48 48
        matrixPart.getMatrix().getDescriptions().add(taxonRowWrapperDTO);
49
        matrixPart.getMatrix().redraw();
49
        matrixPart.getMatrix().layout();
50 50
    }
51 51

  
52 52
    protected abstract DescriptionType getDescriptionType();
eu.etaxonomy.taxeditor.editor/src/main/java/eu/etaxonomy/taxeditor/editor/l10n/Messages.java
66 66
    public static String CharacterMatrix_NO_DESCRIPTION_TITLE;
67 67
    public static String CharacterMatrix_NO_NODE_FOUND_MESSAGE;
68 68
    public static String CharacterMatrix_NO_NODE_FOUND_TITLE;
69
    public static String CharacterMatrixBottomToolbar_AGGREGATE;
70
    public static String CharacterMatrixBottomToolbar_AGGREGATION_MESSAGE;
71
    public static String CharacterMatrixBottomToolbar_AGGREGATION_TITLE;
72
    public static String CharacterMatrixBottomToolbar_CANCEL;
73
    public static String CharacterMatrixBottomToolbar_CHOOSE_TAXON;
74
    public static String CharacterMatrixBottomToolbar_CONFIRM_DELETE_MESSAGE;
75
    public static String CharacterMatrixBottomToolbar_CONFIRM_DELETE_TITLE;
76
    public static String CharacterMatrixBottomToolbar_ERROR_ROW_CREATION_MESSAGE;
77
    public static String CharacterMatrixBottomToolbar_ERROR_ROW_CREATION_TITLE;
78
    public static String CharacterMatrixBottomToolbar_YES;
79
    public static String CharacterMatrixPart_COULD_NOT_OPEN;
80 69
    public static String CharacterMatrixPart_COULD_NOT_OPEN_MESSAGE;
81 70
    public static String CharacterMatrixPart_LOADING_MATRIX;
82 71
    public static String CharacterMatrixPart_LOADING_MATRIX_FAILED;
eu.etaxonomy.taxeditor.editor/src/main/java/eu/etaxonomy/taxeditor/editor/l10n/messages.properties
221 221
CharacterMatrix_VIEW_CONFIG=View configuration
222 222
CharacterMatrix_ONLY_REMOVE=Only remove from descriptive dataset
223 223
CharacterMatrix_DELETE_DESCRIPTION=Do you really want to delete the description
224
CharacterMatrixBottomToolbar_AGGREGATE=Aggregate
225
CharacterMatrixBottomToolbar_AGGREGATION_MESSAGE=The aggregated description will be stored at the common parent taxon of this dataset:\n%s\n\nDo you want to use this taxon?
226
CharacterMatrixBottomToolbar_AGGREGATION_TITLE=Choose location for the aggregated description
227
CharacterMatrixBottomToolbar_CANCEL=Cancel
228
CharacterMatrixBottomToolbar_CHOOSE_TAXON=Choose taxon
229
CharacterMatrixBottomToolbar_CONFIRM_DELETE_MESSAGE=Do you really want to delete the selected element?
230
CharacterMatrixBottomToolbar_CONFIRM_DELETE_TITLE=Confirm delete
231
CharacterMatrixBottomToolbar_ERROR_ROW_CREATION_MESSAGE=Could not create rows for the following description:\n\n%s
232
CharacterMatrixBottomToolbar_ERROR_ROW_CREATION_TITLE=Errors during row creation
233
CharacterMatrixBottomToolbar_YES=Yes
234 224
CharacterMatrixPart_COULD_NOT_OPEN=Editor could not be opened
235 225
CharacterMatrixPart_COULD_NOT_OPEN_MESSAGE=The descriptive dataset has no character tree selected or the tree contains elements that are not characters.
236 226
CharacterMatrixPart_LOADING_MATRIX=Loading matrix...
eu.etaxonomy.taxeditor.editor/src/main/java/eu/etaxonomy/taxeditor/editor/l10n/messages_de.properties
220 220
CharacterMatrix_VIEW_CONFIG=Ansicht konfigurieren
221 221
CharacterMatrix_ONLY_REMOVE=Nur aus Descriptive Dataset entfernen
222 222
CharacterMatrix_DELETE_DESCRIPTION=Wollen Sie die Beschreibung wirklich l?schen?
223
CharacterMatrixBottomToolbar_AGGREGATE=Aggregation
224
CharacterMatrixBottomToolbar_AGGREGATION_MESSAGE=Die aggregierte Beschreibung wird an das gemeinsame, n?chst-h?here Taxon dieses Datasets gehangen:\n%s\n\nSoll dieses Taxon verwenden werden?
225
CharacterMatrixBottomToolbar_AGGREGATION_TITLE=W?hlen Sie den Speicherort f?r die aggregierte Beschreibung
226
CharacterMatrixBottomToolbar_CANCEL=Abbrechen
227
CharacterMatrixBottomToolbar_CHOOSE_TAXON=Taxon w?hlen
228
CharacterMatrixBottomToolbar_CONFIRM_DELETE_MESSAGE=Wollen Sie wirklich das ausgew?hlte Element l?schen?
229
CharacterMatrixBottomToolbar_CONFIRM_DELETE_TITLE=L?schen best?tigen
230
CharacterMatrixBottomToolbar_ERROR_ROW_CREATION_MESSAGE=Konnte keine Zeilen f?r die folgenden Beschreibungen erzeugen:\n\n%s
231
CharacterMatrixBottomToolbar_ERROR_ROW_CREATION_TITLE=Fehler bei der Erstellung der Zeilen
232
CharacterMatrixBottomToolbar_YES=Ja
233 223
CharacterMatrixPart_COULD_NOT_OPEN=Editor konnte nicht ge?ffnet werden
234 224
CharacterMatrixPart_COULD_NOT_OPEN_MESSAGE=Das Dataset hat keinen Character-Baum ausgew?hlt oder enth?lt Elemente, die keine Character sind.
235 225
CharacterMatrixPart_LOADING_MATRIX=Lade Matrix...

Also available in: Unified diff