Project

General

Profile

Download (7.06 KB) Statistics
| Branch: | Tag: | Revision:
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.cdm.service;
10

    
11
import java.util.Arrays;
12
import java.util.List;
13
import java.util.StringTokenizer;
14
import java.util.regex.Matcher;
15
import java.util.regex.Pattern;
16

    
17
import eu.etaxonomy.cdm.model.reference.Reference;
18

    
19
/**
20
 * Creates truncated labels for references by applying ellypsis on the reference authors and title for inReferences an
21
 * ellypsis is also being created.
22
 * <p>
23
 * Here are some examples:
24
 * <table>
25
 * <th>
26
 *  <td>original</td>
27
 *  <td>ellypsis</td></th>
28
 * <tr>
29
 * </tr>
30
 * <td>
31
 *   <td>Gottschling, M., Tillmann, U., Kusber, W.-H. & al., A Gordian knot: Nomenclature and taxonomy of Heterocapsa triquetra (Peridiniales: Heterocapsaceae) in Taxon 67(1): 179–185. 2018<td>
32
 *   </td>Gottschling, M.,…Kusber…, A Gordian knot:… in Taxon 67(1): 179–185. 2018</td>
33
 *   </tr>
34
 * <td>
35
 *   <td>Hamilton, P.B., Stachura-Suchoples, K., Kusber, W.-H. & al., Typification of the puzzling large diatom species Neidium iridis Ehrenb. in Cryptog. Algol.<td>
36
 *   </td>Hamilton, P.B.,…Kusber…, Typification of the… in Cryptog. Algol.</td>
37
 * </tr>
38
 * <td>
39
 * <td>Jahn , R., Kusber, W.-H. & Cocquyt, C., Differentiating Iconella from Surirella (Bacillariophyceae): typifying four Ehrenberg names and a preliminary checklist of the African taxa in PhytoKeys 82: 73-112<td>
40
 * </td>Jahn , R., Kusber, W.-H. & Cocquyt, C., Differentiating… in PhytoKeys 82: 73-112</td>
41
 * </tr>
42
 * <td>
43
 * <td>Jahn, R., Kusber, W.-H., Skibbe, O. & al., Gomphonella olivacea (Hornemann) Rabenhorst – a new phylogenetic position for a well-known taxon, its typification, new species and combinations in Cryptog. Algol.<td>
44
 * </td>Jahn, R., Kusber,…, Gomphonella olivacea… in Cryptog. Algol.</td>
45
 * </td>
46
 * </table>
47
 * @author a.kohlbecker
48
 * @since Dec 12, 2018
49
 *
50
 */
51
public class ReferenceLabelProvider implements ComboboxLabelProvider<Reference> {
52

    
53
    private static final String DELIM = " ";
54

    
55
    /**
56
     * This init strategy should be used when the ReferenceLabelProvider is being used
57
     * outside of a hibernate session
58
     */
59
    public static List<String> INIT_STRATEGY = Arrays.asList(
60
            "authorship",
61
            "inReference.authorship",
62
            "inReference.inReference.authorship",
63
            "inReference.inReference.inReference");
64

    
65
    public enum LabelType {
66
        NOMENCLATURAL,
67
        BIBLIOGRAPHIC;
68
    }
69

    
70
    private LabelType labelType;
71
    private int maxAuthorCharsVisible = 20;
72
    private int maxTitleCharsVisible = 20;
73

    
74
    private String MORE = "\u2026"; // 'HORIZONTAL ELLIPSIS' (U+2026)
75

    
76
    public ReferenceLabelProvider(LabelType labelType){
77
        this.labelType = labelType;
78
    }
79

    
80
    /**
81
     * {@inheritDoc}
82
     */
83
    @Override
84
    public String composeLabel(Reference entity, String filterString) {
85

    
86

    
87
        EllipsisData ed = ellypsis(entity, filterString);
88
        String label = ed.truncated;
89

    
90
        return label;
91
    }
92

    
93
    /**
94
     * @param entity
95
     * @param filterString
96
     * @return
97
     */
98
    public EllipsisData ellypsis(Reference entity, String filterString) {
99

    
100
        String label = "";
101
        String authors = entity.getAuthorship() != null ? entity.getAuthorship().getTitleCache() : "";
102
        String title = null;
103
        String titleCache;
104

    
105
        switch(labelType){
106
            case NOMENCLATURAL:
107
                if(!entity.isProtectedAbbrevTitleCache()){
108
                    title = entity.getAbbrevTitle();
109
                    if(title == null) {
110
                        // fallback to use the title
111
                        title = entity.getTitle();
112
                    }
113
                }
114
                titleCache = entity.getAbbrevTitleCache();
115
                break;
116
            case BIBLIOGRAPHIC:
117
            default:
118
                if(!entity.isProtectedTitleCache()){
119
                    title = entity.getTitle();
120
                    if(title == null) {
121
                        // fallback to use the abbreviated title
122
                        title = entity.getAbbrevTitle();
123
                    }
124
                }
125
                titleCache = entity.getTitleCache();
126
                break;
127
        }
128

    
129
        Pattern pattern = Pattern.compile("(" + filterString +")", Pattern.CASE_INSENSITIVE);
130

    
131
        if(authors != null){
132
            String authorsEllipsed = authors;
133
            if(authorsEllipsed.length() > maxAuthorCharsVisible) {
134
                authorsEllipsed = applyEllipsis(authors, maxAuthorCharsVisible);
135
                authorsEllipsed = preserveFilterstring(filterString, authors, pattern, authorsEllipsed);
136
            }
137
            label = titleCache.replace(authors, authorsEllipsed);
138
        }
139

    
140

    
141
        if(title != null){
142
            String titleEllipsed = title;
143
            if(titleEllipsed.length() > maxTitleCharsVisible) {
144
                titleEllipsed = applyEllipsis(title, maxTitleCharsVisible);
145
                titleEllipsed = preserveFilterstring(filterString, title, pattern, titleEllipsed);
146
            }
147
            label = label.replace(title, titleEllipsed);
148
        }
149

    
150
        if(entity.getInReference() != null){
151
            EllipsisData inRefEd = ellypsis(entity.getInReference(), filterString);
152
            label = label.replace(inRefEd.original, inRefEd.truncated);
153
        }
154

    
155
        EllipsisData ed = new EllipsisData(titleCache, label);
156

    
157

    
158
        return ed;
159
    }
160

    
161
    /**
162
     * @param authors
163
     * @return
164
     */
165
    public String applyEllipsis(String text, int maxCharsVisible) {
166
        String ellipsedText = "";
167
        StringTokenizer tokenizer = new StringTokenizer(text, DELIM);
168
        while(tokenizer.hasMoreElements()){
169
            String token = tokenizer.nextToken();
170
            if(ellipsedText.length() + token.length() + DELIM.length() <= maxCharsVisible){
171
                ellipsedText = ellipsedText + (ellipsedText.isEmpty() ? "" : DELIM) + token;
172
            } else {
173
                break;
174
            }
175
        }
176
        return ellipsedText + MORE;
177
    }
178

    
179
    /**
180
     * @param filterString
181
     * @param authors
182
     * @param pattern
183
     * @param authorsEllipsed
184
     * @return
185
     */
186
    public String preserveFilterstring(String filterString, String text, Pattern pattern, String textEllipsed) {
187
        String matchingSubstring = null;
188
        if(!filterString.isEmpty()){
189
            Matcher m = pattern.matcher(text);
190
            if(m.find()){
191
                matchingSubstring = m.group(1);
192
            }
193
        }
194
        if(matchingSubstring != null && !textEllipsed.toLowerCase().contains(filterString)){
195
            textEllipsed += matchingSubstring + MORE;
196
        }
197
        return textEllipsed;
198
    }
199

    
200
    class EllipsisData {
201
        String original;
202
        String truncated;
203
        /**
204
         * @param original
205
         * @param truncated
206
         */
207
        public EllipsisData(String original, String truncated) {
208
            super();
209
            this.original = original;
210
            this.truncated = truncated;
211
        }
212
    }
213

    
214
}
(7-7/11)