diff --git a/photos/portraits/album.properties b/photos/portraits/album.properties
new file mode 100644
index 0000000..6272b07
--- /dev/null
+++ b/photos/portraits/album.properties
@@ -0,0 +1,2 @@
+
+cover=valdemar-dahl.jpg
diff --git a/pom.xml b/pom.xml
index 251fa4e..2d7245e 100644
--- a/pom.xml
+++ b/pom.xml
@@ -74,7 +74,7 @@
junit
junit
4.4
- test
+
org.springframework
diff --git a/src/org/forkalsrud/album/exif/Album.java b/src/org/forkalsrud/album/exif/Album.java
new file mode 100644
index 0000000..e004243
--- /dev/null
+++ b/src/org/forkalsrud/album/exif/Album.java
@@ -0,0 +1,84 @@
+/**
+ *
+ */
+package org.forkalsrud.album.exif;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * @author knut
+ *
+ */
+public class Album {
+
+ Entry cover;
+
+ List contents = new ArrayList();
+
+ public Entry getCover() {
+ return cover;
+ }
+
+
+ public List getContents() {
+ return contents;
+ }
+
+
+ public void setCover(Entry cover) {
+ this.cover = cover;
+ }
+
+
+ public void addContents(Entry entry) {
+ contents.add(entry);
+ }
+
+
+
+ public void sort() {
+
+ Collections.sort(contents, new Comparator() {
+
+ public int compare(Entry e1, Entry e2) {
+
+ if (!e1.isFile() && e2.isFile()) {
+ return -1;
+ } else if (e1.isFile() && !e2.isFile()) {
+ return +1;
+ }
+ Date d1 = e1.getDate();
+ Date d2 = e2.getDate();
+ if (d1 != null && d2 != null) {
+ return d1.compareTo(d2);
+ } else if (d1 != null) {
+ return -1;
+ } else if (d2 != null) {
+ return +1;
+ } else {
+ return 0;
+ }
+ }
+ });
+ fillLinkedList();
+ }
+
+ void fillLinkedList() {
+
+ Entry prev = null;
+ for (Entry e : contents) {
+ e.prev = prev;
+ if (prev != null) {
+ prev.next = e;
+ }
+ prev = e;
+ }
+ if (prev != null) {
+ prev.next = null;
+ }
+ }
+}
diff --git a/src/org/forkalsrud/album/exif/Entry.java b/src/org/forkalsrud/album/exif/Entry.java
index e1a2874..193758c 100644
--- a/src/org/forkalsrud/album/exif/Entry.java
+++ b/src/org/forkalsrud/album/exif/Entry.java
@@ -15,8 +15,10 @@ import java.util.Date;
*/
public class Entry {
- String name;
- Dimension size;
+ boolean isFile;
+ String name;
+ String path;
+ Dimension size;
String caption;
Date date;
int orientation;
@@ -25,6 +27,17 @@ public class Entry {
String etag;
+ public boolean isFile() {
+ return isFile;
+ }
+
+
+ public void setFile(boolean isFile) {
+ this.isFile = isFile;
+ }
+
+
+
/**
* @return Returns the name.
*/
@@ -132,4 +145,15 @@ public class Entry {
}
+ public String getPath() {
+ return path;
+ }
+
+
+ public void setPath(String path) {
+ this.path = path;
+ }
+
+
+
}
diff --git a/src/org/forkalsrud/album/exif/EntryDao.java b/src/org/forkalsrud/album/exif/EntryDao.java
index 393728f..858efd8 100644
--- a/src/org/forkalsrud/album/exif/EntryDao.java
+++ b/src/org/forkalsrud/album/exif/EntryDao.java
@@ -17,8 +17,6 @@ import java.text.NumberFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
@@ -54,7 +52,7 @@ public class EntryDao {
return directory.lastModified() <= new File(directory, CACHE_FILE).lastModified();
}
- public List read(File directory) throws FileNotFoundException, IOException, JpegProcessingException, MetadataException, ParseException {
+ public Album read(File directory) throws FileNotFoundException, IOException, JpegProcessingException, MetadataException, ParseException {
List entries = new ArrayList();
@@ -73,46 +71,25 @@ public class EntryDao {
Properties combined = new Properties();
combined.putAll(cachedProps);
combined.putAll(overrideProps);
- populate(combined, entries);
- Collections.sort(entries, new Comparator() {
+ Entry cover = populate(combined, entries);
- public int compare(Entry e1, Entry e2) {
-
- Date d1 = e1.getDate();
- Date d2 = e2.getDate();
- if (d1 != null && d2 != null) {
- return d1.compareTo(d2);
- } else if (d1 != null) {
- return -1;
- } else if (d2 != null) {
- return +1;
- } else {
- return 0;
- }
- }
- });
- fillLinkedList(entries);
- return entries;
- }
-
- void fillLinkedList(List entries) {
-
- Entry prev = null;
+ Album alb = new Album();
+ alb.setCover(cover);
for (Entry e : entries) {
- e.prev = prev;
- if (prev != null) {
- prev.next = e;
- }
- prev = e;
- }
- if (prev != null) {
- prev.next = null;
+ alb.addContents(e);
}
+ generateDirectoryEntries(directory, alb);
+ alb.sort();
+ return alb;
}
- private void populate(Properties cachedProps, List entries) throws ParseException {
+
+ private Entry populate(Properties cachedProps, List entries) throws ParseException {
+
+ Entry cover = null;
+ String coverFileName = cachedProps.getProperty("cover");
HashMap entryMap = new HashMap();
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd-HHmmss");
Iterator i = cachedProps.keySet().iterator();
@@ -122,22 +99,28 @@ public class EntryDao {
String name = key.substring("file.".length(), key.length() - ".dimensions".length());
if (!entryMap.containsKey(name)) {
Entry entry = new Entry();
+ entry.setFile(true);
entry.setName(name);
+ entry.setPath(name);
entry.setDate(sdf.parse(cachedProps.getProperty("file." + name + ".captureDate")));
entry.setSize(new Dimension(cachedProps.getProperty("file." + name + ".dimensions")));
entry.setCaption(cachedProps.getProperty("file." + name + ".caption"));
entry.setOrientation(Integer.parseInt(cachedProps.getProperty("file." + name + ".orientation")));
entry.setEtag(cachedProps.getProperty("file." + name + ".etag"));
entries.add(entry);
+ if (name != null && name.equals(coverFileName)) {
+ cover = entry;
+ }
}
}
}
+ return cover;
}
public Entry readFile(File file) throws FileNotFoundException, IOException, JpegProcessingException, MetadataException, ParseException {
-
- List dir = read(file.getParentFile());
+
+ List dir = read(file.getParentFile()).getContents();
String name = file.getName();
for (Entry e : dir) {
if (name.equals(e.name)) {
@@ -149,11 +132,46 @@ public class EntryDao {
void generateEntries(File directory, Properties cachedProps) throws JpegProcessingException, MetadataException, FileNotFoundException, IOException {
- File[] files = directory.listFiles(new FileFilter() {
+ generateFileEntries(directory, cachedProps);
+ File dst = new File(directory, CACHE_FILE);
+ if (directory.canWrite()) {
+ cachedProps.store(new FileOutputStream(dst), "Extra Comments");
+ }
+ }
+
+ void generateDirectoryEntries(File directory, Album album) throws FileNotFoundException, JpegProcessingException, MetadataException, IOException, ParseException {
+
+ File[] dirs = directory.listFiles(new FileFilter() {
public boolean accept(File file) {
- return !file.isHidden() && !file.isDirectory() && !CACHE_FILE.equals(file.getName()) && !OVERRIDE_FILE.equals(file.getName());
+ return !file.isHidden() && file.isDirectory() && !CACHE_FILE.equals(file.getName()) && !OVERRIDE_FILE.equals(file.getName());
+ }
+
+ });
+ for (File dir : dirs) {
+
+ Album childAlbum = read(dir);
+ Entry childCover = childAlbum.getCover();
+ if (childCover != null) {
+ childCover.setFile(false);
+ childCover.setName(dir.getName());
+ childCover.setPath(dir.getName() + "/" + childCover.getPath());
+ album.addContents(childCover);
+ }
+ }
+ }
+
+
+ void generateFileEntries(File directory, Properties cachedProps)
+ throws JpegProcessingException, MetadataException, IOException {
+ File[] files = directory.listFiles(new FileFilter() {
+
+ public boolean accept(File file) {
+
+ String name = file.getName();
+ boolean isImageFile = name.endsWith(".jpg") || name.endsWith(".jpeg") || name.endsWith(".JPG");
+ return isImageFile && !file.isHidden() && !file.isDirectory() && !CACHE_FILE.equals(file.getName()) && !OVERRIDE_FILE.equals(file.getName());
}
});
@@ -213,11 +231,7 @@ public class EntryDao {
}
}
}
- File dst = new File(directory, CACHE_FILE);
- if (directory.canWrite()) {
- cachedProps.store(new FileOutputStream(dst), "Extra Comments");
- }
- }
+ }
Dimension decodeImageForDimensions(File file) throws IOException {
diff --git a/src/org/forkalsrud/album/web/AlbumServlet.java b/src/org/forkalsrud/album/web/AlbumServlet.java
index b3ab0a1..7402dc6 100644
--- a/src/org/forkalsrud/album/web/AlbumServlet.java
+++ b/src/org/forkalsrud/album/web/AlbumServlet.java
@@ -52,8 +52,13 @@ public class AlbumServlet
pathInfo = pathInfo.substring(0, pathInfo.length() - ".photo".length());
page = "photo";
}
+ int parentPos = pathInfo.substring(0, pathInfo.length() - 1).lastIndexOf('/');
+ if (parentPos >= 0) {
+ req.setAttribute("parent", req.getServletPath() + pathInfo.substring(0, parentPos) + "/");
+ }
+ req.setAttribute("assets", "/" + req.getContextPath() + "assets");
File file = new File(basePath + pathInfo);
-// System.out.println("path=" + file);
+// System.out.println("path=" + req.getContextPath());
if (!file.canRead()) {
res.setStatus(HttpServletResponse.SC_FORBIDDEN);
return;
@@ -61,7 +66,7 @@ public class AlbumServlet
if (file.isDirectory()) {
try {
- List entries = dao.read(file);
+ List entries = dao.read(file).getContents();
res.setContentType("text/html");
req.setAttribute("directory", file.getName());
req.setAttribute("path", req.getServletPath());
@@ -169,7 +174,7 @@ public class AlbumServlet
@Override
public String getServletInfo() {
- return "Display a directory as an org.forkalsrud.album";
+ return "Display of org.forkalsrud.album";
}
}
diff --git a/webapp/WEB-INF/velocity/directory.vm b/webapp/WEB-INF/velocity/directory.vm
index 79b7ad5..920d4fb 100644
--- a/webapp/WEB-INF/velocity/directory.vm
+++ b/webapp/WEB-INF/velocity/directory.vm
@@ -14,6 +14,9 @@
margin: 10px auto;
text-align: center;
}
+ h1 {
+ text-align: left;
+ }
a:link, a:visited {
text-decoration: none;
color: #4c4c4c;
@@ -30,18 +33,27 @@
img {
padding: 5px;
}
+ .nav {
+ border: 0 none;
+ padding: 0px;
+ vertical-align: middle;
+ }
- $directory
-
+#if($prev && $prev.isFile())
#else
#end#if($parent)
#else
#end#if($next && $next.isFile())
#else
#end$directory
+
#set($thmb = 150)
#foreach($entry in $entries)
#set($dim = $entry.size.scaled($thmb))
$entry.name
-

+#if($entry.isFile())
+

+#else
+

+#end
$!entry.caption
#end
diff --git a/webapp/WEB-INF/velocity/photo.vm b/webapp/WEB-INF/velocity/photo.vm
index bace66a..87a7c4b 100644
--- a/webapp/WEB-INF/velocity/photo.vm
+++ b/webapp/WEB-INF/velocity/photo.vm
@@ -14,6 +14,9 @@
margin: 10px auto;
text-align: center;
}
+ h1 {
+ text-align: left;
+ }
a:link, a:visited {
text-decoration: none;
color: #4c4c4c;
@@ -30,23 +33,21 @@
img {
padding: 5px;
}
+ .nav {
+ border: 0 none;
+ padding: 0px;
+ vertical-align: middle;
+ }
-
-#if($prev)
- <--
-#end
-#if($next)
- -->
-#end
-
-
+#if($prev && $prev.isFile())
#else
#end#if($parent)
#else
#end#if($next && $next.isFile())
#else
#end$entry.name
+
#set($thmb = 480)
#set($dim = $entry.size.scaled($thmb))
-
$entry.name
+
$!entry.caption
diff --git a/webapp/assets/left-inactive.png b/webapp/assets/left-inactive.png
new file mode 100644
index 0000000..111f3a2
Binary files /dev/null and b/webapp/assets/left-inactive.png differ
diff --git a/webapp/assets/left.png b/webapp/assets/left.png
new file mode 100644
index 0000000..7249de6
Binary files /dev/null and b/webapp/assets/left.png differ
diff --git a/webapp/assets/right-inactive.png b/webapp/assets/right-inactive.png
new file mode 100644
index 0000000..bbf636e
Binary files /dev/null and b/webapp/assets/right-inactive.png differ
diff --git a/webapp/assets/right.png b/webapp/assets/right.png
new file mode 100644
index 0000000..db48ef3
Binary files /dev/null and b/webapp/assets/right.png differ
diff --git a/webapp/assets/up-inactive.png b/webapp/assets/up-inactive.png
new file mode 100644
index 0000000..96283e0
Binary files /dev/null and b/webapp/assets/up-inactive.png differ
diff --git a/webapp/assets/up.png b/webapp/assets/up.png
new file mode 100644
index 0000000..e23378c
Binary files /dev/null and b/webapp/assets/up.png differ