View Javadoc

1   /**
2    * This file Copyright (c) 2012-2013 Magnolia International
3    * Ltd.  (http://www.magnolia-cms.com). All rights reserved.
4    *
5    *
6    * This file is dual-licensed under both the Magnolia
7    * Network Agreement and the GNU General Public License.
8    * You may elect to use one or the other of these licenses.
9    *
10   * This file is distributed in the hope that it will be
11   * useful, but AS-IS and WITHOUT ANY WARRANTY; without even the
12   * implied warranty of MERCHANTABILITY or FITNESS FOR A
13   * PARTICULAR PURPOSE, TITLE, or NONINFRINGEMENT.
14   * Redistribution, except as permitted by whichever of the GPL
15   * or MNA you select, is prohibited.
16   *
17   * 1. For the GPL license (GPL), you can redistribute and/or
18   * modify this file under the terms of the GNU General
19   * Public License, Version 3, as published by the Free Software
20   * Foundation.  You should have received a copy of the GNU
21   * General Public License, Version 3 along with this program;
22   * if not, write to the Free Software Foundation, Inc., 51
23   * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
24   *
25   * 2. For the Magnolia Network Agreement (MNA), this file
26   * and the accompanying materials are made available under the
27   * terms of the MNA which accompanies this distribution, and
28   * is available at http://www.magnolia-cms.com/mna.html
29   *
30   * Any modifications to this file must keep this entire header
31   * intact.
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   * Lazy layout of asset thumbnails.
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      // Maps thumbnailId to itemId
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      * Adds the itemId to the internal mapping or if it's already mapped returns the existing key.
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      * Listener interface for thumbnail selection.
250      */
251     public interface ThumbnailSelectionListener {
252         void onThumbnailSelected(String itemId);
253     }
254 
255     /**
256      * Listener for thumbnail double clicks.
257      */
258     public interface ThumbnailDblClickListener {
259         void onThumbnailDblClicked(String itemId);
260     }
261 
262     /**
263      * Listener for thumbnail right clicks.
264      */
265     public interface ThumbnailRightClickListener {
266         void onThumbnailRightClicked(String itemId, int clickX, int clickY);
267     }
268 
269     /**
270      * Interface for the providers of the actual thumbnails.
271      */
272     public interface LazyThumbnailProvider {
273 
274         void refresh();
275 
276         int getThumbnailsAmount();
277 
278         List<Resource> getThumbnails(int amount);
279 
280     }
281 
282 }