OpenConcerto

Dépôt officiel du code source de l'ERP OpenConcerto
sonarqube

svn://code.openconcerto.org/openconcerto

Rev

Rev 17 | Rev 142 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
17 ilm 1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
5
 *
6
 * The contents of this file are subject to the terms of the GNU General Public License Version 3
7
 * only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
8
 * copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
9
 * language governing permissions and limitations under the License.
10
 *
11
 * When distributing the software, include this License Header Notice in each file.
12
 */
13
 
14
 package org.openconcerto.ui.component.combo;
15
 
16
import org.openconcerto.ui.component.combo.SearchMode.ComboMatcher;
83 ilm 17
import org.openconcerto.utils.IFutureTask;
18
import org.openconcerto.utils.RTInterruptedException;
19
import org.openconcerto.utils.model.ISearchable;
17 ilm 20
 
21
import java.util.ArrayList;
22
import java.util.List;
23
import java.util.StringTokenizer;
83 ilm 24
import java.util.concurrent.ExecutionException;
25
import java.util.concurrent.FutureTask;
17 ilm 26
 
27
import javax.swing.SwingUtilities;
28
 
29
public class ISearchableComboCompletionThread<T> extends Thread {
30
    private final ISearchableCombo<T> combo;
31
    private final String t;
32
    private boolean stopNow;
33
 
83 ilm 34
    public ISearchableComboCompletionThread(final ISearchableCombo<T> combo, final String t) {
17 ilm 35
        this.combo = combo;
36
        this.t = t;
37
        this.stopNow = false;
38
    }
39
 
40
    private ISearchableCombo<T> getCombo() {
41
        return this.combo;
42
    }
43
 
83 ilm 44
    @Override
17 ilm 45
    public void run() {
46
        computeAutoCompletion();
47
    }
48
 
49
    public synchronized void stopNow() {
50
        this.stopNow = true;
51
    }
52
 
53
    private synchronized boolean isStopped() {
54
        return this.stopNow;
55
    }
56
 
57
    private void computeAutoCompletion() {
83 ilm 58
        final boolean showAll = this.t == null;
17 ilm 59
        final List<ISearchableComboItem<T>> l;
83 ilm 60
        if (!showAll) {
17 ilm 61
            l = getMatchingValues();
62
        } else {
63
            l = getMaxValues();
64
        }
65
 
66
        SwingUtilities.invokeLater(new Runnable() {
83 ilm 67
            @Override
17 ilm 68
            public void run() {
69
                if (isStopped()) {
70
                    return;
71
                }
83 ilm 72
                getCombo().setMatchingCompletions(l, showAll);
17 ilm 73
            }
74
        });
75
 
76
    }
77
 
78
    private List<ISearchableComboItem<T>> getMaxValues() {
79
        final List<ISearchableComboItem<T>> allVals = this.getCombo().getModelValues();
80
        return allVals.subList(0, Math.min(this.getCombo().getMaximumResult(), allVals.size()));
81
    }
82
 
83
    private List<ISearchableComboItem<T>> getMatchingValues() {
84
        final List<ISearchableComboItem<T>> result = new ArrayList<ISearchableComboItem<T>>();
85
 
86
        final int minimumSearch = getCombo().getMinimumSearch();
83 ilm 87
        final String aText = this.t.trim();
88
        final String normalizedText = aText.length() < minimumSearch ? "" : aText;
17 ilm 89
 
83 ilm 90
        Boolean searched = null;
91
        // If there was a search and now the text is below minimum, we must unset the search
92
        // Efficient since setSearch() only carry out its action if the search changes
93
        if (getCombo().getCache() instanceof ISearchable) {
94
            final ISearchable searchableListModel = (ISearchable) getCombo().getCache();
95
            if (searchableListModel.isSearchable()) {
96
                // Wait for the new values, which will be added to the model by a listener
97
                final FutureTask<Object> noOp = IFutureTask.createNoOp();
98
                searched = searchableListModel.setSearch(normalizedText, noOp);
99
                try {
100
                    noOp.get();
101
                } catch (InterruptedException e) {
102
                    throw new RTInterruptedException(e);
103
                } catch (ExecutionException e) {
104
                    throw new IllegalStateException("No op couldn't be executed", e);
105
                }
106
            }
107
        }
108
        if (!normalizedText.isEmpty() && searched != Boolean.FALSE) {
17 ilm 109
            final List<ISearchableComboItem<T>> cache = getCombo().getModelValues();
83 ilm 110
            // don't filter twice
111
            final ComboMatcher search = Boolean.TRUE.equals(searched) ? null : getCombo().getCompletionMode().matcher(normalizedText.toLowerCase());
17 ilm 112
            final int maximumResult = getCombo().getMaximumResult();
113
 
114
            for (int index = 0; index < cache.size(); index++) {
115
                final ISearchableComboItem<T> itemO = cache.get(index);
116
                final String item = itemO.asString();
117
                // On s'arrête au plus vite
118
                if (index % 50 == 0) {
119
                    if (isStopped()) {
120
                        return result;
121
                    }
122
                }
123
                // Recherche case insensitive
83 ilm 124
                boolean ok = search == null || search.match(item.toLowerCase());
17 ilm 125
 
126
                // FIXME: mettre dans les prefs removeDuplicate
83 ilm 127
                final boolean removeDuplicate = true;
17 ilm 128
                if (ok && removeDuplicate) {
129
                    for (int i = 0; i < result.size(); i++) {
130
                        if (isStopped()) {
131
                            return result;
132
                        }
83 ilm 133
                        final ISearchableComboItem<T> element = result.get(i);
17 ilm 134
                        if (element.asString().equalsIgnoreCase(item)) {
135
                            ok = false;
136
                            break;
137
                        }
138
                    }
139
                }
140
 
141
                if (ok) {
142
                    result.add(itemO);
143
                }
144
 
145
                if (result.size() > maximumResult) {
146
                    break;
147
                }
148
            }
149
 
150
        }
151
 
152
        return result;
153
    }
154
 
155
    static final List<String> cut(final String value) {
156
        final List<String> v = new ArrayList<String>();
157
        final StringTokenizer tokenizer = new StringTokenizer(value);
158
        while (tokenizer.hasMoreElements()) {
83 ilm 159
            final String element = (String) tokenizer.nextElement();
17 ilm 160
            v.add(element);
161
        }
162
        return v;
163
    }
164
 
165
}