Page navigation is now working.
[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         Link nextLink = new Link("nextLink") {
125             {
126                 if (index + MAX_ROWS * MAX_COLUMNS >= album.size()) {
127                     setEnabled(false);
128                 }
129             }
130
131             @Override
132             public void onClick() {
133                 PageParameters pars = new PageParameters();
134                 pars.put("path", path);
135                 pars.put("index", index + MAX_ROWS * MAX_COLUMNS);
136                 setResponsePage(HomePage.class, pars);
137             }
138         };
139         add(nextLink);
140
141         Link parentLink = new Link("parentLink") {
142             {
143                 if ("/".equals(path)) {
144                     setEnabled(false);
145                 }
146             }
147
148             @Override
149             public void onClick() {
150                 PageParameters pars = new PageParameters();
151                 String parentPath = path.substring(0, path.lastIndexOf("/"));
152                 if (parentPath.length() == 0) {
153                     parentPath = "/";
154                 }
155                 pars.put("path", parentPath);
156                 pars.put("index", 0);
157                 setResponsePage(HomePage.class, pars);
158             }
159         };
160         add(parentLink);
161
162         RepeatingView pageLinks = new RepeatingView("pageLinks");
163         add(pageLinks);
164         for (int i = 0; i < album.size() / MAX_ROWS / MAX_COLUMNS; i++) {
165             final int istart = i * MAX_ROWS * MAX_COLUMNS;
166             Link pageLink = new Link("pageLink") {
167                 {
168                     if (istart == index) {
169                         setEnabled(false);
170                     }
171                 }
172
173                 @Override
174                 public void onClick() {
175                     PageParameters pars = new PageParameters();
176                     pars.put("path", path);
177                     pars.put("index", istart);
178                     setResponsePage(HomePage.class, pars);
179                 }
180             };
181             pageLink.add(new Label("label", i + ""));
182             pageLinks.add(pageLink);
183             WebMarkupContainer container = new WebMarkupContainer(pageLinks.newChildId());
184             container.add(pageLink);
185             pageLinks.add(container);
186         }
187
188         int ientry = index;
189         int irow = 0;
190         RepeatingView row = new RepeatingView("row");
191         add(row);
192         while (irow < MAX_ROWS && ientry < album.size()) {
193             int icolumn = 0;
194             WebMarkupContainer columns = new WebMarkupContainer(row.newChildId());
195             row.add(columns);
196             RepeatingView column = new RepeatingView("column");
197             columns.add(column);
198             while (icolumn < MAX_COLUMNS && ientry < album.size()) {
199                 WebMarkupContainer thumbnail = new WebMarkupContainer(column.newChildId());
200                 column.add(thumbnail);
201
202                 final PhotoEntry entry = album.getEntry(ientry);
203                 Link link = new SerializableEntryLink("thumbnail", entry.getPath());
204                 thumbnail.add(link);
205                 ImageData data = getData(entry);
206
207                 // TODO very inefficient. all data is loaded when generating the page.
208                 link.add(new Image("image", new ByteArrayResource(data.getContentType(), data.getData())));
209
210                 link.add(new Label("name", album.getEntry(ientry).getId()));
211                 icolumn++;
212                 ientry++;
213             }
214             irow++;
215         }
216     }
217
218     public static final class ImageData {
219         private String contentType;
220         private byte[] data;
221
222         public ImageData(String aContentType, byte[] aData) {
223             contentType = aContentType;
224             data = aData;
225         }
226
227         public String getContentType() {
228             return contentType;
229         }
230
231         public byte[] getData() {
232             return data;
233         }
234     }
235
236     private ImageData getData(PhotoEntry aEntry) {
237         if (aEntry instanceof Photo) {
238             return getData((Photo) aEntry);
239         } else if (aEntry instanceof Album) {
240             return getData((Album) aEntry);
241         } else {
242             throw new RuntimeException("Unsupported type " + aEntry.getClass().getName());
243         }
244     }
245
246     private ImageData getData(Photo aPhoto) {
247         try (InputStream is = aPhoto.getThumbNail()) {
248             return new ImageData("image/jpeg", getBytes(is));
249         }
250         catch (IOException e) {
251             // to improve.
252             throw new RuntimeException("Cannot read photo", e);
253         }
254     }
255
256     private byte[] getBytes(InputStream is) throws IOException {
257         ByteArrayOutputStream bos = new ByteArrayOutputStream();
258         byte[] block = new byte[1024];
259         int n = is.read(block);
260         while (n > 0) {
261             bos.write(block, 0, n);
262             n = is.read(block);
263         }
264         return bos.toByteArray();
265     }
266
267     private ImageData getData(Album aAlbum) {
268         try (InputStream is = getClass().getResourceAsStream("folder.png")) {
269             return new ImageData("image/png", getBytes(is));
270         }
271         catch (IOException e) {
272             throw new RuntimeException("Cannot read album jpg", e);
273         }
274     }
275 }