Statistics
| Revision:

gvsig-tools / org.gvsig.tools / library / trunk / org.gvsig.tools / org.gvsig.tools.swing / org.gvsig.tools.swing.impl / src / main / java / org / gvsig / tools / swing / impl / FilteredListModelImpl.java @ 2350

History | View | Annotate | Download (7.56 KB)

1
package org.gvsig.tools.swing.impl;
2

    
3
import java.util.AbstractList;
4
import org.gvsig.tools.swing.api.FilteredListModel;
5
import java.util.List;
6
import java.util.Objects;
7
import javax.swing.AbstractListModel;
8
import javax.swing.DefaultListModel;
9
import javax.swing.ListModel;
10
import javax.swing.SwingUtilities;
11
import org.apache.commons.lang3.ObjectUtils;
12
import org.apache.commons.lang3.StringUtils;
13
import org.gvsig.tools.ToolsLocator;
14
import org.gvsig.tools.i18n.I18nManager;
15
import org.gvsig.tools.task.AbstractCancellableTask;
16
import org.gvsig.tools.util.LabeledValue;
17
import org.gvsig.tools.util.LabeledValueImpl;
18
import org.gvsig.tools.util.CompareUtils;
19

    
20
/**
21
 *
22
 * @author jjdelcerro
23
 */
24
class FilteredListModelImpl extends AbstractListModel implements FilteredListModel {
25

    
26
    private static class ListModelToListAdapter extends AbstractList {
27

    
28
        private final ListModel model;
29

    
30
        public ListModelToListAdapter(ListModel model) {
31
            this.model = model;
32
        }
33

    
34
        @Override
35
        public Object get(int index) {
36
            return this.model.getElementAt(index);
37
        }
38

    
39
        @Override
40
        public int size() {
41
            return this.model.getSize();
42
        }
43

    
44
        @Override
45
        public Object set(int index, Object element) {
46
            if (!(model instanceof DefaultListModel)) {
47
                throw new IllegalStateException("The model is unmodifiable.");
48
            }
49
            return ((DefaultListModel) this.model).set(index, element);
50
        }
51

    
52
    }
53

    
54
    private ListModel elements;
55
    private DefaultListModel<LabeledValue> filteredElements;
56
    private String filter;
57
    private AbstractCancellableTask th;
58
    private FilterFunction filterfn;
59
    private boolean caseSensitive = false;
60

    
61
    public FilteredListModelImpl(ListModel model) {
62
        if (model == null) {
63
            this.elements = new DefaultListModel();
64
        } else {
65
            this.elements = model;
66
        }
67
        this.filteredElements = new DefaultListModel();
68
        this.filter = null;
69
        this.th = null;
70
        final I18nManager i18n = ToolsLocator.getI18nManager();
71
        this.filterfn = (Object theModel, Object item, String theFilter) -> {
72
            if (item == null) {
73
                return false;
74
            }
75
            if (StringUtils.isBlank(theFilter)) {
76
                return true;
77
            }
78
            if( CompareUtils.match(item.toString(), theFilter) ) {
79
                return true;
80
            }
81
            if (item instanceof LabeledValue) {
82
                LabeledValue labeledValue = (LabeledValue) item;
83
                String label = labeledValue.getLabel();
84
                if (label != null) {
85
                    if (CompareUtils.match(label, theFilter) ) {
86
                        return true;
87
                    }
88
                    if (CompareUtils.match(i18n.getTranslation(label), theFilter)) {
89
                        return true;
90
                    }
91
                }
92
            }
93
            return false;
94
        };
95
    }
96

    
97
    @Override
98
    public void setFilterFunction(FilterFunction filter) {
99
        this.filterfn = filter;
100
    }
101

    
102
    @Override
103
    public synchronized ListModel getModel() {
104
        return this.elements;
105
    }
106

    
107
    @Override
108
    public synchronized int getSize() {
109
        return this.filteredElements.getSize();
110
    }
111

    
112
    @Override
113
    public synchronized void clear() {
114
        this.elements = new DefaultListModel();
115
        this.filteredElements = new DefaultListModel();
116
        this.filter = null;
117
        fireContentsChanged();
118
    }
119

    
120
    @Override
121
    public synchronized LabeledValue getElementAt(int index) {
122
        return this.filteredElements.getElementAt(index);
123
    }
124

    
125
    @Override
126
    public synchronized void addElement(LabeledValue element) {
127
        if (element == null) {
128
            return;
129
        }
130
        if (!(elements instanceof DefaultListModel)) {
131
            throw new IllegalStateException("The model is unmodifiable.");
132
        }
133
        ((DefaultListModel) this.elements).addElement(element);
134
        if (this.filterfn.test(this, element, filter)) {
135
            this.filteredElements.addElement(element);
136
        }
137
        fireContentsChanged();
138
    }
139

    
140
    @Override
141
    public synchronized void addElement(Object element) {
142
        if (!(element instanceof LabeledValue)) {
143
            element = new LabeledValueImpl<>(Objects.toString(element, ""), element);
144
        }
145
        this.addElement((LabeledValue) element);
146
    }
147

    
148
    @Override
149
    public synchronized void setFilter(String filter) {
150
        if (StringUtils.isBlank(filter)) {
151
            this.filter = null;
152
        } else {
153
            if (StringUtils.containsAny(filter, "*?")) {
154
                this.filter = filter;
155
            } else {
156
                this.filter = "*" + filter + "*";
157
            }
158
        }
159
        this.copy(elements, filteredElements, this.filter);
160
        fireContentsChanged();
161
    }
162

    
163
    private synchronized void copy(ListModel source, DefaultListModel target, String filter) {
164
        target.clear();
165
        for (int i = 0; i < source.getSize(); i++) {
166
            Object item = source.getElementAt(i);
167
            try {
168
                if (this.filterfn.test(this, item, filter)) {
169
                    target.addElement(item);
170
                }
171
            } catch (Exception e) {
172
                target.addElement(item);
173
            }
174
        }
175
    }
176

    
177
    private void fireContentsChanged() {
178
        if (!SwingUtilities.isEventDispatchThread()) {
179
            SwingUtilities.invokeLater(() -> {
180
                fireContentsChanged();
181
            });
182
            return;
183
        }
184
        this.fireContentsChanged(this, 0, this.filteredElements.size());
185
    }
186

    
187
    @Override
188
    public String getFilter() {
189
        return this.filter;
190
    }
191

    
192
    @Override
193
    public void sort(final boolean ascending) {
194
        this.sortBackground(ascending);
195
    }
196

    
197
    private synchronized void sortBackground(final boolean ascending) {
198
        if (this.th != null) {
199
            this.th.cancelRequest();
200
        }
201
        this.th = new AbstractCancellableTask("FilteredListModelSorter") {
202
            @Override
203
            public void run() {
204
                final List items = new ListModelToListAdapter(elements);
205
                items.sort((Object o1, Object o2) -> {
206
                    int r;
207
                    String o1string;
208
                    String o2string;
209
                    if (o1 instanceof LabeledValue) {
210
                        o1string = ((LabeledValue) o1).getLabel();
211
                    } else {
212
                        o1string = Objects.toString(o1, "");
213
                    }
214
                    if (o2 instanceof LabeledValue) {
215
                        o2string = ((LabeledValue) o2).getLabel();
216
                    } else {
217
                        o2string = Objects.toString(o2, "");
218
                    }
219
                    if (isCaseSensitive()) {
220
                        r = ObjectUtils.compare(o1string, o2string);
221
                    } else {
222
                        r = CompareUtils.compare(o2string, o2string);
223
                    }
224
                    if (ascending) {
225
                        return r;
226
                    }
227
                    return -r;
228
                });
229
                if (this.isCancellationRequested()) {
230
                    return;
231
                }
232
                copy(elements, filteredElements, filter);
233
                fireContentsChanged();
234
            }
235
        };
236
        th.start();
237
    }
238
     
239

    
240
    @Override
241
    public void setCaseSensitive(boolean sensitive) {
242
        this.caseSensitive = sensitive;
243
    }
244

    
245
    @Override
246
    public boolean isCaseSensitive() {
247
        return this.caseSensitive;
248
    }
249

    
250
}