1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.xnap.gui.table;
21
22 import java.util.Iterator;
23 import java.util.LinkedList;
24 import java.util.ListIterator;
25
26 import org.xnap.XNap;
27 import org.xnap.event.ListEvent;
28 import org.xnap.gui.event.SwingListListener;
29 import org.xnap.gui.util.SwingSynchronizedCache;
30 import org.xnap.peer.Peer;
31 import org.xnap.plugin.Plugin;
32 import org.xnap.search.SearchFilter;
33 import org.xnap.search.SearchResult;
34 import org.xnap.search.SearchResultContainer;
35 import org.xnap.util.FileHelper;
36 import org.xnap.util.StringHelper;
37 import org.xnap.util.MultiHashtable;
38
39 /***
40 * The model for the search table.
41 *
42 * @see xnap.gui.SearchResultPanel
43 */
44 public class SearchTableModel extends DefaultColumnTreeTableModel
45 implements SwingListListener {
46
47
48
49
50
51 private SwingSynchronizedCache cache = new SwingSynchronizedCache(this);
52 private FilterHandler filter = new FilterHandler();
53
54 private MultiHashtable nodeByHash = new MultiHashtable();
55
56
57
58 public SearchTableModel()
59 {
60 addColumns(createDefaultColumns());
61 }
62
63
64
65 public static Column[] createDefaultColumns()
66 {
67 return new Column[] {
68 new Column("icon", XNap.tr("Filename"), TreeTableModel.class),
69 new Column("filename", XNap.tr("Filename"),
70 SearchResultWrapper.class),
71 new Column("path", XNap.tr("Path"), String.class,
72 new StringCellRenderer()),
73 new Column("filesize", XNap.tr("Filesize"), Long.class,
74 new FilesizeCellRenderer()),
75 new Column("peer", XNap.tr("Peer"), String.class,
76 new StringCellRenderer()),
77 new Column(XNap.tr("Link Speed"), Integer.class,
78 new LinkSpeedCellRenderer()),
79 new Column("plugin", XNap.tr("Plugin"), String.class),
80 new Column("availability", XNap.tr("Availability"), Integer.class,
81 new AvailabilityCellRenderer()),
82 new Column("type", XNap.tr("Type"), String.class,
83 new StringCellRenderer()),
84 new Column("bitrate", XNap.tr("Bitrate"), Integer.class,
85 new NumberCellRenderer()),
86 new Column("length", XNap.tr("Length"), Integer.class,
87 new TimeCellRenderer()),
88 };
89 }
90
91 public SwingSynchronizedCache getListListener()
92 {
93 return cache;
94 }
95
96 /***
97 * Invoked when search results have been received.
98 */
99 public void itemsAdded(Object[] items)
100 {
101 for (int i = 0; i < items.length; i++) {
102 if (items[i] instanceof SearchResult) {
103 SearchResult result = (SearchResult)items[i];
104 group(result);
105 }
106 else if (items[i] instanceof TreeTableNode) {
107 if (filter.matches((TreeTableNode)items[i])) {
108 add((TreeTableNode)items[i]);
109 }
110 }
111 }
112 }
113
114 /***
115 * Groups results.
116 *
117 * @return true, if result was added to the tree
118 */
119 public void group(SearchResult result)
120 {
121 Object key = result.getHash();
122 if (key != null) {
123 for (ListIterator i = nodeByHash.getList(key).listIterator();
124 i.hasNext();) {
125 LazyTreeTableNode node = (LazyTreeTableNode)i.next();
126 SearchResult sr = (SearchResult)node.getData();
127 if (sr.canGroup(result)) {
128 if (!(sr instanceof SearchResultContainer)) {
129
130 SearchResultContainer c = sr.createContainer();
131
132
133 c.add(sr);
134
135
136
137
138 if (c.add(result)) {
139
140 node.setData(c);
141
142
143 TreeTableNode leaf = new LeafTreeTableNode(sr);
144 node.add(leaf);
145
146
147 leaf = new LeafTreeTableNode(result);
148 node.add(leaf);
149 }
150 }
151 else if (((SearchResultContainer)node.getData()).
152 add(result)) {
153 TreeTableNode leaf = new LeafTreeTableNode(result);
154 node.add(leaf);
155 }
156 return;
157 }
158 }
159 }
160
161 LazyTreeTableNode node = new LazyTreeTableNode(this, result);
162 if (key != null) {
163 nodeByHash.put(key, node);
164 }
165 filter.add(node);
166 if (filter.matches(node)) {
167 add(node);
168 }
169 }
170
171 /***
172 * Never invoked.
173 */
174 public void itemsRemoved(Object[] items)
175 {
176 }
177
178 public Object getValueAt(Object node, int column)
179 {
180 if (node instanceof TreeTableNode) {
181 SearchResult sr = (SearchResult)((TreeTableNode)node).getData();
182 Peer p = sr.getPeer();
183
184 switch (column) {
185 case 0:
186 return (node instanceof LeafTreeTableNode) ? null
187 : sr.getIcon();
188 case 1:
189
190 return new SearchResultWrapper(sr);
191 case 2:
192 String[] path = sr.getPath();
193 return (path != null) ? StringHelper.toString(path, "/")
194 : null;
195 case 3:
196 return new Long(sr.getFilesize());
197 case 4:
198 return (p != null) ? p.getName() : null;
199 case 5:
200 return new Integer((p != null) ? p.getLinkSpeed() : -1);
201 case 6:
202 Plugin plugin = sr.getPlugin();
203 return (plugin != null) ? plugin.getInfo().getName() : null;
204 case 7:
205 return new AvailabilityCellRenderer.Availability
206 (sr.getAvailability(),
207 sr.getSourcesCount());
208 case 8:
209 return FileHelper.extension(sr.getShortFilename());
210 default:
211 return sr.get(getColumnAt(column).getName());
212 }
213 }
214
215 return null;
216 }
217
218 public void setFilter(SearchFilter f)
219 {
220 filter.setFilter(f);
221 }
222
223 /***
224 * Invoked by {@link xnap.gui.SearchResultPanel} to set the tab title.
225 */
226 public int size()
227 {
228 return getChildCount(getRoot());
229 }
230
231
232
233 private class FilterHandler
234 {
235
236 private LinkedList data = new LinkedList();
237 private SearchFilter filter;
238
239 public void add(TreeTableNode node)
240 {
241 data.add(node);
242 }
243
244 public Iterator iterator()
245 {
246 return data.iterator();
247 }
248
249 public boolean matches(TreeTableNode node)
250 {
251 return (filter == null
252 || filter.matches((SearchResult)
253 ((TreeTableNode)node).getData()));
254 }
255
256 public void setFilter(SearchFilter filter)
257 {
258 this.filter = filter;
259 clear();
260
261
262
263
264
265
266
267 for (Iterator i = iterator(); i.hasNext();) {
268 ListEvent event
269 = new ListEvent(this, ListEvent.ITEM_ADDED, i.next());
270 cache.itemAdded(event);
271 }
272 }
273
274 }
275
276 }