Merge lp:~codygarver/pantheon-photos/fix-1322215 into lp:~pantheon-photos/pantheon-photos/trunk

Proposed by Cody Garver
Status: Merged
Approved by: meese
Approved revision: 2602
Merged at revision: 2603
Proposed branch: lp:~codygarver/pantheon-photos/fix-1322215
Merge into: lp:~pantheon-photos/pantheon-photos/trunk
Diff against target: 4098 lines (+6/-3870)
28 files modified
plugins/plugins.mk (+1/-3)
plugins/shotwell-data-imports/FSpotDatabase.vala (+0/-58)
plugins/shotwell-data-imports/FSpotDatabaseBehavior.vala (+0/-208)
plugins/shotwell-data-imports/FSpotDatabaseTable.vala (+0/-54)
plugins/shotwell-data-imports/FSpotImporter.vala (+0/-567)
plugins/shotwell-data-imports/FSpotMetaTable.vala (+0/-113)
plugins/shotwell-data-imports/FSpotPhotoTagsTable.vala (+0/-57)
plugins/shotwell-data-imports/FSpotPhotoVersionsTable.vala (+0/-275)
plugins/shotwell-data-imports/FSpotPhotosTable.vala (+0/-363)
plugins/shotwell-data-imports/FSpotRollsTable.vala (+0/-111)
plugins/shotwell-data-imports/FSpotTableBehavior.vala (+0/-28)
plugins/shotwell-data-imports/FSpotTagsTable.vala (+0/-129)
plugins/shotwell-data-imports/Makefile (+0/-30)
plugins/shotwell-data-imports/shotwell-data-imports.vala (+0/-46)
src/Dialogs.vala (+1/-5)
src/data_imports/DataImportJob.vala (+0/-177)
src/data_imports/DataImportSource.vala (+0/-135)
src/data_imports/DataImports.vala (+0/-30)
src/data_imports/DataImportsPluginHost.vala (+0/-483)
src/data_imports/DataImportsUI.vala (+0/-445)
src/data_imports/mk/data_imports.mk (+0/-31)
src/library/LibraryWindow.vala (+0/-13)
src/library/mk/library.mk (+1/-2)
src/plugins/DataImportsInterfaces.vala (+0/-489)
src/plugins/mk/interfaces.mk (+1/-2)
src/plugins/mk/plugins.mk (+1/-2)
src/tags/HierarchicalTagUtilities.vala (+0/-12)
units.mk (+1/-2)
To merge this branch: bzr merge lp:~codygarver/pantheon-photos/fix-1322215
Reviewer Review Type Date Requested Status
meese Approve
Review via email: mp+232505@code.launchpad.net

Commit message

Drop shotwell-data-imports, includes FSpot plugin (lp:1322215)

To post a comment you must log in.
Revision history for this message
Cody Garver (codygarver) wrote :

The modifications to src/tags/HierarchicalTagUtilities.vala were to satisfy the build failure due to an unused code warning

2602. By Cody Garver

Merge in trunk and resolve conflicts

Revision history for this message
meese (meese) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'plugins/plugins.mk'
--- plugins/plugins.mk 2013-11-14 22:27:35 +0000
+++ plugins/plugins.mk 2014-08-28 06:03:26 +0000
@@ -1,8 +1,7 @@
11
2PLUGINS := \2PLUGINS := \
3 shotwell-transitions \3 shotwell-transitions \
4 shotwell-publishing \4 shotwell-publishing
5 shotwell-data-imports
65
7PLUGINS_RC := \6PLUGINS_RC := \
8 plugins/shotwell-publishing/facebook.png \7 plugins/shotwell-publishing/facebook.png \
@@ -24,7 +23,6 @@
2423
25EXTRA_PLUGINS_RC := \24EXTRA_PLUGINS_RC := \
26 plugins/shotwell-publishing-extras/yandex_publish_model.glade \25 plugins/shotwell-publishing-extras/yandex_publish_model.glade \
27 plugins/shotwell-data-imports/f-spot-24.png \
28 plugins/shotwell-publishing-extras/tumblr.png \26 plugins/shotwell-publishing-extras/tumblr.png \
29 plugins/shotwell-publishing-extras/tumblr_authentication_pane.glade \27 plugins/shotwell-publishing-extras/tumblr_authentication_pane.glade \
30 plugins/shotwell-publishing-extras/tumblr_publishing_options_pane.glade28 plugins/shotwell-publishing-extras/tumblr_publishing_options_pane.glade
3129
=== removed directory 'plugins/shotwell-data-imports'
=== removed file 'plugins/shotwell-data-imports/FSpotDatabase.vala'
--- plugins/shotwell-data-imports/FSpotDatabase.vala 2014-08-08 21:13:09 +0000
+++ plugins/shotwell-data-imports/FSpotDatabase.vala 1970-01-01 00:00:00 +0000
@@ -1,58 +0,0 @@
1/* Copyright 2011-2013 Yorba Foundation
2 *
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.
5 */
6
7namespace DataImports.FSpot.Db {
8
9public const int64 NULL_ID = 0;
10public const int64 INVALID_ID = -1;
11
12/**
13 * Initialization method for the whole module.
14 */
15public void init () {
16 FSpotDatabaseBehavior.create_behavior_map ();
17}
18
19/**
20 * An object that is able to read from the F-Spot
21 * database and extract the relevant objects.
22 */
23public class FSpotDatabase : Object {
24 private Sqlite.Database fspot_db;
25 private FSpotMetaTable meta_table;
26 public FSpotPhotosTable photos_table;
27 public FSpotPhotoVersionsTable photo_versions_table;
28 public FSpotTagsTable tags_table;
29 public FSpotRollsTable rolls_table;
30 public int64 hidden_tag_id;
31
32 public FSpotDatabase (File db_file) throws DatabaseError, Spit.DataImports.DataImportError {
33 string filename = db_file.get_path ();
34 int res = Sqlite.Database.open_v2 (filename, out fspot_db,
35 Sqlite.OPEN_READONLY, null);
36 if (res != Sqlite.OK)
37 throw new DatabaseError.ERROR ("Unable to open F-Spot database %s: %d", filename, res);
38 meta_table = new FSpotMetaTable (fspot_db);
39 hidden_tag_id = meta_table.get_hidden_tag_id ();
40
41 FSpotDatabaseBehavior db_behavior = new FSpotDatabaseBehavior (get_version ());
42
43 photos_table = new FSpotPhotosTable (fspot_db, db_behavior);
44 photo_versions_table = new FSpotPhotoVersionsTable (fspot_db, db_behavior);
45 tags_table = new FSpotTagsTable (fspot_db, db_behavior);
46 rolls_table = new FSpotRollsTable (fspot_db, db_behavior);
47 }
48
49 ~FSpotDatabase () {
50 }
51
52 private Utils.VersionNumber get_version () throws DatabaseError {
53 return new Utils.VersionNumber.from_string (meta_table.get_db_version ());
54 }
55}
56
57}
58
590
=== removed file 'plugins/shotwell-data-imports/FSpotDatabaseBehavior.vala'
--- plugins/shotwell-data-imports/FSpotDatabaseBehavior.vala 2014-08-08 21:13:09 +0000
+++ plugins/shotwell-data-imports/FSpotDatabaseBehavior.vala 1970-01-01 00:00:00 +0000
@@ -1,208 +0,0 @@
1/* Copyright 2011-2013 Yorba Foundation
2 *
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.
5 */
6
7namespace DataImports.FSpot.Db {
8
9private class FSpotBehaviorEntry {
10 private Utils.VersionNumber version;
11 private FSpotTableBehavior behavior;
12
13 public FSpotBehaviorEntry (Utils.VersionNumber version, FSpotTableBehavior behavior) {
14 this.version = version;
15 this.behavior = behavior;
16 }
17
18 public Utils.VersionNumber get_version () {
19 return version;
20 }
21
22 public FSpotTableBehavior get_behavior () {
23 return behavior;
24 }
25}
26
27/**
28 * A class that consolidates the behavior of all F-Spot tables (apart from meta)
29 * and is the one place to check whether the database version is supported.
30 */
31public class FSpotDatabaseBehavior : Object {
32 // Minimum unsupported version: any database from that version and above
33 // is not supported as it's too new and support has not been provided
34 // In practice, the code may work with future versions but this cannot be
35 // guaranteed as it hasn't been tested so it's probably better to just
36 // bomb out at that point rather than risk importing incorrect data
37 public static Utils.VersionNumber MIN_UNSUPPORTED_VERSION =
38 new Utils.VersionNumber ({ 19 });
39 private static Gee.Map<string, Gee.List<FSpotBehaviorEntry>> behavior_map;
40
41 private FSpotTableBehavior<FSpotPhotoRow> photos_behavior;
42 private FSpotTableBehavior<FSpotTagRow> tags_behavior;
43 private FSpotTableBehavior<FSpotPhotoTagRow> photo_tags_behavior;
44 private FSpotTableBehavior<FSpotPhotoVersionRow> photo_versions_behavior;
45 private FSpotTableBehavior<FSpotRollRow> rolls_behavior;
46
47 public static void create_behavior_map () {
48 behavior_map = new Gee.HashMap<string, Gee.List<FSpotBehaviorEntry>> ();
49 // photos table
50 Gee.List<FSpotBehaviorEntry> photos_list = new Gee.ArrayList<FSpotBehaviorEntry> ();
51 // v0-4
52 photos_list.add (new FSpotBehaviorEntry (
53 new Utils.VersionNumber ({ 0 }),
54 FSpotPhotosV0Behavior.get_instance ()
55 ));
56 // v5-6
57 photos_list.add (new FSpotBehaviorEntry (
58 new Utils.VersionNumber ({ 5 }),
59 FSpotPhotosV5Behavior.get_instance ()
60 ));
61 // v7-10
62 photos_list.add (new FSpotBehaviorEntry (
63 new Utils.VersionNumber ({ 7 }),
64 FSpotPhotosV7Behavior.get_instance ()
65 ));
66 // v11-15
67 photos_list.add (new FSpotBehaviorEntry (
68 new Utils.VersionNumber ({ 11 }),
69 FSpotPhotosV11Behavior.get_instance ()
70 ));
71 // v16
72 photos_list.add (new FSpotBehaviorEntry (
73 new Utils.VersionNumber ({ 16 }),
74 FSpotPhotosV16Behavior.get_instance ()
75 ));
76 // v17
77 photos_list.add (new FSpotBehaviorEntry (
78 new Utils.VersionNumber ({ 17 }),
79 FSpotPhotosV17Behavior.get_instance ()
80 ));
81 // v18+
82 photos_list.add (new FSpotBehaviorEntry (
83 new Utils.VersionNumber ({ 18 }),
84 FSpotPhotosV18Behavior.get_instance ()
85 ));
86 behavior_map.set (FSpotPhotosTable.TABLE_NAME, photos_list);
87 // tags table
88 Gee.List<FSpotBehaviorEntry> tags_list = new Gee.ArrayList<FSpotBehaviorEntry> ();
89 // v0+
90 tags_list.add (new FSpotBehaviorEntry (
91 new Utils.VersionNumber ({ 0 }),
92 FSpotTagsV0Behavior.get_instance ()
93 ));
94 behavior_map.set (FSpotTagsTable.TABLE_NAME, tags_list);
95 // photo_tags table
96 Gee.List<FSpotBehaviorEntry> photo_tags_list = new Gee.ArrayList<FSpotBehaviorEntry> ();
97 // v0+
98 photo_tags_list.add (new FSpotBehaviorEntry (
99 new Utils.VersionNumber ({ 0 }),
100 FSpotPhotoTagsV0Behavior.get_instance ()
101 ));
102 behavior_map.set (FSpotPhotoTagsTable.TABLE_NAME, photo_tags_list);
103 // photo_versions table
104 Gee.List<FSpotBehaviorEntry> photo_versions_list = new Gee.ArrayList<FSpotBehaviorEntry> ();
105 // v0-8
106 photo_versions_list.add (new FSpotBehaviorEntry (
107 new Utils.VersionNumber ({ 0 }),
108 FSpotPhotoVersionsV0Behavior.get_instance ()
109 ));
110 // v9-15
111 photo_versions_list.add (new FSpotBehaviorEntry (
112 new Utils.VersionNumber ({ 9 }),
113 FSpotPhotoVersionsV9Behavior.get_instance ()
114 ));
115 // v16
116 photo_versions_list.add (new FSpotBehaviorEntry (
117 new Utils.VersionNumber ({ 16 }),
118 FSpotPhotoVersionsV16Behavior.get_instance ()
119 ));
120 // v17
121 photo_versions_list.add (new FSpotBehaviorEntry (
122 new Utils.VersionNumber ({ 17 }),
123 FSpotPhotoVersionsV17Behavior.get_instance ()
124 ));
125 // v18+
126 photo_versions_list.add (new FSpotBehaviorEntry (
127 new Utils.VersionNumber ({ 18 }),
128 FSpotPhotoVersionsV18Behavior.get_instance ()
129 ));
130 behavior_map.set (FSpotPhotoVersionsTable.TABLE_NAME, photo_versions_list);
131 // rolls table
132 Gee.List<FSpotBehaviorEntry> rolls_list = new Gee.ArrayList<FSpotBehaviorEntry> ();
133 // v0-4
134 rolls_list.add (new FSpotBehaviorEntry (
135 new Utils.VersionNumber ({ 0 }),
136 FSpotRollsV0Behavior.get_instance ()
137 ));
138 // v5+
139 rolls_list.add (new FSpotBehaviorEntry (
140 new Utils.VersionNumber ({ 5 }),
141 FSpotRollsV5Behavior.get_instance ()
142 ));
143 behavior_map.set (FSpotRollsTable.TABLE_NAME, rolls_list);
144 }
145
146 public static FSpotTableBehavior? find_behavior (string table_name, Utils.VersionNumber version) {
147 FSpotTableBehavior behavior = null;
148 Gee.List<FSpotBehaviorEntry> behavior_list = behavior_map.get (table_name);
149 if (behavior_list != null)
150 foreach (FSpotBehaviorEntry entry in behavior_list) {
151 if (version.compare_to (entry.get_version ()) >= 0)
152 behavior = entry.get_behavior ();
153 }
154 else
155 warning ("Could not find behavior list for table %s", table_name);
156 return behavior;
157
158 }
159 public FSpotDatabaseBehavior (Utils.VersionNumber version) throws Spit.DataImports.DataImportError {
160 if (version.compare_to (MIN_UNSUPPORTED_VERSION) >= 0)
161 throw new Spit.DataImports.DataImportError.UNSUPPORTED_VERSION ("Version %s is not yet supported", version.to_string ());
162
163 FSpotTableBehavior? photos_generic_behavior = find_behavior (FSpotPhotosTable.TABLE_NAME, version);
164 if (photos_generic_behavior != null)
165 photos_behavior = photos_generic_behavior as FSpotTableBehavior<FSpotPhotoRow>;
166 FSpotTableBehavior? tags_generic_behavior = find_behavior (FSpotTagsTable.TABLE_NAME, version);
167 if (tags_generic_behavior != null)
168 tags_behavior = tags_generic_behavior as FSpotTableBehavior<FSpotTagRow>;
169 FSpotTableBehavior? photo_tags_generic_behavior = find_behavior (FSpotPhotoTagsTable.TABLE_NAME, version);
170 if (photo_tags_generic_behavior != null)
171 photo_tags_behavior = photo_tags_generic_behavior as FSpotTableBehavior<FSpotPhotoTagRow>;
172 FSpotTableBehavior? photo_versions_generic_behavior = find_behavior (FSpotPhotoVersionsTable.TABLE_NAME, version);
173 if (photo_versions_generic_behavior != null)
174 photo_versions_behavior = photo_versions_generic_behavior as FSpotTableBehavior<FSpotPhotoVersionRow>;
175 FSpotTableBehavior? rolls_generic_behavior = find_behavior (FSpotRollsTable.TABLE_NAME, version);
176 if (rolls_generic_behavior != null)
177 rolls_behavior = rolls_generic_behavior as FSpotTableBehavior<FSpotRollRow>;
178
179 if (photos_behavior == null || tags_behavior == null ||
180 photo_tags_behavior == null || photo_versions_behavior == null ||
181 rolls_behavior == null
182 )
183 throw new Spit.DataImports.DataImportError.UNSUPPORTED_VERSION ("Version %s is not supported", version.to_string ());
184 }
185
186 public FSpotTableBehavior<FSpotPhotoRow> get_photos_behavior () {
187 return photos_behavior;
188 }
189
190 public FSpotTableBehavior<FSpotTagRow> get_tags_behavior () {
191 return tags_behavior;
192 }
193
194 public FSpotTableBehavior<FSpotPhotoTagRow> get_photo_tags_behavior () {
195 return photo_tags_behavior;
196 }
197
198 public FSpotTableBehavior<FSpotPhotoVersionRow> get_photo_versions_behavior () {
199 return photo_versions_behavior;
200 }
201
202 public FSpotTableBehavior<FSpotRollRow> get_rolls_behavior () {
203 return rolls_behavior;
204 }
205}
206
207}
208
2090
=== removed file 'plugins/shotwell-data-imports/FSpotDatabaseTable.vala'
--- plugins/shotwell-data-imports/FSpotDatabaseTable.vala 2014-08-08 21:13:09 +0000
+++ plugins/shotwell-data-imports/FSpotDatabaseTable.vala 1970-01-01 00:00:00 +0000
@@ -1,54 +0,0 @@
1/* Copyright 2009-2013 Yorba Foundation
2 *
3 * This software is licensed under the GNU LGPL (version 2.1 or later).
4 * See the COPYING file in this distribution.
5 */
6
7namespace DataImports.FSpot.Db {
8
9/**
10 * This class represents a generic F-Spot table.
11 */
12public abstract class FSpotDatabaseTable<T> : ImportableDatabaseTable {
13 protected unowned Sqlite.Database fspot_db;
14 protected FSpotTableBehavior<T> behavior;
15
16 public FSpotDatabaseTable (Sqlite.Database db) {
17 this.fspot_db = db;
18 }
19
20 public void set_behavior (FSpotTableBehavior<T> behavior) {
21 this.behavior = behavior;
22 set_table_name (behavior.get_table_name ());
23 }
24
25 public FSpotTableBehavior<T> get_behavior () {
26 return behavior;
27 }
28
29 protected string get_joined_column_list (bool with_table = false) {
30 string[] columns = behavior.list_columns ();
31 if (with_table)
32 for (int i = 0; i < columns.length; i++)
33 columns[i] = "%s.%s".printf (table_name, columns[i]);
34 return string.joinv (", ", columns);
35 }
36
37 protected int select_all (out Sqlite.Statement stmt) throws DatabaseError {
38 string column_list = get_joined_column_list ();
39 string sql = "SELECT %s FROM %s".printf (column_list, table_name);
40
41 int res = fspot_db.prepare_v2 (sql, -1, out stmt);
42 if (res != Sqlite.OK)
43 throw_error ("Statement failed: %s".printf (sql), res);
44
45 res = stmt.step ();
46 if (res != Sqlite.ROW && res != Sqlite.DONE)
47 throw_error ("select_all %s %s".printf (table_name, column_list), res);
48
49 return res;
50 }
51}
52
53}
54
550
=== removed file 'plugins/shotwell-data-imports/FSpotImporter.vala'
--- plugins/shotwell-data-imports/FSpotImporter.vala 2014-08-08 21:13:09 +0000
+++ plugins/shotwell-data-imports/FSpotImporter.vala 1970-01-01 00:00:00 +0000
@@ -1,567 +0,0 @@
1/* Copyright 2009-2013 Yorba Foundation
2 *
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.
5 */
6
7public class FSpotService : Object, Spit.Pluggable, Spit.DataImports.Service {
8 private const string ICON_FILENAME = "f-spot-24.png";
9
10 private static Gdk.Pixbuf[] icon_pixbuf_set = null;
11
12 public FSpotService (GLib.File resource_directory) {
13 // initialize the database layer
14 DataImports.FSpot.Db.init ();
15 if (icon_pixbuf_set == null)
16 icon_pixbuf_set = Resources.load_icon_set (resource_directory.get_child (ICON_FILENAME));
17 }
18
19 public int get_pluggable_interface (int min_host_interface, int max_host_interface) {
20 return Spit.negotiate_interfaces (min_host_interface, max_host_interface,
21 Spit.DataImports.CURRENT_INTERFACE);
22 }
23
24 public unowned string get_id () {
25 return "org.yorba.shotwell.dataimports.fspot";
26 }
27
28 public unowned string get_pluggable_name () {
29 return "F-Spot";
30 }
31
32 public void get_info (ref Spit.PluggableInfo info) {
33 info.authors = "Bruno Girin";
34 info.copyright = _ ("Copyright 2009-2013 Yorba Foundation");
35 info.translators = Resources.TRANSLATORS;
36 info.version = _VERSION;
37 info.website_name = Resources.WEBSITE_NAME;
38 info.website_url = Resources.WEBSITE_URL;
39 info.is_license_wordwrapped = false;
40 info.license = Resources.LICENSE;
41 info.icons = icon_pixbuf_set;
42 }
43
44 public void activation (bool enabled) {
45 }
46
47 public Spit.DataImports.DataImporter create_data_importer (Spit.DataImports.PluginHost host) {
48 return new DataImports.FSpot.FSpotDataImporter (this, host);
49 }
50}
51
52namespace DataImports.FSpot {
53
54internal const string SERVICE_NAME = "F-Spot";
55internal const string SERVICE_WELCOME_MESSAGE =
56 _ ("Welcome to the F-Spot library import service.\n\nPlease select a library to import, either by selecting one of the existing libraries found by Shotwell or by selecting an alternative F-Spot database file.");
57internal const string SERVICE_WELCOME_MESSAGE_FILE_ONLY =
58 _ ("Welcome to the F-Spot library import service.\n\nPlease select an F-Spot database file.");
59internal const string FILE_IMPORT_LABEL =
60 _ ("Manually select an F-Spot database file to import:");
61internal const string ERROR_CANT_OPEN_DB_FILE =
62 _ ("Cannot open the selected F-Spot database file: the file does not exist or is not an F-Spot database");
63internal const string ERROR_UNSUPPORTED_DB_VERSION =
64 _ ("Cannot open the selected F-Spot database file: this version of the F-Spot database is not supported by Shotwell");
65internal const string ERROR_CANT_READ_TAGS_TABLE =
66 _ ("Cannot read the selected F-Spot database file: error while reading tags table");
67internal const string ERROR_CANT_READ_PHOTOS_TABLE =
68 _ ("Cannot read the selected F-Spot database file: error while reading photos table");
69internal const string MESSAGE_FINAL_SCREEN =
70 _ ("Shotwell has found %d photos in the F-Spot library and is currently importing them. Duplicates will be automatically detected and removed.\n\nYou can close this dialog and start using Shotwell while the import is taking place in the background.");
71
72public class FSpotImportableLibrary : Spit.DataImports.ImportableLibrary, GLib.Object {
73 private File db_file;
74
75 public FSpotImportableLibrary (File db_file) {
76 this.db_file = db_file;
77 }
78
79 public File get_db_file () {
80 return db_file;
81 }
82
83 public string get_display_name () {
84 return _ ("F-Spot library: %s").printf (db_file.get_path ());
85 }
86}
87
88public class FSpotImportableItem : Spit.DataImports.ImportableMediaItem, GLib.Object {
89 private DataImports.FSpot.Db.FSpotPhotoRow photo_row;
90 private DataImports.FSpot.Db.FSpotPhotoVersionRow? photo_version_row;
91 private DataImports.FSpot.Db.FSpotRollRow? roll_row;
92 private FSpotImportableTag[] tags;
93 private FSpotImportableEvent? event;
94 private FSpotImportableRating rating;
95 private string folder_path;
96 private string filename;
97
98 public FSpotImportableItem (
99 DataImports.FSpot.Db.FSpotPhotoRow photo_row,
100 DataImports.FSpot.Db.FSpotPhotoVersionRow? photo_version_row,
101 DataImports.FSpot.Db.FSpotRollRow? roll_row,
102 FSpotImportableTag[] tags,
103 FSpotImportableEvent? event,
104 bool is_hidden,
105 bool is_favorite
106 ) {
107 this.photo_row = photo_row;
108 this.photo_version_row = photo_version_row;
109 this.roll_row = roll_row;
110 this.tags = tags;
111 this.event = event;
112 if (photo_row.rating > 0)
113 this.rating = new FSpotImportableRating (photo_row.rating);
114 else if (is_hidden)
115 this.rating = new FSpotImportableRating (FSpotImportableRating.REJECTED);
116 else if (is_favorite)
117 this.rating = new FSpotImportableRating (5);
118 else
119 this.rating = new FSpotImportableRating (FSpotImportableRating.UNRATED);
120
121 // store path and filename
122 folder_path = (photo_version_row != null) ?
123 photo_version_row.base_path.get_path () :
124 photo_row.base_path.get_path ();
125 filename = (photo_version_row != null) ?
126 photo_version_row.filename :
127 photo_row.filename;
128
129 // In theory, neither field should be null at that point but belts
130 // and braces don't hurt
131 if (folder_path != null && filename != null) {
132 // check if file exist and if not decode as URL
133 File photo = File.new_for_path (folder_path).get_child (filename);
134
135 // If file not found, parse as URI and store back
136 if (!photo.query_exists ()) {
137 folder_path = decode_url (folder_path);
138 filename = decode_url (filename);
139 }
140 }
141 }
142
143 public Spit.DataImports.ImportableTag[] get_tags () {
144 Spit.DataImports.ImportableTag[] importable_tags = new Spit.DataImports.ImportableTag[0];
145 foreach (FSpotImportableTag tag in tags)
146 importable_tags += tag;
147 return importable_tags;
148 }
149
150 public Spit.DataImports.ImportableEvent? get_event () {
151 return event;
152 }
153
154 public string get_folder_path () {
155 return folder_path;
156 }
157
158 public string get_filename () {
159 return filename;
160 }
161
162 public string? get_title () {
163 return (photo_row.description == null || photo_row.description == "") ? null : photo_row.description;
164 }
165
166 public Spit.DataImports.ImportableRating get_rating () {
167 return rating;
168 }
169
170 private string decode_url (string url) {
171 StringBuilder builder = new StringBuilder ();
172 for (int idx = 0; idx < url.length; ) {
173 int cidx = url.index_of_char ('%', idx);
174 if (cidx > idx) {
175 builder.append (url.slice (idx, cidx));
176 }
177 if (cidx >= 0) {
178 if (cidx < url.length - 2) {
179 char c1 = url.get (cidx + 1);
180 char c2 = url.get (cidx + 2);
181 if (c1.isxdigit () && c1.isxdigit ()) {
182 int ccode = 0x10 * c1.xdigit_value () + c2.xdigit_value ();
183 builder.append_c ((char)ccode);
184 }
185 idx = cidx + 3;
186 } else {
187 idx = cidx + 1;
188 }
189 } else {
190 builder.append (url.substring (idx));
191 idx = url.length;
192 }
193 }
194 return builder.str;
195 }
196}
197
198public class FSpotImportableTag : Spit.DataImports.ImportableTag, GLib.Object {
199 private DataImports.FSpot.Db.FSpotTagRow row;
200 private FSpotImportableTag? parent;
201
202 public FSpotImportableTag (DataImports.FSpot.Db.FSpotTagRow row, FSpotImportableTag? parent) {
203 this.row = row;
204 this.parent = parent;
205 }
206
207 public int64 get_id () {
208 return row.tag_id;
209 }
210
211 public string get_name () {
212 return row.name;
213 }
214
215 public Spit.DataImports.ImportableTag? get_parent () {
216 return parent;
217 }
218
219 public FSpotImportableTag? get_fspot_parent () {
220 return parent;
221 }
222
223 public string get_stock_icon () {
224 return row.stock_icon;
225 }
226
227 public bool is_stock () {
228 return (row.stock_icon.has_prefix (DataImports.FSpot.Db.FSpotTagsTable.PREFIX_STOCK_ICON));
229 }
230
231 public FSpotImportableEvent to_event () {
232 return new FSpotImportableEvent (this.row);
233 }
234}
235
236public class FSpotImportableEvent : Spit.DataImports.ImportableEvent, GLib.Object {
237 private DataImports.FSpot.Db.FSpotTagRow row;
238
239 public FSpotImportableEvent (DataImports.FSpot.Db.FSpotTagRow row) {
240 this.row = row;
241 }
242
243 public string get_name () {
244 return row.name;
245 }
246}
247
248public class FSpotImportableRating : Spit.DataImports.ImportableRating, GLib.Object {
249 public static const int REJECTED = -1;
250 public static const int UNRATED = 0;
251
252 private int rating_value;
253
254 public FSpotImportableRating (int rating_value) {
255 if (rating_value < -1)
256 rating_value = -1;
257 else if (rating_value > 5)
258 rating_value = 5;
259 this.rating_value = rating_value;
260 }
261
262 public bool is_rejected () {
263 return (rating_value == REJECTED);
264 }
265
266 public bool is_unrated () {
267 return (rating_value == UNRATED);
268 }
269
270 public int get_value () {
271 return rating_value;
272 }
273}
274
275internal class FSpotTagsCache : Object {
276 private DataImports.FSpot.Db.FSpotTagsTable tags_table;
277 private Gee.HashMap < int64?, FSpotImportableTag > tags_map;
278
279 public FSpotTagsCache (DataImports.FSpot.Db.FSpotTagsTable tags_table) throws DatabaseError {
280 this.tags_table = tags_table;
281 tags_map = new Gee.HashMap < int64?, FSpotImportableTag > ();
282 }
283
284 public FSpotImportableTag get_tag (DataImports.FSpot.Db.FSpotTagRow tag_row) throws DatabaseError {
285 FSpotImportableTag? tag = tags_map.get (tag_row.tag_id);
286 if (tag != null) {
287 return tag;
288 } else {
289 FSpotImportableTag? parent_tag = get_tag_from_id (tag_row.category_id);
290 FSpotImportableTag new_tag = new FSpotImportableTag (tag_row, parent_tag);
291 tags_map[tag_row.tag_id] = new_tag;
292 return new_tag;
293 }
294 }
295
296 private FSpotImportableTag? get_tag_from_id (int64 tag_id) throws DatabaseError {
297 // check whether the tag ID is valid first, otherwise return null
298 if (tag_id < 1)
299 return null;
300 FSpotImportableTag? tag = tags_map.get (tag_id);
301 if (tag != null)
302 return tag;
303 DataImports.FSpot.Db.FSpotTagRow? tag_row = tags_table.get_by_id (tag_id);
304 if (tag_row != null) {
305 FSpotImportableTag? parent_tag = get_tag_from_id (tag_row.category_id);
306 FSpotImportableTag new_tag = new FSpotImportableTag (tag_row, parent_tag);
307 tags_map[tag_id] = new_tag;
308 return new_tag;
309 }
310 return null;
311 }
312}
313
314public class FSpotDataImporter : Spit.DataImports.DataImporter, GLib.Object {
315
316 private weak Spit.DataImports.PluginHost host = null;
317 private weak Spit.DataImports.Service service = null;
318 private bool running = false;
319
320 public FSpotDataImporter (Spit.DataImports.Service service,
321 Spit.DataImports.PluginHost host) {
322 debug ("FSpotDataImporter instantiated.");
323 this.service = service;
324 this.host = host;
325 }
326
327 private bool is_running () {
328 return running;
329 }
330
331 public Spit.DataImports.Service get_service () {
332 return service;
333 }
334
335 public void start () {
336 if (is_running ())
337 return;
338
339 debug ("FSpotDataImporter: starting interaction.");
340
341 running = true;
342
343 do_discover_importable_libraries ();
344 }
345
346 public void stop () {
347 debug ("FSpotDataImporter: stopping interaction.");
348
349 running = false;
350 }
351
352 // Actions and event implementation
353
354 /**
355 * Action that discovers importable libraries based on standard locations.
356 */
357 private void do_discover_importable_libraries () {
358 Spit.DataImports.ImportableLibrary[] discovered_libraries =
359 new Spit.DataImports.ImportableLibrary[0];
360
361 File[] db_files = {
362 // where the DB is in Ubuntu Lucid
363 File.new_for_path (Environment.get_user_config_dir ()).
364 get_child ("f-spot").get_child ("photos.db"),
365 // where it seems to be in Ubuntu Jaunty
366 File.new_for_path (Environment.get_home_dir ()).get_child (".gnome2").
367 get_child ("f-spot").get_child ("photos.db"),
368 // where it should really be if it followed the XDG spec
369 File.new_for_path (Environment.get_user_data_dir ()).
370 get_child ("f-spot").get_child ("photos.db")
371 };
372
373 foreach (File db_file in db_files) {
374 if (db_file.query_exists (null)) {
375 discovered_libraries += new FSpotImportableLibrary (db_file);
376 message ("Discovered importable library: %s", db_file.get_path ());
377 }
378 }
379
380 host.install_library_selection_pane (
381 (discovered_libraries.length > 0 ? SERVICE_WELCOME_MESSAGE : SERVICE_WELCOME_MESSAGE_FILE_ONLY),
382 discovered_libraries,
383 FILE_IMPORT_LABEL
384 );
385 }
386
387 public void on_library_selected (Spit.DataImports.ImportableLibrary library) {
388 on_file_selected (((FSpotImportableLibrary)library).get_db_file ());
389 }
390
391 public void on_file_selected (File file) {
392 DataImports.FSpot.Db.FSpotDatabase database;
393 FSpotTagsCache tags_cache;
394 Gee.ArrayList<DataImports.FSpot.Db.FSpotPhotoRow> all_photos;
395 double progress_delta_per_photo = 1.0;
396 double progress_plugin_to_host_ratio = 0.5;
397 double current_progress = 0.0;
398 try {
399 database = new DataImports.FSpot.Db.FSpotDatabase (file);
400 } catch (DatabaseError e) {
401 debug ("FSpotDataImporter: Can't open database file: %s".printf (e.message));
402 host.post_error_message (ERROR_CANT_OPEN_DB_FILE);
403 return;
404 } catch (Spit.DataImports.DataImportError e) {
405 debug ("FSpotDataImporter: Unsupported F-Spot database version: %s".printf (e.message));
406 host.post_error_message (ERROR_UNSUPPORTED_DB_VERSION);
407 return;
408 }
409 try {
410 tags_cache = new FSpotTagsCache (database.tags_table);
411 } catch (DatabaseError e) {
412 debug ("FSpotDataImporter: Can't read tags table: %s".printf (e.message));
413 host.post_error_message (ERROR_CANT_READ_TAGS_TABLE);
414 return;
415 }
416 host.install_import_progress_pane (_ ("Preparing to import"));
417 try {
418 all_photos = database.photos_table.get_all ();
419 } catch (DatabaseError e) {
420 debug ("FSpotDataImporter: Can't read photos table: %s".printf (e.message));
421 host.post_error_message (ERROR_CANT_READ_PHOTOS_TABLE);
422 return;
423 }
424 if (all_photos.size > 0)
425 progress_delta_per_photo = 1.0 / all_photos.size;
426 foreach (DataImports.FSpot.Db.FSpotPhotoRow photo_row in all_photos) {
427 bool hidden = false;
428 bool favorite = false;
429 FSpotImportableTag[] tags = new FSpotImportableTag[0];
430 FSpotImportableEvent? event = null;
431 DataImports.FSpot.Db.FSpotRollRow? roll_row = null;
432
433 // TODO: We do not convert F-Spot events to Shotwell events because F-Spot's events
434 // are essentially tags. We would need to detect if the tag is an event (use
435 // is_tag_event) and then assign the event to the photo ... since a photo can be
436 // in multiple F-Spot events, we would need to pick one, and since their tags
437 // are hierarchical, we would need to pick a name (probably the leaf)
438 try {
439 foreach (
440 DataImports.FSpot.Db.FSpotTagRow tag_row in
441 database.tags_table.get_by_photo_id (photo_row.photo_id)
442 ) {
443 FSpotImportableTag tag = tags_cache.get_tag (tag_row);
444 if (is_tag_hidden (tag, database.hidden_tag_id))
445 hidden = true;
446 else if (is_tag_favorite (tag))
447 favorite = true;
448 else
449 tags += tag;
450 }
451 } catch (DatabaseError e) {
452 // log the error and leave the tag list empty
453 message ("Failed to retrieve tags for photo ID %ld: %s", (long) photo_row.photo_id,
454 e.message);
455 }
456
457 try {
458 roll_row = database.rolls_table.get_by_id (photo_row.roll_id);
459 } catch (DatabaseError e) {
460 // log the error and leave the roll row null
461 message ("Failed to retrieve roll for photo ID %ld: %s", (long) photo_row.photo_id,
462 e.message);
463 }
464
465 Spit.DataImports.ImportableMediaItem[] importable_items = new Spit.DataImports.ImportableMediaItem[0];
466 try {
467 Gee.ArrayList<DataImports.FSpot.Db.FSpotPhotoVersionRow> photo_versions =
468 database.photo_versions_table.get_by_photo_id (photo_row.photo_id);
469 bool photo_versions_added = false; // set to true if at least one version was added
470 bool photo_versions_skipped = false; // set to true if at least one version was skipped due to missing file details
471 foreach (DataImports.FSpot.Db.FSpotPhotoVersionRow photo_version_row in photo_versions) {
472 if (photo_version_row.base_path != null && photo_version_row.filename != null) {
473 importable_items += new FSpotImportableItem (
474 photo_row, photo_version_row, roll_row, tags, event, hidden, favorite
475 );
476 photo_versions_added = true;
477 } else {
478 photo_versions_skipped = true;
479 }
480 }
481
482 // Older versions of F-Spot (0.4.3.1 at least, perhaps later) did not maintain photo_versions,
483 // this handles that case
484 // It also handles the case when we had to skip any photo version due to missing
485 // file details
486 if (photo_versions_skipped || !photo_versions_added) {
487 if (photo_row.base_path != null && photo_row.filename != null) {
488 importable_items += new FSpotImportableItem (
489 photo_row, null, roll_row, tags, event, hidden, favorite
490 );
491 }
492 }
493 } catch (DatabaseError e) {
494 // if we can't load the different versions, do the best we can
495 // and create one photo from the photo row that was found earlier
496 message ("Failed to retrieve versions for photo ID %ld: %s", (long) photo_row.photo_id,
497 e.message);
498 if (photo_row.base_path != null && photo_row.filename != null) {
499 importable_items += new FSpotImportableItem (
500 photo_row, null, roll_row, tags, event, hidden, favorite
501 );
502 }
503 }
504 // If the importer is still running, import the items and loop,
505 // otherwise break the loop
506 if (running) {
507 host.prepare_media_items_for_import (
508 importable_items,
509 current_progress + (progress_delta_per_photo * progress_plugin_to_host_ratio),
510 progress_delta_per_photo * (1 - progress_plugin_to_host_ratio),
511 null
512 );
513 current_progress += progress_delta_per_photo;
514 host.update_import_progress_pane (current_progress);
515 } else {
516 break;
517 }
518 }
519 host.finalize_import (on_imported_items_count);
520 }
521
522 public void on_imported_items_count (int imported_items_count) {
523 host.install_static_message_pane (
524 MESSAGE_FINAL_SCREEN.printf (imported_items_count),
525 Spit.DataImports.PluginHost.ButtonMode.CLOSE
526 );
527 }
528
529 private bool is_tag_event (FSpotImportableTag tag) {
530 bool result = (DataImports.FSpot.Db.FSpotTagsTable.STOCK_ICON_EVENTS == tag.get_stock_icon ());
531 if (!result) {
532 FSpotImportableTag? parent = tag.get_fspot_parent ();
533 if (parent == null)
534 result = false;
535 else
536 result = is_tag_event (parent);
537 }
538 return result;
539 }
540
541 private bool is_tag_hidden (FSpotImportableTag tag, int64 hidden_tag_id) {
542 bool result = (hidden_tag_id == tag.get_id ());
543 if (!result) {
544 FSpotImportableTag? parent = tag.get_fspot_parent ();
545 if (parent == null)
546 result = false;
547 else
548 result = is_tag_hidden (parent, hidden_tag_id);
549 }
550 return result;
551 }
552
553 private bool is_tag_favorite (FSpotImportableTag tag) {
554 bool result = (DataImports.FSpot.Db.FSpotTagsTable.STOCK_ICON_FAV == tag.get_stock_icon ());
555 if (!result) {
556 FSpotImportableTag? parent = tag.get_fspot_parent ();
557 if (parent == null)
558 result = false;
559 else
560 result = is_tag_favorite (parent);
561 }
562 return result;
563 }
564}
565
566} // namespace
567
5680
=== removed file 'plugins/shotwell-data-imports/FSpotMetaTable.vala'
--- plugins/shotwell-data-imports/FSpotMetaTable.vala 2014-08-08 21:13:09 +0000
+++ plugins/shotwell-data-imports/FSpotMetaTable.vala 1970-01-01 00:00:00 +0000
@@ -1,113 +0,0 @@
1/* Copyright 2011-2013 Yorba Foundation
2 *
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.
5 */
6
7namespace DataImports.FSpot.Db {
8
9/**
10 * The value object for the "meta" table, representing a single database row.
11 */
12public class FSpotMetaRow : Object {
13 // ignore the ID
14 public string name;
15 public string data;
16}
17
18/**
19 * This class represents the F-Spot meta table, which stores some essential
20 * meta-data for the whole database. It is implemented as a simple dictionary
21 * where each row in the table is a key/value pair.
22 *
23 * The meta table implementation is the only one that throws a database error
24 * if something goes wrong because:
25 * * it is essential to read the content of that table in order to identify
26 * the version of the database and select the correct behavior,
27 * * this table is read at the very beginning of the process so any failure
28 * will occur immediately,
29 * * failing to read this table means that there is no point in reading the
30 * attempting to read the rest of the database so we might as well abort.
31 */
32public class FSpotMetaTable : FSpotDatabaseTable<FSpotMetaRow> {
33
34 public FSpotMetaTable (Sqlite.Database db) {
35 base (db);
36 set_behavior (FSpotMetaBehavior.get_instance ());
37 }
38
39 public string? get_data (string name) throws DatabaseError {
40 string[] columns = behavior.list_columns ();
41 string column_list = string.joinv (", ", columns);
42 string sql = "SELECT %s FROM %s WHERE name=?".printf (column_list, table_name);
43 Sqlite.Statement stmt;
44 int res = fspot_db.prepare_v2 (sql, -1, out stmt);
45 if (res != Sqlite.OK)
46 throw_error ("Statement failed: %s".printf (sql), res);
47
48 res = stmt.bind_text (1, name);
49 if (res != Sqlite.OK)
50 throw_error ("Bind failed for name %s".printf (name), res);
51
52 res = stmt.step ();
53 if (res != Sqlite.ROW) {
54 if (res != Sqlite.DONE)
55 throw_error ("FSpotMetaTable.get_data", res);
56
57 return null;
58 }
59
60 FSpotMetaRow row;
61 behavior.build_row (stmt, out row);
62 return row.data;
63 }
64
65 public string? get_app_version () throws DatabaseError {
66 return get_data ("F-Spot Version");
67 }
68
69 public string? get_db_version () throws DatabaseError {
70 return get_data ("F-Spot Database Version");
71 }
72
73 public int64 get_hidden_tag_id () throws DatabaseError {
74 string id_str = get_data ("Hidden Tag Id");
75 if (id_str != null) {
76 return int64.parse (id_str);
77 } else {
78 return -1;
79 }
80 }
81}
82
83public class FSpotMetaBehavior : FSpotTableBehavior<FSpotMetaRow>, Object {
84 public static const string TABLE_NAME = "Meta";
85
86 private static FSpotMetaBehavior instance;
87
88 private FSpotMetaBehavior () {
89 }
90
91 public static FSpotMetaBehavior get_instance () {
92 if (instance == null)
93 instance = new FSpotMetaBehavior ();
94 return instance;
95 }
96
97 public string get_table_name () {
98 return TABLE_NAME;
99 }
100
101 public string[] list_columns () {
102 return { "name", "data" };
103 }
104
105 public void build_row (Sqlite.Statement stmt, out FSpotMetaRow row, int offset = 0) {
106 row = new FSpotMetaRow ();
107 row.name = stmt.column_text (offset + 0);
108 row.data = stmt.column_text (offset + 1);
109 }
110}
111
112}
113
1140
=== removed file 'plugins/shotwell-data-imports/FSpotPhotoTagsTable.vala'
--- plugins/shotwell-data-imports/FSpotPhotoTagsTable.vala 2014-08-08 21:13:09 +0000
+++ plugins/shotwell-data-imports/FSpotPhotoTagsTable.vala 1970-01-01 00:00:00 +0000
@@ -1,57 +0,0 @@
1/* Copyright 2011-2013 Yorba Foundation
2 *
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.
5 */
6
7namespace DataImports.FSpot.Db {
8
9/**
10 * The value object for the "photo_tags" table, representing a single database row.
11 */
12public class FSpotPhotoTagRow : Object {
13 public int64 photo_id;
14 public int64 tag_id;
15}
16
17/**
18 * This class represents the F-Spot photo_tags table.
19 */
20public class FSpotPhotoTagsTable : FSpotDatabaseTable<FSpotPhotoTagRow> {
21 public static const string TABLE_NAME = "Photo_Tags";
22
23 public FSpotPhotoTagsTable (Sqlite.Database db, FSpotDatabaseBehavior db_behavior) {
24 base (db);
25 set_behavior (db_behavior.get_photo_tags_behavior ());
26 }
27}
28
29public class FSpotPhotoTagsV0Behavior : FSpotTableBehavior<FSpotPhotoTagRow>, Object {
30 private static FSpotPhotoTagsV0Behavior instance;
31
32 private FSpotPhotoTagsV0Behavior () {
33 }
34
35 public static FSpotPhotoTagsV0Behavior get_instance () {
36 if (instance == null)
37 instance = new FSpotPhotoTagsV0Behavior ();
38 return instance;
39 }
40
41 public string get_table_name () {
42 return FSpotPhotoTagsTable.TABLE_NAME;
43 }
44
45 public string[] list_columns () {
46 return { "photo_id", "tag_id" };
47 }
48
49 public void build_row (Sqlite.Statement stmt, out FSpotPhotoTagRow row, int offset = 0) {
50 row = new FSpotPhotoTagRow ();
51 row.photo_id = stmt.column_int64 (offset + 0);
52 row.tag_id = stmt.column_int64 (offset + 1);
53 }
54}
55
56}
57
580
=== removed file 'plugins/shotwell-data-imports/FSpotPhotoVersionsTable.vala'
--- plugins/shotwell-data-imports/FSpotPhotoVersionsTable.vala 2014-08-08 21:13:09 +0000
+++ plugins/shotwell-data-imports/FSpotPhotoVersionsTable.vala 1970-01-01 00:00:00 +0000
@@ -1,275 +0,0 @@
1/* Copyright 2011-2013 Yorba Foundation
2 *
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.
5 */
6
7namespace DataImports.FSpot.Db {
8
9/**
10 * The value object for the "photo_versions" table, representing a single database row.
11 */
12public class FSpotPhotoVersionRow : Object {
13 public int64 photo_id;
14 public int64 version_id;
15 public string name;
16 public File? base_path;
17 public string? filename;
18 public string md5_sum;
19 public bool is_protected;
20}
21
22/**
23 * This class represents the F-Spot photo_versions table.
24 */
25public class FSpotPhotoVersionsTable : FSpotDatabaseTable<FSpotPhotoVersionRow> {
26 public static const string TABLE_NAME = "Photo_versions";
27
28 public FSpotPhotoVersionsTable (Sqlite.Database db, FSpotDatabaseBehavior db_behavior) {
29 base (db);
30 set_behavior (db_behavior.get_photo_versions_behavior ());
31 }
32
33 public Gee.ArrayList<FSpotPhotoVersionRow> get_by_photo_id (int64 photo_id) throws DatabaseError {
34 Gee.ArrayList<FSpotPhotoVersionRow> rows = new Gee.ArrayList < FSpotPhotoVersionRow?> ();
35
36 Sqlite.Statement stmt;
37
38 string column_list = get_joined_column_list ();
39 string sql = "SELECT %s FROM %s WHERE photo_id=?".printf (
40 column_list, table_name
41 );
42
43 int res = fspot_db.prepare_v2 (sql, -1, out stmt);
44 if (res != Sqlite.OK)
45 throw_error ("Statement failed: %s".printf (sql), res);
46
47 res = stmt.bind_int64 (1, photo_id);
48 if (res != Sqlite.OK)
49 throw_error ("Bind failed for photo_id", res);
50
51 res = stmt.step ();
52 while (res == Sqlite.ROW) {
53 FSpotPhotoVersionRow row;
54 behavior.build_row (stmt, out row);
55 rows.add (row);
56 res = stmt.step ();
57 }
58
59 return rows;
60 }
61}
62
63// Photo_versions table behavior for v0-8
64// Note: there is a change in the URI format in version 8 but the File.new_for_uri
65// constructor should be able to deal with the variation, so the v8 behavior should
66// be handled in a way identical to v0-7
67public class FSpotPhotoVersionsV0Behavior : FSpotTableBehavior<FSpotPhotoVersionRow>, Object {
68 private static FSpotPhotoVersionsV0Behavior instance;
69
70 private FSpotPhotoVersionsV0Behavior () {
71 }
72
73 public static FSpotPhotoVersionsV0Behavior get_instance () {
74 if (instance == null)
75 instance = new FSpotPhotoVersionsV0Behavior ();
76 return instance;
77 }
78
79 public string get_table_name () {
80 return FSpotPhotoVersionsTable.TABLE_NAME;
81 }
82
83 public string[] list_columns () {
84 return { "photo_id", "version_id", "name", "uri" };
85 }
86
87 public void build_row (Sqlite.Statement stmt, out FSpotPhotoVersionRow row, int offset = 0) {
88 row = new FSpotPhotoVersionRow ();
89 row.photo_id = stmt.column_int64 (offset + 0);
90 row.version_id = stmt.column_int64 (offset + 1);
91 row.name = stmt.column_text (offset + 2);
92
93 string? full_path = stmt.column_text (offset + 3);
94 if (full_path != null) {
95 File uri = File.new_for_uri (full_path);
96 row.base_path = uri.get_parent ();
97 row.filename = uri.get_basename ();
98 }
99
100 row.md5_sum = "";
101 row.is_protected = false;
102 }
103}
104
105// Photo_versions table behavior for v9-15
106// add protected field
107public class FSpotPhotoVersionsV9Behavior : FSpotTableBehavior<FSpotPhotoVersionRow>, Object {
108 private static FSpotPhotoVersionsV9Behavior instance;
109
110 private FSpotPhotoVersionsV9Behavior () {
111 }
112
113 public static FSpotPhotoVersionsV9Behavior get_instance () {
114 if (instance == null)
115 instance = new FSpotPhotoVersionsV9Behavior ();
116 return instance;
117 }
118
119 public string get_table_name () {
120 return FSpotPhotoVersionsTable.TABLE_NAME;
121 }
122
123 public string[] list_columns () {
124 return { "photo_id", "version_id", "name", "uri",
125 "protected"
126 };
127 }
128
129 public void build_row (Sqlite.Statement stmt, out FSpotPhotoVersionRow row, int offset = 0) {
130 row = new FSpotPhotoVersionRow ();
131 row.photo_id = stmt.column_int64 (offset + 0);
132 row.version_id = stmt.column_int64 (offset + 1);
133 row.name = stmt.column_text (offset + 2);
134
135 string? full_path = stmt.column_text (offset + 3);
136 if (full_path != null) {
137 File uri = File.new_for_uri (full_path);
138 row.base_path = uri.get_parent ();
139 row.filename = uri.get_basename ();
140 }
141
142 row.md5_sum = "";
143 row.is_protected = (stmt.column_int (offset + 4) > 0);
144 }
145}
146
147// Photo_versions table behavior for v16
148// add md5_sum in photo_versions
149public class FSpotPhotoVersionsV16Behavior : FSpotTableBehavior<FSpotPhotoVersionRow>, Object {
150 private static FSpotPhotoVersionsV16Behavior instance;
151
152 private FSpotPhotoVersionsV16Behavior () {
153 }
154
155 public static FSpotPhotoVersionsV16Behavior get_instance () {
156 if (instance == null)
157 instance = new FSpotPhotoVersionsV16Behavior ();
158 return instance;
159 }
160
161 public string get_table_name () {
162 return FSpotPhotoVersionsTable.TABLE_NAME;
163 }
164
165 public string[] list_columns () {
166 return { "photo_id", "version_id", "name", "uri",
167 "md5_sum", "protected"
168 };
169 }
170
171 public void build_row (Sqlite.Statement stmt, out FSpotPhotoVersionRow row, int offset = 0) {
172 row = new FSpotPhotoVersionRow ();
173 row.photo_id = stmt.column_int64 (offset + 0);
174 row.version_id = stmt.column_int64 (offset + 1);
175 row.name = stmt.column_text (offset + 2);
176
177 string? full_path = stmt.column_text (offset + 3);
178 if (full_path != null) {
179 File uri = File.new_for_uri (full_path);
180 row.base_path = uri.get_parent ();
181 row.filename = uri.get_basename ();
182 }
183
184 row.md5_sum = stmt.column_text (offset + 4);
185 row.is_protected = (stmt.column_int (offset + 5) > 0);
186 }
187}
188
189// Photo_versions table behavior for v17
190// v17 split the URI into base_uri and filename (reverting back to the original
191// design introduced in v0, albeit with a URI rather than a file system path)
192public class FSpotPhotoVersionsV17Behavior : FSpotTableBehavior<FSpotPhotoVersionRow>, Object {
193 private static FSpotPhotoVersionsV17Behavior instance;
194
195 private FSpotPhotoVersionsV17Behavior () {
196 }
197
198 public static FSpotPhotoVersionsV17Behavior get_instance () {
199 if (instance == null)
200 instance = new FSpotPhotoVersionsV17Behavior ();
201 return instance;
202 }
203
204 public string get_table_name () {
205 return FSpotPhotoVersionsTable.TABLE_NAME;
206 }
207
208 public string[] list_columns () {
209 return { "photo_id", "version_id", "name", "base_uri", "filename",
210 "md5_sum", "protected"
211 };
212 }
213
214 public void build_row (Sqlite.Statement stmt, out FSpotPhotoVersionRow row, int offset = 0) {
215 row = new FSpotPhotoVersionRow ();
216 row.photo_id = stmt.column_int64 (offset + 0);
217 row.version_id = stmt.column_int64 (offset + 1);
218 row.name = stmt.column_text (offset + 2);
219
220 string? base_path = stmt.column_text (offset + 3);
221 string? filename = stmt.column_text (offset + 4);
222 if (base_path != null && filename != null) {
223 row.base_path = File.new_for_uri (base_path);
224 row.filename = filename;
225 }
226
227 row.md5_sum = stmt.column_text (offset + 5);
228 row.is_protected = (stmt.column_int (offset + 6) > 0);
229 }
230}
231
232// Photo_versions table behavior for v18
233// md5_sum renamed import_md5
234public class FSpotPhotoVersionsV18Behavior : FSpotTableBehavior<FSpotPhotoVersionRow>, Object {
235 private static FSpotPhotoVersionsV18Behavior instance;
236
237 private FSpotPhotoVersionsV18Behavior () {
238 }
239
240 public static FSpotPhotoVersionsV18Behavior get_instance () {
241 if (instance == null)
242 instance = new FSpotPhotoVersionsV18Behavior ();
243 return instance;
244 }
245
246 public string get_table_name () {
247 return FSpotPhotoVersionsTable.TABLE_NAME;
248 }
249
250 public string[] list_columns () {
251 return { "photo_id", "version_id", "name", "base_uri", "filename",
252 "import_md5", "protected"
253 };
254 }
255
256 public void build_row (Sqlite.Statement stmt, out FSpotPhotoVersionRow row, int offset = 0) {
257 row = new FSpotPhotoVersionRow ();
258 row.photo_id = stmt.column_int64 (offset + 0);
259 row.version_id = stmt.column_int64 (offset + 1);
260 row.name = stmt.column_text (offset + 2);
261
262 string? base_path = stmt.column_text (offset + 3);
263 string? filename = stmt.column_text (offset + 4);
264 if (base_path != null && filename != null) {
265 row.base_path = File.new_for_uri (base_path);
266 row.filename = filename;
267 }
268
269 row.md5_sum = stmt.column_text (offset + 5);
270 row.is_protected = (stmt.column_int (offset + 6) > 0);
271 }
272}
273
274}
275
2760
=== removed file 'plugins/shotwell-data-imports/FSpotPhotosTable.vala'
--- plugins/shotwell-data-imports/FSpotPhotosTable.vala 2014-08-08 21:13:09 +0000
+++ plugins/shotwell-data-imports/FSpotPhotosTable.vala 1970-01-01 00:00:00 +0000
@@ -1,363 +0,0 @@
1/* Copyright 2011-2013 Yorba Foundation
2 *
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.
5 */
6
7namespace DataImports.FSpot.Db {
8
9/**
10 * The value object for the "photos" table, representing a single database row.
11 */
12public class FSpotPhotoRow : Object {
13 public int64 photo_id;
14 public time_t time;
15 public File? base_path;
16 public string? filename;
17 public string description;
18 public int64 roll_id;
19 public int64 default_version_id;
20 public int rating;
21 public string md5_sum;
22}
23
24/**
25 * This class represents the F-Spot photos table.
26 */
27public class FSpotPhotosTable : FSpotDatabaseTable<FSpotPhotoRow> {
28 public static const string TABLE_NAME = "Photos";
29
30 public FSpotPhotosTable (Sqlite.Database db, FSpotDatabaseBehavior db_behavior) {
31 base (db);
32 set_behavior (db_behavior.get_photos_behavior ());
33 }
34
35 public Gee.ArrayList<FSpotPhotoRow> get_all () throws DatabaseError {
36 Gee.ArrayList<FSpotPhotoRow> all = new Gee.ArrayList < FSpotPhotoRow?> ();
37
38 Sqlite.Statement stmt;
39 int res = select_all (out stmt);
40 while (res == Sqlite.ROW) {
41 FSpotPhotoRow row;
42 behavior.build_row (stmt, out row);
43 all.add (row);
44 res = stmt.step ();
45 }
46
47 return all;
48 }
49}
50
51// Photos table behavior for v0-4
52// The original table format
53public class FSpotPhotosV0Behavior : FSpotTableBehavior<FSpotPhotoRow>, Object {
54 private static FSpotPhotosV0Behavior instance;
55
56 private FSpotPhotosV0Behavior () {
57 }
58
59 public static FSpotPhotosV0Behavior get_instance () {
60 if (instance == null)
61 instance = new FSpotPhotosV0Behavior ();
62 return instance;
63 }
64
65 public string get_table_name () {
66 return FSpotPhotosTable.TABLE_NAME;
67 }
68
69 public string[] list_columns () {
70 return { "id", "time", "directory_path", "name", "description",
71 "default_version_id"
72 };
73 }
74
75 public void build_row (Sqlite.Statement stmt, out FSpotPhotoRow row, int offset = 0) {
76 row = new FSpotPhotoRow ();
77 row.photo_id = stmt.column_int64 (offset + 0);
78 row.time = (time_t) stmt.column_int64 (offset + 1);
79
80 string? base_path = stmt.column_text (offset + 2);
81 string? filename = stmt.column_text (offset + 3);
82 if (base_path != null && filename != null) {
83 row.base_path = File.new_for_uri (base_path);
84 row.filename = filename;
85 }
86
87 row.description = stmt.column_text (offset + 4);
88 row.roll_id = INVALID_ID;
89 row.default_version_id = stmt.column_int64 (offset + 5);
90 row.rating = 0;
91 row.md5_sum = "";
92 }
93}
94
95// Photos table behavior for v5-6
96// v5 introduced a roll_id to reference the imported roll (rolls were a new
97// table migrated from imports)
98public class FSpotPhotosV5Behavior : FSpotTableBehavior<FSpotPhotoRow>, Object {
99 private static FSpotPhotosV5Behavior instance;
100
101 private FSpotPhotosV5Behavior () {
102 }
103
104 public static FSpotPhotosV5Behavior get_instance () {
105 if (instance == null)
106 instance = new FSpotPhotosV5Behavior ();
107 return instance;
108 }
109
110 public string get_table_name () {
111 return FSpotPhotosTable.TABLE_NAME;
112 }
113
114 public string[] list_columns () {
115 return { "id", "time", "directory_path", "name", "description", "roll_id",
116 "default_version_id"
117 };
118 }
119
120 public void build_row (Sqlite.Statement stmt, out FSpotPhotoRow row, int offset = 0) {
121 row = new FSpotPhotoRow ();
122 row.photo_id = stmt.column_int64 (offset + 0);
123 row.time = (time_t) stmt.column_int64 (offset + 1);
124
125 string? base_path = stmt.column_text (offset + 2);
126 string? filename = stmt.column_text (offset + 3);
127 if (base_path != null && filename != null) {
128 row.base_path = File.new_for_uri (base_path);
129 row.filename = filename;
130 }
131
132 row.description = stmt.column_text (offset + 4);
133 row.roll_id = stmt.column_int64 (offset + 5);
134 row.default_version_id = stmt.column_int64 (offset + 6);
135 row.rating = 0;
136 row.md5_sum = "";
137 }
138}
139
140// Photos table behavior for v7-10
141// v7 merged directory_path and name into a single URI value with a file://
142// prefix; presumaly this is meant to be able to handle remote files using a
143// different URI prefix such as remote files
144public class FSpotPhotosV7Behavior : FSpotTableBehavior<FSpotPhotoRow>, Object {
145 private static FSpotPhotosV7Behavior instance;
146
147 private FSpotPhotosV7Behavior () {
148 }
149
150 public static FSpotPhotosV7Behavior get_instance () {
151 if (instance == null)
152 instance = new FSpotPhotosV7Behavior ();
153 return instance;
154 }
155
156 public string get_table_name () {
157 return FSpotPhotosTable.TABLE_NAME;
158 }
159
160 public string[] list_columns () {
161 return { "id", "time", "uri", "description", "roll_id",
162 "default_version_id"
163 };
164 }
165
166 public void build_row (Sqlite.Statement stmt, out FSpotPhotoRow row, int offset = 0) {
167 row = new FSpotPhotoRow ();
168 row.photo_id = stmt.column_int64 (offset + 0);
169 row.time = (time_t) stmt.column_int64 (offset + 1);
170
171 string? full_path = stmt.column_text (offset + 2);
172 if (full_path != null) {
173 File uri = File.new_for_uri (full_path);
174 row.base_path = uri.get_parent ();
175 row.filename = uri.get_basename ();
176 }
177
178 row.description = stmt.column_text (offset + 3);
179 row.roll_id = stmt.column_int64 (offset + 4);
180 row.default_version_id = stmt.column_int64 (offset + 5);
181 row.rating = 0;
182 row.md5_sum = "";
183 }
184}
185
186// Photos table behavior for v11-15
187// v11 introduced the concept of rating so add this to the list of fields
188public class FSpotPhotosV11Behavior : FSpotTableBehavior<FSpotPhotoRow>, Object {
189 private static FSpotPhotosV11Behavior instance;
190
191 private FSpotPhotosV11Behavior () {
192 }
193
194 public static FSpotPhotosV11Behavior get_instance () {
195 if (instance == null)
196 instance = new FSpotPhotosV11Behavior ();
197 return instance;
198 }
199
200 public string get_table_name () {
201 return FSpotPhotosTable.TABLE_NAME;
202 }
203
204 public string[] list_columns () {
205 return { "id", "time", "uri", "description", "roll_id",
206 "default_version_id", "rating"
207 };
208 }
209
210 public void build_row (Sqlite.Statement stmt, out FSpotPhotoRow row, int offset = 0) {
211 row = new FSpotPhotoRow ();
212 row.photo_id = stmt.column_int64 (offset + 0);
213 row.time = (time_t) stmt.column_int64 (offset + 1);
214
215 string? full_path = stmt.column_text (offset + 2);
216 if (full_path != null) {
217 File uri = File.new_for_uri (full_path);
218 row.base_path = uri.get_parent ();
219 row.filename = uri.get_basename ();
220 }
221
222 row.description = stmt.column_text (offset + 3);
223 row.roll_id = stmt.column_int64 (offset + 4);
224 row.default_version_id = stmt.column_int64 (offset + 5);
225 row.rating = stmt.column_int (offset + 6);
226 row.md5_sum = "";
227 }
228}
229
230// Photos table behavior for v16
231// v16 introduced the MD5 sum so add this to the list of fields
232public class FSpotPhotosV16Behavior : FSpotTableBehavior<FSpotPhotoRow>, Object {
233 private static FSpotPhotosV16Behavior instance;
234
235 private FSpotPhotosV16Behavior () {
236 }
237
238 public static FSpotPhotosV16Behavior get_instance () {
239 if (instance == null)
240 instance = new FSpotPhotosV16Behavior ();
241 return instance;
242 }
243
244 public string get_table_name () {
245 return FSpotPhotosTable.TABLE_NAME;
246 }
247
248 public string[] list_columns () {
249 return { "id", "time", "uri", "description", "roll_id",
250 "default_version_id", "rating", "md5_sum"
251 };
252 }
253
254 public void build_row (Sqlite.Statement stmt, out FSpotPhotoRow row, int offset = 0) {
255 row = new FSpotPhotoRow ();
256 row.photo_id = stmt.column_int64 (offset + 0);
257 row.time = (time_t) stmt.column_int64 (offset + 1);
258
259 string? full_path = stmt.column_text (offset + 2);
260 if (full_path != null) {
261 File uri = File.new_for_uri (full_path);
262 row.base_path = uri.get_parent ();
263 row.filename = uri.get_basename ();
264 }
265
266 row.description = stmt.column_text (offset + 3);
267 row.roll_id = stmt.column_int64 (offset + 4);
268 row.default_version_id = stmt.column_int64 (offset + 5);
269 row.rating = stmt.column_int (offset + 6);
270 row.md5_sum = stmt.column_text (offset + 7);
271 }
272}
273
274// Photos table behavior for v17
275// v17 split the URI into base_uri and filename (reverting back to the original
276// design introduced in v0, albeit with a URI rather than a file system path)
277public class FSpotPhotosV17Behavior : FSpotTableBehavior<FSpotPhotoRow>, Object {
278 private static FSpotPhotosV17Behavior instance;
279
280 private FSpotPhotosV17Behavior () {
281 }
282
283 public static FSpotPhotosV17Behavior get_instance () {
284 if (instance == null)
285 instance = new FSpotPhotosV17Behavior ();
286 return instance;
287 }
288
289 public string get_table_name () {
290 return FSpotPhotosTable.TABLE_NAME;
291 }
292
293 public string[] list_columns () {
294 return { "id", "time", "base_uri", "filename", "description", "roll_id",
295 "default_version_id", "rating", "md5_sum"
296 };
297 }
298
299 public void build_row (Sqlite.Statement stmt, out FSpotPhotoRow row, int offset = 0) {
300 row = new FSpotPhotoRow ();
301 row.photo_id = stmt.column_int64 (offset + 0);
302 row.time = (time_t) stmt.column_int64 (offset + 1);
303
304 string? base_path = stmt.column_text (offset + 2);
305 string? filename = stmt.column_text (offset + 3);
306 if (base_path != null && filename != null) {
307 row.base_path = File.new_for_uri (base_path);
308 row.filename = filename;
309 }
310
311 row.description = stmt.column_text (offset + 4);
312 row.roll_id = stmt.column_int64 (offset + 5);
313 row.default_version_id = stmt.column_int64 (offset + 6);
314 row.rating = stmt.column_int (offset + 7);
315 row.md5_sum = stmt.column_text (offset + 8);
316 }
317}
318
319// v18: no more MD5 hash in the photos table: moved to photo_versions table
320public class FSpotPhotosV18Behavior : FSpotTableBehavior<FSpotPhotoRow>, Object {
321 private static FSpotPhotosV18Behavior instance;
322
323 private FSpotPhotosV18Behavior () {
324 }
325
326 public static FSpotPhotosV18Behavior get_instance () {
327 if (instance == null)
328 instance = new FSpotPhotosV18Behavior ();
329 return instance;
330 }
331
332 public string get_table_name () {
333 return FSpotPhotosTable.TABLE_NAME;
334 }
335
336 public string[] list_columns () {
337 return { "id", "time", "base_uri", "filename", "description", "roll_id",
338 "default_version_id", "rating"
339 };
340 }
341
342 public void build_row (Sqlite.Statement stmt, out FSpotPhotoRow row, int offset = 0) {
343 row = new FSpotPhotoRow ();
344 row.photo_id = stmt.column_int64 (offset + 0);
345 row.time = (time_t) stmt.column_int64 (offset + 1);
346
347 string? base_path = stmt.column_text (offset + 2);
348 string? filename = stmt.column_text (offset + 3);
349 if (base_path != null && filename != null) {
350 row.base_path = File.new_for_uri (base_path);
351 row.filename = filename;
352 }
353
354 row.description = stmt.column_text (offset + 4);
355 row.roll_id = stmt.column_int64 (offset + 5);
356 row.default_version_id = stmt.column_int64 (offset + 6);
357 row.rating = stmt.column_int (offset + 7);
358 row.md5_sum = "";
359 }
360}
361
362}
363
3640
=== removed file 'plugins/shotwell-data-imports/FSpotRollsTable.vala'
--- plugins/shotwell-data-imports/FSpotRollsTable.vala 2014-08-08 21:13:09 +0000
+++ plugins/shotwell-data-imports/FSpotRollsTable.vala 1970-01-01 00:00:00 +0000
@@ -1,111 +0,0 @@
1/* Copyright 2011-2013 Yorba Foundation
2 *
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.
5 */
6
7namespace DataImports.FSpot.Db {
8
9/**
10 * The value object for the "rolls" table, representing a single database row.
11 */
12public class FSpotRollRow : Object {
13 public int64 id;
14 public time_t time;
15}
16
17/**
18 * This class represents the F-Spot rolls table.
19 */
20public class FSpotRollsTable : FSpotDatabaseTable<FSpotRollRow> {
21 public static const string TABLE_NAME = "Rolls";
22 public static const string TABLE_NAME_PRE_V5 = "Imports";
23
24 public FSpotRollsTable (Sqlite.Database db, FSpotDatabaseBehavior db_behavior) {
25 base (db);
26 set_behavior (db_behavior.get_rolls_behavior ());
27 }
28
29 public FSpotRollRow? get_by_id (int64 roll_id) throws DatabaseError {
30 Sqlite.Statement stmt;
31 FSpotRollRow? row = null;
32 string column_list = get_joined_column_list ();
33 string sql = "SELECT %s FROM %s WHERE id=?".printf (column_list, table_name);
34
35 int res = fspot_db.prepare_v2 (sql, -1, out stmt);
36 if (res != Sqlite.OK)
37 throw_error ("Statement failed: %s".printf (sql), res);
38
39 res = stmt.bind_int64 (1, roll_id);
40 if (res != Sqlite.OK)
41 throw_error ("Bind failed for roll_id", res);
42
43 res = stmt.step ();
44 if (res == Sqlite.ROW)
45 behavior.build_row (stmt, out row);
46 else if (res == Sqlite.DONE)
47 message ("Could not find roll row with ID %d", (int)roll_id);
48
49 return row;
50 }
51}
52
53// Rolls table behavior for v0-4
54public class FSpotRollsV0Behavior : FSpotTableBehavior<FSpotRollRow>, Object {
55 private static FSpotRollsV0Behavior instance;
56
57 private FSpotRollsV0Behavior () {
58 }
59
60 public static FSpotRollsV0Behavior get_instance () {
61 if (instance == null)
62 instance = new FSpotRollsV0Behavior ();
63 return instance;
64 }
65
66 public string get_table_name () {
67 return FSpotRollsTable.TABLE_NAME_PRE_V5;
68 }
69
70 public string[] list_columns () {
71 return { "id", "time" };
72 }
73
74 public void build_row (Sqlite.Statement stmt, out FSpotRollRow row, int offset = 0) {
75 row = new FSpotRollRow ();
76 row.id = stmt.column_int64 (offset + 0);
77 row.time = (time_t) stmt.column_int64 (offset + 1);
78 }
79}
80
81// Rolls table behavior for v5+
82// Table name changed from "imports" to "rolls"
83public class FSpotRollsV5Behavior : FSpotTableBehavior<FSpotRollRow>, Object {
84 private static FSpotRollsV5Behavior instance;
85
86 private FSpotRollsV5Behavior () {
87 }
88
89 public static FSpotRollsV5Behavior get_instance () {
90 if (instance == null)
91 instance = new FSpotRollsV5Behavior ();
92 return instance;
93 }
94
95 public string get_table_name () {
96 return FSpotRollsTable.TABLE_NAME;
97 }
98
99 public string[] list_columns () {
100 return { "id", "time" };
101 }
102
103 public void build_row (Sqlite.Statement stmt, out FSpotRollRow row, int offset = 0) {
104 row = new FSpotRollRow ();
105 row.id = stmt.column_int64 (offset + 0);
106 row.time = (time_t) stmt.column_int64 (offset + 1);
107 }
108}
109
110}
111
1120
=== removed file 'plugins/shotwell-data-imports/FSpotTableBehavior.vala'
--- plugins/shotwell-data-imports/FSpotTableBehavior.vala 2014-08-08 21:13:09 +0000
+++ plugins/shotwell-data-imports/FSpotTableBehavior.vala 1970-01-01 00:00:00 +0000
@@ -1,28 +0,0 @@
1/* Copyright 2011-2013 Yorba Foundation
2 *
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.
5 */
6
7namespace DataImports.FSpot.Db {
8
9/**
10 * This class defines a generic table behavior. In practice, it implements
11 * the concept of a DAO (Data Access Object) in ORM terms and is responsible
12 * for transforming the data extracted from a relational statement into a
13 * lightweight value object.
14 *
15 * The type T defined in the generic is the value object type a behavior
16 * implementation is designed to handle. Value object types are designed to
17 * contain the data for a single database row.
18 */
19public interface FSpotTableBehavior<T> : Object {
20 public abstract string get_table_name ();
21
22 public abstract string[] list_columns ();
23
24 public abstract void build_row (Sqlite.Statement stmt, out T row, int offset = 0);
25}
26
27}
28
290
=== removed file 'plugins/shotwell-data-imports/FSpotTagsTable.vala'
--- plugins/shotwell-data-imports/FSpotTagsTable.vala 2014-08-08 21:13:09 +0000
+++ plugins/shotwell-data-imports/FSpotTagsTable.vala 1970-01-01 00:00:00 +0000
@@ -1,129 +0,0 @@
1/* Copyright 2011-2013 Yorba Foundation
2 *
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.
5 */
6
7namespace DataImports.FSpot.Db {
8
9/**
10 * The value object for the "tags" table, representing a single database row.
11 */
12public class FSpotTagRow : Object {
13 public int64 tag_id;
14 public string name;
15 public int64 category_id;
16 public bool is_category;
17 public int sort_priority;
18 public string stock_icon; // only store stock icons
19}
20
21/**
22 * This class represents the F-Spot tags table.
23 */
24public class FSpotTagsTable : FSpotDatabaseTable<FSpotTagRow> {
25 public static const string TABLE_NAME = "Tags";
26
27 public static const string PREFIX_STOCK_ICON = "stock_icon:";
28 public static const string STOCK_ICON_FAV = "stock_icon:emblem-favorite";
29 public static const string STOCK_ICON_PEOPLE = "stock_icon:emblem-people";
30 public static const string STOCK_ICON_PLACES = "stock_icon:emblem-places";
31 public static const string STOCK_ICON_EVENTS = "stock_icon:emblem-event";
32
33 private FSpotTableBehavior<FSpotPhotoTagRow> photo_tags_behavior;
34
35 public FSpotTagsTable (Sqlite.Database db, FSpotDatabaseBehavior db_behavior) {
36 base (db);
37 set_behavior (db_behavior.get_tags_behavior ());
38 photo_tags_behavior = db_behavior.get_photo_tags_behavior ();
39 }
40
41 public FSpotTagRow? get_by_id (int64 tag_id) throws DatabaseError {
42 Sqlite.Statement stmt;
43 FSpotTagRow? row = null;
44 string column_list = get_joined_column_list ();
45 string sql = "SELECT %s FROM %s WHERE id=?".printf (column_list, table_name);
46
47 int res = fspot_db.prepare_v2 (sql, -1, out stmt);
48 if (res != Sqlite.OK)
49 throw_error ("Statement failed: %s".printf (sql), res);
50
51 res = stmt.bind_int64 (1, tag_id);
52 assert (res == Sqlite.OK);
53
54 res = stmt.step ();
55 if (res == Sqlite.ROW)
56 behavior.build_row (stmt, out row);
57 else if (res == Sqlite.DONE)
58 message ("Could not find tag row with ID %d", (int)tag_id);
59
60 return row;
61 }
62
63 public Gee.ArrayList<FSpotTagRow> get_by_photo_id (int64 photo_id) throws DatabaseError {
64 Gee.ArrayList<FSpotTagRow> rows = new Gee.ArrayList < FSpotTagRow?> ();
65
66 Sqlite.Statement stmt;
67
68 string column_list = get_joined_column_list (true);
69 string sql = "SELECT %1$s FROM %2$s, %3$s WHERE %3$s.photo_id=? AND %3$s.tag_id = %2$s.id".printf (
70 column_list, table_name, photo_tags_behavior.get_table_name ()
71 );
72
73 int res = fspot_db.prepare_v2 (sql, -1, out stmt);
74 if (res != Sqlite.OK)
75 throw_error ("Statement failed: %s".printf (sql), res);
76
77 res = stmt.bind_int64 (1, photo_id);
78 if (res != Sqlite.OK)
79 throw_error ("Bind failed for photo_id", res);
80
81 res = stmt.step ();
82 while (res == Sqlite.ROW) {
83 FSpotTagRow row;
84 behavior.build_row (stmt, out row);
85 rows.add (row);
86 res = stmt.step ();
87 }
88
89 return rows;
90 }
91}
92
93public class FSpotTagsV0Behavior : FSpotTableBehavior<FSpotTagRow>, Object {
94 private static FSpotTagsV0Behavior instance;
95
96 private FSpotTagsV0Behavior () {
97 }
98
99 public static FSpotTagsV0Behavior get_instance () {
100 if (instance == null)
101 instance = new FSpotTagsV0Behavior ();
102 return instance;
103 }
104
105 public string get_table_name () {
106 return FSpotTagsTable.TABLE_NAME;
107 }
108
109 public string[] list_columns () {
110 return { "id", "name", "category_id", "is_category", "sort_priority", "icon" };
111 }
112
113 public void build_row (Sqlite.Statement stmt, out FSpotTagRow row, int offset = 0) {
114 row = new FSpotTagRow ();
115 row.tag_id = stmt.column_int64 (offset + 0);
116 row.name = stmt.column_text (offset + 1);
117 row.category_id = stmt.column_int64 (offset + 2);
118 row.is_category = (stmt.column_int (offset + 3) > 0);
119 row.sort_priority = stmt.column_int (offset + 4);
120 string icon_str = stmt.column_text (offset + 5);
121 if (icon_str != null && icon_str.has_prefix (FSpotTagsTable.PREFIX_STOCK_ICON))
122 row.stock_icon = icon_str;
123 else
124 row.stock_icon = "";
125 }
126}
127
128}
129
1300
=== removed file 'plugins/shotwell-data-imports/Makefile'
--- plugins/shotwell-data-imports/Makefile 2013-04-25 00:53:04 +0000
+++ plugins/shotwell-data-imports/Makefile 1970-01-01 00:00:00 +0000
@@ -1,30 +0,0 @@
1
2PLUGIN := shotwell-data-imports
3
4PLUGIN_PKGS := \
5 gtk+-3.0 \
6 gexiv2 \
7 gee-0.8 \
8 sqlite3
9
10SRC_FILES := \
11 shotwell-data-imports.vala \
12 ../common/VersionNumber.vala \
13 ../common/SqliteSupport.vala \
14 FSpotImporter.vala \
15 FSpotDatabaseBehavior.vala \
16 FSpotDatabase.vala \
17 FSpotDatabaseTable.vala \
18 FSpotTableBehavior.vala \
19 FSpotMetaTable.vala \
20 FSpotPhotosTable.vala \
21 FSpotPhotoTagsTable.vala \
22 FSpotPhotoVersionsTable.vala \
23 FSpotRollsTable.vala \
24 FSpotTagsTable.vala
25
26RC_FILES := \
27 f-spot-24.png
28
29include ../Makefile.plugin.mk
30
310
=== removed file 'plugins/shotwell-data-imports/f-spot-24.png'
32Binary files plugins/shotwell-data-imports/f-spot-24.png 2012-02-02 22:56:06 +0000 and plugins/shotwell-data-imports/f-spot-24.png 1970-01-01 00:00:00 +0000 differ1Binary files plugins/shotwell-data-imports/f-spot-24.png 2012-02-02 22:56:06 +0000 and plugins/shotwell-data-imports/f-spot-24.png 1970-01-01 00:00:00 +0000 differ
=== removed file 'plugins/shotwell-data-imports/shotwell-data-imports.vala'
--- plugins/shotwell-data-imports/shotwell-data-imports.vala 2014-08-08 21:13:09 +0000
+++ plugins/shotwell-data-imports/shotwell-data-imports.vala 1970-01-01 00:00:00 +0000
@@ -1,46 +0,0 @@
1/* Copyright 2011-2013 Yorba Foundation
2 *
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.
5 */
6
7extern const string _VERSION;
8
9// "core services" are: F-Spot
10private class ShotwellDataImportsCoreServices : Object, Spit.Module {
11 private Spit.Pluggable[] pluggables = new Spit.Pluggable[0];
12
13 // we need to get a module file handle because our pluggables have to load resources from the
14 // module file directory
15 public ShotwellDataImportsCoreServices (GLib.File module_file) {
16 GLib.File resource_directory = module_file.get_parent ();
17
18 pluggables += new FSpotService (resource_directory);
19 }
20
21 public unowned string get_module_name () {
22 return _ ("Core Data Import Services");
23 }
24
25 public unowned string get_version () {
26 return _VERSION;
27 }
28
29 public unowned string get_id () {
30 return "org.yorba.shotwell.data_imports.core_services";
31 }
32
33 public unowned Spit.Pluggable[]? get_pluggables () {
34 return pluggables;
35 }
36}
37
38// This entry point is required for all SPIT modules.
39public Spit.Module? spit_entry_point (Spit.EntryPointParams *params) {
40 params->module_spit_interface = Spit.negotiate_interfaces (params->host_min_spit_interface,
41 params->host_max_spit_interface, Spit.CURRENT_INTERFACE);
42
43 return (params->module_spit_interface != Spit.UNSUPPORTED_INTERFACE)
44 ? new ShotwellDataImportsCoreServices (params->module_file) : null;
45}
46
470
=== modified file 'src/Dialogs.vala'
--- src/Dialogs.vala 2014-08-20 20:14:47 +0000
+++ src/Dialogs.vala 2014-08-28 06:03:26 +0000
@@ -1884,12 +1884,10 @@
1884 Gtk.Box import_content;1884 Gtk.Box import_content;
1885 Gtk.Box import_action_checkbox_packer;1885 Gtk.Box import_action_checkbox_packer;
1886 Gtk.Box external_import_action_checkbox_packer;1886 Gtk.Box external_import_action_checkbox_packer;
1887 Spit.DataImports.WelcomeImportMetaHost import_meta_host;
1888 bool import_content_already_installed = false;1887 bool import_content_already_installed = false;
1889 bool ok_clicked = false;1888 bool ok_clicked = false;
18901889
1891 public WelcomeDialog (Gtk.Window owner) {1890 public WelcomeDialog (Gtk.Window owner) {
1892 import_meta_host = new Spit.DataImports.WelcomeImportMetaHost (this);
1893 bool show_system_pictures_import = is_system_pictures_import_possible ();1891 bool show_system_pictures_import = is_system_pictures_import_possible ();
1894 Gtk.Widget ok_button = add_button (_ ("_Close"), Gtk.ResponseType.OK);1892 Gtk.Widget ok_button = add_button (_ ("_Close"), Gtk.ResponseType.OK);
1895 set_title (_ ("Welcome!"));1893 set_title (_ ("Welcome!"));
@@ -1966,8 +1964,6 @@
1966 ok_button.grab_focus ();1964 ok_button.grab_focus ();
19671965
1968 install_import_content ();1966 install_import_content ();
1969
1970 import_meta_host.start ();
1971 }1967 }
19721968
1973 private void install_import_content () {1969 private void install_import_content () {
@@ -2498,4 +2494,4 @@
2498 progress.close ();2494 progress.close ();
24992495
2500 AppWindow.get_instance ().set_normal_cursor ();2496 AppWindow.get_instance ().set_normal_cursor ();
2501}
2502\ No newline at end of file2497\ No newline at end of file
2498}
25032499
=== removed directory 'src/data_imports'
=== removed file 'src/data_imports/DataImportJob.vala'
--- src/data_imports/DataImportJob.vala 2014-08-08 21:13:09 +0000
+++ src/data_imports/DataImportJob.vala 1970-01-01 00:00:00 +0000
@@ -1,177 +0,0 @@
1/* Copyright 2009-2013 Yorba Foundation
2 *
3 * This software is licensed under the GNU LGPL (version 2.1 or later).
4 * See the COPYING file in this distribution.
5 */
6
7namespace Spit.DataImports {
8
9/**
10 * A specialized import job implementation for alien databases.
11 */
12public class DataImportJob : BatchImportJob {
13 private DataImportSource import_source;
14 private File? src_file;
15 private uint64 filesize;
16 private time_t exposure_time;
17 private DataImportJob? associated = null;
18 private HierarchicalTagIndex? detected_htags = null;
19
20 public DataImportJob (DataImportSource import_source) {
21 this.import_source = import_source;
22
23 // stash everything called in prepare (), as it may/will be called from a separate thread
24 src_file = import_source.get_file ();
25 filesize = import_source.get_filesize ();
26 exposure_time = import_source.get_exposure_time ();
27 }
28
29 private HierarchicalTagIndex? build_exclusion_index (ImportableTag[] src_tags) {
30 Gee.Set<string> detected_htags = new Gee.HashSet<string> ();
31
32 foreach (ImportableTag src_tag in src_tags) {
33 string? prepped = HierarchicalTagUtilities.join_path_components (
34 Tag.prep_tag_names (
35 build_path_components (src_tag)
36 )
37 );
38
39 if (prepped != null && prepped.has_prefix (Tag.PATH_SEPARATOR_STRING)) {
40 detected_htags.add (prepped);
41
42 Gee.List<string> parents = HierarchicalTagUtilities.enumerate_parent_paths (prepped);
43 foreach (string parent in parents)
44 detected_htags.add (parent);
45 }
46 }
47
48 return (detected_htags.size > 0) ? HierarchicalTagIndex.from_paths (detected_htags) : null;
49 }
50
51 public time_t get_exposure_time () {
52 return exposure_time;
53 }
54
55 public override string get_dest_identifier () {
56 return import_source.get_filename ();
57 }
58
59 public override string get_source_identifier () {
60 return import_source.get_filename ();
61 }
62
63 public override bool is_directory () {
64 return false;
65 }
66
67 public override string get_basename () {
68 return src_file.get_basename ();
69 }
70
71 public override string get_path () {
72 return src_file.get_parent ().get_path ();
73 }
74
75 public override void set_associated (BatchImportJob associated) {
76 this.associated = associated as DataImportJob;
77 }
78
79 public override bool determine_file_size (out uint64 filesize, out File file) {
80 file = null;
81 filesize = this.filesize;
82
83 return true;
84 }
85
86 public override bool prepare (out File file_to_import, out bool copy_to_library) throws Error {
87 file_to_import = src_file;
88 copy_to_library = false;
89
90 detected_htags = build_exclusion_index (import_source.get_photo ().get_tags ());
91
92 return true;
93 }
94
95 public override bool complete (MediaSource source, BatchImportRoll import_roll) throws Error {
96 LibraryPhoto? photo = source as LibraryPhoto;
97 if (photo == null)
98 return false;
99
100 ImportableMediaItem src_photo = import_source.get_photo ();
101
102 // tags
103 if (detected_htags != null) {
104 Gee.Collection<string> paths = detected_htags.get_all_paths ();
105
106 foreach (string path in paths)
107 Tag.for_path (path);
108 }
109
110 ImportableTag[] src_tags = src_photo.get_tags ();
111 foreach (ImportableTag src_tag in src_tags) {
112 string? prepped = HierarchicalTagUtilities.join_path_components (
113 Tag.prep_tag_names (
114 build_path_components (src_tag)
115 )
116 );
117 if (prepped != null) {
118 if (HierarchicalTagUtilities.enumerate_path_components (prepped).size == 1) {
119 if (prepped.has_prefix (Tag.PATH_SEPARATOR_STRING))
120 prepped = HierarchicalTagUtilities.hierarchical_to_flat (prepped);
121 } else {
122 Gee.List<string> parents =
123 HierarchicalTagUtilities.enumerate_parent_paths (prepped);
124
125 assert (parents.size > 0);
126
127 string top_level_parent = parents.get (0);
128 string flat_top_level_parent =
129 HierarchicalTagUtilities.hierarchical_to_flat (top_level_parent);
130
131 if (Tag.global.exists (flat_top_level_parent))
132 Tag.for_path (flat_top_level_parent).promote ();
133 }
134
135 Tag.for_path (prepped).attach (photo);
136 }
137 }
138 // event
139 ImportableEvent? src_event = src_photo.get_event ();
140 if (src_event != null) {
141 string? prepped = prepare_input_text (src_event.get_name (),
142 PrepareInputTextOptions.DEFAULT, -1);
143 if (prepped != null)
144 Event.generate_single_event (photo, import_roll.generated_events, prepped);
145 }
146 // rating
147 Rating dst_rating;
148 ImportableRating src_rating = src_photo.get_rating ();
149 if (src_rating.is_rejected ())
150 dst_rating = Rating.REJECTED;
151 else if (src_rating.is_unrated ())
152 dst_rating = Rating.UNRATED;
153 else
154 dst_rating = Rating.unserialize (src_rating.get_value ());
155 photo.set_rating (dst_rating);
156 // title
157 string? title = src_photo.get_title ();
158 if (title != null)
159 photo.set_title (title);
160 // import ID
161 photo.set_import_id (import_roll.import_id);
162
163 return true;
164 }
165
166 private string[] build_path_components (ImportableTag tag) {
167 // use a linked list as we are always inserting in head position
168 Gee.List<string> components = new Gee.LinkedList<string> ();
169 for (ImportableTag current_tag = tag; current_tag != null; current_tag = current_tag.get_parent ()) {
170 components.insert (0, HierarchicalTagUtilities.make_flat_tag_safe (current_tag.get_name ()));
171 }
172 return components.to_array ();
173 }
174}
175
176}
177
1780
=== removed file 'src/data_imports/DataImportSource.vala'
--- src/data_imports/DataImportSource.vala 2014-08-08 21:13:09 +0000
+++ src/data_imports/DataImportSource.vala 1970-01-01 00:00:00 +0000
@@ -1,135 +0,0 @@
1/* Copyright 2011-2013 Yorba Foundation
2 *
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.
5 */
6
7namespace Spit.DataImports {
8
9/**
10 * Photo source implementation for alien databases. This class is responsible
11 * for extracting meta-data out of a source photo to support the import
12 * process.
13 *
14 * This class does not extend PhotoSource in order to minimise the API to the
15 * absolute minimum required to run the import job.
16 */
17public class DataImportSource {
18 private bool backing_file_found;
19 private ImportableMediaItem db_photo;
20 private string? title = null;
21 private string? preview_md5 = null;
22 private uint64 file_size;
23 private time_t modification_time;
24 private MetadataDateTime? exposure_time;
25
26 public DataImportSource (ImportableMediaItem db_photo) {
27 this.db_photo = db_photo;
28
29 // A well-behaved plugin will ensure that the path and file name are
30 // not null but we check just in case
31 string folder_path = db_photo.get_folder_path ();
32 string filename = db_photo.get_filename ();
33 File? photo = null;
34 if (folder_path != null && filename != null) {
35 photo = File.new_for_path (db_photo.get_folder_path ()).
36 get_child (db_photo.get_filename ());
37
38 backing_file_found = photo.query_exists ();
39 } else {
40 backing_file_found = false;
41 }
42
43 if (photo != null && backing_file_found) {
44 PhotoMetadata? metadata = new PhotoMetadata ();
45 try {
46 metadata.read_from_file (photo);
47 } catch (Error e) {
48 warning ("Could not get file metadata for %s: %s", get_filename (), e.message);
49 metadata = null;
50 }
51
52 title = (metadata != null) ? metadata.get_title () : null;
53 exposure_time = (metadata != null) ? metadata.get_exposure_date_time () : null;
54 PhotoPreview ? preview = metadata != null ? metadata.get_preview (0) : null;
55 if (preview != null) {
56 try {
57 uint8[] preview_raw = preview.flatten ();
58 preview_md5 = md5_binary (preview_raw, preview_raw.length);
59 } catch (Error e) {
60 warning ("Could not get raw preview for %s: %s", get_filename (), e.message);
61 }
62 }
63#if TRACE_MD5
64 debug ("Photo MD5 %s: preview=%s", get_filename (), preview_md5);
65#endif
66
67 try {
68 file_size = query_total_file_size (photo);
69 } catch (Error e) {
70 warning ("Could not get file size for %s: %s", get_filename (), e.message);
71 }
72 try {
73 modification_time = query_file_modified (photo);
74 } catch (Error e) {
75 warning ("Could not get modification time for %s: %s", get_filename (), e.message);
76 }
77 } else {
78 debug ("Photo file %s not found".printf (photo.get_path ()));
79 }
80 }
81
82 public string get_filename () {
83 return db_photo.get_filename ();
84 }
85
86 public string get_fulldir () {
87 return db_photo.get_folder_path ();
88 }
89
90 public File get_file () {
91 return File.new_for_path (get_fulldir ()).get_child (get_filename ());
92 }
93
94 public string get_name () {
95 return !is_string_empty (title) ? title : get_filename ();
96 }
97
98 public string? get_title () {
99 return title;
100 }
101
102 public PhotoFileFormat get_file_format () {
103 return PhotoFileFormat.get_by_basename_extension (get_filename ());
104 }
105
106 public string to_string () {
107 return get_name ();
108 }
109
110 public time_t get_exposure_time () {
111 return (exposure_time != null) ? exposure_time.get_timestamp () : modification_time;
112 }
113
114 public uint64 get_filesize () {
115 return file_size;
116 }
117
118 public ImportableMediaItem get_photo () {
119 return db_photo;
120 }
121
122 public bool is_already_imported () {
123 // ignore trashed duplicates
124 return (preview_md5 != null)
125 ? LibraryPhoto.has_nontrash_duplicate (null, preview_md5, null, get_file_format ())
126 : false;
127 }
128
129 public bool was_backing_file_found () {
130 return backing_file_found;
131 }
132}
133
134}
135
1360
=== removed file 'src/data_imports/DataImports.vala'
--- src/data_imports/DataImports.vala 2014-08-08 21:13:09 +0000
+++ src/data_imports/DataImports.vala 1970-01-01 00:00:00 +0000
@@ -1,30 +0,0 @@
1/* Copyright 2011-2013 Yorba Foundation
2 *
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.
5 */
6
7/* This file is the master unit file for the DataImports unit. It should be edited to include
8 * whatever code is deemed necessary.
9 *
10 * The init () and terminate () methods are mandatory.
11 *
12 * If the unit needs to be configured prior to initialization, add the proper parameters to
13 * the preconfigure () method, implement it, and ensure in init () that it's been called.
14 */
15
16namespace DataImports {
17
18public void init () throws Error {
19 string[] core_ids = new string[0];
20 core_ids += "org.yorba.shotwell.dataimports.fspot";
21
22 Plugins.register_extension_point (typeof (Spit.DataImports.Service), _ ("Data Imports"),
23 Resources.IMPORT, core_ids);
24}
25
26public void terminate () {
27}
28
29}
30
310
=== removed file 'src/data_imports/DataImportsPluginHost.vala'
--- src/data_imports/DataImportsPluginHost.vala 2014-08-08 21:13:09 +0000
+++ src/data_imports/DataImportsPluginHost.vala 1970-01-01 00:00:00 +0000
@@ -1,483 +0,0 @@
1/* Copyright 2011-2013 Yorba Foundation
2 *
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.
5 */
6
7namespace Spit.DataImports {
8
9private class CoreImporter {
10 private weak Spit.DataImports.PluginHost host;
11 public int imported_items_count = 0;
12 public BatchImportRoll? current_import_roll = null;
13
14 public CoreImporter (Spit.DataImports.PluginHost host) {
15 this.host = host;
16 }
17
18 public void prepare_media_items_for_import (
19 ImportableMediaItem[] items,
20 double progress,
21 double host_progress_delta = 0.0,
22 string? progress_message = null
23 ) {
24 host.update_import_progress_pane (progress, progress_message);
25 //
26 SortedList<DataImportJob> jobs =
27 new SortedList<DataImportJob> (import_job_comparator);
28 Gee.ArrayList<DataImportJob> already_imported =
29 new Gee.ArrayList<DataImportJob> ();
30 Gee.ArrayList<DataImportJob> failed =
31 new Gee.ArrayList<DataImportJob> ();
32
33 int item_idx = 0;
34 double item_progress_delta = host_progress_delta / items.length;
35 foreach (ImportableMediaItem src_item in items) {
36 DataImportSource import_source = new DataImportSource (src_item);
37
38 if (!import_source.was_backing_file_found ()) {
39 message ("Skipping import of %s: backing file not found",
40 import_source.get_filename ());
41 failed.add (new DataImportJob (import_source));
42
43 continue;
44 }
45
46 if (import_source.is_already_imported ()) {
47 message ("Skipping import of %s: checksum detected in library",
48 import_source.get_filename ());
49 already_imported.add (new DataImportJob (import_source));
50
51 continue;
52 }
53
54 jobs.add (new DataImportJob (import_source));
55 item_idx++;
56 host.update_import_progress_pane (progress + item_idx * item_progress_delta);
57 }
58
59 if (jobs.size > 0) {
60 // If there it no current import roll, create one to ensure that all
61 // imported items end up in the same roll even if this method is called
62 // several times
63 if (current_import_roll == null)
64 current_import_roll = new BatchImportRoll ();
65 string db_name = _ ("%s Database").printf (host.get_data_importer ().get_service ().get_pluggable_name ());
66 BatchImport batch_import = new BatchImport (jobs, db_name, data_import_reporter,
67 failed, already_imported, null, current_import_roll);
68
69 LibraryWindow.get_app ().enqueue_batch_import (batch_import, true);
70 imported_items_count += jobs.size;
71 }
72
73 host.update_import_progress_pane (progress + host_progress_delta);
74 }
75
76 public void finalize_import () {
77 // Send an empty job to the queue to mark the end of the import
78 string db_name = _ ("%s Database").printf (host.get_data_importer ().get_service ().get_pluggable_name ());
79 BatchImport batch_import = new BatchImport (
80 new Gee.ArrayList<BatchImportJob> (), db_name, data_import_reporter, null, null, null, current_import_roll
81 );
82 LibraryWindow.get_app ().enqueue_batch_import (batch_import, true);
83 current_import_roll = null;
84 }
85}
86
87public class ConcreteDataImportsHost : Plugins.StandardHostInterface,
88 Spit.DataImports.PluginHost {
89
90 private Spit.DataImports.DataImporter active_importer = null;
91 private weak DataImportsUI.DataImportsDialog dialog = null;
92 private DataImportsUI.ProgressPane? progress_pane = null;
93 private bool importing_halted = false;
94 private CoreImporter core_importer;
95
96 public ConcreteDataImportsHost (Service service, DataImportsUI.DataImportsDialog dialog) {
97 base (service, "data_imports");
98 this.dialog = dialog;
99
100 this.active_importer = service.create_data_importer (this);
101 this.core_importer = new CoreImporter (this);
102 }
103
104 public DataImporter get_data_importer () {
105 return active_importer;
106 }
107
108 public void start_importing () {
109 if (get_data_importer ().is_running ())
110 return;
111
112 debug ("ConcreteDataImportsHost.start_importing( ): invoked.");
113
114 get_data_importer ().start ();
115 }
116
117 public void stop_importing () {
118 debug ("ConcreteDataImportsHost.stop_importing( ): invoked.");
119
120 if (get_data_importer ().is_running ())
121 get_data_importer ().stop ();
122
123 clean_up ();
124
125 importing_halted = true;
126 }
127
128 private void clean_up () {
129 progress_pane = null;
130 }
131
132 public void set_button_mode (Spit.DataImports.PluginHost.ButtonMode mode) {
133 if (mode == Spit.DataImports.PluginHost.ButtonMode.CLOSE)
134 dialog.set_close_button_mode ();
135 else if (mode == Spit.DataImports.PluginHost.ButtonMode.CANCEL)
136 dialog.set_cancel_button_mode ();
137 else
138 error ("unrecognized button mode enumeration value");
139 }
140
141 // Pane handling methods
142
143 public void post_error (Error err) {
144 post_error_message (err.message);
145 }
146
147 public void post_error_message (string message) {
148 string msg = _ ("Importing from %s can't continue because an error occurred:").printf (
149 active_importer.get_service ().get_pluggable_name ());
150 msg += GLib.Markup.printf_escaped ("\n\n<i>%s</i>\n\n", message);
151 msg += _ ("To try importing from another service, select one from the above menu.");
152
153 dialog.install_pane (new DataImportsUI.StaticMessagePane.with_pango (msg));
154 dialog.set_close_button_mode ();
155 dialog.unlock_service ();
156
157 get_data_importer ().stop ();
158
159 // post_error_message( ) tells the active_importer to stop importing and displays a
160 // non-removable error pane that effectively ends the publishing interaction,
161 // so no problem calling clean_up( ) here.
162 clean_up ();
163 }
164
165 public void install_dialog_pane (Spit.DataImports.DialogPane pane,
166 Spit.DataImports.PluginHost.ButtonMode button_mode = Spit.DataImports.PluginHost.ButtonMode.CANCEL) {
167 debug ("DataImports.PluginHost: install_dialog_pane( ): invoked.");
168
169 if (get_data_importer () == null || (!get_data_importer ().is_running ()))
170 return;
171
172 dialog.install_pane (pane);
173
174 set_button_mode (button_mode);
175 }
176
177 public void install_static_message_pane (string message,
178 Spit.DataImports.PluginHost.ButtonMode button_mode = Spit.DataImports.PluginHost.ButtonMode.CANCEL) {
179
180 set_button_mode (button_mode);
181
182 dialog.install_pane (new DataImportsUI.StaticMessagePane.with_pango (message));
183 }
184
185 public void install_library_selection_pane (
186 string welcome_message,
187 ImportableLibrary[] discovered_libraries,
188 string? file_select_label
189 ) {
190 if (discovered_libraries.length == 0 && file_select_label == null)
191 post_error_message ("Libraries or file option needed");
192 else
193 dialog.install_pane (new DataImportsUI.LibrarySelectionPane (
194 this,
195 welcome_message,
196 discovered_libraries,
197 file_select_label
198 ));
199 set_button_mode (Spit.DataImports.PluginHost.ButtonMode.CLOSE);
200 }
201
202 public void install_import_progress_pane (
203 string message
204 ) {
205 progress_pane = new DataImportsUI.ProgressPane (message);
206 dialog.install_pane (progress_pane);
207 set_button_mode (Spit.DataImports.PluginHost.ButtonMode.CANCEL);
208 // initialize the import
209 core_importer.imported_items_count = 0;
210 core_importer.current_import_roll = null;
211 }
212
213 public void update_import_progress_pane (
214 double progress,
215 string? progress_message = null
216 ) {
217 if (progress_pane != null) {
218 progress_pane.update_progress (progress, progress_message);
219 }
220 }
221
222 public void prepare_media_items_for_import (
223 ImportableMediaItem[] items,
224 double progress,
225 double host_progress_delta = 0.0,
226 string? progress_message = null
227 ) {
228 core_importer.prepare_media_items_for_import (items, progress, host_progress_delta, progress_message);
229 }
230
231 public void finalize_import (
232 ImportedItemsCountCallback report_imported_items_count,
233 string? finalize_message = null
234 ) {
235 update_import_progress_pane (1.0, finalize_message);
236 set_button_mode (Spit.DataImports.PluginHost.ButtonMode.CLOSE);
237 core_importer.finalize_import ();
238 report_imported_items_count (core_importer.imported_items_count);
239 if (core_importer.imported_items_count > 0)
240 LibraryWindow.get_app ().switch_to_import_queue_page ();
241 }
242}
243
244public class WelcomeDataImportsHost : Plugins.StandardHostInterface,
245 Spit.DataImports.PluginHost {
246
247 private weak WelcomeImportMetaHost meta_host;
248 private Spit.DataImports.DataImporter active_importer = null;
249 private bool importing_halted = false;
250 private CoreImporter core_importer;
251
252 public WelcomeDataImportsHost (Service service, WelcomeImportMetaHost meta_host) {
253 base (service, "data_imports");
254
255 this.active_importer = service.create_data_importer (this);
256 this.core_importer = new CoreImporter (this);
257 this.meta_host = meta_host;
258 }
259
260 public DataImporter get_data_importer () {
261 return active_importer;
262 }
263
264 public void start_importing () {
265 if (get_data_importer ().is_running ())
266 return;
267
268 debug ("WelcomeDataImportsHost.start_importing( ): invoked.");
269
270 get_data_importer ().start ();
271 }
272
273 public void stop_importing () {
274 debug ("WelcomeDataImportsHost.stop_importing( ): invoked.");
275
276 if (get_data_importer ().is_running ())
277 get_data_importer ().stop ();
278
279 clean_up ();
280
281 importing_halted = true;
282 }
283
284 private void clean_up () {
285 }
286
287 // Pane handling methods
288
289 public void post_error (Error err) {
290 post_error_message (err.message);
291 }
292
293 public void post_error_message (string message) {
294 string msg = _ ("Importing from %s can't continue because an error occurred:").printf (
295 active_importer.get_service ().get_pluggable_name ());
296
297 debug (msg);
298
299 get_data_importer ().stop ();
300
301 // post_error_message( ) tells the active_importer to stop importing and displays a
302 // non-removable error pane that effectively ends the publishing interaction,
303 // so no problem calling clean_up( ) here.
304 clean_up ();
305 }
306
307 public void install_dialog_pane (Spit.DataImports.DialogPane pane,
308 Spit.DataImports.PluginHost.ButtonMode button_mode = Spit.DataImports.PluginHost.ButtonMode.CANCEL) {
309 // do nothing
310 }
311
312 public void install_static_message_pane (string message,
313 Spit.DataImports.PluginHost.ButtonMode button_mode = Spit.DataImports.PluginHost.ButtonMode.CANCEL) {
314 // do nothing
315 }
316
317 public void install_library_selection_pane (
318 string welcome_message,
319 ImportableLibrary[] discovered_libraries,
320 string? file_select_label
321 ) {
322 debug ("WelcomeDataImportsHost: Installing library selection pane for %s".printf (get_data_importer ().get_service ().get_pluggable_name ()));
323 if (discovered_libraries.length > 0) {
324 meta_host.install_service_entry (new WelcomeImportServiceEntry (
325 this,
326 get_data_importer ().get_service ().get_pluggable_name (),
327 discovered_libraries
328 ));
329 }
330 }
331
332 public void install_import_progress_pane (
333 string message
334 ) {
335 // empty implementation
336 }
337
338 public void update_import_progress_pane (
339 double progress,
340 string? progress_message = null
341 ) {
342 // empty implementation
343 }
344
345 public void prepare_media_items_for_import (
346 ImportableMediaItem[] items,
347 double progress,
348 double host_progress_delta = 0.0,
349 string? progress_message = null
350 ) {
351 core_importer.prepare_media_items_for_import (items, progress, host_progress_delta, progress_message);
352 }
353
354 public void finalize_import (
355 ImportedItemsCountCallback report_imported_items_count,
356 string? finalize_message = null
357 ) {
358 core_importer.finalize_import ();
359 report_imported_items_count (core_importer.imported_items_count);
360 meta_host.finalize_import (this);
361 }
362}
363
364
365//public delegate void WelcomeImporterCallback ();
366
367public class WelcomeImportServiceEntry : GLib.Object, WelcomeServiceEntry {
368 private string pluggable_name;
369 private ImportableLibrary[] discovered_libraries;
370 private Spit.DataImports.PluginHost host;
371
372 public WelcomeImportServiceEntry (
373 Spit.DataImports.PluginHost host,
374 string pluggable_name, ImportableLibrary[] discovered_libraries) {
375
376 this.host = host;
377 this.pluggable_name = pluggable_name;
378 this.discovered_libraries = discovered_libraries;
379 }
380
381 public string get_service_name () {
382 return pluggable_name;
383 }
384
385 public void execute () {
386 foreach (ImportableLibrary library in discovered_libraries) {
387 host.get_data_importer ().on_library_selected (library);
388 }
389 }
390}
391
392public class WelcomeImportMetaHost : GLib.Object {
393 private WelcomeDialog dialog;
394
395 public WelcomeImportMetaHost (WelcomeDialog dialog) {
396 this.dialog = dialog;
397 }
398
399 public void start () {
400 Service[] services = load_all_services ();
401 foreach (Service service in services) {
402 WelcomeDataImportsHost host = new WelcomeDataImportsHost (service, this);
403 host.start_importing ();
404 }
405 }
406
407 public void finalize_import (WelcomeDataImportsHost host) {
408 host.stop_importing ();
409 }
410
411 public void install_service_entry (WelcomeServiceEntry entry) {
412 debug ("WelcomeImportMetaHost: Installing service entry for %s".printf (entry.get_service_name ()));
413 dialog.install_service_entry (entry);
414 }
415}
416
417public static Spit.DataImports.Service[] load_all_services () {
418 return load_services (true);
419}
420
421public static Spit.DataImports.Service[] load_services (bool load_all = false) {
422 Spit.DataImports.Service[] loaded_services = new Spit.DataImports.Service[0];
423
424 // load publishing services from plug-ins
425 Gee.Collection<Spit.Pluggable> pluggables = Plugins.get_pluggables_for_type (
426 typeof (Spit.DataImports.Service), null, load_all);
427 // TODO: include sorting function to ensure consistent order
428
429 debug ("DataImportsDialog: discovered %d pluggable data import services.", pluggables.size);
430
431 foreach (Spit.Pluggable pluggable in pluggables) {
432 int pluggable_interface = pluggable.get_pluggable_interface (
433 Spit.DataImports.CURRENT_INTERFACE, Spit.DataImports.CURRENT_INTERFACE);
434 if (pluggable_interface != Spit.DataImports.CURRENT_INTERFACE) {
435 warning ("Unable to load data import plugin %s: reported interface %d.",
436 Plugins.get_pluggable_module_id (pluggable), pluggable_interface);
437
438 continue;
439 }
440
441 Spit.DataImports.Service service =
442 (Spit.DataImports.Service) pluggable;
443
444 debug ("DataImportsDialog: discovered pluggable data import service '%s'.",
445 service.get_pluggable_name ());
446
447 loaded_services += service;
448 }
449
450 // Sort import services by name.
451 // TODO: extract to a function to sort it on initial request
452 Posix.qsort (loaded_services, loaded_services.length, sizeof (Spit.DataImports.Service),
453 (a, b) => {
454 return utf8_cs_compare ((* ((Spit.DataImports.Service **) a))->get_pluggable_name (),
455 (* ((Spit.DataImports.Service **) b))->get_pluggable_name ());
456 });
457
458 return loaded_services;
459}
460
461private ImportManifest? meta_manifest = null;
462
463private void data_import_reporter (ImportManifest manifest, BatchImportRoll import_roll) {
464 if (manifest.all.size > 0) {
465 if (meta_manifest == null)
466 meta_manifest = new ImportManifest ();
467 foreach (BatchImportResult result in manifest.all) {
468 meta_manifest.add_result (result);
469 }
470 } else {
471 DataImportsUI.DataImportsDialog.terminate_instance ();
472 ImportUI.report_manifest (meta_manifest, true);
473 meta_manifest = null;
474 }
475}
476
477private int64 import_job_comparator (void *a, void *b) {
478 return ((DataImportJob *) a)->get_exposure_time ()
479 - ((DataImportJob *) b)->get_exposure_time ();
480}
481
482}
483
4840
=== removed file 'src/data_imports/DataImportsUI.vala'
--- src/data_imports/DataImportsUI.vala 2014-08-08 21:13:09 +0000
+++ src/data_imports/DataImportsUI.vala 1970-01-01 00:00:00 +0000
@@ -1,445 +0,0 @@
1/* Copyright 2011-2013 Yorba Foundation
2 *
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.
5 */
6
7namespace DataImportsUI {
8
9internal const string NO_PLUGINS_ENABLED_MESSAGE =
10 _ ("You do not have any data imports plugins enabled.\n\nIn order to use the Import From Application functionality, you need to have at least one data imports plugin enabled. Plugins can be enabled in the Preferences dialog.");
11
12public class ConcreteDialogPane : Spit.DataImports.DialogPane, GLib.Object {
13 private Gtk.Box pane_widget;
14
15 public ConcreteDialogPane () {
16 pane_widget = new Gtk.Box (Gtk.Orientation.VERTICAL, 8);
17 }
18
19 public Gtk.Widget get_widget () {
20 return pane_widget;
21 }
22
23 public Spit.DataImports.DialogPane.GeometryOptions get_preferred_geometry () {
24 return Spit.DataImports.DialogPane.GeometryOptions.NONE;
25 }
26
27 public void on_pane_installed () {
28 }
29
30 public void on_pane_uninstalled () {
31 }
32}
33
34public class StaticMessagePane : ConcreteDialogPane {
35 public StaticMessagePane (string message_string) {
36 Gtk.Label message_label = new Gtk.Label (message_string);
37 (get_widget () as Gtk.Box).pack_start (message_label, true, true, 0);
38 }
39
40 public StaticMessagePane.with_pango (string msg) {
41 Gtk.Label label = new Gtk.Label (null);
42 label.set_markup (msg);
43 label.set_line_wrap (true);
44
45 (get_widget () as Gtk.Box).pack_start (label, true, true, 0);
46 }
47}
48
49public class LibrarySelectionPane : ConcreteDialogPane {
50 private weak Spit.DataImports.PluginHost host;
51 private Spit.DataImports.ImportableLibrary? selected_library = null;
52 private File? selected_file = null;
53 private Gtk.Button import_button;
54 private Gtk.RadioButton? file_radio = null;
55
56 public LibrarySelectionPane (
57 Spit.DataImports.PluginHost host,
58 string welcome_message,
59 Spit.DataImports.ImportableLibrary[] discovered_libraries,
60 string? file_select_label
61 ) {
62 assert (discovered_libraries.length > 0 || on_file_selected != null);
63
64 this.host = host;
65
66 Gtk.Box content_box = new Gtk.Box (Gtk.Orientation.VERTICAL, 8);
67 content_box.set_margin_left (30);
68 content_box.set_margin_right (30);
69 Gtk.Label welcome_label = new Gtk.Label (null);
70 welcome_label.set_markup (welcome_message);
71 welcome_label.set_line_wrap (true);
72 welcome_label.set_halign (Gtk.Align.START);
73 content_box.pack_start (welcome_label, true, true, 6);
74
75 // margins for buttons
76 int radio_margin_left = 20;
77 int radio_margin_right = 20;
78 int chooser_margin_left = radio_margin_left;
79 int chooser_margin_right = radio_margin_right;
80
81 Gtk.RadioButton lib_radio = null;
82 if (discovered_libraries.length > 0) {
83 chooser_margin_left = radio_margin_left + 20;
84 foreach (Spit.DataImports.ImportableLibrary library in discovered_libraries) {
85 string lib_radio_label = library.get_display_name ();
86 lib_radio = create_radio_button (
87 content_box, lib_radio, library, lib_radio_label,
88 radio_margin_left, radio_margin_right
89 );
90 }
91 if (file_select_label != null) {
92 lib_radio = create_radio_button (
93 content_box, lib_radio, null, file_select_label,
94 radio_margin_left, radio_margin_right
95 );
96 file_radio = lib_radio;
97 }
98 }
99 if (file_select_label != null) {
100 Gtk.FileChooserButton file_chooser = new Gtk.FileChooserButton (_ ("Database file:"), Gtk.FileChooserAction.OPEN);
101 file_chooser.selection_changed.connect ( () => {
102 selected_file = file_chooser.get_file ();
103 if (file_radio != null)
104 file_radio.active = true;
105 set_import_button_sensitivity ();
106 });
107 file_chooser.set_margin_left (chooser_margin_left);
108 file_chooser.set_margin_right (chooser_margin_right);
109 content_box.pack_start (file_chooser, false, false, 6);
110 }
111
112 import_button = new Gtk.Button.with_mnemonic (_ ("_Import"));
113 import_button.clicked.connect ( () => {
114 if (selected_library != null)
115 on_library_selected (selected_library);
116 else if (selected_file != null)
117 on_file_selected (selected_file);
118 else
119 debug ("LibrarySelectionPane: Library or file should be selected.");
120 });
121 Gtk.ButtonBox button_box = new Gtk.ButtonBox (Gtk.Orientation.HORIZONTAL);
122 button_box.layout_style = Gtk.ButtonBoxStyle.CENTER;
123 button_box.add (import_button);
124 content_box.pack_end (button_box, true, false, 6);
125
126 (get_widget () as Gtk.Box).pack_start (content_box, true, true, 0);
127
128 set_import_button_sensitivity ();
129 }
130
131 private Gtk.RadioButton create_radio_button (
132 Gtk.Box box, Gtk.RadioButton? group, Spit.DataImports.ImportableLibrary? library, string label,
133 int margin_left, int margin_right
134 ) {
135 var button = new Gtk.RadioButton.with_label_from_widget (group, label);
136 if (group == null) { // first radio button is active
137 button.active = true;
138 selected_library = library;
139 }
140 button.toggled.connect ( () => {
141 if (button.active) {
142 this.selected_library = library;
143 set_import_button_sensitivity ();
144 }
145
146 });
147 button.set_margin_left (margin_left);
148 button.set_margin_right (margin_right);
149 box.pack_start (button, false, false, 6);
150 return button;
151 }
152
153 private void set_import_button_sensitivity () {
154 import_button.set_sensitive (selected_library != null || selected_file != null);
155 }
156
157 private void on_library_selected (Spit.DataImports.ImportableLibrary library) {
158 host.get_data_importer ().on_library_selected (library);
159 }
160
161 private void on_file_selected (File file) {
162 host.get_data_importer ().on_file_selected (file);
163 }
164}
165
166public class ProgressPane : ConcreteDialogPane {
167 private Gtk.Label message_label;
168 private Gtk.Label progress_label;
169 private Gtk.ProgressBar progress_bar;
170
171 public ProgressPane (string message) {
172 Gtk.Box content_box = new Gtk.Box (Gtk.Orientation.VERTICAL, 8);
173 message_label = new Gtk.Label (message);
174 content_box.pack_start (message_label, true, true, 6);
175 progress_bar = new Gtk.ProgressBar ();
176 content_box.pack_start (progress_bar, false, true, 6);
177 progress_label = new Gtk.Label ("");
178 content_box.pack_start (progress_label, false, true, 6);
179
180 (get_widget () as Gtk.Container).add (content_box);
181 }
182
183 public void update_progress (double progress, string? progress_message) {
184 progress_bar.set_fraction (progress);
185 if (progress_message != null)
186 progress_label.set_label (progress_message);
187 spin_event_loop ();
188 }
189}
190
191public class DataImportsDialog : Gtk.Dialog {
192 private const int LARGE_WINDOW_WIDTH = 860;
193 private const int LARGE_WINDOW_HEIGHT = 688;
194 private const int COLOSSAL_WINDOW_WIDTH = 1024;
195 private const int COLOSSAL_WINDOW_HEIGHT = 688;
196 private const int STANDARD_WINDOW_WIDTH = 600;
197 private const int STANDARD_WINDOW_HEIGHT = 510;
198 private const int BORDER_REGION_WIDTH = 16;
199 private const int BORDER_REGION_HEIGHT = 100;
200
201 public const int STANDARD_CONTENT_LABEL_WIDTH = 500;
202 public const int STANDARD_ACTION_BUTTON_WIDTH = 128;
203
204 private Gtk.ComboBoxText service_selector_box;
205 private Gtk.Label service_selector_box_label;
206 private Gtk.Box central_area_layouter;
207 private Gtk.Button close_cancel_button;
208 private Spit.DataImports.DialogPane active_pane;
209 private Spit.DataImports.ConcreteDataImportsHost host;
210
211 protected DataImportsDialog () {
212
213 resizable = false;
214 delete_event.connect (on_window_close);
215
216 string title = _ ("Import From Application");
217 string label = _ ("Import media _from:");
218
219 set_title (title);
220
221 Spit.DataImports.Service[] loaded_services = Spit.DataImports.load_services ();
222
223 if (loaded_services.length > 0) {
224 // Install the service selector part only if there is at least one
225 // service to select from
226 service_selector_box = new Gtk.ComboBoxText ();
227 service_selector_box.set_active (0);
228 service_selector_box_label = new Gtk.Label.with_mnemonic (label);
229 service_selector_box_label.set_mnemonic_widget (service_selector_box);
230 service_selector_box_label.set_alignment (0.0f, 0.5f);
231
232 // get the name of the service the user last used
233 string? last_used_service = Config.Facade.get_instance ().get_last_used_dataimports_service ();
234
235 int ticker = 0;
236 int last_used_index = -1;
237 foreach (Spit.DataImports.Service service in loaded_services) {
238 string curr_service_id = service.get_id ();
239 if (last_used_service != null && last_used_service == curr_service_id)
240 last_used_index = ticker;
241
242 service_selector_box.append_text (service.get_pluggable_name ());
243 ticker++;
244 }
245 if (last_used_index >= 0)
246 service_selector_box.set_active (last_used_index);
247 else
248 service_selector_box.set_active (0);
249
250 service_selector_box.changed.connect (on_service_changed);
251
252 /* the wrapper is not an extraneous widget -- it's necessary to prevent the service
253 selection box from growing and shrinking whenever its parent's size changes.
254 When wrapped inside a Gtk.Alignment, the Alignment grows and shrinks instead of
255 the service selection box. */
256 Gtk.Alignment service_selector_box_wrapper = new Gtk.Alignment (1.0f, 0.5f, 0.0f, 0.0f);
257 service_selector_box_wrapper.add (service_selector_box);
258
259 Gtk.Box service_selector_layouter = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 8);
260 service_selector_layouter.set_border_width (12);
261 service_selector_layouter.add (service_selector_box_label);
262 service_selector_layouter.pack_start (service_selector_box_wrapper, true, true, 0);
263
264 /* 'service area' is the selector assembly plus the horizontal rule dividing it from the
265 rest of the dialog */
266 Gtk.Box service_area_layouter = new Gtk.Box (Gtk.Orientation.VERTICAL, 0);
267 service_area_layouter.pack_start (service_selector_layouter, true, true, 0);
268 Gtk.Separator service_central_separator = new Gtk.Separator (Gtk.Orientation.HORIZONTAL);
269 service_area_layouter.add (service_central_separator);
270
271 Gtk.Alignment service_area_wrapper = new Gtk.Alignment (0.0f, 0.0f, 1.0f, 0.0f);
272 service_area_wrapper.add (service_area_layouter);
273
274 ((Gtk.Box) get_content_area ()).pack_start (service_area_wrapper, false, false, 0);
275 }
276
277 // Intall the central area in all cases
278 central_area_layouter = new Gtk.Box (Gtk.Orientation.VERTICAL, 0);
279 ((Gtk.Box) get_content_area ()).pack_start (central_area_layouter, true, true, 0);
280
281 close_cancel_button = new Gtk.Button.with_mnemonic ("_Cancel");
282 close_cancel_button.set_can_default (true);
283 close_cancel_button.clicked.connect (on_close_cancel_clicked);
284 ((Gtk.Box) get_action_area ()).add (close_cancel_button);
285
286 set_standard_window_mode ();
287
288 if (loaded_services.length > 0) {
289 // trigger the selected service if at least one service is available
290 on_service_changed ();
291 } else {
292 // otherwise, install a message pane advising the user what to do
293 install_pane (new StaticMessagePane.with_pango (NO_PLUGINS_ENABLED_MESSAGE));
294 set_close_button_mode ();
295 }
296
297 show_all ();
298 }
299
300 public static DataImportsDialog get_or_create_instance () {
301 if (instance == null) {
302 instance = new DataImportsDialog ();
303 }
304 return instance;
305 }
306
307 public static void terminate_instance () {
308 if (instance != null) {
309 instance.terminate ();
310 }
311 instance = null;
312 }
313
314 private bool on_window_close (Gdk.EventAny evt) {
315 debug ("DataImportsDialog: on_window_close( ): invoked.");
316 terminate ();
317
318 return true;
319 }
320
321 private void on_service_changed () {
322 debug ("DataImportsDialog: on_service_changed invoked.");
323 string service_name = service_selector_box.get_active_text ();
324
325 Spit.DataImports.Service? selected_service = null;
326 Spit.DataImports.Service[] services = Spit.DataImports.load_all_services ();
327 foreach (Spit.DataImports.Service service in services) {
328 if (service.get_pluggable_name () == service_name) {
329 selected_service = service;
330 break;
331 }
332 }
333 assert (selected_service != null);
334
335 Config.Facade.get_instance ().set_last_used_dataimports_service (selected_service.get_id ());
336
337 host = new Spit.DataImports.ConcreteDataImportsHost (selected_service, this);
338 host.start_importing ();
339 }
340
341 private void on_close_cancel_clicked () {
342 debug ("DataImportsDialog: on_close_cancel_clicked( ): invoked.");
343
344 terminate ();
345 }
346
347 private void terminate () {
348 debug ("DataImportsDialog: terminate( ): invoked.");
349
350 if (host != null) {
351 host.stop_importing ();
352 host = null;
353 }
354
355 hide ();
356 destroy ();
357 instance = null;
358 }
359
360 private void set_large_window_mode () {
361 set_size_request (LARGE_WINDOW_WIDTH, LARGE_WINDOW_HEIGHT);
362 central_area_layouter.set_size_request (LARGE_WINDOW_WIDTH - BORDER_REGION_WIDTH,
363 LARGE_WINDOW_HEIGHT - BORDER_REGION_HEIGHT);
364 resizable = false;
365 }
366
367 private void set_colossal_window_mode () {
368 set_size_request (COLOSSAL_WINDOW_WIDTH, COLOSSAL_WINDOW_HEIGHT);
369 central_area_layouter.set_size_request (COLOSSAL_WINDOW_WIDTH - BORDER_REGION_WIDTH,
370 COLOSSAL_WINDOW_HEIGHT - BORDER_REGION_HEIGHT);
371 resizable = false;
372 }
373
374 private void set_standard_window_mode () {
375 set_size_request (STANDARD_WINDOW_WIDTH, STANDARD_WINDOW_HEIGHT);
376 central_area_layouter.set_size_request (STANDARD_WINDOW_WIDTH - BORDER_REGION_WIDTH,
377 STANDARD_WINDOW_HEIGHT - BORDER_REGION_HEIGHT);
378 resizable = false;
379 }
380
381 private void set_free_sizable_window_mode () {
382 resizable = true;
383 }
384
385 private void clear_free_sizable_window_mode () {
386 resizable = false;
387 }
388
389 public Spit.DataImports.DialogPane get_active_pane () {
390 return active_pane;
391 }
392
393 public void set_close_button_mode () {
394 close_cancel_button.set_label (_ ("_Close"));
395 set_default (close_cancel_button);
396 }
397
398 public void set_cancel_button_mode () {
399 close_cancel_button.set_label (_ ("_Cancel"));
400 }
401
402 public void lock_service () {
403 service_selector_box.set_sensitive (false);
404 }
405
406 public void unlock_service () {
407 service_selector_box.set_sensitive (true);
408 }
409
410 public void install_pane (Spit.DataImports.DialogPane pane) {
411 debug ("DataImportsDialog: install_pane( ): invoked.");
412
413 if (active_pane != null) {
414 debug ("DataImportsDialog: install_pane( ): a pane is already installed; removing it.");
415
416 active_pane.on_pane_uninstalled ();
417 central_area_layouter.remove (active_pane.get_widget ());
418 }
419
420 central_area_layouter.pack_start (pane.get_widget (), true, true, 0);
421 show_all ();
422
423 Spit.DataImports.DialogPane.GeometryOptions geometry_options =
424 pane.get_preferred_geometry ();
425 if ((geometry_options & Spit.Publishing.DialogPane.GeometryOptions.EXTENDED_SIZE) != 0)
426 set_large_window_mode ();
427 else if ((geometry_options & Spit.Publishing.DialogPane.GeometryOptions.COLOSSAL_SIZE) != 0)
428 set_colossal_window_mode ();
429 else
430 set_standard_window_mode ();
431
432 if ((geometry_options & Spit.Publishing.DialogPane.GeometryOptions.RESIZABLE) != 0)
433 set_free_sizable_window_mode ();
434 else
435 clear_free_sizable_window_mode ();
436
437 active_pane = pane;
438 pane.on_pane_installed ();
439 }
440
441 private static DataImportsDialog? instance;
442}
443
444}
445
4460
=== removed directory 'src/data_imports/mk'
=== removed file 'src/data_imports/mk/data_imports.mk'
--- src/data_imports/mk/data_imports.mk 2012-02-02 22:56:06 +0000
+++ src/data_imports/mk/data_imports.mk 1970-01-01 00:00:00 +0000
@@ -1,31 +0,0 @@
1
2# UNIT_NAME is the Vala namespace. A file named UNIT_NAME.vala must be in this directory with
3# a init() and terminate() function declared in the namespace.
4UNIT_NAME := DataImports
5
6# UNIT_DIR should match the subdirectory the files are located in. Generally UNIT_NAME in all
7# lowercase. The name of this file should be UNIT_DIR.mk.
8UNIT_DIR := data_imports
9
10# All Vala files in the unit should be listed here with no subdirectory prefix.
11#
12# NOTE: Do *not* include the unit's master file, i.e. UNIT_NAME.vala.
13UNIT_FILES := \
14 DataImportsPluginHost.vala \
15 DataImportsUI.vala \
16 DataImportJob.vala \
17 DataImportSource.vala
18
19# Any unit this unit relies upon (and should be initialized before it's initialized) should
20# be listed here using its Vala namespace.
21#
22# NOTE: All units are assumed to rely upon the unit-unit. Do not include that here.
23UNIT_USES :=
24
25# List any additional files that are used in the build process as a part of this unit that should
26# be packaged in the tarball. File names should be relative to the unit's home directory.
27UNIT_RC :=
28
29# unitize.mk must be called at the end of each UNIT_DIR.mk file.
30include unitize.mk
31
320
=== modified file 'src/library/LibraryWindow.vala'
--- src/library/LibraryWindow.vala 2014-08-28 03:37:44 +0000
+++ src/library/LibraryWindow.vala 2014-08-28 06:03:26 +0000
@@ -288,13 +288,6 @@
288 import.tooltip = _ ("Import photos from disk to library");288 import.tooltip = _ ("Import photos from disk to library");
289 actions += import;289 actions += import;
290290
291 Gtk.ActionEntry import_from_external = {
292 "ExternalLibraryImport", Resources.IMPORT, TRANSLATABLE,
293 null, TRANSLATABLE, on_external_library_import
294 };
295 import_from_external.label = _ ("Import From _Application...");
296 actions += import_from_external;
297
298 Gtk.ActionEntry sort = { "CommonSortEvents", null, TRANSLATABLE, null, null, null };291 Gtk.ActionEntry sort = { "CommonSortEvents", null, TRANSLATABLE, null, null, null };
299 sort.label = _ ("Sort _Events");292 sort.label = _ ("Sort _Events");
300 actions += sort;293 actions += sort;
@@ -667,12 +660,6 @@
667 import_dialog.destroy ();660 import_dialog.destroy ();
668 }661 }
669662
670 private void on_external_library_import () {
671 Gtk.Dialog import_dialog = DataImportsUI.DataImportsDialog.get_or_create_instance ();
672
673 import_dialog.run ();
674 }
675
676 protected override void update_common_action_availability (Page? old_page, Page? new_page) {663 protected override void update_common_action_availability (Page? old_page, Page? new_page) {
677 base.update_common_action_availability (old_page, new_page);664 base.update_common_action_availability (old_page, new_page);
678665
679666
=== modified file 'src/library/mk/library.mk'
--- src/library/mk/library.mk 2014-08-28 03:37:44 +0000
+++ src/library/mk/library.mk 2014-08-28 06:03:26 +0000
@@ -41,8 +41,7 @@
41 Events \41 Events \
42 Tags \42 Tags \
43 Camera \43 Camera \
44 Searches \44 Searches
45 DataImports
4645
47# List any additional files that are used in the build process as a part of this unit that should46# List any additional files that are used in the build process as a part of this unit that should
48# be packaged in the tarball. File names should be relative to the unit's home directory.47# be packaged in the tarball. File names should be relative to the unit's home directory.
4948
=== removed file 'src/plugins/DataImportsInterfaces.vala'
--- src/plugins/DataImportsInterfaces.vala 2014-08-08 21:13:09 +0000
+++ src/plugins/DataImportsInterfaces.vala 1970-01-01 00:00:00 +0000
@@ -1,489 +0,0 @@
1/* Copyright 2011-2013 Yorba Foundation
2 *
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.
5 */
6
7/**
8 * Shotwell Pluggable Data Imports API
9 *
10 * The Shotwell Pluggable Data Imports API allows you to write plugins that import
11 * information from other media library databases to help migration to Shotwell.
12 * The Shotwell distribution includes import support for F-Spot.
13 * To enable Shotwell to import from additional libaries, developers like you write
14 * data import plugins, dynamically-loadable shared objects that are linked into the
15 * Shotwell process at runtime. Data import plugins are just one of several kinds of
16 * plugins supported by {@link Spit}, the Shotwell Pluggable Interfaces Technology.
17 */
18namespace Spit.DataImports {
19
20/**
21 * The current version of the Pluggable Data Import API
22 */
23public const int CURRENT_INTERFACE = 0;
24
25/**
26 * The error domain for alien databases
27 */
28public errordomain DataImportError {
29 /**
30 * Indicates that the version of the external database being imported is
31 * not supported by this version of the plugin.
32 *
33 * This occurs for example when trying to import an F-Spot database that
34 * has a version that is more recent than what the current plugin supports.
35 */
36 UNSUPPORTED_VERSION
37}
38
39/**
40 * Represents a module that is able to import data from a specific database format.
41 *
42 * Developers of data import plugins provide a class that implements this interface. At
43 * any given time, only one DataImporter can be running. When a data importer is running, it
44 * has exclusive use of the shared user-interface and
45 * configuration services provided by the {@link PluginHost}. Data importers are created in
46 * a non-running state and do not begin running until start( ) is invoked. Data importers
47 * run until stop( ) is invoked.
48 */
49public interface DataImporter : GLib.Object {
50 /**
51 * Returns a {@link Service} object describing the service to which this connects.
52 */
53 public abstract Service get_service ();
54
55 /**
56 * Makes this data importer enter the running state and endows it with exclusive access
57 * to the shared services provided by the {@link PluginHost}. Through the host’s interface,
58 * this data importer can install user interface panes and query configuration information.
59 */
60 public abstract void start ();
61
62 /**
63 * Returns true if this data importer is in the running state; false otherwise.
64 */
65 public abstract bool is_running ();
66
67 /**
68 * Causes this data importer to enter a non-running state. This data importer should stop all
69 * data access operations and cease use of the shared services provided by the {@link PluginHost}.
70 */
71 public abstract void stop ();
72
73 /**
74 * Causes this data importer to enter start the import of a library.
75 */
76 public abstract void on_library_selected (ImportableLibrary library);
77
78 /**
79 * Causes this data importer to enter start the import of a library file.
80 */
81 public abstract void on_file_selected (File file);
82
83 //
84 // For future expansion.
85 //
86 protected virtual void reserved0 () {}
87 protected virtual void reserved1 () {}
88 protected virtual void reserved2 () {}
89 protected virtual void reserved3 () {}
90 protected virtual void reserved4 () {}
91 protected virtual void reserved5 () {}
92 protected virtual void reserved6 () {}
93 protected virtual void reserved7 () {}
94}
95
96/**
97 * Represents a library of importable media items.
98 *
99 * Developers of data import plugins provide a class that implements this interface.
100 */
101public interface ImportableLibrary : GLib.Object {
102 public abstract string get_display_name ();
103}
104
105/**
106 * Represents an importable media item such as a photo or a video file.
107 *
108 * Developers of data import plugins provide a class that implements this interface.
109 */
110public interface ImportableMediaItem : GLib.Object {
111 public abstract ImportableTag[] get_tags ();
112
113 public abstract ImportableEvent? get_event ();
114
115 public abstract ImportableRating get_rating ();
116
117 public abstract string? get_title ();
118
119 public abstract string get_folder_path ();
120
121 public abstract string get_filename ();
122}
123
124/**
125 * Represents an importable tag.
126 *
127 * Developers of data import plugins provide a class that implements this interface.
128 */
129public interface ImportableTag : GLib.Object {
130 public abstract string get_name ();
131
132 public abstract ImportableTag? get_parent ();
133}
134
135/**
136 * Represents an importable event.
137 *
138 * Developers of data import plugins provide a class that implements this interface.
139 */
140public interface ImportableEvent : GLib.Object {
141 public abstract string get_name ();
142}
143
144/**
145 * Represents an importable rating value.
146 *
147 * Developers of data import plugins provide a class that implements this interface.
148 * Note that the value returned by the get_value method should be a value between
149 * 1 and 5, unless the rating object is unrated or rejected, in which case the
150 * value is unspecified.
151 */
152public interface ImportableRating : GLib.Object {
153 public abstract bool is_unrated ();
154
155 public abstract bool is_rejected ();
156
157 public abstract int get_value ();
158}
159
160/**
161 * Encapsulates a pane that can be installed in the on-screen import dialog box to
162 * communicate status to and to get information from the user.
163 *
164 */
165public interface DialogPane : GLib.Object {
166
167 /**
168 * Describes how the on-screen publishing dialog box should look and behave when an associated
169 * pane is installed in the on-screen publishing dialog box.
170 */
171 public enum GeometryOptions {
172
173 /**
174 * When the associated pane is installed, the on-screen publishing dialog box will be
175 * sized normally and will not allow the user to change its size.
176 */
177 NONE = 0,
178
179 /**
180 * If this bit is set, when the associated pane is installed, the on-screen publishing
181 * dialog box will grow to a larger size.
182 */
183 EXTENDED_SIZE = 1 << 0,
184
185 /**
186 * If this bit is set, when the associated pane is installed, the on-screen publishing
187 * dialog box will allow the user to change its size.
188 */
189 RESIZABLE = 1 << 1,
190
191 /**
192 * If this bit is set, when the associated pane is installed, the on-screen publishing
193 * dialog box will grow to accommodate a full-width 1024 pixel web page. If both
194 * EXTENDED_SIZE and COLOSSAL_SIZE are set, EXTENDED_SIZE takes precedence.
195 */
196 COLOSSAL_SIZE = 1 << 2;
197 }
198
199 /**
200 * Returns the Gtk.Widget that is this pane's on-screen representation.
201 */
202 public abstract Gtk.Widget get_widget ();
203
204 /**
205 * Returns a {@link GeometryOptions} bitfield describing how the on-screen publishing dialog
206 * box should look and behave when this pane is installed.
207 */
208 public abstract GeometryOptions get_preferred_geometry ();
209
210 /**
211 * Invoked automatically by Shotwell when this pane has been installed into the on-screen
212 * publishing dialog box and become visible to the user.
213 */
214 public abstract void on_pane_installed ();
215
216 /**
217 * Invoked automatically by Shotwell when this pane has been removed from the on-screen
218 * publishing dialog box and is no longer visible to the user.
219 */
220 public abstract void on_pane_uninstalled ();
221
222 //
223 // For future expansion.
224 //
225 protected virtual void reserved0 () {}
226 protected virtual void reserved1 () {}
227 protected virtual void reserved2 () {}
228 protected virtual void reserved3 () {}
229 protected virtual void reserved4 () {}
230 protected virtual void reserved5 () {}
231 protected virtual void reserved6 () {}
232 protected virtual void reserved7 () {}
233}
234
235/**
236 * Called by the data imports system at the end of an import batch to report
237 * to the plugin the number of items that were really imported. This enables
238 * the plugin to display a final message to the user. However, the plugin
239 * should not rely on this callback being called in order to clean up.
240 */
241public delegate void ImportedItemsCountCallback (int imported_items_count);
242
243/**
244 * Manages and provides services for data import plugins.
245 *
246 * Implemented inside Shotwell, the PluginHost provides an interface through which the
247 * developers of data import plugins can query and make changes to the import
248 * environment. Plugins can use the services of the PluginHost only when their
249 * {@link DataImporter} is in the running state. This ensures that non-running data importers
250 * don’t destructively interfere with the actively running importer.
251 */
252public interface PluginHost : GLib.Object, Spit.HostInterface {
253
254 /**
255 * Specifies the label text on the push button control that appears in the
256 * lower-right-hand corner of the on-screen publishing dialog box.
257 */
258 public enum ButtonMode {
259 CLOSE = 0,
260 CANCEL = 1
261 }
262
263 /**
264 * Notifies the user that an unrecoverable import error has occurred and halts
265 * the import process.
266 *
267 * @param err An error object that describes the kind of error that occurred.
268 */
269 public abstract void post_error (Error err);
270
271 /**
272 * Notifies the user that an unrecoverable import error has occurred and halts
273 * the import process.
274 *
275 * @param msg A message that describes the kind of error that occurred.
276 */
277 public abstract void post_error_message (string msg);
278
279 /**
280 * Starts the import process.
281 *
282 * Calling this method starts the import activity for this host.
283 */
284 public abstract void start_importing ();
285
286 /**
287 * Halts the import process.
288 *
289 * Calling this method stops all import activity and hides the on-screen import
290 * dialog box.
291 */
292 public abstract void stop_importing ();
293
294 /**
295 * Returns a reference to the {@link DataImporter} object that this is currently hosting.
296 */
297 public abstract DataImporter get_data_importer ();
298
299 /**
300 * Attempts to install a pane in the on-screen data import dialog box, making the pane visible
301 * and allowing it to interact with the user.
302 *
303 * If an error has posted, the {@link PluginHost} will not honor this request.
304 *
305 * @param pane the pane to install
306 *
307 * @param mode allows you to set the text displayed on the close/cancel button in the
308 * lower-right-hand corner of the on-screen data import dialog box when pane is installed.
309 * If mode is ButtonMode.CLOSE, the button will have the title "Close." If mode is
310 * ButtonMode.CANCEL, the button will be titled "Cancel." You should set mode depending on
311 * whether a cancellable action is in progress. For example, if your importer is in the
312 * middle of processing 3 of 8 videos, then mode should be ButtonMode.CANCEL. However, if
313 * the processing operation has completed and the success pane is displayed, then mode
314 * should be ButtonMode.CLOSE, because all cancellable actions have already
315 * occurred.
316 */
317 public abstract void install_dialog_pane (Spit.DataImports.DialogPane pane,
318 ButtonMode mode = ButtonMode.CANCEL);
319
320 /**
321 * Attempts to install a pane in the on-screen data import dialog box that contains
322 * static text.
323 *
324 * The text appears centered in the data import dialog box and is drawn in
325 * the system font. This is a convenience method only; similar results could be
326 * achieved by manually constructing a Gtk.Label widget, wrapping it inside a
327 * {@link DialogPane}, and installing it manually with a call to
328 * install_dialog_pane( ). To provide visual consistency across data import services,
329 * however, always use this convenience method instead of constructing label panes when
330 * you need to display static text to the user.
331 *
332 * If an error has posted, the {@link PluginHost} will not honor this request.
333 *
334 * @param message the text to show in the pane
335 *
336 * @param mode allows you to set the text displayed on the close/cancel button in the
337 * lower-right-hand corner of the on-screen data import dialog box when pane is installed.
338 * If mode is ButtonMode.CLOSE, the button will have the title "Close." If mode is
339 * ButtonMode.CANCEL, the button will be titled "Cancel." You should set mode depending on
340 * whether a cancellable action is in progress. For example, if your importer is in the
341 * middle of processing 3 of 8 videos, then mode should be ButtonMode.CANCEL. However, if
342 * the processing operation has completed and the success pane is displayed, then mode
343 * should be ButtonMode.CLOSE, because all cancellable actions have already
344 * occurred.
345 */
346 public abstract void install_static_message_pane (string message,
347 ButtonMode mode = ButtonMode.CANCEL);
348
349 /**
350 * Attempts to install a library selection pane that presents a list of
351 * discovered libraries to the user.
352 *
353 * When the user clicks the “OK” button, you’ll be notified of the user’s action through
354 * the 'on_library_selected' callback if a discovered library was selected or through
355 * the 'on_file_selected' callback if a file was selected.
356 *
357 * If an error has posted, the {@link PluginHost} will not honor this request.
358 *
359 * @param welcome_message the text to be displayed above the list of discovered
360 * libraries.
361 *
362 * @param discovered_libraries the list of importable libraries that the plugin
363 * has discovered in well known locations.
364 *
365 * @param file_select_label the label to display for the file selection
366 * option. If this label is null, the
367 * user will not be presented with a file selection option.
368 */
369 public abstract void install_library_selection_pane (
370 string welcome_message,
371 ImportableLibrary[] discovered_libraries,
372 string? file_select_label
373 );
374
375 /**
376 * Attempts to install a progress pane that provides the user with feedback
377 * on import preparation.
378 *
379 * If an error has posted, the {@link PluginHost} will not honor this request.
380 *
381 * @param message the text to be displayed above the progress bar.
382 */
383 public abstract void install_import_progress_pane (
384 string message
385 );
386
387 /**
388 * Update the progress bar installed by install_import_progress_pane.
389 *
390 * If an error has posted, the {@link PluginHost} will not honor this request.
391 *
392 * @param progress a value between 0.0 and 1.0 identifying progress for the
393 * plugin.
394 *
395 * @param progress_label the text to be displayed below the progress bar. If that
396 * parameter is null, the message will be left unchanged.
397 */
398 public abstract void update_import_progress_pane (
399 double progress,
400 string? progress_message = null
401 );
402
403 /**
404 * Sends an importable media item to the host in order to prepare it for import
405 * and update the progress bar installed by install_import_progress_pane.
406 *
407 * If an error has posted, the {@link PluginHost} will not honor this request.
408 *
409 * @param item the importable media item to prepare for import.
410 *
411 * @param progress a value between 0.0 and 1.0 identifying progress for the
412 * plugin.
413 *
414 * @param host_progress_delta the amount of progress the host should update
415 * the progress bar during import preparation. Plugins should ensure that
416 * a proportion of progress for each media item is set aside for the host
417 * in oder to ensure a smoother update to the progress bar.
418 *
419 * @param progress_message the text to be displayed below the progress bar. If that
420 * parameter is null, the message will be left unchanged.
421 */
422 public abstract void prepare_media_items_for_import (
423 ImportableMediaItem[] items,
424 double progress,
425 double host_progress_delta = 0.0,
426 string? progress_message = null
427 );
428
429 /**
430 * Finalize the import sequence for the plugin. This tells the host that
431 * all media items have been processed and that the plugin has finished all
432 * import work. Once this method has been called, all resources used by the
433 * plugin for import should be released and the plugin should be back to the
434 * state it had just after running the start method. The host will then display
435 * the final message and show progress as fully complete. In a standard import
436 * scenario, the user is expected to click the Close button to dismiss the
437 * dialog. On first run, the host may call the LibrarySelectedCallback again
438 * to import another library handled by the same plugin.
439 *
440 * If an error has posted, the {@link PluginHost} will not honor this request.
441 *
442 * @param finalize_message the text to be displayed below the progress bar. If that
443 * parameter is null, the message will be left unchanged.
444 */
445 public abstract void finalize_import (
446 ImportedItemsCountCallback report_imported_items_count,
447 string? finalize_message = null
448 );
449
450 //
451 // For future expansion.
452 //
453 protected virtual void reserved0 () {}
454 protected virtual void reserved1 () {}
455 protected virtual void reserved2 () {}
456 protected virtual void reserved3 () {}
457 protected virtual void reserved4 () {}
458 protected virtual void reserved5 () {}
459 protected virtual void reserved6 () {}
460 protected virtual void reserved7 () {}
461}
462
463/**
464 * Describes the features and capabilities of a data import service.
465 *
466 * Developers of data import plugins provide a class that implements this interface.
467 */
468public interface Service : Object, Spit.Pluggable {
469 /**
470 * A factory method that instantiates and returns a new {@link DataImporter} object
471 * that this Service describes.
472 */
473 public abstract Spit.DataImports.DataImporter create_data_importer (Spit.DataImports.PluginHost host);
474
475 //
476 // For future expansion.
477 //
478 protected virtual void reserved0 () {}
479 protected virtual void reserved1 () {}
480 protected virtual void reserved2 () {}
481 protected virtual void reserved3 () {}
482 protected virtual void reserved4 () {}
483 protected virtual void reserved5 () {}
484 protected virtual void reserved6 () {}
485 protected virtual void reserved7 () {}
486}
487
488}
489
4900
=== modified file 'src/plugins/mk/interfaces.mk'
--- src/plugins/mk/interfaces.mk 2013-04-25 00:53:04 +0000
+++ src/plugins/mk/interfaces.mk 2014-08-28 06:03:26 +0000
@@ -2,8 +2,7 @@
2PLUGIN_INTERFACES := \2PLUGIN_INTERFACES := \
3 src/plugins/SpitInterfaces.vala \3 src/plugins/SpitInterfaces.vala \
4 src/plugins/TransitionsInterfaces.vala \4 src/plugins/TransitionsInterfaces.vala \
5 src/plugins/PublishingInterfaces.vala \5 src/plugins/PublishingInterfaces.vala
6 src/plugins/DataImportsInterfaces.vala
76
8PLUGIN_PKG_REQS := \7PLUGIN_PKG_REQS := \
9 gobject-2.0 \8 gobject-2.0 \
109
=== modified file 'src/plugins/mk/plugins.mk'
--- src/plugins/mk/plugins.mk 2012-02-02 22:56:06 +0000
+++ src/plugins/mk/plugins.mk 2014-08-28 06:03:26 +0000
@@ -15,8 +15,7 @@
15 SpitInterfaces.vala \15 SpitInterfaces.vala \
16 TransitionsInterfaces.vala \16 TransitionsInterfaces.vala \
17 StandardHostInterface.vala \17 StandardHostInterface.vala \
18 ManifestWidget.vala \18 ManifestWidget.vala
19 DataImportsInterfaces.vala
2019
21# Any unit this unit relies upon (and should be initialized before it's initialized) should20# Any unit this unit relies upon (and should be initialized before it's initialized) should
22# be listed here using its Vala namespace.21# be listed here using its Vala namespace.
2322
=== modified file 'src/tags/HierarchicalTagUtilities.vala'
--- src/tags/HierarchicalTagUtilities.vala 2014-08-08 21:13:09 +0000
+++ src/tags/HierarchicalTagUtilities.vala 2014-08-28 06:03:26 +0000
@@ -78,18 +78,6 @@
78 return components;78 return components;
79 }79 }
8080
81 /**
82 * given a list of path elements, create a fully qualified path string.
83 * For example if 'path_elements' is the list { "Animals", "Mammals", "Elephant" }
84 * the path "/Animals/Mammals/Elephant" will be returned
85 */
86 public static string? join_path_components (string[] path_components) {
87 if (path_components.length <= 0)
88 return null;
89 string tmp = string.joinv (Tag.PATH_SEPARATOR_STRING, path_components);
90 return string.joinv (Tag.PATH_SEPARATOR_STRING, { "", tmp });
91 }
92
93 public static string get_basename (string in_path) {81 public static string get_basename (string in_path) {
94 string path = flat_to_hierarchical (in_path);82 string path = flat_to_hierarchical (in_path);
9583
9684
=== modified file 'units.mk'
--- units.mk 2014-08-28 03:37:44 +0000
+++ units.mk 2014-08-28 06:03:26 +0000
@@ -24,8 +24,7 @@
24 tags \24 tags \
25 camera \25 camera \
26 searches \26 searches \
27 config \27 config
28 data_imports
2928
30# Name(s) of units that represent application entry points. These units will have init and29# Name(s) of units that represent application entry points. These units will have init and
31# termination entry points generated: Name.unitize_init() and Name.unitize_terminate(). These30# termination entry points generated: Name.unitize_init() and Name.unitize_terminate(). These

Subscribers

People subscribed via source and target branches

to all changes: