Full navigation is working including viewing individual photos.
[photos] / src / main / java / org / wamblee / photos / wicket / AlbumPanel.java
1 /*
2  * Copyright 2005-2010 the original author or authors.
3  * 
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  * 
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  * 
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package org.wamblee.photos.wicket;
17
18 import java.io.ByteArrayOutputStream;
19 import java.io.IOException;
20 import java.io.InputStream;
21 import java.util.logging.Logger;
22 import javax.inject.Inject;
23
24 import org.apache.wicket.PageParameters;
25 import org.apache.wicket.markup.html.WebMarkupContainer;
26 import org.apache.wicket.markup.html.basic.Label;
27 import org.apache.wicket.markup.html.image.Image;
28 import org.apache.wicket.markup.html.link.Link;
29 import org.apache.wicket.markup.html.panel.Panel;
30 import org.apache.wicket.markup.repeater.RepeatingView;
31 import org.apache.wicket.resource.ByteArrayResource;
32 import org.wamblee.photos.model.Album;
33 import org.wamblee.photos.model.Photo;
34 import org.wamblee.photos.model.PhotoEntry;
35 import org.wamblee.photos.model.plumbing.AuthorizedPhotos;
36
37 /**
38  * Homepage
39  */
40 public class AlbumPanel extends Panel {
41
42     private static final Logger LOGGER = Logger.getLogger(AlbumPanel.class.getName());
43
44     private static final long serialVersionUID = 1L;
45     public static final int MAX_ROWS = 5;
46     public static final int MAX_COLUMNS = 5;
47
48     @Inject
49     @AuthorizedPhotos
50     private transient Album authorized;
51
52     private class SerializableEntryLink extends Link {
53
54         private String path;
55
56         public SerializableEntryLink(String aId, String aPath) {
57             super(aId);
58             path = aPath;
59         }
60
61         @Override
62         public void onClick() {
63             System.out.println("Entry " + path + " was clicked");
64             PageParameters pars = new PageParameters();
65             pars.put("path", path);
66
67             setResponsePage(HomePage.class, pars);
68         }
69     }
70
71     private String path;
72     private int index;
73
74     /**
75      * Constructor that is invoked when page is invoked without a session.
76      *
77      * @param parameters Page parameters
78      */
79     public AlbumPanel(String aId, final PageParameters parameters) throws Exception {
80         super(aId);
81
82         path = parameters.getString("path", "/");
83         if (!path.startsWith("/")) {
84             info("Invalid album '" + path + "', showing root album instead");
85             path = "/";
86         }
87         add(new Label("path", path));
88
89         index = 0;
90         String indexString = parameters.getString("index", "0");
91         try {
92             index = Integer.parseInt(indexString);
93         }
94         catch (NumberFormatException e) {
95             // use default value 0
96         }
97         if (index < 0) {
98             index = 0;
99         }
100
101         PhotoEntry current = authorized.getEntry(path);
102         if (current instanceof Photo) {
103             throw new RuntimeException("AlbumPanel can only show album: " + current.getClass().getName());
104         }
105         final Album album = (Album) current;
106
107         Link prevLink = new Link("prevLink") {
108             {
109                 if (index - MAX_ROWS * MAX_COLUMNS < 0) {
110                     setEnabled(false);
111                 }
112             }
113
114             @Override
115             public void onClick() {
116                 PageParameters pars = new PageParameters();
117                 pars.put("path", path);
118                 pars.put("index", index - MAX_ROWS * MAX_COLUMNS);
119                 setResponsePage(HomePage.class, pars);
120             }
121         };
122         add(prevLink);
123
124         // Avoid implicit references to the album to keep the link objects
125         // small and serializable.
126         final int albumSize = album.size();
127         Link nextLink = new Link("nextLink") {
128             {
129                 if (index + MAX_ROWS * MAX_COLUMNS >= albumSize) {
130                     setEnabled(false);
131                 }
132             }
133
134             @Override
135             public void onClick() {
136                 PageParameters pars = new PageParameters();
137                 pars.put("path", path);
138                 pars.put("index", index + MAX_ROWS * MAX_COLUMNS);
139                 setResponsePage(HomePage.class, pars);
140             }
141         };
142         add(nextLink);
143
144         Link parentLink = new Link("parentLink") {
145             {
146                 if ("/".equals(path)) {
147                     setEnabled(false);
148                 }
149             }
150
151             @Override
152             public void onClick() {
153                 PageParameters pars = new PageParameters();
154                 String parentPath = path.substring(0, path.lastIndexOf("/"));
155                 if (parentPath.length() == 0) {
156                     parentPath = "/";
157                 }
158                 pars.put("path", parentPath);
159                 pars.put("index", 0);
160                 setResponsePage(HomePage.class, pars);
161             }
162         };
163         add(parentLink);
164
165         RepeatingView pageLinks = new RepeatingView("pageLinks");
166         add(pageLinks);
167         for (int i = 0; i < album.size() / MAX_ROWS / MAX_COLUMNS; i++) {
168             final int istart = i * MAX_ROWS * MAX_COLUMNS;
169             Link pageLink = new Link("pageLink") {
170                 {
171                     if (istart == index) {
172                         setEnabled(false);
173                     }
174                 }
175
176                 @Override
177                 public void onClick() {
178                     PageParameters pars = new PageParameters();
179                     pars.put("path", path);
180                     pars.put("index", istart);
181                     setResponsePage(HomePage.class, pars);
182                 }
183             };
184             pageLink.add(new Label("label", i + ""));
185             pageLinks.add(pageLink);
186             WebMarkupContainer container = new WebMarkupContainer(pageLinks.newChildId());
187             container.add(pageLink);
188             pageLinks.add(container);
189         }
190
191         int ientry = index;
192         int irow = 0;
193         RepeatingView row = new RepeatingView("row");
194         add(row);
195         while (irow < MAX_ROWS && ientry < album.size()) {
196             int icolumn = 0;
197             WebMarkupContainer columns = new WebMarkupContainer(row.newChildId());
198             row.add(columns);
199             RepeatingView column = new RepeatingView("column");
200             columns.add(column);
201             while (icolumn < MAX_COLUMNS && ientry < album.size()) {
202                 WebMarkupContainer thumbnail = new WebMarkupContainer(column.newChildId());
203                 column.add(thumbnail);
204
205                 final PhotoEntry entry = album.getEntry(ientry);
206                 Link link = new SerializableEntryLink("thumbnail", entry.getPath());
207                 thumbnail.add(link);
208                 ImageData data = getData(entry);
209
210                 // TODO very inefficient. all data is loaded when generating the page.
211                 link.add(new Image("image", new ByteArrayResource(data.getContentType(), data.getData())));
212
213                 link.add(new Label("name", album.getEntry(ientry).getId()));
214                 icolumn++;
215                 ientry++;
216             }
217             irow++;
218         }
219     }
220
221     public static final class ImageData {
222         private String contentType;
223         private byte[] data;
224
225         public ImageData(String aContentType, byte[] aData) {
226             contentType = aContentType;
227             data = aData;
228         }
229
230         public String getContentType() {
231             return contentType;
232         }
233
234         public byte[] getData() {
235             return data;
236         }
237     }
238
239     private ImageData getData(PhotoEntry aEntry) {
240         if (aEntry instanceof Photo) {
241             return getData((Photo) aEntry);
242         } else if (aEntry instanceof Album) {
243             return getData((Album) aEntry);
244         } else {
245             throw new RuntimeException("Unsupported type " + aEntry.getClass().getName());
246         }
247     }
248
249     private ImageData getData(Photo aPhoto) {
250         try (InputStream is = aPhoto.getThumbNail()) {
251             return new ImageData("image/jpeg", getBytes(is));
252         }
253         catch (IOException e) {
254             // to improve.
255             throw new RuntimeException("Cannot read photo", e);
256         }
257     }
258
259     private byte[] getBytes(InputStream is) throws IOException {
260         ByteArrayOutputStream bos = new ByteArrayOutputStream();
261         byte[] block = new byte[1024];
262         int n = is.read(block);
263         while (n > 0) {
264             bos.write(block, 0, n);
265             n = is.read(block);
266         }
267         return bos.toByteArray();
268     }
269
270     private ImageData getData(Album aAlbum) {
271         try (InputStream is = getClass().getResourceAsStream("folder.png")) {
272             return new ImageData("image/png", getBytes(is));
273         }
274         catch (IOException e) {
275             throw new RuntimeException("Cannot read album jpg", e);
276         }
277     }
278 }