1
/* Copyright 2011 Yorba Foundation
3
* This software is licensed under the GNU Lesser General Public License
4
* (version 2.1 or later). See the COPYING file in this distribution.
7
namespace AlienDb.FSpot {
9
internal class FSpotTagsCache : Object {
10
private FSpotTagsTable tags_table;
11
private Gee.HashMap<FSpotTagID, FSpotDatabaseTag> tags_map;
13
public FSpotTagsCache(FSpotTagsTable tags_table) throws DatabaseError {
14
this.tags_table = tags_table;
15
tags_map = new Gee.HashMap<FSpotTagID, FSpotDatabaseTag> ();
18
public FSpotDatabaseTag get_tag(FSpotTagRow tag_row) throws DatabaseError {
19
FSpotDatabaseTag? tag = tags_map.get(tag_row.tag_id);
23
FSpotDatabaseTag? parent_tag = get_tag_from_id(tag_row.category_id);
24
FSpotDatabaseTag new_tag = new FSpotDatabaseTag(tag_row, parent_tag);
25
tags_map[tag_row.tag_id] = new_tag;
30
private FSpotDatabaseTag? get_tag_from_id(FSpotTagID tag_id) throws DatabaseError {
31
if (tag_id.is_null() || tag_id.is_invalid())
33
FSpotDatabaseTag? tag = tags_map.get(tag_id);
36
FSpotTagRow? tag_row = tags_table.get_by_id(tag_id);
37
if (tag_row != null) {
38
FSpotDatabaseTag? parent_tag = get_tag_from_id(tag_row.category_id);
39
FSpotDatabaseTag new_tag = new FSpotDatabaseTag(tag_row, parent_tag);
40
tags_map[tag_id] = new_tag;
48
* An implementation of AlienDatabase that is able to read from the F-Spot
49
* database and extract the relevant objects.
51
public class FSpotDatabase : Object, AlienDatabase {
52
private AlienDatabaseID id;
53
private Sqlite.Database fspot_db;
54
private FSpotMetaTable meta_table;
55
private FSpotPhotosTable photos_table;
56
private FSpotPhotoVersionsTable photo_versions_table;
57
private FSpotTagsTable tags_table;
58
private FSpotTagsCache tags_cache;
59
private FSpotRollsTable rolls_table;
60
private int64 hidden_tag_id;
62
public FSpotDatabase(FSpotDatabaseDriver driver, AlienDatabaseID id) throws DatabaseError, AlienDatabaseError {
64
initialize(driver, id.driver_specific_uri);
67
public FSpotDatabase.from_file(FSpotDatabaseDriver driver, File db_file) throws DatabaseError, AlienDatabaseError {
68
this.id = new AlienDatabaseID(driver.get_id(), db_file.get_path());
69
initialize(driver, db_file.get_path());
72
private void initialize(FSpotDatabaseDriver driver, string filename) throws DatabaseError, AlienDatabaseError {
73
int res = Sqlite.Database.open_v2(filename, out fspot_db,
74
Sqlite.OPEN_READONLY, null);
76
throw new DatabaseError.ERROR("Unable to open F-Spot database %s: %d", filename, res);
77
meta_table = new FSpotMetaTable(fspot_db);
78
hidden_tag_id = meta_table.get_hidden_tag_id();
80
FSpotDatabaseBehavior db_behavior = new FSpotDatabaseBehavior(driver, get_version());
82
photos_table = new FSpotPhotosTable(fspot_db, db_behavior);
83
photo_versions_table = new FSpotPhotoVersionsTable(fspot_db, db_behavior);
84
tags_table = new FSpotTagsTable(fspot_db, db_behavior);
85
tags_cache = new FSpotTagsCache(tags_table);
86
rolls_table = new FSpotRollsTable(fspot_db, db_behavior);
92
public string get_uri() {
96
public string get_display_name() {
100
private AlienDatabaseVersion get_version() throws DatabaseError {
101
return new AlienDatabaseVersion.from_string(meta_table.get_db_version());
104
public Gee.Collection<AlienDatabasePhoto> get_photos() throws DatabaseError {
105
Gee.List<AlienDatabasePhoto> photos = new Gee.ArrayList<AlienDatabasePhoto>();
107
foreach (FSpotPhotoRow photo_row in photos_table.get_all()) {
109
bool favorite = false;
110
Gee.ArrayList<AlienDatabaseTag> tags = new Gee.ArrayList<AlienDatabaseTag>();
111
AlienDatabaseEvent? event = null;
112
FSpotRollRow? roll_row = null;
114
// TODO: We do not convert F-Spot events to Shotwell events because F-Spot's events
115
// are essentially tags. We would need to detect if the tag is an event (use
116
// is_tag_event) and then assign the event to the photo ... since a photo can be
117
// in multiple F-Spot events, we would need to pick one, and since their tags
118
// are heirarchical, we would need to pick a name (probably the leaf)
120
foreach (FSpotTagRow tag_row in tags_table.get_by_photo_id(photo_row.photo_id)) {
121
FSpotDatabaseTag tag = tags_cache.get_tag(tag_row);
122
if (is_tag_hidden(tag))
124
else if (is_tag_favorite(tag))
129
} catch(DatabaseError e) {
130
// log the error and leave the tag list empty
131
message("Failed to retrieve tags for photo ID %ld: %s", (long) photo_row.photo_id.id,
136
roll_row = rolls_table.get_by_id(photo_row.roll_id);
137
} catch (DatabaseError e) {
138
// log the error and leave the roll row null
139
message("Failed to retrieve roll for photo ID %ld: %s", (long) photo_row.photo_id.id,
144
bool photo_versions_added = false;
145
foreach (FSpotPhotoVersionRow photo_version_row in photo_versions_table.get_by_photo_id(photo_row.photo_id)) {
146
photos.add(new FSpotDatabasePhoto(
147
photo_row, photo_version_row, roll_row, tags, event, hidden, favorite
149
photo_versions_added = true;
152
// older versions of F-Spot (0.4.3.1 at least, perhaps later) did not maintain photo_versions,
153
// this handles that case
154
if (!photo_versions_added)
155
photos.add(new FSpotDatabasePhoto(
156
photo_row, null, roll_row, tags, event, hidden, favorite
158
} catch (DatabaseError e) {
159
// if we can't load the different versions, do the best we can
160
// and create one photo from the photo row that was found earlier
161
message("Failed to retrieve versions for photo ID %ld: %s", (long) photo_row.photo_id.id,
163
photos.add(new FSpotDatabasePhoto(
164
photo_row, null, roll_row, tags, event, hidden, favorite
172
public bool is_tag_event(FSpotDatabaseTag tag) {
173
bool result = (FSpotTagsTable.STOCK_ICON_EVENTS == tag.get_row().stock_icon);
175
FSpotDatabaseTag? parent = tag.get_fspot_parent();
179
result = is_tag_event(parent);
184
public bool is_tag_hidden(FSpotDatabaseTag tag) {
185
bool result = (hidden_tag_id == tag.get_row().tag_id.id);
187
FSpotDatabaseTag? parent = tag.get_fspot_parent();
191
result = is_tag_hidden(parent);
196
public bool is_tag_favorite(FSpotDatabaseTag tag) {
197
bool result = (FSpotTagsTable.STOCK_ICON_FAV == tag.get_row().stock_icon);
199
FSpotDatabaseTag? parent = tag.get_fspot_parent();
203
result = is_tag_favorite(parent);