1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34 package info.magnolia.ui.vaadin.layout;
35
36 import info.magnolia.ui.vaadin.gwt.client.layout.thumbnaillayout.connector.ThumbnailLayoutState;
37 import info.magnolia.ui.vaadin.gwt.client.layout.thumbnaillayout.rpc.ThumbnailLayoutClientRpc;
38 import info.magnolia.ui.vaadin.gwt.client.layout.thumbnaillayout.rpc.ThumbnailLayoutServerRpc;
39 import info.magnolia.ui.vaadin.gwt.client.layout.thumbnaillayout.shared.ThumbnailData;
40
41 import java.util.ArrayList;
42 import java.util.List;
43 import java.util.concurrent.atomic.AtomicInteger;
44
45 import org.apache.commons.lang.StringUtils;
46
47 import com.google.common.collect.BiMap;
48 import com.google.common.collect.HashBiMap;
49 import com.vaadin.data.Container;
50 import com.vaadin.data.Container.Ordered;
51 import com.vaadin.server.Resource;
52 import com.vaadin.ui.AbstractComponent;
53
54
55
56
57 public class LazyThumbnailLayout extends AbstractComponent implements Container.Viewer {
58
59 private final List<ThumbnailSelectionListener> selectionListeners = new ArrayList<LazyThumbnailLayout.ThumbnailSelectionListener>();
60
61 private final List<ThumbnailDblClickListener> dblClickListeners = new ArrayList<LazyThumbnailLayout.ThumbnailDblClickListener>();
62
63 private final List<ThumbnailRightClickListener> rightClickListeners = new ArrayList<LazyThumbnailLayout.ThumbnailRightClickListener>();
64
65 private Ordered container;
66
67
68 private final BiMap<String, String> mapper = HashBiMap.create();
69 private final AtomicInteger counter = new AtomicInteger();
70
71 private String selectedItemId;
72
73 private final ThumbnailLayoutServerRpc rpcHandler = new ThumbnailLayoutServerRpc() {
74
75 @Override
76 public void onThumbnailSelected(String id) {
77 final Object itemId = mapper.get(id);
78 if (itemId != null) {
79 LazyThumbnailLayout.this.onThumbnailSelected(itemId);
80 }
81 }
82
83 @Override
84 public void onThumbnailDoubleClicked(String id) {
85 final Object itemId = mapper.get(id);
86 if (itemId != null) {
87 LazyThumbnailLayout.this.onThumbnailDoubleClicked(itemId);
88 }
89 }
90
91 @Override
92 public void onThumbnailRightClicked(String id, int clickX, int clickY) {
93 final Object itemId = mapper.get(id);
94 if (itemId != null) {
95 LazyThumbnailLayout.this.onThumbnailRightClicked(itemId, clickX, clickY);
96 }
97 }
98
99 @Override
100 public void loadThumbnails(int amount) {
101 getRpcProxy(ThumbnailLayoutClientRpc.class).addThumbnails(fetchThumbnails(amount));
102 getRpcProxy(ThumbnailLayoutClientRpc.class).setSelected(mapper.inverse().get(selectedItemId));
103 }
104
105 @Override
106 public void clearThumbnails() {
107 LazyThumbnailLayout.this.clear();
108 }
109
110 };
111
112 public LazyThumbnailLayout() {
113 setImmediate(true);
114 registerRpc(rpcHandler);
115 }
116
117 private void onThumbnailDoubleClicked(Object itemId) {
118 for (final ThumbnailDblClickListener listener : dblClickListeners) {
119 listener.onThumbnailDblClicked(String.valueOf(itemId));
120 }
121 }
122
123 private void onThumbnailRightClicked(Object itemId, int clickX, int clickY) {
124 for (final ThumbnailRightClickListener listener : rightClickListeners) {
125 listener.onThumbnailRightClicked(String.valueOf(itemId), clickX, clickY);
126 }
127 }
128
129 private void onThumbnailSelected(Object itemId) {
130 for (final ThumbnailSelectionListener listener : selectionListeners) {
131 listener.onThumbnailSelected(String.valueOf(itemId));
132 }
133 }
134
135 private List<ThumbnailData> fetchThumbnails(int amount) {
136 List<ThumbnailData> thumbnails = new ArrayList<ThumbnailData>();
137 Object id = mapper.get(getState().lastQueried);
138 if (id == null) {
139 id = container.firstItemId();
140 }
141 int i = 0;
142 while (id != null && i < amount) {
143 Object resource = container.getContainerProperty(id, "thumbnail").getValue();
144 boolean isRealResource = resource instanceof Resource;
145 String thumbnailId = mapItemIdToThumbnailId((String) id);
146 String iconFontId = isRealResource ? null : String.valueOf(resource);
147 if (isRealResource) {
148 setResource(thumbnailId, (Resource) resource);
149 }
150 thumbnails.add(new ThumbnailData(thumbnailId, iconFontId, isRealResource));
151 id = container.nextItemId(id);
152 ++i;
153 }
154 getState().lastQueried = StringUtils.defaultString(mapItemIdToThumbnailId((String) id), "null");
155 return thumbnails;
156 }
157
158
159
160
161 private String mapItemIdToThumbnailId(String itemId) {
162 if (itemId == null) {
163 return null;
164 }
165 String thumbnailId = mapper.inverse().get(itemId);
166 if (thumbnailId != null) {
167 return thumbnailId;
168 }
169 thumbnailId = String.valueOf(counter.incrementAndGet());
170 mapper.put(thumbnailId, itemId);
171 return thumbnailId;
172 }
173
174 private void setThumbnailAmount(int thumbnailAmount) {
175 getState().thumbnailAmount = Math.max(thumbnailAmount, 0);
176 }
177
178 public void setThumbnailSize(int width, int height) {
179 getState().size.height = height;
180 getState().size.width = width;
181 }
182
183 public int getThumbnailWidth() {
184 return getState(false).size.width;
185 }
186
187 public int getThumbnailHeight() {
188 return getState(false).size.height;
189 }
190
191 public void clear() {
192 getState().resources.clear();
193 getState().lastQueried = null;
194 counter.set(0);
195 mapper.clear();
196 }
197
198 public void refresh() {
199 if (getState(false).thumbnailAmount > 0) {
200 clear();
201 }
202 if (container != null) {
203 setThumbnailAmount(container.size());
204 }
205 }
206
207 public void addThumbnailSelectionListener(final ThumbnailSelectionListener listener) {
208 this.selectionListeners.add(listener);
209 }
210
211 public void addDoubleClickListener(final ThumbnailDblClickListener listener) {
212 this.dblClickListeners.add(listener);
213 }
214
215 public void addRightClickListener(final ThumbnailRightClickListener listener) {
216 this.rightClickListeners.add(listener);
217 }
218
219 @Override
220 public void setContainerDataSource(Container newDataSource) {
221 if (newDataSource instanceof Ordered) {
222 this.container = (Ordered) newDataSource;
223 refresh();
224 } else {
225 throw new IllegalArgumentException("Container must be ordered.");
226 }
227 }
228
229 @Override
230 public Ordered getContainerDataSource() {
231 return container;
232 }
233
234 @Override
235 protected ThumbnailLayoutState getState() {
236 return (ThumbnailLayoutState) super.getState();
237 }
238
239 @Override
240 protected ThumbnailLayoutState getState(boolean markAsDirty) {
241 return (ThumbnailLayoutState) super.getState(markAsDirty);
242 }
243
244 public void setSelectedItemId(String selectedItemId) {
245 this.selectedItemId = selectedItemId;
246 }
247
248
249
250
251 public interface ThumbnailSelectionListener {
252 void onThumbnailSelected(String itemId);
253 }
254
255
256
257
258 public interface ThumbnailDblClickListener {
259 void onThumbnailDblClicked(String itemId);
260 }
261
262
263
264
265 public interface ThumbnailRightClickListener {
266 void onThumbnailRightClicked(String itemId, int clickX, int clickY);
267 }
268
269
270
271
272 public interface LazyThumbnailProvider {
273
274 void refresh();
275
276 int getThumbnailsAmount();
277
278 List<Resource> getThumbnails(int amount);
279
280 }
281
282 }