Major overhaul of navigation. Now shows directories and navigation buttons.
This commit is contained in:
parent
79a499ceec
commit
9d2fb0ea6e
14 changed files with 206 additions and 64 deletions
2
photos/portraits/album.properties
Normal file
2
photos/portraits/album.properties
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
|
||||
cover=valdemar-dahl.jpg
|
||||
2
pom.xml
2
pom.xml
|
|
@ -74,7 +74,7 @@
|
|||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>4.4</version>
|
||||
<scope>test</scope>
|
||||
<!-- <scope>test</scope> -->
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
|
|
|
|||
84
src/org/forkalsrud/album/exif/Album.java
Normal file
84
src/org/forkalsrud/album/exif/Album.java
Normal file
|
|
@ -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<Entry> contents = new ArrayList<Entry>();
|
||||
|
||||
public Entry getCover() {
|
||||
return cover;
|
||||
}
|
||||
|
||||
|
||||
public List<Entry> 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<Entry>() {
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<Entry> read(File directory) throws FileNotFoundException, IOException, JpegProcessingException, MetadataException, ParseException {
|
||||
public Album read(File directory) throws FileNotFoundException, IOException, JpegProcessingException, MetadataException, ParseException {
|
||||
|
||||
List<Entry> entries = new ArrayList<Entry>();
|
||||
|
||||
|
|
@ -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>() {
|
||||
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<Entry> 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<Entry> entries) throws ParseException {
|
||||
|
||||
|
||||
private Entry populate(Properties cachedProps, List<Entry> entries) throws ParseException {
|
||||
|
||||
Entry cover = null;
|
||||
String coverFileName = cachedProps.getProperty("cover");
|
||||
HashMap<String, Entry> entryMap = new HashMap<String, Entry>();
|
||||
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<Entry> dir = read(file.getParentFile());
|
||||
List<Entry> 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 {
|
||||
|
||||
|
|
|
|||
|
|
@ -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<Entry> entries = dao.read(file);
|
||||
List<Entry> 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";
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
</style>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<h1>$directory</h1>
|
||||
<hr/>
|
||||
<h1>#if($prev && $prev.isFile())<a href="${prev.name}.photo"><img class="nav" src="${assets}/left.png"/></a>#else<img class="nav" src="${assets}/left-inactive.png"/>#end#if($parent)<a href="$parent"><img class="nav" src="${assets}/up.png"/></a>#else<img class="nav" src="${assets}/up-inactive.png"/>#end#if($next && $next.isFile())<a href="${next.name}.photo"><img class="nav" src="${assets}/right.png"/></a>#else<img class="nav" src="${assets}/right-inactive.png"/>#end$directory</h1>
|
||||
<hr/>
|
||||
#set($thmb = 150)
|
||||
#foreach($entry in $entries)
|
||||
#set($dim = $entry.size.scaled($thmb))
|
||||
<div class="home_entry_table">
|
||||
<span class="name">$entry.name</span><br/>
|
||||
<a href="${entry.name}.photo"><img src="$entry.name?size=$thmb" border="0" width="$dim.width" height="$dim.height"/></a><br/>
|
||||
#if($entry.isFile())
|
||||
<a href="${entry.name}.photo"><img src="$entry.path?size=$thmb" border="0" width="$dim.width" height="$dim.height"/></a><br/>
|
||||
#else
|
||||
<a href="${entry.name}/"><img src="$entry.path?size=$thmb" border="0" width="$dim.width" height="$dim.height"/></a><br/>
|
||||
#end
|
||||
<span class="caption">$!entry.caption</span>
|
||||
</div>
|
||||
#end
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
</style>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<center>
|
||||
#if($prev)
|
||||
<a href="${prev.name}.photo"><--</a>
|
||||
#end
|
||||
#if($next)
|
||||
<a href="${next.name}.photo">--></a>
|
||||
#end
|
||||
</center>
|
||||
|
||||
<h1>#if($prev && $prev.isFile())<a href="${prev.name}.photo"><img class="nav" src="${assets}/left.png"/></a>#else<img class="nav" src="${assets}/left-inactive.png"/>#end#if($parent)<a href="$parent"><img class="nav" src="${assets}/up.png"/></a>#else<img class="nav" src="${assets}/up-inactive.png"/>#end#if($next && $next.isFile())<a href="${next.name}.photo"><img class="nav" src="${assets}/right.png"/></a>#else<img class="nav" src="${assets}/right-inactive.png"/>#end$entry.name</h1>
|
||||
<hr/>
|
||||
#set($thmb = 480)
|
||||
#set($dim = $entry.size.scaled($thmb))
|
||||
<div class="photo">
|
||||
<span class="name">$entry.name</span><br/>
|
||||
<span class="name"></span><br/>
|
||||
<a href="$entry.name"><img src="$entry.name?size=$thmb" border="0" width="$dim.width" height="$dim.height"/></a><br/>
|
||||
<span class="caption">$!entry.caption</span>
|
||||
</div>
|
||||
|
|
|
|||
BIN
webapp/assets/left-inactive.png
Normal file
BIN
webapp/assets/left-inactive.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 499 B |
BIN
webapp/assets/left.png
Normal file
BIN
webapp/assets/left.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 540 B |
BIN
webapp/assets/right-inactive.png
Normal file
BIN
webapp/assets/right-inactive.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 509 B |
BIN
webapp/assets/right.png
Normal file
BIN
webapp/assets/right.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 550 B |
BIN
webapp/assets/up-inactive.png
Normal file
BIN
webapp/assets/up-inactive.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 443 B |
BIN
webapp/assets/up.png
Normal file
BIN
webapp/assets/up.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 511 B |
Loading…
Add table
Reference in a new issue