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 @ 2287

History | View | Annotate | Download (7.53 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.io.FilenameUtils;
12
import org.apache.commons.lang3.ObjectUtils;
13
import org.apache.commons.lang3.StringUtils;
14
import org.gvsig.tools.ToolsLocator;
15
import org.gvsig.tools.i18n.I18nManager;
16
import org.gvsig.tools.task.AbstractCancellableTask;
17
import org.gvsig.tools.util.LabeledValue;
18
import org.gvsig.tools.util.LabeledValueImpl;
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
            theFilter = theFilter.toLowerCase();
79
            if (FilenameUtils.wildcardMatch(item.toString().toLowerCase(), theFilter)) {
80
                return true;
81
            }
82
            if (item instanceof LabeledValue) {
83
                LabeledValue labeledValue = (LabeledValue) item;
84
                String label = labeledValue.getLabel();
85
                if (label != null) {
86
                    if (FilenameUtils.wildcardMatch(label.toLowerCase(), theFilter)) {
87
                        return true;
88
                    }
89
                    if (FilenameUtils.wildcardMatch(i18n.getTranslation(label).toLowerCase(), theFilter)) {
90
                        return true;
91
                    }
92
                }
93
            }
94
            return false;
95
        };
96
    }
97

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

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

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

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

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

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

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

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

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

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

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

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

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

    
236
    @Override
237
    public void setCaseSensitive(boolean sensitive) {
238
        this.caseSensitive = sensitive;
239
    }
240

    
241
    @Override
242
    public boolean isCaseSensitive() {
243
        return this.caseSensitive;
244
    }
245

    
246
}