mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-01 01:07:51 -04:00
handle larger, nested indexes
This commit is contained in:
parent
ae4ad65a8b
commit
d99b1ff360
@ -20,9 +20,10 @@
|
||||
#include "pnmTextMaker.h"
|
||||
#include "default_font.h"
|
||||
#include "pnmImage.h"
|
||||
|
||||
#include "notify.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: FontSamples::Constructor
|
||||
// Access: Public
|
||||
|
@ -96,8 +96,8 @@ generate_images(const Filename &archive_dir, PNMTextMaker *text_maker) {
|
||||
PNMImage index_image;
|
||||
|
||||
Filename reduced_dir(archive_dir, "reduced/" + _dir->get_basename());
|
||||
|
||||
Filename output_filename(archive_dir, _name);
|
||||
Filename thumbnail_dir(archive_dir, "thumbs");
|
||||
Filename output_filename(thumbnail_dir, _name);
|
||||
output_filename.set_extension("jpg");
|
||||
|
||||
Photos::const_iterator pi;
|
||||
@ -161,9 +161,11 @@ generate_images(const Filename &archive_dir, PNMTextMaker *text_maker) {
|
||||
Photo *photo = _dir->get_photo(pinfo._photo_index);
|
||||
Filename photo_filename(_dir->get_dir(), photo->get_basename());
|
||||
Filename reduced_filename(reduced_dir, photo->get_basename());
|
||||
photo_filename.standardize();
|
||||
reduced_filename.standardize();
|
||||
PNMImage reduced_image;
|
||||
|
||||
if (!dummy_mode &&
|
||||
if (!dummy_mode && photo_filename != reduced_filename &&
|
||||
(force_regenerate ||
|
||||
reduced_filename.compare_timestamps(photo_filename) < 0)) {
|
||||
// If the reduced filename does not exist or is older than the
|
||||
@ -182,6 +184,10 @@ generate_images(const Filename &archive_dir, PNMTextMaker *text_maker) {
|
||||
|
||||
// Generate a reduced image for the photo.
|
||||
compute_reduction(photo_image, reduced_image, reduced_width, reduced_height);
|
||||
|
||||
photo->_reduced_x_size = reduced_image.get_x_size();
|
||||
photo->_reduced_y_size = reduced_image.get_y_size();
|
||||
|
||||
reduced_image.quick_filter_from(photo_image);
|
||||
reduced_filename.make_dir();
|
||||
nout << "Writing " << reduced_filename << "\n";
|
||||
@ -190,9 +196,6 @@ generate_images(const Filename &archive_dir, PNMTextMaker *text_maker) {
|
||||
return false;
|
||||
}
|
||||
|
||||
photo->_reduced_x_size = reduced_image.get_x_size();
|
||||
photo->_reduced_y_size = reduced_image.get_y_size();
|
||||
|
||||
} else {
|
||||
// If the reduced image already exists and is newer than the
|
||||
// source image, use it.
|
||||
@ -262,7 +265,8 @@ generate_images(const Filename &archive_dir, PNMTextMaker *text_maker) {
|
||||
pinfo._x_place + x_center, pinfo._y_place + y_center,
|
||||
thumbnail_image.get_x_size(), thumbnail_image.get_y_size());
|
||||
}
|
||||
|
||||
|
||||
thumbnail_image.set_color_type(index_image.get_color_type());
|
||||
index_image.copy_sub_image(thumbnail_image,
|
||||
pinfo._x_place + x_center,
|
||||
pinfo._y_place + y_center);
|
||||
@ -277,6 +281,7 @@ generate_images(const Filename &archive_dir, PNMTextMaker *text_maker) {
|
||||
|
||||
if (generate_index_image) {
|
||||
nout << "Writing " << output_filename << "\n";
|
||||
output_filename.make_dir();
|
||||
if (!index_image.write(output_filename)) {
|
||||
nout << "Unable to write.\n";
|
||||
return false;
|
||||
@ -304,21 +309,22 @@ generate_html(ostream &root_html, const Filename &archive_dir,
|
||||
const Filename &roll_dir_root) {
|
||||
root_html
|
||||
<< "<a name=\"" << _name << "\">\n"
|
||||
<< "<img src=\"" << _index_basename
|
||||
<< "<img src=\"../thumbs/" << _index_basename
|
||||
<< "\" width=" << _index_x_size << " height=" << _index_y_size
|
||||
<< " ismap usemap=\"#" << _name << "\">\n"
|
||||
<< "<map name=\"" << _name << "\"><br>\n";
|
||||
|
||||
Filename html_dir(archive_dir, "html");
|
||||
|
||||
Photos::const_iterator pi;
|
||||
for (pi = _photos.begin(); pi != _photos.end(); ++pi) {
|
||||
const PhotoInfo &pinfo = (*pi);
|
||||
int photo_index = pinfo._photo_index;
|
||||
Photo *photo = _dir->get_photo(pinfo._photo_index);
|
||||
Filename html_relname("html/" + _dir->get_basename(),
|
||||
photo->get_basename());
|
||||
Filename html_relname(_dir->get_basename(), photo->get_basename());
|
||||
html_relname.set_extension("htm");
|
||||
|
||||
Filename html_filename(archive_dir, html_relname);
|
||||
Filename html_filename(html_dir, html_relname);
|
||||
html_filename.make_dir();
|
||||
html_filename.set_text();
|
||||
ofstream reduced_html;
|
||||
@ -382,15 +388,18 @@ write(ostream &out, int indent_level) const {
|
||||
bool IndexImage::
|
||||
generate_reduced_html(ostream &html, Photo *photo, int photo_index, int pi,
|
||||
const Filename &roll_dir_root) {
|
||||
Filename full_dir =
|
||||
Filename full_dir;
|
||||
if (roll_dir_root.empty()) {
|
||||
full_dir = Filename("../..", _dir->get_dir());
|
||||
} else {
|
||||
compose_href("../..", roll_dir_root, _dir->get_basename());
|
||||
}
|
||||
Filename full(full_dir, photo->get_basename());
|
||||
|
||||
Filename reduced_dir("../../reduced", _dir->get_basename());
|
||||
Filename reduced(reduced_dir, photo->get_basename());
|
||||
|
||||
Filename root_html("../..", "index.htm");
|
||||
string up_href = root_html.get_fullpath() + "#" + _name;
|
||||
string up_href = "../" + _dir->get_basename() + ".htm#" + _name;
|
||||
|
||||
Filename prev_photo_filename;
|
||||
Filename next_photo_filename;
|
||||
@ -485,7 +494,9 @@ generate_reduced_html(ostream &html, Photo *photo, int photo_index, int pi,
|
||||
<< " height=" << photo->_reduced_y_size << " alt=\"" << photo->get_name()
|
||||
<< "\"></a></p>\n";
|
||||
|
||||
if (!omit_full_links) {
|
||||
if (!omit_full_links &&
|
||||
(photo->_full_x_size != photo->_reduced_x_size ||
|
||||
photo->_full_y_size != photo->_reduced_y_size)) {
|
||||
html
|
||||
<< "<p><a href=\"" << full << "\">View full size image ("
|
||||
<< photo->_full_x_size << " x " << photo->_full_y_size << ")</a></p>";
|
||||
@ -503,7 +514,7 @@ generate_reduced_html(ostream &html, Photo *photo, int photo_index, int pi,
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: IndexImage::generate_nav_buttons
|
||||
// Access: Private, Static
|
||||
// Access: Private
|
||||
// Description: Outputs the HTML code to generate the next, prev,
|
||||
// up buttons when viewing each reduced image.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
@ -570,54 +581,6 @@ generate_nav_buttons(ostream &html, const Filename &prev_photo_filename,
|
||||
html << "</p>\n";
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: IndexImage::compose_href
|
||||
// Access: Private
|
||||
// Description: Combines a user-supplied prefix with a relative
|
||||
// directory to generate the appropriate href to the
|
||||
// file.
|
||||
//
|
||||
// rel_dir is the relative path to archive_dir.
|
||||
// user_prefix is the string the user indicated as the
|
||||
// relative or absolute path to the file's parent
|
||||
// directory from archive_dir. basename is the name
|
||||
// of the file, or empty if the filename is part of
|
||||
// user_prefix.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
Filename IndexImage::
|
||||
compose_href(const Filename &rel_dir, const Filename &user_prefix,
|
||||
const Filename &basename) {
|
||||
Filename result;
|
||||
|
||||
if (user_prefix.empty()) {
|
||||
result = rel_dir;
|
||||
|
||||
} else {
|
||||
// Check to see if the user prefix begins with a URL designator,
|
||||
// like http:// or ftp://.
|
||||
size_t ui = 0;
|
||||
while (ui < user_prefix.length() && isalpha(user_prefix[ui])) {
|
||||
ui++;
|
||||
}
|
||||
bool is_url = (user_prefix.get_fullpath().substr(ui, 3) == "://");
|
||||
|
||||
if (!is_url && user_prefix.is_local()) {
|
||||
Filename rel_user_dir(rel_dir, user_prefix);
|
||||
result = rel_user_dir;
|
||||
result.standardize();
|
||||
|
||||
} else {
|
||||
result = user_prefix;
|
||||
}
|
||||
}
|
||||
|
||||
if (basename.empty()) {
|
||||
return result;
|
||||
} else {
|
||||
return Filename(result, basename);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: IndexImage::compute_reduction
|
||||
// Access: Private, Static
|
||||
|
@ -56,9 +56,6 @@ private:
|
||||
const Filename &next_photo_filename,
|
||||
const string &up_href);
|
||||
|
||||
Filename compose_href(const Filename &rel_dir, const Filename &user_prefix,
|
||||
const Filename &basename = Filename());
|
||||
|
||||
static void compute_reduction(const PNMImageHeader &source_image,
|
||||
PNMImage &dest_image,
|
||||
int x_size, int y_size);
|
||||
|
@ -44,6 +44,7 @@ Filename up_icon;
|
||||
|
||||
bool force_regenerate = false;
|
||||
bool format_rose = false;
|
||||
bool sort_date = false;
|
||||
bool dummy_mode = false;
|
||||
bool draw_frames = false;
|
||||
bool omit_roll_headers = false;
|
||||
@ -87,3 +88,116 @@ finalize_parameters() {
|
||||
thumb_interior_height = thumb_height;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: compose_href
|
||||
// Description: Combines a user-supplied prefix with a relative
|
||||
// directory to generate the appropriate href to the
|
||||
// file.
|
||||
//
|
||||
// rel_dir is the relative path to archive_dir.
|
||||
// user_prefix is the string the user indicated as the
|
||||
// relative or absolute path to the file's parent
|
||||
// directory from archive_dir. basename is the name
|
||||
// of the file, or empty if the filename is part of
|
||||
// user_prefix.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
Filename
|
||||
compose_href(const Filename &rel_dir, const Filename &user_prefix,
|
||||
const Filename &basename) {
|
||||
Filename result;
|
||||
|
||||
if (user_prefix.empty()) {
|
||||
result = rel_dir;
|
||||
|
||||
} else {
|
||||
// Check to see if the user prefix begins with a URL designator,
|
||||
// like http:// or ftp://.
|
||||
size_t ui = 0;
|
||||
while (ui < user_prefix.length() && isalpha(user_prefix[ui])) {
|
||||
ui++;
|
||||
}
|
||||
bool is_url = (user_prefix.get_fullpath().substr(ui, 3) == "://");
|
||||
|
||||
if (!is_url && user_prefix.is_local()) {
|
||||
Filename rel_user_dir(rel_dir, user_prefix);
|
||||
result = rel_user_dir;
|
||||
result.standardize();
|
||||
|
||||
} else {
|
||||
result = user_prefix;
|
||||
}
|
||||
}
|
||||
|
||||
if (basename.empty()) {
|
||||
return result;
|
||||
} else {
|
||||
return Filename(result, basename);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: escape_html
|
||||
// Description: Returns the input string with all invalid characters
|
||||
// for HTML code replaced by their HTML equivalents.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
string
|
||||
escape_html(const string &input) {
|
||||
static const struct {
|
||||
const char *name;
|
||||
int code;
|
||||
} tokens[] = {
|
||||
{ "amp", '&' }, { "lt", '<' }, { "gt", '>' }, { "quot", '"' },
|
||||
{ "nbsp", 160 },
|
||||
|
||||
{ "iexcl", 161 }, { "cent", 162 }, { "pound", 163 }, { "curren", 164 },
|
||||
{ "yen", 165 }, { "brvbar", 166 }, { "brkbar", 166 }, { "sect", 167 },
|
||||
{ "uml", 168 }, { "die", 168 }, { "copy", 169 }, { "ordf", 170 },
|
||||
{ "laquo", 171 }, { "not", 172 }, { "shy", 173 }, { "reg", 174 },
|
||||
{ "macr", 175 }, { "hibar", 175 }, { "deg", 176 }, { "plusmn", 177 },
|
||||
{ "sup2", 178 }, { "sup3", 179 }, { "acute", 180 }, { "micro", 181 },
|
||||
{ "para", 182 }, { "middot", 183 }, { "cedil", 184 }, { "sup1", 185 },
|
||||
{ "ordm", 186 }, { "raquo", 187 }, { "frac14", 188 }, { "frac12", 189 },
|
||||
{ "frac34", 190 }, { "iquest", 191 }, { "Agrave", 192 }, { "Aacute", 193 },
|
||||
{ "Acirc", 194 }, { "Atilde", 195 }, { "Auml", 196 }, { "Aring", 197 },
|
||||
{ "AElig", 198 }, { "Ccedil", 199 }, { "Egrave", 200 }, { "Eacute", 201 },
|
||||
{ "Ecirc", 202 }, { "Euml", 203 }, { "Igrave", 204 }, { "Iacute", 205 },
|
||||
{ "Icirc", 206 }, { "Iuml", 207 }, { "ETH", 208 }, { "Dstrok", 208 },
|
||||
{ "Ntilde", 209 }, { "Ograve", 210 }, { "Oacute", 211 }, { "Ocirc", 212 },
|
||||
{ "Otilde", 213 }, { "Ouml", 214 }, { "times", 215 }, { "Oslash", 216 },
|
||||
{ "Ugrave", 217 }, { "Uacute", 218 }, { "Ucirc", 219 }, { "Uuml", 220 },
|
||||
{ "Yacute", 221 }, { "THORN", 222 }, { "szlig", 223 }, { "agrave", 224 },
|
||||
{ "aacute", 225 }, { "acirc", 226 }, { "atilde", 227 }, { "auml", 228 },
|
||||
{ "aring", 229 }, { "aelig", 230 }, { "ccedil", 231 }, { "egrave", 232 },
|
||||
{ "eacute", 233 }, { "ecirc", 234 }, { "euml", 235 }, { "igrave", 236 },
|
||||
{ "iacute", 237 }, { "icirc", 238 }, { "iuml", 239 }, { "eth", 240 },
|
||||
{ "ntilde", 241 }, { "ograve", 242 }, { "oacute", 243 }, { "ocirc", 244 },
|
||||
{ "otilde", 245 }, { "ouml", 246 }, { "divide", 247 }, { "oslash", 248 },
|
||||
{ "ugrave", 249 }, { "uacute", 250 }, { "ucirc", 251 }, { "uuml", 252 },
|
||||
{ "yacute", 253 }, { "thorn", 254 }, { "yuml", 255 },
|
||||
|
||||
{ NULL, 0 },
|
||||
};
|
||||
|
||||
string result;
|
||||
for (string::const_iterator ii = input.begin();
|
||||
ii != input.end();
|
||||
++ii) {
|
||||
int code = (unsigned char)(*ii);
|
||||
bool found_match = false;
|
||||
for (int i = 0; !found_match && tokens[i].name != NULL; i++) {
|
||||
if (code == tokens[i].code) {
|
||||
result += '&';
|
||||
result += tokens[i].name;
|
||||
result += ';';
|
||||
found_match = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found_match) {
|
||||
result += (*ii);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
@ -83,6 +83,9 @@ extern bool force_regenerate;
|
||||
// True to use the Rose formatting convention for roll directory names.
|
||||
extern bool format_rose;
|
||||
|
||||
// True to sort roll directory names by date. Useful only with -r.
|
||||
extern bool sort_date;
|
||||
|
||||
// True to place dummy thumbnails instead of loading actual images.
|
||||
extern bool dummy_mode;
|
||||
|
||||
@ -127,6 +130,11 @@ extern int actual_index_width;
|
||||
extern int thumb_interior_width;
|
||||
extern int thumb_interior_height;
|
||||
|
||||
Filename compose_href(const Filename &rel_dir, const Filename &user_prefix,
|
||||
const Filename &basename = Filename());
|
||||
|
||||
string escape_html(const string &input);
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
@ -25,6 +25,8 @@
|
||||
#include "indexParameters.h"
|
||||
#include "string_utils.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: Indexify::Constructor
|
||||
// Access: Public
|
||||
@ -34,6 +36,7 @@ Indexify::
|
||||
Indexify() {
|
||||
clear_runlines();
|
||||
add_runline("[opts] roll1-dir roll2-dir [roll3-dir ...]");
|
||||
add_runline("[opts] full/*");
|
||||
|
||||
set_program_description
|
||||
("This program reads a collection of directories containing photo "
|
||||
@ -47,18 +50,24 @@ Indexify() {
|
||||
"should be within the same parent directory. Each directory is "
|
||||
"considered a \"roll\", which may or may not correspond to a physical "
|
||||
"roll of film, and the photos within each directory are grouped "
|
||||
"correspondingly on the generated HTML pages.\n\n"
|
||||
"correspondingly on the generated HTML pages. One common special case "
|
||||
"is in which all the roll directories are found in the subdirectory "
|
||||
"named \"full\" (e.g., the second example above) or \"reduced\". This "
|
||||
"keeps the root directory nice and clean.\n\n"
|
||||
|
||||
"If a file exists by the same name as an image file but with the "
|
||||
"extension \"cm\", that file is taken to be a HTML comment about that "
|
||||
"particular image and is inserted the HTML page for that image. "
|
||||
"Similarly, if there is a file within a roll directory with the same "
|
||||
"name as the directory itself (but with the extension \"cm\"), that file "
|
||||
"is inserted into the front page to introduce that particular roll.\n\n"
|
||||
"is inserted into the front page to introduce that particular roll. "
|
||||
"Finally, a file with the name of the directory, but with the extension "
|
||||
"\"ds\" may contain a brief one-line description of the directory, for "
|
||||
"the toplevel index page.\n\n"
|
||||
|
||||
"Normally, all image files with the specified extension (normally "
|
||||
"\"jpg\") within a roll directory are included in the index, and sorted "
|
||||
"into alphabetical (or numeric) order. If you wish to specify a "
|
||||
"into alphabetical (or numerical) order. If you wish to specify a "
|
||||
"different order, or use only a subset of the images in a directory, "
|
||||
"create a file in the roll directory with the same name as the "
|
||||
"directory itself, and the extension \"ls\". This file should "
|
||||
@ -81,8 +90,8 @@ Indexify() {
|
||||
|
||||
add_option
|
||||
("r", "relative-dir", 0,
|
||||
"When -a is specifies to place the generate html files in a directory "
|
||||
"other than the one above the actual roll directories, you may need "
|
||||
"When -a is specified to place the generated html files in a directory "
|
||||
"other than the default, you may need "
|
||||
"to specify how the html files will address the roll directories. This "
|
||||
"parameter specifies the relative path to the directory above the roll "
|
||||
"directories, from the directory named by -a.",
|
||||
@ -103,6 +112,12 @@ Indexify() {
|
||||
"name will be reformatted to m-yy/s for output.",
|
||||
&Indexify::dispatch_none, &format_rose);
|
||||
|
||||
add_option
|
||||
("s", "", 0,
|
||||
"When used in conjunction with -r, requests sorting of the roll "
|
||||
"directory names by date.",
|
||||
&Indexify::dispatch_none, &sort_date);
|
||||
|
||||
add_option
|
||||
("d", "", 0,
|
||||
"Run in \"dummy\" mode; don't load any images, but instead just "
|
||||
@ -261,7 +276,8 @@ handle_args(ProgramBase::Args &args) {
|
||||
filename.standardize();
|
||||
if (filename.is_directory()) {
|
||||
string basename = filename.get_basename();
|
||||
if (basename == "icons" || basename == "html" || basename == "reduced") {
|
||||
if (basename == "icons" || basename == "html" ||
|
||||
basename == "reduced" || basename == "thumbs") {
|
||||
nout << "Ignoring " << filename << "; indexify-generated directory.\n";
|
||||
|
||||
} else {
|
||||
@ -287,6 +303,13 @@ handle_args(ProgramBase::Args &args) {
|
||||
return true;
|
||||
}
|
||||
|
||||
class SortRollDirs {
|
||||
public:
|
||||
bool operator () (const RollDirectory *a, const RollDirectory *b) const {
|
||||
return a->sort_date_before(*b);
|
||||
}
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: Indexify::post_command_line
|
||||
// Access: Protected, Virtual
|
||||
@ -307,6 +330,12 @@ post_command_line() {
|
||||
if (_archive_dir.empty()) {
|
||||
// Choose a default archive directory, above the first roll directory.
|
||||
_archive_dir = _roll_dirs.front()->get_dir().get_dirname();
|
||||
string parent_dirname = _archive_dir.get_basename();
|
||||
if (parent_dirname == "full" || parent_dirname == "reduced") {
|
||||
// As a special case, if the subdirectory name is "full" or
|
||||
// "reduced", use the directory above that.
|
||||
_archive_dir = _archive_dir.get_dirname();
|
||||
}
|
||||
if (_archive_dir.empty()) {
|
||||
_archive_dir = ".";
|
||||
}
|
||||
@ -317,12 +346,17 @@ post_command_line() {
|
||||
_roll_dir_root.standardize();
|
||||
}
|
||||
|
||||
// Sort the roll directories, if specified.
|
||||
if (format_rose && sort_date) {
|
||||
sort(_roll_dirs.begin(), _roll_dirs.end(), SortRollDirs());
|
||||
}
|
||||
|
||||
if (_front_title.empty()) {
|
||||
// Supply a default title.
|
||||
if (_roll_dirs.size() == 1) {
|
||||
_front_title = _roll_dirs.front()->get_name();
|
||||
} else {
|
||||
_front_title = _roll_dirs.front()->get_name() + " to " + _roll_dirs.back()->get_name();
|
||||
_front_title = _roll_dirs.front()->get_name() + " through " + _roll_dirs.back()->get_name();
|
||||
}
|
||||
}
|
||||
|
||||
@ -479,17 +513,26 @@ run() {
|
||||
}
|
||||
|
||||
// Then go back and generate the HTML.
|
||||
for (di = _roll_dirs.begin(); di != _roll_dirs.end(); ++di) {
|
||||
RollDirectory *roll_dir = (*di);
|
||||
if (!roll_dir->generate_html(_archive_dir, _roll_dir_root)) {
|
||||
nout << "Failure.\n";
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
Filename html_filename(_archive_dir, "index.htm");
|
||||
nout << "Generating " << html_filename << "\n";
|
||||
html_filename.set_text();
|
||||
ofstream root_html;
|
||||
if (!html_filename.open_write(root_html)) {
|
||||
nout << "Unable to write to " << html_filename << "\n";
|
||||
// Generate the complete index that browses all the roll directories
|
||||
// at once.
|
||||
Filename complete_filename(_archive_dir, "html/complete.htm");
|
||||
nout << "Generating " << complete_filename << "\n";
|
||||
complete_filename.set_text();
|
||||
ofstream complete_html;
|
||||
if (!complete_filename.open_write(complete_html)) {
|
||||
nout << "Unable to write to " << complete_filename << "\n";
|
||||
exit(1);
|
||||
}
|
||||
|
||||
root_html
|
||||
complete_html
|
||||
<< "<html>\n"
|
||||
<< "<head>\n"
|
||||
<< "<title>" << _front_title << "</title>\n"
|
||||
@ -499,13 +542,63 @@ run() {
|
||||
|
||||
for (di = _roll_dirs.begin(); di != _roll_dirs.end(); ++di) {
|
||||
RollDirectory *roll_dir = (*di);
|
||||
if (!roll_dir->generate_html(root_html, _archive_dir, _roll_dir_root)) {
|
||||
nout << "Failure.\n";
|
||||
exit(1);
|
||||
complete_html
|
||||
<< roll_dir->get_comment_html()
|
||||
<< roll_dir->get_index_html();
|
||||
}
|
||||
|
||||
complete_html << "<p>\n";
|
||||
if (!up_icon.empty()) {
|
||||
// Use an icon to go up.
|
||||
Filename up_icon_href = compose_href("..", up_icon);
|
||||
complete_html
|
||||
<< "<a href=\"../index.htm\"><img src=\"" << up_icon_href
|
||||
<< "\" alt=\"return to index\"></a>\n";
|
||||
} else {
|
||||
// No up icon; use text to go up.
|
||||
complete_html
|
||||
<< "<br><a href=\"../index.htm\">Return to index</a>\n";
|
||||
}
|
||||
complete_html << "</p>\n";
|
||||
|
||||
complete_html
|
||||
<< "</body>\n"
|
||||
<< "</html>\n";
|
||||
|
||||
// And finally, generate the index HTML file that sits on the top of
|
||||
// all of this.
|
||||
Filename index_filename(_archive_dir, "index.htm");
|
||||
nout << "Generating " << index_filename << "\n";
|
||||
index_filename.set_text();
|
||||
ofstream index_html;
|
||||
if (!index_filename.open_write(index_html)) {
|
||||
nout << "Unable to write to " << index_filename << "\n";
|
||||
exit(1);
|
||||
}
|
||||
|
||||
index_html
|
||||
<< "<html>\n"
|
||||
<< "<head>\n"
|
||||
<< "<title>" << _front_title << "</title>\n"
|
||||
<< "</head>\n"
|
||||
<< "<body>\n"
|
||||
<< "<h1>" << _front_title << "</h1>\n"
|
||||
<< "<ul>\n";
|
||||
|
||||
for (di = _roll_dirs.begin(); di != _roll_dirs.end(); ++di) {
|
||||
RollDirectory *roll_dir = (*di);
|
||||
if (!roll_dir->is_empty()) {
|
||||
index_html
|
||||
<< "<a name=\"" << roll_dir->get_basename() << "\">\n"
|
||||
<< "<a href=\"html/" << roll_dir->get_basename() << ".htm\"><li>"
|
||||
<< roll_dir->get_name() << " " << escape_html(roll_dir->get_desc())
|
||||
<< "</li></a>\n";
|
||||
}
|
||||
}
|
||||
|
||||
root_html
|
||||
index_html
|
||||
<< "</ul>\n"
|
||||
<< "<a href=\"html/complete.htm\">(complete archive)</a>\n"
|
||||
<< "</body>\n"
|
||||
<< "</html>\n";
|
||||
}
|
||||
|
@ -101,6 +101,16 @@ get_name() const {
|
||||
return _name;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: RollDirectory::get_desc
|
||||
// Access: Public
|
||||
// Description: Returns the one-line description for the directory.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
const string &RollDirectory::
|
||||
get_desc() const {
|
||||
return _desc;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: RollDirectory::scan
|
||||
// Access: Public
|
||||
@ -111,9 +121,47 @@ scan(const string &extension) {
|
||||
bool reverse_order = false;
|
||||
bool explicit_list = false;
|
||||
|
||||
// Check for a .ds file, which contains a one-line description of
|
||||
// the contents of the directory.
|
||||
Filename ds_filename(_basename);
|
||||
ds_filename.set_extension("ds");
|
||||
if (cm_search.is_empty() || !ds_filename.resolve_filename(cm_search)) {
|
||||
// If the ds file isn't found along the search path specified
|
||||
// via -cmdir on the command line, then look for it in the
|
||||
// appropriate source directory.
|
||||
ds_filename = Filename(_dir, ds_filename);
|
||||
}
|
||||
if (ds_filename.exists()) {
|
||||
ds_filename.set_text();
|
||||
ifstream ds;
|
||||
if (!ds_filename.open_read(ds)) {
|
||||
nout << "Could not read " << ds_filename << "\n";
|
||||
} else {
|
||||
// Get the words out one at a time and put just one space
|
||||
// between them.
|
||||
string word;
|
||||
ds >> word;
|
||||
while (!ds.eof() && !ds.fail()) {
|
||||
if (!_desc.empty()) {
|
||||
_desc += ' ';
|
||||
}
|
||||
_desc += word;
|
||||
word = string();
|
||||
ds >> word;
|
||||
}
|
||||
if (!word.empty()) {
|
||||
if (!_desc.empty()) {
|
||||
_desc += ' ';
|
||||
}
|
||||
_desc += word;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check for an .ls file in the roll directory, which may give an
|
||||
// explicit ordering, or if empty, it specifies reverse ordering.
|
||||
Filename ls_filename(_dir, _basename + ".ls");
|
||||
Filename ls_filename(_dir, _basename);
|
||||
ls_filename.set_extension("ls");
|
||||
if (ls_filename.exists()) {
|
||||
add_contributing_filename(ls_filename);
|
||||
ls_filename.set_text();
|
||||
@ -213,6 +261,51 @@ collect_index_images() {
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: RollDirectory::sort_date_before
|
||||
// Access: Public
|
||||
// Description: Returns true if the given directory name should sort
|
||||
// before the other one, assuming the Rose naming
|
||||
// convention of mmyyss is in place.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool RollDirectory::
|
||||
sort_date_before(const RollDirectory &other) const {
|
||||
if (_name == _basename && other._name == other._basename) {
|
||||
// If Rose naming convention is not in place in either case, sort
|
||||
// alphabetically.
|
||||
return _basename < other._basename;
|
||||
|
||||
} else if (_name == _basename) {
|
||||
// If Rose naming convention is in place on this one and not the
|
||||
// other, it sorts first.
|
||||
return true;
|
||||
|
||||
} else if (other._name == other._basename) {
|
||||
// And vice-versa.
|
||||
return false;
|
||||
|
||||
} else {
|
||||
// Rose naming convention holds. Sort based on year first. Years
|
||||
// above 90 are deemed to belong to the previous century.
|
||||
string yy = _basename.substr(2, 2);
|
||||
string other_yy = other._basename.substr(2, 2);
|
||||
int year = atoi(yy.c_str());
|
||||
int other_year = atoi(other_yy.c_str());
|
||||
if (year < 90) {
|
||||
year += 100;
|
||||
}
|
||||
if (other_year < 90) {
|
||||
other_year += 100;
|
||||
}
|
||||
if (year != other_year) {
|
||||
return year < other_year;
|
||||
}
|
||||
|
||||
// After year, sort alphabetically.
|
||||
return _basename < other._basename;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: RollDirectory::get_newest_contributing_filename
|
||||
// Access: Public
|
||||
@ -310,17 +403,18 @@ generate_images(const Filename &archive_dir, PNMTextMaker *text_maker) {
|
||||
// Access: Public
|
||||
// Description: Generates all appropriate HTML files for this
|
||||
// directory, and generate the appropriate HTML code
|
||||
// into the root_html file.
|
||||
// into the html strings (retrieved by
|
||||
// get_comment_html() and get_index_html()).
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool RollDirectory::
|
||||
generate_html(ostream &root_html, const Filename &archive_dir,
|
||||
const Filename &roll_dir_root) {
|
||||
generate_html(const Filename &archive_dir, const Filename &roll_dir_root) {
|
||||
if (is_empty()) {
|
||||
return true;
|
||||
}
|
||||
nassertr(!_index_images.empty(), false);
|
||||
|
||||
root_html
|
||||
ostringstream comment_strm;
|
||||
comment_strm
|
||||
<< "<a name=\"" << _basename << "\">\n";
|
||||
|
||||
if (!omit_roll_headers) {
|
||||
@ -336,32 +430,122 @@ generate_html(ostream &root_html, const Filename &archive_dir,
|
||||
if (cm_filename.exists()) {
|
||||
// If the comment file for the roll exists, insert its contents
|
||||
// here instead of the generic header.
|
||||
if (!insert_html_comment(root_html, cm_filename)) {
|
||||
if (!insert_html_comment(comment_strm, cm_filename)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
} else {
|
||||
root_html
|
||||
comment_strm
|
||||
<< "<h2>" << _name << "</h2>\n";
|
||||
if (!_desc.empty()) {
|
||||
comment_strm << "<p>" << escape_html(_desc) << ".</p>\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
_comment_html = comment_strm.str();
|
||||
|
||||
nout << "Generating " << Filename(archive_dir, "html/")
|
||||
<< _basename << "/*\n";
|
||||
Filename html_dir(archive_dir, "html");
|
||||
nout << "Generating " << Filename(html_dir, _basename) << "/*\n";
|
||||
|
||||
root_html << "<p>\n";
|
||||
ostringstream index_strm;
|
||||
index_strm << "<p>\n";
|
||||
IndexImages::iterator ii;
|
||||
for (ii = _index_images.begin(); ii != _index_images.end(); ++ii) {
|
||||
IndexImage *index_image = (*ii);
|
||||
if (!index_image->generate_html(root_html, archive_dir, roll_dir_root)) {
|
||||
if (!index_image->generate_html(index_strm, archive_dir, roll_dir_root)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
root_html << "</p>\n";
|
||||
index_strm << "</p>\n";
|
||||
_index_html = index_strm.str();
|
||||
|
||||
// Also generate the index html for this directory.
|
||||
Filename html_filename(html_dir, _basename);
|
||||
html_filename.set_extension("htm");
|
||||
nout << "Generating " << html_filename << "\n";
|
||||
html_filename.set_text();
|
||||
ofstream index_html;
|
||||
if (!html_filename.open_write(index_html)) {
|
||||
nout << "Unable to write to " << html_filename << "\n";
|
||||
exit(1);
|
||||
}
|
||||
|
||||
string up_href = "../index.htm#" + _basename;
|
||||
|
||||
Filename prev_roll_filename;
|
||||
Filename next_roll_filename;
|
||||
|
||||
if (_prev != (RollDirectory *)NULL) {
|
||||
prev_roll_filename = _prev->_basename;
|
||||
prev_roll_filename.set_extension("htm");
|
||||
}
|
||||
if (_next != (RollDirectory *)NULL) {
|
||||
next_roll_filename = _next->_basename;
|
||||
next_roll_filename.set_extension("htm");
|
||||
}
|
||||
|
||||
index_html
|
||||
<< "<html>\n"
|
||||
<< "<head>\n";
|
||||
if (_desc.empty()) {
|
||||
index_html
|
||||
<< "<title>" << _name << "</title>\n";
|
||||
} else {
|
||||
index_html
|
||||
<< "<title>" << _name << " " << escape_html(_desc) << "</title>\n";
|
||||
}
|
||||
index_html
|
||||
<< "</head>\n"
|
||||
<< "<body>\n"
|
||||
<< get_comment_html();
|
||||
|
||||
generate_nav_buttons(index_html, prev_roll_filename, next_roll_filename,
|
||||
up_href);
|
||||
index_html << get_index_html();
|
||||
generate_nav_buttons(index_html, prev_roll_filename, next_roll_filename,
|
||||
up_href);
|
||||
|
||||
index_html
|
||||
<< "<a href=\"complete.htm#" << _basename << "\">(complete archive)</a>\n"
|
||||
<< "</body>\n"
|
||||
<< "</html>\n";
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: RollDirectory::get_comment_html
|
||||
// Access: Public
|
||||
// Description: Returns the HTML text that describes this directory's
|
||||
// index. This is set when generate_html() returns
|
||||
// true.
|
||||
//
|
||||
// This text may be inserted into the middle of a HTML
|
||||
// page to include the imagemap that references each of
|
||||
// the images in this directory.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
const string &RollDirectory::
|
||||
get_comment_html() const {
|
||||
return _comment_html;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: RollDirectory::get_index_html
|
||||
// Access: Public
|
||||
// Description: Returns the HTML text that describes this directory's
|
||||
// index. This is set when generate_html() returns
|
||||
// true.
|
||||
//
|
||||
// This text may be inserted into the middle of a HTML
|
||||
// page to include the imagemap that references each of
|
||||
// the images in this directory.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
const string &RollDirectory::
|
||||
get_index_html() const {
|
||||
return _index_html;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: RollDirectory::output
|
||||
// Access: Public
|
||||
@ -492,23 +676,103 @@ format_basename(const string &basename) {
|
||||
return basename;
|
||||
}
|
||||
|
||||
// The first four characters must be digits.
|
||||
for (size_t i = 0; i < 4; i++) {
|
||||
if (!isdigit(basename[i])) {
|
||||
return basename;
|
||||
}
|
||||
// The first two characters must be alphanumeric.
|
||||
if (!isalnum(basename[0]) || !isalnum(basename[1])) {
|
||||
return basename;
|
||||
}
|
||||
|
||||
// The next two characters must be digits.
|
||||
if (!isdigit(basename[2]) || !isdigit(basename[3])) {
|
||||
return basename;
|
||||
}
|
||||
|
||||
// If the first two were digits as well as being alphanumeric, then
|
||||
// we have mm-yy/sequence. Otherwise, we just have xxyy/sequence.
|
||||
bool mm_is_month = (isdigit(basename[0]) && isdigit(basename[1]));
|
||||
|
||||
string mm = basename.substr(0, 2);
|
||||
string yy = basename.substr(2, 2);
|
||||
string ss = basename.substr(4);
|
||||
|
||||
if (mm[0] == '0') {
|
||||
if (mm_is_month && mm[0] == '0') {
|
||||
mm = mm[1];
|
||||
}
|
||||
while (ss.length() > 1 && ss[0] == '0') {
|
||||
ss = ss.substr(1);
|
||||
}
|
||||
|
||||
return mm + "-" + yy + "/" + ss;
|
||||
if (mm_is_month) {
|
||||
return mm + "-" + yy + "/" + ss;
|
||||
} else {
|
||||
return mm + yy + "/" + ss;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: RollDirectory::generate_nav_buttons
|
||||
// Access: Private, Static
|
||||
// Description: Outputs the HTML code to generate the next, prev,
|
||||
// up buttons when viewing each reduced image.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void RollDirectory::
|
||||
generate_nav_buttons(ostream &html, const Filename &prev_roll_filename,
|
||||
const Filename &next_roll_filename,
|
||||
const string &up_href) {
|
||||
html << "<p>\n";
|
||||
|
||||
bool first_icons = false;
|
||||
if (!prev_icon.empty() && !next_icon.empty()) {
|
||||
first_icons = true;
|
||||
// Use icons to go forward and back.
|
||||
Filename prev_icon_href = compose_href("..", prev_icon);
|
||||
if (prev_roll_filename.empty()) {
|
||||
html << "<img src=\"" << prev_icon_href << "\" alt=\"No previous roll\">\n";
|
||||
} else {
|
||||
html << "<a href=\"" << prev_roll_filename
|
||||
<< "\"><img src=\"" << prev_icon_href << "\" alt=\"previous\"></a>\n";
|
||||
}
|
||||
|
||||
Filename next_icon_href = compose_href("..", next_icon);
|
||||
if (next_roll_filename.empty()) {
|
||||
html << "<img src=\"" << next_icon_href << "\" alt=\"No next roll\">\n";
|
||||
} else {
|
||||
html << "<a href=\"" << next_roll_filename
|
||||
<< "\"><img src=\"" << next_icon_href << "\" alt=\"next\"></a>\n";
|
||||
}
|
||||
|
||||
} else {
|
||||
// No prev/next icons; use text to go forward and back.
|
||||
if (prev_roll_filename.empty()) {
|
||||
html << "(This is the first roll.)\n";
|
||||
} else {
|
||||
html << "<a href=\"" << prev_roll_filename
|
||||
<< "\">Back to previous roll</a>\n";
|
||||
}
|
||||
|
||||
if (next_roll_filename.empty()) {
|
||||
html << "<br>(This is the last roll.)\n";
|
||||
} else {
|
||||
html << "<br><a href=\"" << next_roll_filename
|
||||
<< "\">On to next roll</a>\n";
|
||||
}
|
||||
}
|
||||
|
||||
if (!up_href.empty()) {
|
||||
if (!up_icon.empty()) {
|
||||
// Use an icon to go up.
|
||||
if (!first_icons) {
|
||||
html << "<br>";
|
||||
} else {
|
||||
html << " ";
|
||||
}
|
||||
Filename up_icon_href = compose_href("..", up_icon);
|
||||
html << "<a href=\"" << up_href
|
||||
<< "\"><img src=\"" << up_icon_href << "\" alt=\"return to index\"></a>\n";
|
||||
} else {
|
||||
// No up icon; use text to go up.
|
||||
html << "<br><a href=\"" << up_href
|
||||
<< "\">Return to index</a>\n";
|
||||
}
|
||||
}
|
||||
html << "</p>\n";
|
||||
}
|
||||
|
@ -41,9 +41,12 @@ public:
|
||||
const Filename &get_dir() const;
|
||||
const string &get_basename() const;
|
||||
const string &get_name() const;
|
||||
const string &get_desc() const;
|
||||
bool scan(const string &extension);
|
||||
void collect_index_images();
|
||||
|
||||
bool sort_date_before(const RollDirectory &other) const;
|
||||
|
||||
const Filename &get_newest_contributing_filename() const;
|
||||
|
||||
bool is_empty() const;
|
||||
@ -54,8 +57,10 @@ public:
|
||||
IndexImage *get_index_image(int n) const;
|
||||
|
||||
bool generate_images(const Filename &archive_dir, PNMTextMaker *text_maker);
|
||||
bool generate_html(ostream &root_html, const Filename &archive_dir,
|
||||
const Filename &roll_dir_root);
|
||||
bool generate_html(const Filename &archive_dir,
|
||||
const Filename &roll_dir_root);
|
||||
const string &get_comment_html() const;
|
||||
const string &get_index_html() const;
|
||||
|
||||
void output(ostream &out) const;
|
||||
void write(ostream &out, int indent_level) const;
|
||||
@ -66,6 +71,10 @@ private:
|
||||
void add_contributing_filename(const Filename &filename);
|
||||
static bool insert_html_comment_body(ostream &html, istream &cm);
|
||||
static string format_basename(const string &basename);
|
||||
void generate_nav_buttons(ostream &html,
|
||||
const Filename &prev_roll_filename,
|
||||
const Filename &next_roll_filename,
|
||||
const string &up_href);
|
||||
|
||||
public:
|
||||
RollDirectory *_prev;
|
||||
@ -75,6 +84,7 @@ private:
|
||||
Filename _dir;
|
||||
string _basename;
|
||||
string _name;
|
||||
string _desc;
|
||||
typedef pvector<Photo *> Photos;
|
||||
Photos _photos;
|
||||
|
||||
@ -82,6 +92,9 @@ private:
|
||||
|
||||
typedef pvector<IndexImage *> IndexImages;
|
||||
IndexImages _index_images;
|
||||
|
||||
string _comment_html;
|
||||
string _index_html;
|
||||
};
|
||||
|
||||
INLINE ostream &operator << (ostream &out, const RollDirectory &d) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user