diff options
Diffstat (limited to 'src/db/PhotoTable.vala')
-rw-r--r-- | src/db/PhotoTable.vala | 206 |
1 files changed, 142 insertions, 64 deletions
diff --git a/src/db/PhotoTable.vala b/src/db/PhotoTable.vala index 24cec86..4e3f672 100644 --- a/src/db/PhotoTable.vala +++ b/src/db/PhotoTable.vala @@ -44,9 +44,7 @@ public struct ImportID { } public static ImportID generate() { - TimeVal timestamp = TimeVal(); - timestamp.get_current_time(); - int64 id = timestamp.tv_sec; + int64 id = GLib.get_real_time () / Util.USEC_PER_SEC; return ImportID(id); } @@ -72,7 +70,7 @@ public struct ImportID { public class PhotoRow { public PhotoID photo_id; public BackingPhotoRow master; - public time_t exposure_time; + public DateTime? exposure_time; public ImportID import_id; public EventID event_id; public Orientation orientation; @@ -80,13 +78,14 @@ public class PhotoRow { public string md5; public string thumbnail_md5; public string exif_md5; - public time_t time_created; + public int64 time_created; public uint64 flags; public Rating rating; public string title; + public GpsCoords gps_coords; public string comment; public string? backlinks; - public time_t time_reimported; + public int64 time_reimported; public BackingPhotoID editable_id; public bool metadata_dirty; @@ -103,6 +102,10 @@ public class PhotoRow { development_ids = new BackingPhotoID[RawDeveloper.as_array().length]; foreach (RawDeveloper d in RawDeveloper.as_array()) development_ids[d] = BackingPhotoID(); + gps_coords = GpsCoords(); + development_ids = new BackingPhotoID[RawDeveloper.as_array().length]; + foreach (RawDeveloper d in RawDeveloper.as_array()) + development_ids[d] = BackingPhotoID(); } } @@ -140,6 +143,9 @@ public class PhotoTable : DatabaseTable { + "develop_shotwell_id INTEGER DEFAULT -1, " + "develop_camera_id INTEGER DEFAULT -1, " + "develop_embedded_id INTEGER DEFAULT -1, " + + "has_gps INTEGER DEFAULT -1, " + + "gps_lat REAL, " + + "gps_lon REAL, " + "comment TEXT" + ")", -1, out stmt); assert(res == Sqlite.OK); @@ -209,12 +215,12 @@ public class PhotoTable : DatabaseTable { int res = db.prepare_v2( "INSERT INTO PhotoTable (filename, width, height, filesize, timestamp, exposure_time, " + "orientation, original_orientation, import_id, event_id, md5, thumbnail_md5, " - + "exif_md5, time_created, file_format, title, rating, editable_id, developer, comment) " - + "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", + + "exif_md5, time_created, file_format, title, rating, editable_id, developer, has_gps, gps_lat, gps_lon, comment) " + + "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", -1, out stmt); assert(res == Sqlite.OK); - ulong time_created = now_sec(); + var time_created = now_sec(); res = stmt.bind_text(1, photo_row.master.filepath); assert(res == Sqlite.OK); @@ -224,9 +230,17 @@ public class PhotoTable : DatabaseTable { assert(res == Sqlite.OK); res = stmt.bind_int64(4, photo_row.master.filesize); assert(res == Sqlite.OK); - res = stmt.bind_int64(5, photo_row.master.timestamp); + if (photo_row.master.timestamp == null) { + res = stmt.bind_null(5); + } else { + res = stmt.bind_int64(5, photo_row.master.timestamp.to_unix()); + } assert(res == Sqlite.OK); - res = stmt.bind_int64(6, photo_row.exposure_time); + if (photo_row.exposure_time == null) { + res = stmt.bind_null(6); + } else { + res = stmt.bind_int64(6, photo_row.exposure_time.to_unix()); + } assert(res == Sqlite.OK); res = stmt.bind_int(7, photo_row.master.original_orientation); assert(res == Sqlite.OK); @@ -254,7 +268,13 @@ public class PhotoTable : DatabaseTable { assert(res == Sqlite.OK); res = stmt.bind_text(19, photo_row.developer.to_string()); assert(res == Sqlite.OK); - res = stmt.bind_text(20, photo_row.comment); + res = stmt.bind_int(20, photo_row.gps_coords.has_gps); + assert(res == Sqlite.OK); + res = stmt.bind_double(21, photo_row.gps_coords.latitude); + assert(res == Sqlite.OK); + res = stmt.bind_double(22, photo_row.gps_coords.longitude); + assert(res == Sqlite.OK); + res = stmt.bind_text(23, photo_row.comment); assert(res == Sqlite.OK); res = stmt.step(); @@ -269,7 +289,7 @@ public class PhotoTable : DatabaseTable { photo_row.photo_id = PhotoID(db.last_insert_rowid()); photo_row.orientation = photo_row.master.original_orientation; photo_row.event_id = EventID(); - photo_row.time_created = (time_t) time_created; + photo_row.time_created = time_created; photo_row.flags = 0; return photo_row.photo_id; @@ -285,11 +305,12 @@ public class PhotoTable : DatabaseTable { int res = db.prepare_v2( "UPDATE PhotoTable SET width = ?, height = ?, filesize = ?, timestamp = ?, " + "exposure_time = ?, orientation = ?, original_orientation = ?, md5 = ?, " - + "exif_md5 = ?, thumbnail_md5 = ?, file_format = ?, title = ?, time_reimported = ? " + + "exif_md5 = ?, thumbnail_md5 = ?, file_format = ?, title = ?, " + + "has_gps = ?, gps_lat = ?, gps_lon = ?, time_reimported = ? " + "WHERE id = ?", -1, out stmt); assert(res == Sqlite.OK); - time_t time_reimported = (time_t) now_sec(); + var time_reimported = now_sec(); res = stmt.bind_int(1, row.master.dim.width); assert(res == Sqlite.OK); @@ -297,9 +318,13 @@ public class PhotoTable : DatabaseTable { assert(res == Sqlite.OK); res = stmt.bind_int64(3, row.master.filesize); assert(res == Sqlite.OK); - res = stmt.bind_int64(4, row.master.timestamp); + res = stmt.bind_int64(4, row.master.timestamp.to_unix()); assert(res == Sqlite.OK); - res = stmt.bind_int64(5, row.exposure_time); + if (row.exposure_time == null) { + res = stmt.bind_null(5); + } else { + res = stmt.bind_int64(5, row.exposure_time.to_unix()); + } assert(res == Sqlite.OK); res = stmt.bind_int(6, row.master.original_orientation); assert(res == Sqlite.OK); @@ -315,9 +340,15 @@ public class PhotoTable : DatabaseTable { assert(res == Sqlite.OK); res = stmt.bind_text(12, row.title); assert(res == Sqlite.OK); - res = stmt.bind_int64(13, time_reimported); + res = stmt.bind_int(13, row.gps_coords.has_gps); + assert(res == Sqlite.OK); + res = stmt.bind_double(14, row.gps_coords.latitude); + assert(res == Sqlite.OK); + res = stmt.bind_double(15, row.gps_coords.longitude); + assert(res == Sqlite.OK); + res = stmt.bind_int64(16, time_reimported); assert(res == Sqlite.OK); - res = stmt.bind_int64(14, row.photo_id.id); + res = stmt.bind_int64(17, row.photo_id.id); assert(res == Sqlite.OK); res = stmt.step(); @@ -328,7 +359,7 @@ public class PhotoTable : DatabaseTable { row.orientation = row.master.original_orientation; } - public bool master_exif_updated(PhotoID photoID, int64 filesize, long timestamp, + public bool master_exif_updated(PhotoID photoID, int64 filesize, DateTime timestamp, string md5, string? exif_md5, string? thumbnail_md5, PhotoRow row) { Sqlite.Statement stmt; int res = db.prepare_v2( @@ -338,7 +369,7 @@ public class PhotoTable : DatabaseTable { res = stmt.bind_int64(1, filesize); assert(res == Sqlite.OK); - res = stmt.bind_int64(2, timestamp); + res = stmt.bind_int64(2, timestamp.to_unix()); assert(res == Sqlite.OK); res = stmt.bind_text(3, md5); assert(res == Sqlite.OK); @@ -372,7 +403,7 @@ public class PhotoTable : DatabaseTable { // the DB as a zero due to Vala 0.14 breaking the way it handled // objects passed as 'ref' arguments to methods. // - // For further details, please see http://redmine.yorba.org/issues/4354 and + // For further details, please see https://bugzilla.gnome.org/show_bug.cgi?id=718194 and // https://bugzilla.gnome.org/show_bug.cgi?id=663818 . private void validate_orientation(PhotoRow row) { if ((row.orientation < Orientation.MIN) || @@ -390,7 +421,7 @@ public class PhotoTable : DatabaseTable { + "original_orientation, import_id, event_id, transformations, md5, thumbnail_md5, " + "exif_md5, time_created, flags, rating, file_format, title, backlinks, " + "time_reimported, editable_id, metadata_dirty, developer, develop_shotwell_id, " - + "develop_camera_id, develop_embedded_id, comment " + + "develop_camera_id, develop_embedded_id, has_gps, gps_lat, gps_lon, comment " + "FROM PhotoTable WHERE id=?", -1, out stmt); assert(res == Sqlite.OK); @@ -406,8 +437,12 @@ public class PhotoTable : DatabaseTable { row.master.filepath = stmt.column_text(0); row.master.dim = Dimensions(stmt.column_int(1), stmt.column_int(2)); row.master.filesize = stmt.column_int64(3); - row.master.timestamp = (time_t) stmt.column_int64(4); - row.exposure_time = (time_t) stmt.column_int64(5); + row.master.timestamp = new DateTime.from_unix_utc(stmt.column_int64(4)); + if (stmt.column_type(5) == Sqlite.NULL) { + row.exposure_time = null; + } else { + row.exposure_time = new DateTime.from_unix_utc(stmt.column_int64(5)); + } row.orientation = (Orientation) stmt.column_int(6); row.master.original_orientation = (Orientation) stmt.column_int(7); row.import_id.id = stmt.column_int64(8); @@ -416,13 +451,13 @@ public class PhotoTable : DatabaseTable { row.md5 = stmt.column_text(11); row.thumbnail_md5 = stmt.column_text(12); row.exif_md5 = stmt.column_text(13); - row.time_created = (time_t) stmt.column_int64(14); + row.time_created = stmt.column_int64(14); row.flags = stmt.column_int64(15); row.rating = Rating.unserialize(stmt.column_int(16)); row.master.file_format = PhotoFileFormat.unserialize(stmt.column_int(17)); row.title = stmt.column_text(18); row.backlinks = stmt.column_text(19); - row.time_reimported = (time_t) stmt.column_int64(20); + row.time_reimported = stmt.column_int64(20); row.editable_id = BackingPhotoID(stmt.column_int64(21)); row.metadata_dirty = stmt.column_int(22) != 0; row.developer = stmt.column_text(23) != null ? RawDeveloper.from_string(stmt.column_text(23)) : @@ -430,7 +465,10 @@ public class PhotoTable : DatabaseTable { row.development_ids[RawDeveloper.SHOTWELL] = BackingPhotoID(stmt.column_int64(24)); row.development_ids[RawDeveloper.CAMERA] = BackingPhotoID(stmt.column_int64(25)); row.development_ids[RawDeveloper.EMBEDDED] = BackingPhotoID(stmt.column_int64(26)); - row.comment = stmt.column_text(27); + row.gps_coords.has_gps = stmt.column_int(27); + row.gps_coords.latitude = stmt.column_double(28); + row.gps_coords.longitude = stmt.column_double(29); + row.comment = stmt.column_text(30); return row; } @@ -442,7 +480,7 @@ public class PhotoTable : DatabaseTable { + "original_orientation, import_id, event_id, transformations, md5, thumbnail_md5, " + "exif_md5, time_created, flags, rating, file_format, title, backlinks, time_reimported, " + "editable_id, metadata_dirty, developer, develop_shotwell_id, develop_camera_id, " - + "develop_embedded_id, comment FROM PhotoTable", + + "develop_embedded_id, has_gps, gps_lat, gps_lon, comment FROM PhotoTable", -1, out stmt); assert(res == Sqlite.OK); @@ -454,8 +492,12 @@ public class PhotoTable : DatabaseTable { row.master.filepath = stmt.column_text(1); row.master.dim = Dimensions(stmt.column_int(2), stmt.column_int(3)); row.master.filesize = stmt.column_int64(4); - row.master.timestamp = (time_t) stmt.column_int64(5); - row.exposure_time = (time_t) stmt.column_int64(6); + row.master.timestamp = new DateTime.from_unix_utc(stmt.column_int64(5)); + if (stmt.column_type(6) == Sqlite.NULL) { + row.exposure_time = null; + } else { + row.exposure_time = new DateTime.from_unix_utc(stmt.column_int64(6)); + } row.orientation = (Orientation) stmt.column_int(7); row.master.original_orientation = (Orientation) stmt.column_int(8); row.import_id.id = stmt.column_int64(9); @@ -464,13 +506,13 @@ public class PhotoTable : DatabaseTable { row.md5 = stmt.column_text(12); row.thumbnail_md5 = stmt.column_text(13); row.exif_md5 = stmt.column_text(14); - row.time_created = (time_t) stmt.column_int64(15); + row.time_created = stmt.column_int64(15); row.flags = stmt.column_int64(16); row.rating = Rating.unserialize(stmt.column_int(17)); row.master.file_format = PhotoFileFormat.unserialize(stmt.column_int(18)); row.title = stmt.column_text(19); row.backlinks = stmt.column_text(20); - row.time_reimported = (time_t) stmt.column_int64(21); + row.time_reimported = stmt.column_int64(21); row.editable_id = BackingPhotoID(stmt.column_int64(22)); row.metadata_dirty = stmt.column_int(23) != 0; row.developer = stmt.column_text(24) != null ? RawDeveloper.from_string(stmt.column_text(24)) : @@ -478,7 +520,10 @@ public class PhotoTable : DatabaseTable { row.development_ids[RawDeveloper.SHOTWELL] = BackingPhotoID(stmt.column_int64(25)); row.development_ids[RawDeveloper.CAMERA] = BackingPhotoID(stmt.column_int64(26)); row.development_ids[RawDeveloper.EMBEDDED] = BackingPhotoID(stmt.column_int64(27)); - row.comment = stmt.column_text(28); + row.gps_coords.has_gps = stmt.column_int(28); + row.gps_coords.latitude = stmt.column_double(29); + row.gps_coords.longitude = stmt.column_double(30); + row.comment = stmt.column_text(31); validate_orientation(row); @@ -500,9 +545,9 @@ public class PhotoTable : DatabaseTable { int res = db.prepare_v2("INSERT INTO PhotoTable (filename, width, height, filesize, " + "timestamp, exposure_time, orientation, original_orientation, import_id, event_id, " + "transformations, md5, thumbnail_md5, exif_md5, time_created, flags, rating, " - + "file_format, title, editable_id, developer, develop_shotwell_id, develop_camera_id, " - + "develop_embedded_id, comment) " - + "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", + + "file_format, title, has_gps, gps_lat, gps_lon, editable_id, developer, " + + "develop_shotwell_id, develop_camera_id, develop_embedded_id, comment) " + + "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", -1, out stmt); assert(res == Sqlite.OK); @@ -514,9 +559,13 @@ public class PhotoTable : DatabaseTable { assert(res == Sqlite.OK); res = stmt.bind_int64(4, original.master.filesize); assert(res == Sqlite.OK); - res = stmt.bind_int64(5, original.master.timestamp); + res = stmt.bind_int64(5, original.master.timestamp.to_unix()); assert(res == Sqlite.OK); - res = stmt.bind_int64(6, original.exposure_time); + if (original.exposure_time == null) { + res = stmt.bind_null(6); + } else { + res = stmt.bind_int64(6, original.exposure_time.to_unix()); + } assert(res == Sqlite.OK); res = stmt.bind_int(7, original.orientation); assert(res == Sqlite.OK); @@ -544,18 +593,23 @@ public class PhotoTable : DatabaseTable { assert(res == Sqlite.OK); res = stmt.bind_text(19, original.title); assert(res == Sqlite.OK); - res = stmt.bind_int64(20, editable_id.id); + res = stmt.bind_int(20, original.gps_coords.has_gps); assert(res == Sqlite.OK); - - res = stmt.bind_text(21, original.developer.to_string()); + res = stmt.bind_double(21, original.gps_coords.latitude); assert(res == Sqlite.OK); - res = stmt.bind_int64(22, develop_shotwell.id); + res = stmt.bind_double(22, original.gps_coords.longitude); assert(res == Sqlite.OK); - res = stmt.bind_int64(23, develop_camera_id.id); + res = stmt.bind_int64(23, editable_id.id); assert(res == Sqlite.OK); - res = stmt.bind_int64(24, develop_embedded_id.id); + res = stmt.bind_text(24, original.developer.to_string()); assert(res == Sqlite.OK); - res = stmt.bind_text(25, original.comment); + res = stmt.bind_int64(25, develop_shotwell.id); + assert(res == Sqlite.OK); + res = stmt.bind_int64(26, develop_camera_id.id); + assert(res == Sqlite.OK); + res = stmt.bind_int64(27, develop_embedded_id.id); + assert(res == Sqlite.OK); + res = stmt.bind_text(28, original.comment); assert(res == Sqlite.OK); res = stmt.step(); @@ -572,7 +626,15 @@ public class PhotoTable : DatabaseTable { public bool set_title(PhotoID photo_id, string? new_title) { return update_text_by_id(photo_id.id, "title", new_title != null ? new_title : ""); } - + + public void set_gps_coords(PhotoID photo_id, GpsCoords new_gps_coords) throws DatabaseError { + update_int_by_id_2(photo_id.id, "has_gps", new_gps_coords.has_gps); + if (new_gps_coords.has_gps > 0) { + update_double_by_id_2(photo_id.id, "gps_lat", new_gps_coords.latitude); + update_double_by_id_2(photo_id.id, "gps_lon", new_gps_coords.longitude); + } + } + public bool set_comment(PhotoID photo_id, string? new_comment) { return update_text_by_id(photo_id.id, "comment", new_comment != null ? new_comment : ""); } @@ -581,12 +643,12 @@ public class PhotoTable : DatabaseTable { update_text_by_id_2(photo_id.id, "filename", filepath); } - public void update_timestamp(PhotoID photo_id, time_t timestamp) throws DatabaseError { - update_int64_by_id_2(photo_id.id, "timestamp", timestamp); + public void update_timestamp(PhotoID photo_id, DateTime timestamp) throws DatabaseError { + update_int64_by_id_2(photo_id.id, "timestamp", timestamp.to_unix()); } - public bool set_exposure_time(PhotoID photo_id, time_t time) { - return update_int64_by_id(photo_id.id, "exposure_time", (int64) time); + public bool set_exposure_time(PhotoID photo_id, DateTime time) { + return update_int64_by_id(photo_id.id, "exposure_time", time.to_unix()); } public void set_import_id(PhotoID photo_id, ImportID import_id) throws DatabaseError { @@ -1051,6 +1113,16 @@ public class PhotoTable : DatabaseTable { public void remove_development(PhotoRow row, RawDeveloper rd) throws DatabaseError { update_raw_development(row, rd, BackingPhotoID()); } + + public static void upgrade_for_unset_timestamp() throws DatabaseError { + Sqlite.Statement stmt; + int res = db.prepare_v2("UPDATE PhotoTable SET exposure_time = NULL WHERE exposure_time = '0'", -1, out stmt); + assert(res == Sqlite.OK); + res = stmt.step(); + if (res != Sqlite.DONE) { + throw_error("PhotoTable.upgrade_for_unset_timestamp", res); + } + } } @@ -1084,10 +1156,10 @@ public struct BackingPhotoID { public class BackingPhotoRow { public BackingPhotoID id; - public time_t time_created; + public int64 time_created; public string? filepath = null; public int64 filesize; - public time_t timestamp; + public DateTime? timestamp; public PhotoFileFormat file_format; public Dimensions dim; public Orientation original_orientation; @@ -1095,15 +1167,21 @@ public class BackingPhotoRow { public bool matches_file_info(FileInfo info) { if (filesize != info.get_size()) return false; + + if (timestamp == null) + return false; - return timestamp == info.get_modification_time().tv_sec; + return timestamp.equal(info.get_modification_date_time()); } public bool is_touched(FileInfo info) { if (filesize != info.get_size()) return false; + + if (timestamp == null) + return true; - return timestamp != info.get_modification_time().tv_sec; + return !timestamp.equal(info.get_modification_date_time()); } // Copies another backing photo row into this one. @@ -1162,11 +1240,11 @@ public class BackingPhotoTable : DatabaseTable { -1, out stmt); assert(res == Sqlite.OK); - time_t time_created = (time_t) now_sec(); + var time_created = now_sec(); res = stmt.bind_text(1, state.filepath); assert(res == Sqlite.OK); - res = stmt.bind_int64(2, state.timestamp); + res = stmt.bind_int64(2, state.timestamp.to_unix()); assert(res == Sqlite.OK); res = stmt.bind_int64(3, state.filesize); assert(res == Sqlite.OK); @@ -1208,12 +1286,12 @@ public class BackingPhotoTable : DatabaseTable { BackingPhotoRow row = new BackingPhotoRow(); row.id = id; row.filepath = stmt.column_text(0); - row.timestamp = (time_t) stmt.column_int64(1); + row.timestamp = new DateTime.from_unix_utc(stmt.column_int64(1)); row.filesize = stmt.column_int64(2); row.dim = Dimensions(stmt.column_int(3), stmt.column_int(4)); row.original_orientation = (Orientation) stmt.column_int(5); row.file_format = PhotoFileFormat.unserialize(stmt.column_int(6)); - row.time_created = (time_t) stmt.column_int64(7); + row.time_created = stmt.column_int64(7); return row; } @@ -1227,7 +1305,7 @@ public class BackingPhotoTable : DatabaseTable { -1, out stmt); assert(res == Sqlite.OK); - res = stmt.bind_int64(1, row.timestamp); + res = stmt.bind_int64(1, row.timestamp.to_unix()); assert(res == Sqlite.OK); res = stmt.bind_int64(2, row.filesize); assert(res == Sqlite.OK); @@ -1247,13 +1325,13 @@ public class BackingPhotoTable : DatabaseTable { throw_error("BackingPhotoTable.update", res); } - public void update_attributes(BackingPhotoID id, time_t timestamp, int64 filesize) throws DatabaseError { + public void update_attributes(BackingPhotoID id, DateTime timestamp, int64 filesize) throws DatabaseError { Sqlite.Statement stmt; int res = db.prepare_v2("UPDATE BackingPhotoTable SET timestamp=?, filesize=? WHERE id=?", -1, out stmt); assert(res == Sqlite.OK); - res = stmt.bind_int64(1, timestamp); + res = stmt.bind_int64(1, timestamp.to_unix()); assert(res == Sqlite.OK); res = stmt.bind_int64(2, filesize); assert(res == Sqlite.OK); @@ -1273,8 +1351,8 @@ public class BackingPhotoTable : DatabaseTable { update_text_by_id_2(id.id, "filepath", filepath); } - public void update_timestamp(BackingPhotoID id, time_t timestamp) throws DatabaseError { - update_int64_by_id_2(id.id, "timestamp", timestamp); + public void update_timestamp(BackingPhotoID id, DateTime timestamp) throws DatabaseError { + update_int64_by_id_2(id.id, "timestamp", timestamp.to_unix()); } } |