Merge lp:~codygarver/pantheon-photos/fix-1322215 into lp:~pantheon-photos/pantheon-photos/trunk
- fix-1322215
- Merge into 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 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
meese | Approve | ||
Review via email: mp+232505@code.launchpad.net |
Commit message
Drop shotwell-
Description of the change
To post a comment you must log in.
Revision history for this message
Cody Garver (codygarver) wrote : | # |
- 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
1 | === modified file 'plugins/plugins.mk' | |||
2 | --- plugins/plugins.mk 2013-11-14 22:27:35 +0000 | |||
3 | +++ plugins/plugins.mk 2014-08-28 06:03:26 +0000 | |||
4 | @@ -1,8 +1,7 @@ | |||
5 | 1 | 1 | ||
6 | 2 | PLUGINS := \ | 2 | PLUGINS := \ |
7 | 3 | shotwell-transitions \ | 3 | shotwell-transitions \ |
10 | 4 | shotwell-publishing \ | 4 | shotwell-publishing |
9 | 5 | shotwell-data-imports | ||
11 | 6 | 5 | ||
12 | 7 | PLUGINS_RC := \ | 6 | PLUGINS_RC := \ |
13 | 8 | plugins/shotwell-publishing/facebook.png \ | 7 | plugins/shotwell-publishing/facebook.png \ |
14 | @@ -24,7 +23,6 @@ | |||
15 | 24 | 23 | ||
16 | 25 | EXTRA_PLUGINS_RC := \ | 24 | EXTRA_PLUGINS_RC := \ |
17 | 26 | plugins/shotwell-publishing-extras/yandex_publish_model.glade \ | 25 | plugins/shotwell-publishing-extras/yandex_publish_model.glade \ |
18 | 27 | plugins/shotwell-data-imports/f-spot-24.png \ | ||
19 | 28 | plugins/shotwell-publishing-extras/tumblr.png \ | 26 | plugins/shotwell-publishing-extras/tumblr.png \ |
20 | 29 | plugins/shotwell-publishing-extras/tumblr_authentication_pane.glade \ | 27 | plugins/shotwell-publishing-extras/tumblr_authentication_pane.glade \ |
21 | 30 | plugins/shotwell-publishing-extras/tumblr_publishing_options_pane.glade | 28 | plugins/shotwell-publishing-extras/tumblr_publishing_options_pane.glade |
22 | 31 | 29 | ||
23 | === removed directory 'plugins/shotwell-data-imports' | |||
24 | === removed file 'plugins/shotwell-data-imports/FSpotDatabase.vala' | |||
25 | --- plugins/shotwell-data-imports/FSpotDatabase.vala 2014-08-08 21:13:09 +0000 | |||
26 | +++ plugins/shotwell-data-imports/FSpotDatabase.vala 1970-01-01 00:00:00 +0000 | |||
27 | @@ -1,58 +0,0 @@ | |||
28 | 1 | /* Copyright 2011-2013 Yorba Foundation | ||
29 | 2 | * | ||
30 | 3 | * This software is licensed under the GNU Lesser General Public License | ||
31 | 4 | * (version 2.1 or later). See the COPYING file in this distribution. | ||
32 | 5 | */ | ||
33 | 6 | |||
34 | 7 | namespace DataImports.FSpot.Db { | ||
35 | 8 | |||
36 | 9 | public const int64 NULL_ID = 0; | ||
37 | 10 | public const int64 INVALID_ID = -1; | ||
38 | 11 | |||
39 | 12 | /** | ||
40 | 13 | * Initialization method for the whole module. | ||
41 | 14 | */ | ||
42 | 15 | public void init () { | ||
43 | 16 | FSpotDatabaseBehavior.create_behavior_map (); | ||
44 | 17 | } | ||
45 | 18 | |||
46 | 19 | /** | ||
47 | 20 | * An object that is able to read from the F-Spot | ||
48 | 21 | * database and extract the relevant objects. | ||
49 | 22 | */ | ||
50 | 23 | public class FSpotDatabase : Object { | ||
51 | 24 | private Sqlite.Database fspot_db; | ||
52 | 25 | private FSpotMetaTable meta_table; | ||
53 | 26 | public FSpotPhotosTable photos_table; | ||
54 | 27 | public FSpotPhotoVersionsTable photo_versions_table; | ||
55 | 28 | public FSpotTagsTable tags_table; | ||
56 | 29 | public FSpotRollsTable rolls_table; | ||
57 | 30 | public int64 hidden_tag_id; | ||
58 | 31 | |||
59 | 32 | public FSpotDatabase (File db_file) throws DatabaseError, Spit.DataImports.DataImportError { | ||
60 | 33 | string filename = db_file.get_path (); | ||
61 | 34 | int res = Sqlite.Database.open_v2 (filename, out fspot_db, | ||
62 | 35 | Sqlite.OPEN_READONLY, null); | ||
63 | 36 | if (res != Sqlite.OK) | ||
64 | 37 | throw new DatabaseError.ERROR ("Unable to open F-Spot database %s: %d", filename, res); | ||
65 | 38 | meta_table = new FSpotMetaTable (fspot_db); | ||
66 | 39 | hidden_tag_id = meta_table.get_hidden_tag_id (); | ||
67 | 40 | |||
68 | 41 | FSpotDatabaseBehavior db_behavior = new FSpotDatabaseBehavior (get_version ()); | ||
69 | 42 | |||
70 | 43 | photos_table = new FSpotPhotosTable (fspot_db, db_behavior); | ||
71 | 44 | photo_versions_table = new FSpotPhotoVersionsTable (fspot_db, db_behavior); | ||
72 | 45 | tags_table = new FSpotTagsTable (fspot_db, db_behavior); | ||
73 | 46 | rolls_table = new FSpotRollsTable (fspot_db, db_behavior); | ||
74 | 47 | } | ||
75 | 48 | |||
76 | 49 | ~FSpotDatabase () { | ||
77 | 50 | } | ||
78 | 51 | |||
79 | 52 | private Utils.VersionNumber get_version () throws DatabaseError { | ||
80 | 53 | return new Utils.VersionNumber.from_string (meta_table.get_db_version ()); | ||
81 | 54 | } | ||
82 | 55 | } | ||
83 | 56 | |||
84 | 57 | } | ||
85 | 58 | |||
86 | 59 | 0 | ||
87 | === removed file 'plugins/shotwell-data-imports/FSpotDatabaseBehavior.vala' | |||
88 | --- plugins/shotwell-data-imports/FSpotDatabaseBehavior.vala 2014-08-08 21:13:09 +0000 | |||
89 | +++ plugins/shotwell-data-imports/FSpotDatabaseBehavior.vala 1970-01-01 00:00:00 +0000 | |||
90 | @@ -1,208 +0,0 @@ | |||
91 | 1 | /* Copyright 2011-2013 Yorba Foundation | ||
92 | 2 | * | ||
93 | 3 | * This software is licensed under the GNU Lesser General Public License | ||
94 | 4 | * (version 2.1 or later). See the COPYING file in this distribution. | ||
95 | 5 | */ | ||
96 | 6 | |||
97 | 7 | namespace DataImports.FSpot.Db { | ||
98 | 8 | |||
99 | 9 | private class FSpotBehaviorEntry { | ||
100 | 10 | private Utils.VersionNumber version; | ||
101 | 11 | private FSpotTableBehavior behavior; | ||
102 | 12 | |||
103 | 13 | public FSpotBehaviorEntry (Utils.VersionNumber version, FSpotTableBehavior behavior) { | ||
104 | 14 | this.version = version; | ||
105 | 15 | this.behavior = behavior; | ||
106 | 16 | } | ||
107 | 17 | |||
108 | 18 | public Utils.VersionNumber get_version () { | ||
109 | 19 | return version; | ||
110 | 20 | } | ||
111 | 21 | |||
112 | 22 | public FSpotTableBehavior get_behavior () { | ||
113 | 23 | return behavior; | ||
114 | 24 | } | ||
115 | 25 | } | ||
116 | 26 | |||
117 | 27 | /** | ||
118 | 28 | * A class that consolidates the behavior of all F-Spot tables (apart from meta) | ||
119 | 29 | * and is the one place to check whether the database version is supported. | ||
120 | 30 | */ | ||
121 | 31 | public class FSpotDatabaseBehavior : Object { | ||
122 | 32 | // Minimum unsupported version: any database from that version and above | ||
123 | 33 | // is not supported as it's too new and support has not been provided | ||
124 | 34 | // In practice, the code may work with future versions but this cannot be | ||
125 | 35 | // guaranteed as it hasn't been tested so it's probably better to just | ||
126 | 36 | // bomb out at that point rather than risk importing incorrect data | ||
127 | 37 | public static Utils.VersionNumber MIN_UNSUPPORTED_VERSION = | ||
128 | 38 | new Utils.VersionNumber ({ 19 }); | ||
129 | 39 | private static Gee.Map<string, Gee.List<FSpotBehaviorEntry>> behavior_map; | ||
130 | 40 | |||
131 | 41 | private FSpotTableBehavior<FSpotPhotoRow> photos_behavior; | ||
132 | 42 | private FSpotTableBehavior<FSpotTagRow> tags_behavior; | ||
133 | 43 | private FSpotTableBehavior<FSpotPhotoTagRow> photo_tags_behavior; | ||
134 | 44 | private FSpotTableBehavior<FSpotPhotoVersionRow> photo_versions_behavior; | ||
135 | 45 | private FSpotTableBehavior<FSpotRollRow> rolls_behavior; | ||
136 | 46 | |||
137 | 47 | public static void create_behavior_map () { | ||
138 | 48 | behavior_map = new Gee.HashMap<string, Gee.List<FSpotBehaviorEntry>> (); | ||
139 | 49 | // photos table | ||
140 | 50 | Gee.List<FSpotBehaviorEntry> photos_list = new Gee.ArrayList<FSpotBehaviorEntry> (); | ||
141 | 51 | // v0-4 | ||
142 | 52 | photos_list.add (new FSpotBehaviorEntry ( | ||
143 | 53 | new Utils.VersionNumber ({ 0 }), | ||
144 | 54 | FSpotPhotosV0Behavior.get_instance () | ||
145 | 55 | )); | ||
146 | 56 | // v5-6 | ||
147 | 57 | photos_list.add (new FSpotBehaviorEntry ( | ||
148 | 58 | new Utils.VersionNumber ({ 5 }), | ||
149 | 59 | FSpotPhotosV5Behavior.get_instance () | ||
150 | 60 | )); | ||
151 | 61 | // v7-10 | ||
152 | 62 | photos_list.add (new FSpotBehaviorEntry ( | ||
153 | 63 | new Utils.VersionNumber ({ 7 }), | ||
154 | 64 | FSpotPhotosV7Behavior.get_instance () | ||
155 | 65 | )); | ||
156 | 66 | // v11-15 | ||
157 | 67 | photos_list.add (new FSpotBehaviorEntry ( | ||
158 | 68 | new Utils.VersionNumber ({ 11 }), | ||
159 | 69 | FSpotPhotosV11Behavior.get_instance () | ||
160 | 70 | )); | ||
161 | 71 | // v16 | ||
162 | 72 | photos_list.add (new FSpotBehaviorEntry ( | ||
163 | 73 | new Utils.VersionNumber ({ 16 }), | ||
164 | 74 | FSpotPhotosV16Behavior.get_instance () | ||
165 | 75 | )); | ||
166 | 76 | // v17 | ||
167 | 77 | photos_list.add (new FSpotBehaviorEntry ( | ||
168 | 78 | new Utils.VersionNumber ({ 17 }), | ||
169 | 79 | FSpotPhotosV17Behavior.get_instance () | ||
170 | 80 | )); | ||
171 | 81 | // v18+ | ||
172 | 82 | photos_list.add (new FSpotBehaviorEntry ( | ||
173 | 83 | new Utils.VersionNumber ({ 18 }), | ||
174 | 84 | FSpotPhotosV18Behavior.get_instance () | ||
175 | 85 | )); | ||
176 | 86 | behavior_map.set (FSpotPhotosTable.TABLE_NAME, photos_list); | ||
177 | 87 | // tags table | ||
178 | 88 | Gee.List<FSpotBehaviorEntry> tags_list = new Gee.ArrayList<FSpotBehaviorEntry> (); | ||
179 | 89 | // v0+ | ||
180 | 90 | tags_list.add (new FSpotBehaviorEntry ( | ||
181 | 91 | new Utils.VersionNumber ({ 0 }), | ||
182 | 92 | FSpotTagsV0Behavior.get_instance () | ||
183 | 93 | )); | ||
184 | 94 | behavior_map.set (FSpotTagsTable.TABLE_NAME, tags_list); | ||
185 | 95 | // photo_tags table | ||
186 | 96 | Gee.List<FSpotBehaviorEntry> photo_tags_list = new Gee.ArrayList<FSpotBehaviorEntry> (); | ||
187 | 97 | // v0+ | ||
188 | 98 | photo_tags_list.add (new FSpotBehaviorEntry ( | ||
189 | 99 | new Utils.VersionNumber ({ 0 }), | ||
190 | 100 | FSpotPhotoTagsV0Behavior.get_instance () | ||
191 | 101 | )); | ||
192 | 102 | behavior_map.set (FSpotPhotoTagsTable.TABLE_NAME, photo_tags_list); | ||
193 | 103 | // photo_versions table | ||
194 | 104 | Gee.List<FSpotBehaviorEntry> photo_versions_list = new Gee.ArrayList<FSpotBehaviorEntry> (); | ||
195 | 105 | // v0-8 | ||
196 | 106 | photo_versions_list.add (new FSpotBehaviorEntry ( | ||
197 | 107 | new Utils.VersionNumber ({ 0 }), | ||
198 | 108 | FSpotPhotoVersionsV0Behavior.get_instance () | ||
199 | 109 | )); | ||
200 | 110 | // v9-15 | ||
201 | 111 | photo_versions_list.add (new FSpotBehaviorEntry ( | ||
202 | 112 | new Utils.VersionNumber ({ 9 }), | ||
203 | 113 | FSpotPhotoVersionsV9Behavior.get_instance () | ||
204 | 114 | )); | ||
205 | 115 | // v16 | ||
206 | 116 | photo_versions_list.add (new FSpotBehaviorEntry ( | ||
207 | 117 | new Utils.VersionNumber ({ 16 }), | ||
208 | 118 | FSpotPhotoVersionsV16Behavior.get_instance () | ||
209 | 119 | )); | ||
210 | 120 | // v17 | ||
211 | 121 | photo_versions_list.add (new FSpotBehaviorEntry ( | ||
212 | 122 | new Utils.VersionNumber ({ 17 }), | ||
213 | 123 | FSpotPhotoVersionsV17Behavior.get_instance () | ||
214 | 124 | )); | ||
215 | 125 | // v18+ | ||
216 | 126 | photo_versions_list.add (new FSpotBehaviorEntry ( | ||
217 | 127 | new Utils.VersionNumber ({ 18 }), | ||
218 | 128 | FSpotPhotoVersionsV18Behavior.get_instance () | ||
219 | 129 | )); | ||
220 | 130 | behavior_map.set (FSpotPhotoVersionsTable.TABLE_NAME, photo_versions_list); | ||
221 | 131 | // rolls table | ||
222 | 132 | Gee.List<FSpotBehaviorEntry> rolls_list = new Gee.ArrayList<FSpotBehaviorEntry> (); | ||
223 | 133 | // v0-4 | ||
224 | 134 | rolls_list.add (new FSpotBehaviorEntry ( | ||
225 | 135 | new Utils.VersionNumber ({ 0 }), | ||
226 | 136 | FSpotRollsV0Behavior.get_instance () | ||
227 | 137 | )); | ||
228 | 138 | // v5+ | ||
229 | 139 | rolls_list.add (new FSpotBehaviorEntry ( | ||
230 | 140 | new Utils.VersionNumber ({ 5 }), | ||
231 | 141 | FSpotRollsV5Behavior.get_instance () | ||
232 | 142 | )); | ||
233 | 143 | behavior_map.set (FSpotRollsTable.TABLE_NAME, rolls_list); | ||
234 | 144 | } | ||
235 | 145 | |||
236 | 146 | public static FSpotTableBehavior? find_behavior (string table_name, Utils.VersionNumber version) { | ||
237 | 147 | FSpotTableBehavior behavior = null; | ||
238 | 148 | Gee.List<FSpotBehaviorEntry> behavior_list = behavior_map.get (table_name); | ||
239 | 149 | if (behavior_list != null) | ||
240 | 150 | foreach (FSpotBehaviorEntry entry in behavior_list) { | ||
241 | 151 | if (version.compare_to (entry.get_version ()) >= 0) | ||
242 | 152 | behavior = entry.get_behavior (); | ||
243 | 153 | } | ||
244 | 154 | else | ||
245 | 155 | warning ("Could not find behavior list for table %s", table_name); | ||
246 | 156 | return behavior; | ||
247 | 157 | |||
248 | 158 | } | ||
249 | 159 | public FSpotDatabaseBehavior (Utils.VersionNumber version) throws Spit.DataImports.DataImportError { | ||
250 | 160 | if (version.compare_to (MIN_UNSUPPORTED_VERSION) >= 0) | ||
251 | 161 | throw new Spit.DataImports.DataImportError.UNSUPPORTED_VERSION ("Version %s is not yet supported", version.to_string ()); | ||
252 | 162 | |||
253 | 163 | FSpotTableBehavior? photos_generic_behavior = find_behavior (FSpotPhotosTable.TABLE_NAME, version); | ||
254 | 164 | if (photos_generic_behavior != null) | ||
255 | 165 | photos_behavior = photos_generic_behavior as FSpotTableBehavior<FSpotPhotoRow>; | ||
256 | 166 | FSpotTableBehavior? tags_generic_behavior = find_behavior (FSpotTagsTable.TABLE_NAME, version); | ||
257 | 167 | if (tags_generic_behavior != null) | ||
258 | 168 | tags_behavior = tags_generic_behavior as FSpotTableBehavior<FSpotTagRow>; | ||
259 | 169 | FSpotTableBehavior? photo_tags_generic_behavior = find_behavior (FSpotPhotoTagsTable.TABLE_NAME, version); | ||
260 | 170 | if (photo_tags_generic_behavior != null) | ||
261 | 171 | photo_tags_behavior = photo_tags_generic_behavior as FSpotTableBehavior<FSpotPhotoTagRow>; | ||
262 | 172 | FSpotTableBehavior? photo_versions_generic_behavior = find_behavior (FSpotPhotoVersionsTable.TABLE_NAME, version); | ||
263 | 173 | if (photo_versions_generic_behavior != null) | ||
264 | 174 | photo_versions_behavior = photo_versions_generic_behavior as FSpotTableBehavior<FSpotPhotoVersionRow>; | ||
265 | 175 | FSpotTableBehavior? rolls_generic_behavior = find_behavior (FSpotRollsTable.TABLE_NAME, version); | ||
266 | 176 | if (rolls_generic_behavior != null) | ||
267 | 177 | rolls_behavior = rolls_generic_behavior as FSpotTableBehavior<FSpotRollRow>; | ||
268 | 178 | |||
269 | 179 | if (photos_behavior == null || tags_behavior == null || | ||
270 | 180 | photo_tags_behavior == null || photo_versions_behavior == null || | ||
271 | 181 | rolls_behavior == null | ||
272 | 182 | ) | ||
273 | 183 | throw new Spit.DataImports.DataImportError.UNSUPPORTED_VERSION ("Version %s is not supported", version.to_string ()); | ||
274 | 184 | } | ||
275 | 185 | |||
276 | 186 | public FSpotTableBehavior<FSpotPhotoRow> get_photos_behavior () { | ||
277 | 187 | return photos_behavior; | ||
278 | 188 | } | ||
279 | 189 | |||
280 | 190 | public FSpotTableBehavior<FSpotTagRow> get_tags_behavior () { | ||
281 | 191 | return tags_behavior; | ||
282 | 192 | } | ||
283 | 193 | |||
284 | 194 | public FSpotTableBehavior<FSpotPhotoTagRow> get_photo_tags_behavior () { | ||
285 | 195 | return photo_tags_behavior; | ||
286 | 196 | } | ||
287 | 197 | |||
288 | 198 | public FSpotTableBehavior<FSpotPhotoVersionRow> get_photo_versions_behavior () { | ||
289 | 199 | return photo_versions_behavior; | ||
290 | 200 | } | ||
291 | 201 | |||
292 | 202 | public FSpotTableBehavior<FSpotRollRow> get_rolls_behavior () { | ||
293 | 203 | return rolls_behavior; | ||
294 | 204 | } | ||
295 | 205 | } | ||
296 | 206 | |||
297 | 207 | } | ||
298 | 208 | |||
299 | 209 | 0 | ||
300 | === removed file 'plugins/shotwell-data-imports/FSpotDatabaseTable.vala' | |||
301 | --- plugins/shotwell-data-imports/FSpotDatabaseTable.vala 2014-08-08 21:13:09 +0000 | |||
302 | +++ plugins/shotwell-data-imports/FSpotDatabaseTable.vala 1970-01-01 00:00:00 +0000 | |||
303 | @@ -1,54 +0,0 @@ | |||
304 | 1 | /* Copyright 2009-2013 Yorba Foundation | ||
305 | 2 | * | ||
306 | 3 | * This software is licensed under the GNU LGPL (version 2.1 or later). | ||
307 | 4 | * See the COPYING file in this distribution. | ||
308 | 5 | */ | ||
309 | 6 | |||
310 | 7 | namespace DataImports.FSpot.Db { | ||
311 | 8 | |||
312 | 9 | /** | ||
313 | 10 | * This class represents a generic F-Spot table. | ||
314 | 11 | */ | ||
315 | 12 | public abstract class FSpotDatabaseTable<T> : ImportableDatabaseTable { | ||
316 | 13 | protected unowned Sqlite.Database fspot_db; | ||
317 | 14 | protected FSpotTableBehavior<T> behavior; | ||
318 | 15 | |||
319 | 16 | public FSpotDatabaseTable (Sqlite.Database db) { | ||
320 | 17 | this.fspot_db = db; | ||
321 | 18 | } | ||
322 | 19 | |||
323 | 20 | public void set_behavior (FSpotTableBehavior<T> behavior) { | ||
324 | 21 | this.behavior = behavior; | ||
325 | 22 | set_table_name (behavior.get_table_name ()); | ||
326 | 23 | } | ||
327 | 24 | |||
328 | 25 | public FSpotTableBehavior<T> get_behavior () { | ||
329 | 26 | return behavior; | ||
330 | 27 | } | ||
331 | 28 | |||
332 | 29 | protected string get_joined_column_list (bool with_table = false) { | ||
333 | 30 | string[] columns = behavior.list_columns (); | ||
334 | 31 | if (with_table) | ||
335 | 32 | for (int i = 0; i < columns.length; i++) | ||
336 | 33 | columns[i] = "%s.%s".printf (table_name, columns[i]); | ||
337 | 34 | return string.joinv (", ", columns); | ||
338 | 35 | } | ||
339 | 36 | |||
340 | 37 | protected int select_all (out Sqlite.Statement stmt) throws DatabaseError { | ||
341 | 38 | string column_list = get_joined_column_list (); | ||
342 | 39 | string sql = "SELECT %s FROM %s".printf (column_list, table_name); | ||
343 | 40 | |||
344 | 41 | int res = fspot_db.prepare_v2 (sql, -1, out stmt); | ||
345 | 42 | if (res != Sqlite.OK) | ||
346 | 43 | throw_error ("Statement failed: %s".printf (sql), res); | ||
347 | 44 | |||
348 | 45 | res = stmt.step (); | ||
349 | 46 | if (res != Sqlite.ROW && res != Sqlite.DONE) | ||
350 | 47 | throw_error ("select_all %s %s".printf (table_name, column_list), res); | ||
351 | 48 | |||
352 | 49 | return res; | ||
353 | 50 | } | ||
354 | 51 | } | ||
355 | 52 | |||
356 | 53 | } | ||
357 | 54 | |||
358 | 55 | 0 | ||
359 | === removed file 'plugins/shotwell-data-imports/FSpotImporter.vala' | |||
360 | --- plugins/shotwell-data-imports/FSpotImporter.vala 2014-08-08 21:13:09 +0000 | |||
361 | +++ plugins/shotwell-data-imports/FSpotImporter.vala 1970-01-01 00:00:00 +0000 | |||
362 | @@ -1,567 +0,0 @@ | |||
363 | 1 | /* Copyright 2009-2013 Yorba Foundation | ||
364 | 2 | * | ||
365 | 3 | * This software is licensed under the GNU Lesser General Public License | ||
366 | 4 | * (version 2.1 or later). See the COPYING file in this distribution. | ||
367 | 5 | */ | ||
368 | 6 | |||
369 | 7 | public class FSpotService : Object, Spit.Pluggable, Spit.DataImports.Service { | ||
370 | 8 | private const string ICON_FILENAME = "f-spot-24.png"; | ||
371 | 9 | |||
372 | 10 | private static Gdk.Pixbuf[] icon_pixbuf_set = null; | ||
373 | 11 | |||
374 | 12 | public FSpotService (GLib.File resource_directory) { | ||
375 | 13 | // initialize the database layer | ||
376 | 14 | DataImports.FSpot.Db.init (); | ||
377 | 15 | if (icon_pixbuf_set == null) | ||
378 | 16 | icon_pixbuf_set = Resources.load_icon_set (resource_directory.get_child (ICON_FILENAME)); | ||
379 | 17 | } | ||
380 | 18 | |||
381 | 19 | public int get_pluggable_interface (int min_host_interface, int max_host_interface) { | ||
382 | 20 | return Spit.negotiate_interfaces (min_host_interface, max_host_interface, | ||
383 | 21 | Spit.DataImports.CURRENT_INTERFACE); | ||
384 | 22 | } | ||
385 | 23 | |||
386 | 24 | public unowned string get_id () { | ||
387 | 25 | return "org.yorba.shotwell.dataimports.fspot"; | ||
388 | 26 | } | ||
389 | 27 | |||
390 | 28 | public unowned string get_pluggable_name () { | ||
391 | 29 | return "F-Spot"; | ||
392 | 30 | } | ||
393 | 31 | |||
394 | 32 | public void get_info (ref Spit.PluggableInfo info) { | ||
395 | 33 | info.authors = "Bruno Girin"; | ||
396 | 34 | info.copyright = _ ("Copyright 2009-2013 Yorba Foundation"); | ||
397 | 35 | info.translators = Resources.TRANSLATORS; | ||
398 | 36 | info.version = _VERSION; | ||
399 | 37 | info.website_name = Resources.WEBSITE_NAME; | ||
400 | 38 | info.website_url = Resources.WEBSITE_URL; | ||
401 | 39 | info.is_license_wordwrapped = false; | ||
402 | 40 | info.license = Resources.LICENSE; | ||
403 | 41 | info.icons = icon_pixbuf_set; | ||
404 | 42 | } | ||
405 | 43 | |||
406 | 44 | public void activation (bool enabled) { | ||
407 | 45 | } | ||
408 | 46 | |||
409 | 47 | public Spit.DataImports.DataImporter create_data_importer (Spit.DataImports.PluginHost host) { | ||
410 | 48 | return new DataImports.FSpot.FSpotDataImporter (this, host); | ||
411 | 49 | } | ||
412 | 50 | } | ||
413 | 51 | |||
414 | 52 | namespace DataImports.FSpot { | ||
415 | 53 | |||
416 | 54 | internal const string SERVICE_NAME = "F-Spot"; | ||
417 | 55 | internal const string SERVICE_WELCOME_MESSAGE = | ||
418 | 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."); | ||
419 | 57 | internal const string SERVICE_WELCOME_MESSAGE_FILE_ONLY = | ||
420 | 58 | _ ("Welcome to the F-Spot library import service.\n\nPlease select an F-Spot database file."); | ||
421 | 59 | internal const string FILE_IMPORT_LABEL = | ||
422 | 60 | _ ("Manually select an F-Spot database file to import:"); | ||
423 | 61 | internal const string ERROR_CANT_OPEN_DB_FILE = | ||
424 | 62 | _ ("Cannot open the selected F-Spot database file: the file does not exist or is not an F-Spot database"); | ||
425 | 63 | internal const string ERROR_UNSUPPORTED_DB_VERSION = | ||
426 | 64 | _ ("Cannot open the selected F-Spot database file: this version of the F-Spot database is not supported by Shotwell"); | ||
427 | 65 | internal const string ERROR_CANT_READ_TAGS_TABLE = | ||
428 | 66 | _ ("Cannot read the selected F-Spot database file: error while reading tags table"); | ||
429 | 67 | internal const string ERROR_CANT_READ_PHOTOS_TABLE = | ||
430 | 68 | _ ("Cannot read the selected F-Spot database file: error while reading photos table"); | ||
431 | 69 | internal const string MESSAGE_FINAL_SCREEN = | ||
432 | 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."); | ||
433 | 71 | |||
434 | 72 | public class FSpotImportableLibrary : Spit.DataImports.ImportableLibrary, GLib.Object { | ||
435 | 73 | private File db_file; | ||
436 | 74 | |||
437 | 75 | public FSpotImportableLibrary (File db_file) { | ||
438 | 76 | this.db_file = db_file; | ||
439 | 77 | } | ||
440 | 78 | |||
441 | 79 | public File get_db_file () { | ||
442 | 80 | return db_file; | ||
443 | 81 | } | ||
444 | 82 | |||
445 | 83 | public string get_display_name () { | ||
446 | 84 | return _ ("F-Spot library: %s").printf (db_file.get_path ()); | ||
447 | 85 | } | ||
448 | 86 | } | ||
449 | 87 | |||
450 | 88 | public class FSpotImportableItem : Spit.DataImports.ImportableMediaItem, GLib.Object { | ||
451 | 89 | private DataImports.FSpot.Db.FSpotPhotoRow photo_row; | ||
452 | 90 | private DataImports.FSpot.Db.FSpotPhotoVersionRow? photo_version_row; | ||
453 | 91 | private DataImports.FSpot.Db.FSpotRollRow? roll_row; | ||
454 | 92 | private FSpotImportableTag[] tags; | ||
455 | 93 | private FSpotImportableEvent? event; | ||
456 | 94 | private FSpotImportableRating rating; | ||
457 | 95 | private string folder_path; | ||
458 | 96 | private string filename; | ||
459 | 97 | |||
460 | 98 | public FSpotImportableItem ( | ||
461 | 99 | DataImports.FSpot.Db.FSpotPhotoRow photo_row, | ||
462 | 100 | DataImports.FSpot.Db.FSpotPhotoVersionRow? photo_version_row, | ||
463 | 101 | DataImports.FSpot.Db.FSpotRollRow? roll_row, | ||
464 | 102 | FSpotImportableTag[] tags, | ||
465 | 103 | FSpotImportableEvent? event, | ||
466 | 104 | bool is_hidden, | ||
467 | 105 | bool is_favorite | ||
468 | 106 | ) { | ||
469 | 107 | this.photo_row = photo_row; | ||
470 | 108 | this.photo_version_row = photo_version_row; | ||
471 | 109 | this.roll_row = roll_row; | ||
472 | 110 | this.tags = tags; | ||
473 | 111 | this.event = event; | ||
474 | 112 | if (photo_row.rating > 0) | ||
475 | 113 | this.rating = new FSpotImportableRating (photo_row.rating); | ||
476 | 114 | else if (is_hidden) | ||
477 | 115 | this.rating = new FSpotImportableRating (FSpotImportableRating.REJECTED); | ||
478 | 116 | else if (is_favorite) | ||
479 | 117 | this.rating = new FSpotImportableRating (5); | ||
480 | 118 | else | ||
481 | 119 | this.rating = new FSpotImportableRating (FSpotImportableRating.UNRATED); | ||
482 | 120 | |||
483 | 121 | // store path and filename | ||
484 | 122 | folder_path = (photo_version_row != null) ? | ||
485 | 123 | photo_version_row.base_path.get_path () : | ||
486 | 124 | photo_row.base_path.get_path (); | ||
487 | 125 | filename = (photo_version_row != null) ? | ||
488 | 126 | photo_version_row.filename : | ||
489 | 127 | photo_row.filename; | ||
490 | 128 | |||
491 | 129 | // In theory, neither field should be null at that point but belts | ||
492 | 130 | // and braces don't hurt | ||
493 | 131 | if (folder_path != null && filename != null) { | ||
494 | 132 | // check if file exist and if not decode as URL | ||
495 | 133 | File photo = File.new_for_path (folder_path).get_child (filename); | ||
496 | 134 | |||
497 | 135 | // If file not found, parse as URI and store back | ||
498 | 136 | if (!photo.query_exists ()) { | ||
499 | 137 | folder_path = decode_url (folder_path); | ||
500 | 138 | filename = decode_url (filename); | ||
501 | 139 | } | ||
502 | 140 | } | ||
503 | 141 | } | ||
504 | 142 | |||
505 | 143 | public Spit.DataImports.ImportableTag[] get_tags () { | ||
506 | 144 | Spit.DataImports.ImportableTag[] importable_tags = new Spit.DataImports.ImportableTag[0]; | ||
507 | 145 | foreach (FSpotImportableTag tag in tags) | ||
508 | 146 | importable_tags += tag; | ||
509 | 147 | return importable_tags; | ||
510 | 148 | } | ||
511 | 149 | |||
512 | 150 | public Spit.DataImports.ImportableEvent? get_event () { | ||
513 | 151 | return event; | ||
514 | 152 | } | ||
515 | 153 | |||
516 | 154 | public string get_folder_path () { | ||
517 | 155 | return folder_path; | ||
518 | 156 | } | ||
519 | 157 | |||
520 | 158 | public string get_filename () { | ||
521 | 159 | return filename; | ||
522 | 160 | } | ||
523 | 161 | |||
524 | 162 | public string? get_title () { | ||
525 | 163 | return (photo_row.description == null || photo_row.description == "") ? null : photo_row.description; | ||
526 | 164 | } | ||
527 | 165 | |||
528 | 166 | public Spit.DataImports.ImportableRating get_rating () { | ||
529 | 167 | return rating; | ||
530 | 168 | } | ||
531 | 169 | |||
532 | 170 | private string decode_url (string url) { | ||
533 | 171 | StringBuilder builder = new StringBuilder (); | ||
534 | 172 | for (int idx = 0; idx < url.length; ) { | ||
535 | 173 | int cidx = url.index_of_char ('%', idx); | ||
536 | 174 | if (cidx > idx) { | ||
537 | 175 | builder.append (url.slice (idx, cidx)); | ||
538 | 176 | } | ||
539 | 177 | if (cidx >= 0) { | ||
540 | 178 | if (cidx < url.length - 2) { | ||
541 | 179 | char c1 = url.get (cidx + 1); | ||
542 | 180 | char c2 = url.get (cidx + 2); | ||
543 | 181 | if (c1.isxdigit () && c1.isxdigit ()) { | ||
544 | 182 | int ccode = 0x10 * c1.xdigit_value () + c2.xdigit_value (); | ||
545 | 183 | builder.append_c ((char)ccode); | ||
546 | 184 | } | ||
547 | 185 | idx = cidx + 3; | ||
548 | 186 | } else { | ||
549 | 187 | idx = cidx + 1; | ||
550 | 188 | } | ||
551 | 189 | } else { | ||
552 | 190 | builder.append (url.substring (idx)); | ||
553 | 191 | idx = url.length; | ||
554 | 192 | } | ||
555 | 193 | } | ||
556 | 194 | return builder.str; | ||
557 | 195 | } | ||
558 | 196 | } | ||
559 | 197 | |||
560 | 198 | public class FSpotImportableTag : Spit.DataImports.ImportableTag, GLib.Object { | ||
561 | 199 | private DataImports.FSpot.Db.FSpotTagRow row; | ||
562 | 200 | private FSpotImportableTag? parent; | ||
563 | 201 | |||
564 | 202 | public FSpotImportableTag (DataImports.FSpot.Db.FSpotTagRow row, FSpotImportableTag? parent) { | ||
565 | 203 | this.row = row; | ||
566 | 204 | this.parent = parent; | ||
567 | 205 | } | ||
568 | 206 | |||
569 | 207 | public int64 get_id () { | ||
570 | 208 | return row.tag_id; | ||
571 | 209 | } | ||
572 | 210 | |||
573 | 211 | public string get_name () { | ||
574 | 212 | return row.name; | ||
575 | 213 | } | ||
576 | 214 | |||
577 | 215 | public Spit.DataImports.ImportableTag? get_parent () { | ||
578 | 216 | return parent; | ||
579 | 217 | } | ||
580 | 218 | |||
581 | 219 | public FSpotImportableTag? get_fspot_parent () { | ||
582 | 220 | return parent; | ||
583 | 221 | } | ||
584 | 222 | |||
585 | 223 | public string get_stock_icon () { | ||
586 | 224 | return row.stock_icon; | ||
587 | 225 | } | ||
588 | 226 | |||
589 | 227 | public bool is_stock () { | ||
590 | 228 | return (row.stock_icon.has_prefix (DataImports.FSpot.Db.FSpotTagsTable.PREFIX_STOCK_ICON)); | ||
591 | 229 | } | ||
592 | 230 | |||
593 | 231 | public FSpotImportableEvent to_event () { | ||
594 | 232 | return new FSpotImportableEvent (this.row); | ||
595 | 233 | } | ||
596 | 234 | } | ||
597 | 235 | |||
598 | 236 | public class FSpotImportableEvent : Spit.DataImports.ImportableEvent, GLib.Object { | ||
599 | 237 | private DataImports.FSpot.Db.FSpotTagRow row; | ||
600 | 238 | |||
601 | 239 | public FSpotImportableEvent (DataImports.FSpot.Db.FSpotTagRow row) { | ||
602 | 240 | this.row = row; | ||
603 | 241 | } | ||
604 | 242 | |||
605 | 243 | public string get_name () { | ||
606 | 244 | return row.name; | ||
607 | 245 | } | ||
608 | 246 | } | ||
609 | 247 | |||
610 | 248 | public class FSpotImportableRating : Spit.DataImports.ImportableRating, GLib.Object { | ||
611 | 249 | public static const int REJECTED = -1; | ||
612 | 250 | public static const int UNRATED = 0; | ||
613 | 251 | |||
614 | 252 | private int rating_value; | ||
615 | 253 | |||
616 | 254 | public FSpotImportableRating (int rating_value) { | ||
617 | 255 | if (rating_value < -1) | ||
618 | 256 | rating_value = -1; | ||
619 | 257 | else if (rating_value > 5) | ||
620 | 258 | rating_value = 5; | ||
621 | 259 | this.rating_value = rating_value; | ||
622 | 260 | } | ||
623 | 261 | |||
624 | 262 | public bool is_rejected () { | ||
625 | 263 | return (rating_value == REJECTED); | ||
626 | 264 | } | ||
627 | 265 | |||
628 | 266 | public bool is_unrated () { | ||
629 | 267 | return (rating_value == UNRATED); | ||
630 | 268 | } | ||
631 | 269 | |||
632 | 270 | public int get_value () { | ||
633 | 271 | return rating_value; | ||
634 | 272 | } | ||
635 | 273 | } | ||
636 | 274 | |||
637 | 275 | internal class FSpotTagsCache : Object { | ||
638 | 276 | private DataImports.FSpot.Db.FSpotTagsTable tags_table; | ||
639 | 277 | private Gee.HashMap < int64?, FSpotImportableTag > tags_map; | ||
640 | 278 | |||
641 | 279 | public FSpotTagsCache (DataImports.FSpot.Db.FSpotTagsTable tags_table) throws DatabaseError { | ||
642 | 280 | this.tags_table = tags_table; | ||
643 | 281 | tags_map = new Gee.HashMap < int64?, FSpotImportableTag > (); | ||
644 | 282 | } | ||
645 | 283 | |||
646 | 284 | public FSpotImportableTag get_tag (DataImports.FSpot.Db.FSpotTagRow tag_row) throws DatabaseError { | ||
647 | 285 | FSpotImportableTag? tag = tags_map.get (tag_row.tag_id); | ||
648 | 286 | if (tag != null) { | ||
649 | 287 | return tag; | ||
650 | 288 | } else { | ||
651 | 289 | FSpotImportableTag? parent_tag = get_tag_from_id (tag_row.category_id); | ||
652 | 290 | FSpotImportableTag new_tag = new FSpotImportableTag (tag_row, parent_tag); | ||
653 | 291 | tags_map[tag_row.tag_id] = new_tag; | ||
654 | 292 | return new_tag; | ||
655 | 293 | } | ||
656 | 294 | } | ||
657 | 295 | |||
658 | 296 | private FSpotImportableTag? get_tag_from_id (int64 tag_id) throws DatabaseError { | ||
659 | 297 | // check whether the tag ID is valid first, otherwise return null | ||
660 | 298 | if (tag_id < 1) | ||
661 | 299 | return null; | ||
662 | 300 | FSpotImportableTag? tag = tags_map.get (tag_id); | ||
663 | 301 | if (tag != null) | ||
664 | 302 | return tag; | ||
665 | 303 | DataImports.FSpot.Db.FSpotTagRow? tag_row = tags_table.get_by_id (tag_id); | ||
666 | 304 | if (tag_row != null) { | ||
667 | 305 | FSpotImportableTag? parent_tag = get_tag_from_id (tag_row.category_id); | ||
668 | 306 | FSpotImportableTag new_tag = new FSpotImportableTag (tag_row, parent_tag); | ||
669 | 307 | tags_map[tag_id] = new_tag; | ||
670 | 308 | return new_tag; | ||
671 | 309 | } | ||
672 | 310 | return null; | ||
673 | 311 | } | ||
674 | 312 | } | ||
675 | 313 | |||
676 | 314 | public class FSpotDataImporter : Spit.DataImports.DataImporter, GLib.Object { | ||
677 | 315 | |||
678 | 316 | private weak Spit.DataImports.PluginHost host = null; | ||
679 | 317 | private weak Spit.DataImports.Service service = null; | ||
680 | 318 | private bool running = false; | ||
681 | 319 | |||
682 | 320 | public FSpotDataImporter (Spit.DataImports.Service service, | ||
683 | 321 | Spit.DataImports.PluginHost host) { | ||
684 | 322 | debug ("FSpotDataImporter instantiated."); | ||
685 | 323 | this.service = service; | ||
686 | 324 | this.host = host; | ||
687 | 325 | } | ||
688 | 326 | |||
689 | 327 | private bool is_running () { | ||
690 | 328 | return running; | ||
691 | 329 | } | ||
692 | 330 | |||
693 | 331 | public Spit.DataImports.Service get_service () { | ||
694 | 332 | return service; | ||
695 | 333 | } | ||
696 | 334 | |||
697 | 335 | public void start () { | ||
698 | 336 | if (is_running ()) | ||
699 | 337 | return; | ||
700 | 338 | |||
701 | 339 | debug ("FSpotDataImporter: starting interaction."); | ||
702 | 340 | |||
703 | 341 | running = true; | ||
704 | 342 | |||
705 | 343 | do_discover_importable_libraries (); | ||
706 | 344 | } | ||
707 | 345 | |||
708 | 346 | public void stop () { | ||
709 | 347 | debug ("FSpotDataImporter: stopping interaction."); | ||
710 | 348 | |||
711 | 349 | running = false; | ||
712 | 350 | } | ||
713 | 351 | |||
714 | 352 | // Actions and event implementation | ||
715 | 353 | |||
716 | 354 | /** | ||
717 | 355 | * Action that discovers importable libraries based on standard locations. | ||
718 | 356 | */ | ||
719 | 357 | private void do_discover_importable_libraries () { | ||
720 | 358 | Spit.DataImports.ImportableLibrary[] discovered_libraries = | ||
721 | 359 | new Spit.DataImports.ImportableLibrary[0]; | ||
722 | 360 | |||
723 | 361 | File[] db_files = { | ||
724 | 362 | // where the DB is in Ubuntu Lucid | ||
725 | 363 | File.new_for_path (Environment.get_user_config_dir ()). | ||
726 | 364 | get_child ("f-spot").get_child ("photos.db"), | ||
727 | 365 | // where it seems to be in Ubuntu Jaunty | ||
728 | 366 | File.new_for_path (Environment.get_home_dir ()).get_child (".gnome2"). | ||
729 | 367 | get_child ("f-spot").get_child ("photos.db"), | ||
730 | 368 | // where it should really be if it followed the XDG spec | ||
731 | 369 | File.new_for_path (Environment.get_user_data_dir ()). | ||
732 | 370 | get_child ("f-spot").get_child ("photos.db") | ||
733 | 371 | }; | ||
734 | 372 | |||
735 | 373 | foreach (File db_file in db_files) { | ||
736 | 374 | if (db_file.query_exists (null)) { | ||
737 | 375 | discovered_libraries += new FSpotImportableLibrary (db_file); | ||
738 | 376 | message ("Discovered importable library: %s", db_file.get_path ()); | ||
739 | 377 | } | ||
740 | 378 | } | ||
741 | 379 | |||
742 | 380 | host.install_library_selection_pane ( | ||
743 | 381 | (discovered_libraries.length > 0 ? SERVICE_WELCOME_MESSAGE : SERVICE_WELCOME_MESSAGE_FILE_ONLY), | ||
744 | 382 | discovered_libraries, | ||
745 | 383 | FILE_IMPORT_LABEL | ||
746 | 384 | ); | ||
747 | 385 | } | ||
748 | 386 | |||
749 | 387 | public void on_library_selected (Spit.DataImports.ImportableLibrary library) { | ||
750 | 388 | on_file_selected (((FSpotImportableLibrary)library).get_db_file ()); | ||
751 | 389 | } | ||
752 | 390 | |||
753 | 391 | public void on_file_selected (File file) { | ||
754 | 392 | DataImports.FSpot.Db.FSpotDatabase database; | ||
755 | 393 | FSpotTagsCache tags_cache; | ||
756 | 394 | Gee.ArrayList<DataImports.FSpot.Db.FSpotPhotoRow> all_photos; | ||
757 | 395 | double progress_delta_per_photo = 1.0; | ||
758 | 396 | double progress_plugin_to_host_ratio = 0.5; | ||
759 | 397 | double current_progress = 0.0; | ||
760 | 398 | try { | ||
761 | 399 | database = new DataImports.FSpot.Db.FSpotDatabase (file); | ||
762 | 400 | } catch (DatabaseError e) { | ||
763 | 401 | debug ("FSpotDataImporter: Can't open database file: %s".printf (e.message)); | ||
764 | 402 | host.post_error_message (ERROR_CANT_OPEN_DB_FILE); | ||
765 | 403 | return; | ||
766 | 404 | } catch (Spit.DataImports.DataImportError e) { | ||
767 | 405 | debug ("FSpotDataImporter: Unsupported F-Spot database version: %s".printf (e.message)); | ||
768 | 406 | host.post_error_message (ERROR_UNSUPPORTED_DB_VERSION); | ||
769 | 407 | return; | ||
770 | 408 | } | ||
771 | 409 | try { | ||
772 | 410 | tags_cache = new FSpotTagsCache (database.tags_table); | ||
773 | 411 | } catch (DatabaseError e) { | ||
774 | 412 | debug ("FSpotDataImporter: Can't read tags table: %s".printf (e.message)); | ||
775 | 413 | host.post_error_message (ERROR_CANT_READ_TAGS_TABLE); | ||
776 | 414 | return; | ||
777 | 415 | } | ||
778 | 416 | host.install_import_progress_pane (_ ("Preparing to import")); | ||
779 | 417 | try { | ||
780 | 418 | all_photos = database.photos_table.get_all (); | ||
781 | 419 | } catch (DatabaseError e) { | ||
782 | 420 | debug ("FSpotDataImporter: Can't read photos table: %s".printf (e.message)); | ||
783 | 421 | host.post_error_message (ERROR_CANT_READ_PHOTOS_TABLE); | ||
784 | 422 | return; | ||
785 | 423 | } | ||
786 | 424 | if (all_photos.size > 0) | ||
787 | 425 | progress_delta_per_photo = 1.0 / all_photos.size; | ||
788 | 426 | foreach (DataImports.FSpot.Db.FSpotPhotoRow photo_row in all_photos) { | ||
789 | 427 | bool hidden = false; | ||
790 | 428 | bool favorite = false; | ||
791 | 429 | FSpotImportableTag[] tags = new FSpotImportableTag[0]; | ||
792 | 430 | FSpotImportableEvent? event = null; | ||
793 | 431 | DataImports.FSpot.Db.FSpotRollRow? roll_row = null; | ||
794 | 432 | |||
795 | 433 | // TODO: We do not convert F-Spot events to Shotwell events because F-Spot's events | ||
796 | 434 | // are essentially tags. We would need to detect if the tag is an event (use | ||
797 | 435 | // is_tag_event) and then assign the event to the photo ... since a photo can be | ||
798 | 436 | // in multiple F-Spot events, we would need to pick one, and since their tags | ||
799 | 437 | // are hierarchical, we would need to pick a name (probably the leaf) | ||
800 | 438 | try { | ||
801 | 439 | foreach ( | ||
802 | 440 | DataImports.FSpot.Db.FSpotTagRow tag_row in | ||
803 | 441 | database.tags_table.get_by_photo_id (photo_row.photo_id) | ||
804 | 442 | ) { | ||
805 | 443 | FSpotImportableTag tag = tags_cache.get_tag (tag_row); | ||
806 | 444 | if (is_tag_hidden (tag, database.hidden_tag_id)) | ||
807 | 445 | hidden = true; | ||
808 | 446 | else if (is_tag_favorite (tag)) | ||
809 | 447 | favorite = true; | ||
810 | 448 | else | ||
811 | 449 | tags += tag; | ||
812 | 450 | } | ||
813 | 451 | } catch (DatabaseError e) { | ||
814 | 452 | // log the error and leave the tag list empty | ||
815 | 453 | message ("Failed to retrieve tags for photo ID %ld: %s", (long) photo_row.photo_id, | ||
816 | 454 | e.message); | ||
817 | 455 | } | ||
818 | 456 | |||
819 | 457 | try { | ||
820 | 458 | roll_row = database.rolls_table.get_by_id (photo_row.roll_id); | ||
821 | 459 | } catch (DatabaseError e) { | ||
822 | 460 | // log the error and leave the roll row null | ||
823 | 461 | message ("Failed to retrieve roll for photo ID %ld: %s", (long) photo_row.photo_id, | ||
824 | 462 | e.message); | ||
825 | 463 | } | ||
826 | 464 | |||
827 | 465 | Spit.DataImports.ImportableMediaItem[] importable_items = new Spit.DataImports.ImportableMediaItem[0]; | ||
828 | 466 | try { | ||
829 | 467 | Gee.ArrayList<DataImports.FSpot.Db.FSpotPhotoVersionRow> photo_versions = | ||
830 | 468 | database.photo_versions_table.get_by_photo_id (photo_row.photo_id); | ||
831 | 469 | bool photo_versions_added = false; // set to true if at least one version was added | ||
832 | 470 | bool photo_versions_skipped = false; // set to true if at least one version was skipped due to missing file details | ||
833 | 471 | foreach (DataImports.FSpot.Db.FSpotPhotoVersionRow photo_version_row in photo_versions) { | ||
834 | 472 | if (photo_version_row.base_path != null && photo_version_row.filename != null) { | ||
835 | 473 | importable_items += new FSpotImportableItem ( | ||
836 | 474 | photo_row, photo_version_row, roll_row, tags, event, hidden, favorite | ||
837 | 475 | ); | ||
838 | 476 | photo_versions_added = true; | ||
839 | 477 | } else { | ||
840 | 478 | photo_versions_skipped = true; | ||
841 | 479 | } | ||
842 | 480 | } | ||
843 | 481 | |||
844 | 482 | // Older versions of F-Spot (0.4.3.1 at least, perhaps later) did not maintain photo_versions, | ||
845 | 483 | // this handles that case | ||
846 | 484 | // It also handles the case when we had to skip any photo version due to missing | ||
847 | 485 | // file details | ||
848 | 486 | if (photo_versions_skipped || !photo_versions_added) { | ||
849 | 487 | if (photo_row.base_path != null && photo_row.filename != null) { | ||
850 | 488 | importable_items += new FSpotImportableItem ( | ||
851 | 489 | photo_row, null, roll_row, tags, event, hidden, favorite | ||
852 | 490 | ); | ||
853 | 491 | } | ||
854 | 492 | } | ||
855 | 493 | } catch (DatabaseError e) { | ||
856 | 494 | // if we can't load the different versions, do the best we can | ||
857 | 495 | // and create one photo from the photo row that was found earlier | ||
858 | 496 | message ("Failed to retrieve versions for photo ID %ld: %s", (long) photo_row.photo_id, | ||
859 | 497 | e.message); | ||
860 | 498 | if (photo_row.base_path != null && photo_row.filename != null) { | ||
861 | 499 | importable_items += new FSpotImportableItem ( | ||
862 | 500 | photo_row, null, roll_row, tags, event, hidden, favorite | ||
863 | 501 | ); | ||
864 | 502 | } | ||
865 | 503 | } | ||
866 | 504 | // If the importer is still running, import the items and loop, | ||
867 | 505 | // otherwise break the loop | ||
868 | 506 | if (running) { | ||
869 | 507 | host.prepare_media_items_for_import ( | ||
870 | 508 | importable_items, | ||
871 | 509 | current_progress + (progress_delta_per_photo * progress_plugin_to_host_ratio), | ||
872 | 510 | progress_delta_per_photo * (1 - progress_plugin_to_host_ratio), | ||
873 | 511 | null | ||
874 | 512 | ); | ||
875 | 513 | current_progress += progress_delta_per_photo; | ||
876 | 514 | host.update_import_progress_pane (current_progress); | ||
877 | 515 | } else { | ||
878 | 516 | break; | ||
879 | 517 | } | ||
880 | 518 | } | ||
881 | 519 | host.finalize_import (on_imported_items_count); | ||
882 | 520 | } | ||
883 | 521 | |||
884 | 522 | public void on_imported_items_count (int imported_items_count) { | ||
885 | 523 | host.install_static_message_pane ( | ||
886 | 524 | MESSAGE_FINAL_SCREEN.printf (imported_items_count), | ||
887 | 525 | Spit.DataImports.PluginHost.ButtonMode.CLOSE | ||
888 | 526 | ); | ||
889 | 527 | } | ||
890 | 528 | |||
891 | 529 | private bool is_tag_event (FSpotImportableTag tag) { | ||
892 | 530 | bool result = (DataImports.FSpot.Db.FSpotTagsTable.STOCK_ICON_EVENTS == tag.get_stock_icon ()); | ||
893 | 531 | if (!result) { | ||
894 | 532 | FSpotImportableTag? parent = tag.get_fspot_parent (); | ||
895 | 533 | if (parent == null) | ||
896 | 534 | result = false; | ||
897 | 535 | else | ||
898 | 536 | result = is_tag_event (parent); | ||
899 | 537 | } | ||
900 | 538 | return result; | ||
901 | 539 | } | ||
902 | 540 | |||
903 | 541 | private bool is_tag_hidden (FSpotImportableTag tag, int64 hidden_tag_id) { | ||
904 | 542 | bool result = (hidden_tag_id == tag.get_id ()); | ||
905 | 543 | if (!result) { | ||
906 | 544 | FSpotImportableTag? parent = tag.get_fspot_parent (); | ||
907 | 545 | if (parent == null) | ||
908 | 546 | result = false; | ||
909 | 547 | else | ||
910 | 548 | result = is_tag_hidden (parent, hidden_tag_id); | ||
911 | 549 | } | ||
912 | 550 | return result; | ||
913 | 551 | } | ||
914 | 552 | |||
915 | 553 | private bool is_tag_favorite (FSpotImportableTag tag) { | ||
916 | 554 | bool result = (DataImports.FSpot.Db.FSpotTagsTable.STOCK_ICON_FAV == tag.get_stock_icon ()); | ||
917 | 555 | if (!result) { | ||
918 | 556 | FSpotImportableTag? parent = tag.get_fspot_parent (); | ||
919 | 557 | if (parent == null) | ||
920 | 558 | result = false; | ||
921 | 559 | else | ||
922 | 560 | result = is_tag_favorite (parent); | ||
923 | 561 | } | ||
924 | 562 | return result; | ||
925 | 563 | } | ||
926 | 564 | } | ||
927 | 565 | |||
928 | 566 | } // namespace | ||
929 | 567 | |||
930 | 568 | 0 | ||
931 | === removed file 'plugins/shotwell-data-imports/FSpotMetaTable.vala' | |||
932 | --- plugins/shotwell-data-imports/FSpotMetaTable.vala 2014-08-08 21:13:09 +0000 | |||
933 | +++ plugins/shotwell-data-imports/FSpotMetaTable.vala 1970-01-01 00:00:00 +0000 | |||
934 | @@ -1,113 +0,0 @@ | |||
935 | 1 | /* Copyright 2011-2013 Yorba Foundation | ||
936 | 2 | * | ||
937 | 3 | * This software is licensed under the GNU Lesser General Public License | ||
938 | 4 | * (version 2.1 or later). See the COPYING file in this distribution. | ||
939 | 5 | */ | ||
940 | 6 | |||
941 | 7 | namespace DataImports.FSpot.Db { | ||
942 | 8 | |||
943 | 9 | /** | ||
944 | 10 | * The value object for the "meta" table, representing a single database row. | ||
945 | 11 | */ | ||
946 | 12 | public class FSpotMetaRow : Object { | ||
947 | 13 | // ignore the ID | ||
948 | 14 | public string name; | ||
949 | 15 | public string data; | ||
950 | 16 | } | ||
951 | 17 | |||
952 | 18 | /** | ||
953 | 19 | * This class represents the F-Spot meta table, which stores some essential | ||
954 | 20 | * meta-data for the whole database. It is implemented as a simple dictionary | ||
955 | 21 | * where each row in the table is a key/value pair. | ||
956 | 22 | * | ||
957 | 23 | * The meta table implementation is the only one that throws a database error | ||
958 | 24 | * if something goes wrong because: | ||
959 | 25 | * * it is essential to read the content of that table in order to identify | ||
960 | 26 | * the version of the database and select the correct behavior, | ||
961 | 27 | * * this table is read at the very beginning of the process so any failure | ||
962 | 28 | * will occur immediately, | ||
963 | 29 | * * failing to read this table means that there is no point in reading the | ||
964 | 30 | * attempting to read the rest of the database so we might as well abort. | ||
965 | 31 | */ | ||
966 | 32 | public class FSpotMetaTable : FSpotDatabaseTable<FSpotMetaRow> { | ||
967 | 33 | |||
968 | 34 | public FSpotMetaTable (Sqlite.Database db) { | ||
969 | 35 | base (db); | ||
970 | 36 | set_behavior (FSpotMetaBehavior.get_instance ()); | ||
971 | 37 | } | ||
972 | 38 | |||
973 | 39 | public string? get_data (string name) throws DatabaseError { | ||
974 | 40 | string[] columns = behavior.list_columns (); | ||
975 | 41 | string column_list = string.joinv (", ", columns); | ||
976 | 42 | string sql = "SELECT %s FROM %s WHERE name=?".printf (column_list, table_name); | ||
977 | 43 | Sqlite.Statement stmt; | ||
978 | 44 | int res = fspot_db.prepare_v2 (sql, -1, out stmt); | ||
979 | 45 | if (res != Sqlite.OK) | ||
980 | 46 | throw_error ("Statement failed: %s".printf (sql), res); | ||
981 | 47 | |||
982 | 48 | res = stmt.bind_text (1, name); | ||
983 | 49 | if (res != Sqlite.OK) | ||
984 | 50 | throw_error ("Bind failed for name %s".printf (name), res); | ||
985 | 51 | |||
986 | 52 | res = stmt.step (); | ||
987 | 53 | if (res != Sqlite.ROW) { | ||
988 | 54 | if (res != Sqlite.DONE) | ||
989 | 55 | throw_error ("FSpotMetaTable.get_data", res); | ||
990 | 56 | |||
991 | 57 | return null; | ||
992 | 58 | } | ||
993 | 59 | |||
994 | 60 | FSpotMetaRow row; | ||
995 | 61 | behavior.build_row (stmt, out row); | ||
996 | 62 | return row.data; | ||
997 | 63 | } | ||
998 | 64 | |||
999 | 65 | public string? get_app_version () throws DatabaseError { | ||
1000 | 66 | return get_data ("F-Spot Version"); | ||
1001 | 67 | } | ||
1002 | 68 | |||
1003 | 69 | public string? get_db_version () throws DatabaseError { | ||
1004 | 70 | return get_data ("F-Spot Database Version"); | ||
1005 | 71 | } | ||
1006 | 72 | |||
1007 | 73 | public int64 get_hidden_tag_id () throws DatabaseError { | ||
1008 | 74 | string id_str = get_data ("Hidden Tag Id"); | ||
1009 | 75 | if (id_str != null) { | ||
1010 | 76 | return int64.parse (id_str); | ||
1011 | 77 | } else { | ||
1012 | 78 | return -1; | ||
1013 | 79 | } | ||
1014 | 80 | } | ||
1015 | 81 | } | ||
1016 | 82 | |||
1017 | 83 | public class FSpotMetaBehavior : FSpotTableBehavior<FSpotMetaRow>, Object { | ||
1018 | 84 | public static const string TABLE_NAME = "Meta"; | ||
1019 | 85 | |||
1020 | 86 | private static FSpotMetaBehavior instance; | ||
1021 | 87 | |||
1022 | 88 | private FSpotMetaBehavior () { | ||
1023 | 89 | } | ||
1024 | 90 | |||
1025 | 91 | public static FSpotMetaBehavior get_instance () { | ||
1026 | 92 | if (instance == null) | ||
1027 | 93 | instance = new FSpotMetaBehavior (); | ||
1028 | 94 | return instance; | ||
1029 | 95 | } | ||
1030 | 96 | |||
1031 | 97 | public string get_table_name () { | ||
1032 | 98 | return TABLE_NAME; | ||
1033 | 99 | } | ||
1034 | 100 | |||
1035 | 101 | public string[] list_columns () { | ||
1036 | 102 | return { "name", "data" }; | ||
1037 | 103 | } | ||
1038 | 104 | |||
1039 | 105 | public void build_row (Sqlite.Statement stmt, out FSpotMetaRow row, int offset = 0) { | ||
1040 | 106 | row = new FSpotMetaRow (); | ||
1041 | 107 | row.name = stmt.column_text (offset + 0); | ||
1042 | 108 | row.data = stmt.column_text (offset + 1); | ||
1043 | 109 | } | ||
1044 | 110 | } | ||
1045 | 111 | |||
1046 | 112 | } | ||
1047 | 113 | |||
1048 | 114 | 0 | ||
1049 | === removed file 'plugins/shotwell-data-imports/FSpotPhotoTagsTable.vala' | |||
1050 | --- plugins/shotwell-data-imports/FSpotPhotoTagsTable.vala 2014-08-08 21:13:09 +0000 | |||
1051 | +++ plugins/shotwell-data-imports/FSpotPhotoTagsTable.vala 1970-01-01 00:00:00 +0000 | |||
1052 | @@ -1,57 +0,0 @@ | |||
1053 | 1 | /* Copyright 2011-2013 Yorba Foundation | ||
1054 | 2 | * | ||
1055 | 3 | * This software is licensed under the GNU Lesser General Public License | ||
1056 | 4 | * (version 2.1 or later). See the COPYING file in this distribution. | ||
1057 | 5 | */ | ||
1058 | 6 | |||
1059 | 7 | namespace DataImports.FSpot.Db { | ||
1060 | 8 | |||
1061 | 9 | /** | ||
1062 | 10 | * The value object for the "photo_tags" table, representing a single database row. | ||
1063 | 11 | */ | ||
1064 | 12 | public class FSpotPhotoTagRow : Object { | ||
1065 | 13 | public int64 photo_id; | ||
1066 | 14 | public int64 tag_id; | ||
1067 | 15 | } | ||
1068 | 16 | |||
1069 | 17 | /** | ||
1070 | 18 | * This class represents the F-Spot photo_tags table. | ||
1071 | 19 | */ | ||
1072 | 20 | public class FSpotPhotoTagsTable : FSpotDatabaseTable<FSpotPhotoTagRow> { | ||
1073 | 21 | public static const string TABLE_NAME = "Photo_Tags"; | ||
1074 | 22 | |||
1075 | 23 | public FSpotPhotoTagsTable (Sqlite.Database db, FSpotDatabaseBehavior db_behavior) { | ||
1076 | 24 | base (db); | ||
1077 | 25 | set_behavior (db_behavior.get_photo_tags_behavior ()); | ||
1078 | 26 | } | ||
1079 | 27 | } | ||
1080 | 28 | |||
1081 | 29 | public class FSpotPhotoTagsV0Behavior : FSpotTableBehavior<FSpotPhotoTagRow>, Object { | ||
1082 | 30 | private static FSpotPhotoTagsV0Behavior instance; | ||
1083 | 31 | |||
1084 | 32 | private FSpotPhotoTagsV0Behavior () { | ||
1085 | 33 | } | ||
1086 | 34 | |||
1087 | 35 | public static FSpotPhotoTagsV0Behavior get_instance () { | ||
1088 | 36 | if (instance == null) | ||
1089 | 37 | instance = new FSpotPhotoTagsV0Behavior (); | ||
1090 | 38 | return instance; | ||
1091 | 39 | } | ||
1092 | 40 | |||
1093 | 41 | public string get_table_name () { | ||
1094 | 42 | return FSpotPhotoTagsTable.TABLE_NAME; | ||
1095 | 43 | } | ||
1096 | 44 | |||
1097 | 45 | public string[] list_columns () { | ||
1098 | 46 | return { "photo_id", "tag_id" }; | ||
1099 | 47 | } | ||
1100 | 48 | |||
1101 | 49 | public void build_row (Sqlite.Statement stmt, out FSpotPhotoTagRow row, int offset = 0) { | ||
1102 | 50 | row = new FSpotPhotoTagRow (); | ||
1103 | 51 | row.photo_id = stmt.column_int64 (offset + 0); | ||
1104 | 52 | row.tag_id = stmt.column_int64 (offset + 1); | ||
1105 | 53 | } | ||
1106 | 54 | } | ||
1107 | 55 | |||
1108 | 56 | } | ||
1109 | 57 | |||
1110 | 58 | 0 | ||
1111 | === removed file 'plugins/shotwell-data-imports/FSpotPhotoVersionsTable.vala' | |||
1112 | --- plugins/shotwell-data-imports/FSpotPhotoVersionsTable.vala 2014-08-08 21:13:09 +0000 | |||
1113 | +++ plugins/shotwell-data-imports/FSpotPhotoVersionsTable.vala 1970-01-01 00:00:00 +0000 | |||
1114 | @@ -1,275 +0,0 @@ | |||
1115 | 1 | /* Copyright 2011-2013 Yorba Foundation | ||
1116 | 2 | * | ||
1117 | 3 | * This software is licensed under the GNU Lesser General Public License | ||
1118 | 4 | * (version 2.1 or later). See the COPYING file in this distribution. | ||
1119 | 5 | */ | ||
1120 | 6 | |||
1121 | 7 | namespace DataImports.FSpot.Db { | ||
1122 | 8 | |||
1123 | 9 | /** | ||
1124 | 10 | * The value object for the "photo_versions" table, representing a single database row. | ||
1125 | 11 | */ | ||
1126 | 12 | public class FSpotPhotoVersionRow : Object { | ||
1127 | 13 | public int64 photo_id; | ||
1128 | 14 | public int64 version_id; | ||
1129 | 15 | public string name; | ||
1130 | 16 | public File? base_path; | ||
1131 | 17 | public string? filename; | ||
1132 | 18 | public string md5_sum; | ||
1133 | 19 | public bool is_protected; | ||
1134 | 20 | } | ||
1135 | 21 | |||
1136 | 22 | /** | ||
1137 | 23 | * This class represents the F-Spot photo_versions table. | ||
1138 | 24 | */ | ||
1139 | 25 | public class FSpotPhotoVersionsTable : FSpotDatabaseTable<FSpotPhotoVersionRow> { | ||
1140 | 26 | public static const string TABLE_NAME = "Photo_versions"; | ||
1141 | 27 | |||
1142 | 28 | public FSpotPhotoVersionsTable (Sqlite.Database db, FSpotDatabaseBehavior db_behavior) { | ||
1143 | 29 | base (db); | ||
1144 | 30 | set_behavior (db_behavior.get_photo_versions_behavior ()); | ||
1145 | 31 | } | ||
1146 | 32 | |||
1147 | 33 | public Gee.ArrayList<FSpotPhotoVersionRow> get_by_photo_id (int64 photo_id) throws DatabaseError { | ||
1148 | 34 | Gee.ArrayList<FSpotPhotoVersionRow> rows = new Gee.ArrayList < FSpotPhotoVersionRow?> (); | ||
1149 | 35 | |||
1150 | 36 | Sqlite.Statement stmt; | ||
1151 | 37 | |||
1152 | 38 | string column_list = get_joined_column_list (); | ||
1153 | 39 | string sql = "SELECT %s FROM %s WHERE photo_id=?".printf ( | ||
1154 | 40 | column_list, table_name | ||
1155 | 41 | ); | ||
1156 | 42 | |||
1157 | 43 | int res = fspot_db.prepare_v2 (sql, -1, out stmt); | ||
1158 | 44 | if (res != Sqlite.OK) | ||
1159 | 45 | throw_error ("Statement failed: %s".printf (sql), res); | ||
1160 | 46 | |||
1161 | 47 | res = stmt.bind_int64 (1, photo_id); | ||
1162 | 48 | if (res != Sqlite.OK) | ||
1163 | 49 | throw_error ("Bind failed for photo_id", res); | ||
1164 | 50 | |||
1165 | 51 | res = stmt.step (); | ||
1166 | 52 | while (res == Sqlite.ROW) { | ||
1167 | 53 | FSpotPhotoVersionRow row; | ||
1168 | 54 | behavior.build_row (stmt, out row); | ||
1169 | 55 | rows.add (row); | ||
1170 | 56 | res = stmt.step (); | ||
1171 | 57 | } | ||
1172 | 58 | |||
1173 | 59 | return rows; | ||
1174 | 60 | } | ||
1175 | 61 | } | ||
1176 | 62 | |||
1177 | 63 | // Photo_versions table behavior for v0-8 | ||
1178 | 64 | // Note: there is a change in the URI format in version 8 but the File.new_for_uri | ||
1179 | 65 | // constructor should be able to deal with the variation, so the v8 behavior should | ||
1180 | 66 | // be handled in a way identical to v0-7 | ||
1181 | 67 | public class FSpotPhotoVersionsV0Behavior : FSpotTableBehavior<FSpotPhotoVersionRow>, Object { | ||
1182 | 68 | private static FSpotPhotoVersionsV0Behavior instance; | ||
1183 | 69 | |||
1184 | 70 | private FSpotPhotoVersionsV0Behavior () { | ||
1185 | 71 | } | ||
1186 | 72 | |||
1187 | 73 | public static FSpotPhotoVersionsV0Behavior get_instance () { | ||
1188 | 74 | if (instance == null) | ||
1189 | 75 | instance = new FSpotPhotoVersionsV0Behavior (); | ||
1190 | 76 | return instance; | ||
1191 | 77 | } | ||
1192 | 78 | |||
1193 | 79 | public string get_table_name () { | ||
1194 | 80 | return FSpotPhotoVersionsTable.TABLE_NAME; | ||
1195 | 81 | } | ||
1196 | 82 | |||
1197 | 83 | public string[] list_columns () { | ||
1198 | 84 | return { "photo_id", "version_id", "name", "uri" }; | ||
1199 | 85 | } | ||
1200 | 86 | |||
1201 | 87 | public void build_row (Sqlite.Statement stmt, out FSpotPhotoVersionRow row, int offset = 0) { | ||
1202 | 88 | row = new FSpotPhotoVersionRow (); | ||
1203 | 89 | row.photo_id = stmt.column_int64 (offset + 0); | ||
1204 | 90 | row.version_id = stmt.column_int64 (offset + 1); | ||
1205 | 91 | row.name = stmt.column_text (offset + 2); | ||
1206 | 92 | |||
1207 | 93 | string? full_path = stmt.column_text (offset + 3); | ||
1208 | 94 | if (full_path != null) { | ||
1209 | 95 | File uri = File.new_for_uri (full_path); | ||
1210 | 96 | row.base_path = uri.get_parent (); | ||
1211 | 97 | row.filename = uri.get_basename (); | ||
1212 | 98 | } | ||
1213 | 99 | |||
1214 | 100 | row.md5_sum = ""; | ||
1215 | 101 | row.is_protected = false; | ||
1216 | 102 | } | ||
1217 | 103 | } | ||
1218 | 104 | |||
1219 | 105 | // Photo_versions table behavior for v9-15 | ||
1220 | 106 | // add protected field | ||
1221 | 107 | public class FSpotPhotoVersionsV9Behavior : FSpotTableBehavior<FSpotPhotoVersionRow>, Object { | ||
1222 | 108 | private static FSpotPhotoVersionsV9Behavior instance; | ||
1223 | 109 | |||
1224 | 110 | private FSpotPhotoVersionsV9Behavior () { | ||
1225 | 111 | } | ||
1226 | 112 | |||
1227 | 113 | public static FSpotPhotoVersionsV9Behavior get_instance () { | ||
1228 | 114 | if (instance == null) | ||
1229 | 115 | instance = new FSpotPhotoVersionsV9Behavior (); | ||
1230 | 116 | return instance; | ||
1231 | 117 | } | ||
1232 | 118 | |||
1233 | 119 | public string get_table_name () { | ||
1234 | 120 | return FSpotPhotoVersionsTable.TABLE_NAME; | ||
1235 | 121 | } | ||
1236 | 122 | |||
1237 | 123 | public string[] list_columns () { | ||
1238 | 124 | return { "photo_id", "version_id", "name", "uri", | ||
1239 | 125 | "protected" | ||
1240 | 126 | }; | ||
1241 | 127 | } | ||
1242 | 128 | |||
1243 | 129 | public void build_row (Sqlite.Statement stmt, out FSpotPhotoVersionRow row, int offset = 0) { | ||
1244 | 130 | row = new FSpotPhotoVersionRow (); | ||
1245 | 131 | row.photo_id = stmt.column_int64 (offset + 0); | ||
1246 | 132 | row.version_id = stmt.column_int64 (offset + 1); | ||
1247 | 133 | row.name = stmt.column_text (offset + 2); | ||
1248 | 134 | |||
1249 | 135 | string? full_path = stmt.column_text (offset + 3); | ||
1250 | 136 | if (full_path != null) { | ||
1251 | 137 | File uri = File.new_for_uri (full_path); | ||
1252 | 138 | row.base_path = uri.get_parent (); | ||
1253 | 139 | row.filename = uri.get_basename (); | ||
1254 | 140 | } | ||
1255 | 141 | |||
1256 | 142 | row.md5_sum = ""; | ||
1257 | 143 | row.is_protected = (stmt.column_int (offset + 4) > 0); | ||
1258 | 144 | } | ||
1259 | 145 | } | ||
1260 | 146 | |||
1261 | 147 | // Photo_versions table behavior for v16 | ||
1262 | 148 | // add md5_sum in photo_versions | ||
1263 | 149 | public class FSpotPhotoVersionsV16Behavior : FSpotTableBehavior<FSpotPhotoVersionRow>, Object { | ||
1264 | 150 | private static FSpotPhotoVersionsV16Behavior instance; | ||
1265 | 151 | |||
1266 | 152 | private FSpotPhotoVersionsV16Behavior () { | ||
1267 | 153 | } | ||
1268 | 154 | |||
1269 | 155 | public static FSpotPhotoVersionsV16Behavior get_instance () { | ||
1270 | 156 | if (instance == null) | ||
1271 | 157 | instance = new FSpotPhotoVersionsV16Behavior (); | ||
1272 | 158 | return instance; | ||
1273 | 159 | } | ||
1274 | 160 | |||
1275 | 161 | public string get_table_name () { | ||
1276 | 162 | return FSpotPhotoVersionsTable.TABLE_NAME; | ||
1277 | 163 | } | ||
1278 | 164 | |||
1279 | 165 | public string[] list_columns () { | ||
1280 | 166 | return { "photo_id", "version_id", "name", "uri", | ||
1281 | 167 | "md5_sum", "protected" | ||
1282 | 168 | }; | ||
1283 | 169 | } | ||
1284 | 170 | |||
1285 | 171 | public void build_row (Sqlite.Statement stmt, out FSpotPhotoVersionRow row, int offset = 0) { | ||
1286 | 172 | row = new FSpotPhotoVersionRow (); | ||
1287 | 173 | row.photo_id = stmt.column_int64 (offset + 0); | ||
1288 | 174 | row.version_id = stmt.column_int64 (offset + 1); | ||
1289 | 175 | row.name = stmt.column_text (offset + 2); | ||
1290 | 176 | |||
1291 | 177 | string? full_path = stmt.column_text (offset + 3); | ||
1292 | 178 | if (full_path != null) { | ||
1293 | 179 | File uri = File.new_for_uri (full_path); | ||
1294 | 180 | row.base_path = uri.get_parent (); | ||
1295 | 181 | row.filename = uri.get_basename (); | ||
1296 | 182 | } | ||
1297 | 183 | |||
1298 | 184 | row.md5_sum = stmt.column_text (offset + 4); | ||
1299 | 185 | row.is_protected = (stmt.column_int (offset + 5) > 0); | ||
1300 | 186 | } | ||
1301 | 187 | } | ||
1302 | 188 | |||
1303 | 189 | // Photo_versions table behavior for v17 | ||
1304 | 190 | // v17 split the URI into base_uri and filename (reverting back to the original | ||
1305 | 191 | // design introduced in v0, albeit with a URI rather than a file system path) | ||
1306 | 192 | public class FSpotPhotoVersionsV17Behavior : FSpotTableBehavior<FSpotPhotoVersionRow>, Object { | ||
1307 | 193 | private static FSpotPhotoVersionsV17Behavior instance; | ||
1308 | 194 | |||
1309 | 195 | private FSpotPhotoVersionsV17Behavior () { | ||
1310 | 196 | } | ||
1311 | 197 | |||
1312 | 198 | public static FSpotPhotoVersionsV17Behavior get_instance () { | ||
1313 | 199 | if (instance == null) | ||
1314 | 200 | instance = new FSpotPhotoVersionsV17Behavior (); | ||
1315 | 201 | return instance; | ||
1316 | 202 | } | ||
1317 | 203 | |||
1318 | 204 | public string get_table_name () { | ||
1319 | 205 | return FSpotPhotoVersionsTable.TABLE_NAME; | ||
1320 | 206 | } | ||
1321 | 207 | |||
1322 | 208 | public string[] list_columns () { | ||
1323 | 209 | return { "photo_id", "version_id", "name", "base_uri", "filename", | ||
1324 | 210 | "md5_sum", "protected" | ||
1325 | 211 | }; | ||
1326 | 212 | } | ||
1327 | 213 | |||
1328 | 214 | public void build_row (Sqlite.Statement stmt, out FSpotPhotoVersionRow row, int offset = 0) { | ||
1329 | 215 | row = new FSpotPhotoVersionRow (); | ||
1330 | 216 | row.photo_id = stmt.column_int64 (offset + 0); | ||
1331 | 217 | row.version_id = stmt.column_int64 (offset + 1); | ||
1332 | 218 | row.name = stmt.column_text (offset + 2); | ||
1333 | 219 | |||
1334 | 220 | string? base_path = stmt.column_text (offset + 3); | ||
1335 | 221 | string? filename = stmt.column_text (offset + 4); | ||
1336 | 222 | if (base_path != null && filename != null) { | ||
1337 | 223 | row.base_path = File.new_for_uri (base_path); | ||
1338 | 224 | row.filename = filename; | ||
1339 | 225 | } | ||
1340 | 226 | |||
1341 | 227 | row.md5_sum = stmt.column_text (offset + 5); | ||
1342 | 228 | row.is_protected = (stmt.column_int (offset + 6) > 0); | ||
1343 | 229 | } | ||
1344 | 230 | } | ||
1345 | 231 | |||
1346 | 232 | // Photo_versions table behavior for v18 | ||
1347 | 233 | // md5_sum renamed import_md5 | ||
1348 | 234 | public class FSpotPhotoVersionsV18Behavior : FSpotTableBehavior<FSpotPhotoVersionRow>, Object { | ||
1349 | 235 | private static FSpotPhotoVersionsV18Behavior instance; | ||
1350 | 236 | |||
1351 | 237 | private FSpotPhotoVersionsV18Behavior () { | ||
1352 | 238 | } | ||
1353 | 239 | |||
1354 | 240 | public static FSpotPhotoVersionsV18Behavior get_instance () { | ||
1355 | 241 | if (instance == null) | ||
1356 | 242 | instance = new FSpotPhotoVersionsV18Behavior (); | ||
1357 | 243 | return instance; | ||
1358 | 244 | } | ||
1359 | 245 | |||
1360 | 246 | public string get_table_name () { | ||
1361 | 247 | return FSpotPhotoVersionsTable.TABLE_NAME; | ||
1362 | 248 | } | ||
1363 | 249 | |||
1364 | 250 | public string[] list_columns () { | ||
1365 | 251 | return { "photo_id", "version_id", "name", "base_uri", "filename", | ||
1366 | 252 | "import_md5", "protected" | ||
1367 | 253 | }; | ||
1368 | 254 | } | ||
1369 | 255 | |||
1370 | 256 | public void build_row (Sqlite.Statement stmt, out FSpotPhotoVersionRow row, int offset = 0) { | ||
1371 | 257 | row = new FSpotPhotoVersionRow (); | ||
1372 | 258 | row.photo_id = stmt.column_int64 (offset + 0); | ||
1373 | 259 | row.version_id = stmt.column_int64 (offset + 1); | ||
1374 | 260 | row.name = stmt.column_text (offset + 2); | ||
1375 | 261 | |||
1376 | 262 | string? base_path = stmt.column_text (offset + 3); | ||
1377 | 263 | string? filename = stmt.column_text (offset + 4); | ||
1378 | 264 | if (base_path != null && filename != null) { | ||
1379 | 265 | row.base_path = File.new_for_uri (base_path); | ||
1380 | 266 | row.filename = filename; | ||
1381 | 267 | } | ||
1382 | 268 | |||
1383 | 269 | row.md5_sum = stmt.column_text (offset + 5); | ||
1384 | 270 | row.is_protected = (stmt.column_int (offset + 6) > 0); | ||
1385 | 271 | } | ||
1386 | 272 | } | ||
1387 | 273 | |||
1388 | 274 | } | ||
1389 | 275 | |||
1390 | 276 | 0 | ||
1391 | === removed file 'plugins/shotwell-data-imports/FSpotPhotosTable.vala' | |||
1392 | --- plugins/shotwell-data-imports/FSpotPhotosTable.vala 2014-08-08 21:13:09 +0000 | |||
1393 | +++ plugins/shotwell-data-imports/FSpotPhotosTable.vala 1970-01-01 00:00:00 +0000 | |||
1394 | @@ -1,363 +0,0 @@ | |||
1395 | 1 | /* Copyright 2011-2013 Yorba Foundation | ||
1396 | 2 | * | ||
1397 | 3 | * This software is licensed under the GNU Lesser General Public License | ||
1398 | 4 | * (version 2.1 or later). See the COPYING file in this distribution. | ||
1399 | 5 | */ | ||
1400 | 6 | |||
1401 | 7 | namespace DataImports.FSpot.Db { | ||
1402 | 8 | |||
1403 | 9 | /** | ||
1404 | 10 | * The value object for the "photos" table, representing a single database row. | ||
1405 | 11 | */ | ||
1406 | 12 | public class FSpotPhotoRow : Object { | ||
1407 | 13 | public int64 photo_id; | ||
1408 | 14 | public time_t time; | ||
1409 | 15 | public File? base_path; | ||
1410 | 16 | public string? filename; | ||
1411 | 17 | public string description; | ||
1412 | 18 | public int64 roll_id; | ||
1413 | 19 | public int64 default_version_id; | ||
1414 | 20 | public int rating; | ||
1415 | 21 | public string md5_sum; | ||
1416 | 22 | } | ||
1417 | 23 | |||
1418 | 24 | /** | ||
1419 | 25 | * This class represents the F-Spot photos table. | ||
1420 | 26 | */ | ||
1421 | 27 | public class FSpotPhotosTable : FSpotDatabaseTable<FSpotPhotoRow> { | ||
1422 | 28 | public static const string TABLE_NAME = "Photos"; | ||
1423 | 29 | |||
1424 | 30 | public FSpotPhotosTable (Sqlite.Database db, FSpotDatabaseBehavior db_behavior) { | ||
1425 | 31 | base (db); | ||
1426 | 32 | set_behavior (db_behavior.get_photos_behavior ()); | ||
1427 | 33 | } | ||
1428 | 34 | |||
1429 | 35 | public Gee.ArrayList<FSpotPhotoRow> get_all () throws DatabaseError { | ||
1430 | 36 | Gee.ArrayList<FSpotPhotoRow> all = new Gee.ArrayList < FSpotPhotoRow?> (); | ||
1431 | 37 | |||
1432 | 38 | Sqlite.Statement stmt; | ||
1433 | 39 | int res = select_all (out stmt); | ||
1434 | 40 | while (res == Sqlite.ROW) { | ||
1435 | 41 | FSpotPhotoRow row; | ||
1436 | 42 | behavior.build_row (stmt, out row); | ||
1437 | 43 | all.add (row); | ||
1438 | 44 | res = stmt.step (); | ||
1439 | 45 | } | ||
1440 | 46 | |||
1441 | 47 | return all; | ||
1442 | 48 | } | ||
1443 | 49 | } | ||
1444 | 50 | |||
1445 | 51 | // Photos table behavior for v0-4 | ||
1446 | 52 | // The original table format | ||
1447 | 53 | public class FSpotPhotosV0Behavior : FSpotTableBehavior<FSpotPhotoRow>, Object { | ||
1448 | 54 | private static FSpotPhotosV0Behavior instance; | ||
1449 | 55 | |||
1450 | 56 | private FSpotPhotosV0Behavior () { | ||
1451 | 57 | } | ||
1452 | 58 | |||
1453 | 59 | public static FSpotPhotosV0Behavior get_instance () { | ||
1454 | 60 | if (instance == null) | ||
1455 | 61 | instance = new FSpotPhotosV0Behavior (); | ||
1456 | 62 | return instance; | ||
1457 | 63 | } | ||
1458 | 64 | |||
1459 | 65 | public string get_table_name () { | ||
1460 | 66 | return FSpotPhotosTable.TABLE_NAME; | ||
1461 | 67 | } | ||
1462 | 68 | |||
1463 | 69 | public string[] list_columns () { | ||
1464 | 70 | return { "id", "time", "directory_path", "name", "description", | ||
1465 | 71 | "default_version_id" | ||
1466 | 72 | }; | ||
1467 | 73 | } | ||
1468 | 74 | |||
1469 | 75 | public void build_row (Sqlite.Statement stmt, out FSpotPhotoRow row, int offset = 0) { | ||
1470 | 76 | row = new FSpotPhotoRow (); | ||
1471 | 77 | row.photo_id = stmt.column_int64 (offset + 0); | ||
1472 | 78 | row.time = (time_t) stmt.column_int64 (offset + 1); | ||
1473 | 79 | |||
1474 | 80 | string? base_path = stmt.column_text (offset + 2); | ||
1475 | 81 | string? filename = stmt.column_text (offset + 3); | ||
1476 | 82 | if (base_path != null && filename != null) { | ||
1477 | 83 | row.base_path = File.new_for_uri (base_path); | ||
1478 | 84 | row.filename = filename; | ||
1479 | 85 | } | ||
1480 | 86 | |||
1481 | 87 | row.description = stmt.column_text (offset + 4); | ||
1482 | 88 | row.roll_id = INVALID_ID; | ||
1483 | 89 | row.default_version_id = stmt.column_int64 (offset + 5); | ||
1484 | 90 | row.rating = 0; | ||
1485 | 91 | row.md5_sum = ""; | ||
1486 | 92 | } | ||
1487 | 93 | } | ||
1488 | 94 | |||
1489 | 95 | // Photos table behavior for v5-6 | ||
1490 | 96 | // v5 introduced a roll_id to reference the imported roll (rolls were a new | ||
1491 | 97 | // table migrated from imports) | ||
1492 | 98 | public class FSpotPhotosV5Behavior : FSpotTableBehavior<FSpotPhotoRow>, Object { | ||
1493 | 99 | private static FSpotPhotosV5Behavior instance; | ||
1494 | 100 | |||
1495 | 101 | private FSpotPhotosV5Behavior () { | ||
1496 | 102 | } | ||
1497 | 103 | |||
1498 | 104 | public static FSpotPhotosV5Behavior get_instance () { | ||
1499 | 105 | if (instance == null) | ||
1500 | 106 | instance = new FSpotPhotosV5Behavior (); | ||
1501 | 107 | return instance; | ||
1502 | 108 | } | ||
1503 | 109 | |||
1504 | 110 | public string get_table_name () { | ||
1505 | 111 | return FSpotPhotosTable.TABLE_NAME; | ||
1506 | 112 | } | ||
1507 | 113 | |||
1508 | 114 | public string[] list_columns () { | ||
1509 | 115 | return { "id", "time", "directory_path", "name", "description", "roll_id", | ||
1510 | 116 | "default_version_id" | ||
1511 | 117 | }; | ||
1512 | 118 | } | ||
1513 | 119 | |||
1514 | 120 | public void build_row (Sqlite.Statement stmt, out FSpotPhotoRow row, int offset = 0) { | ||
1515 | 121 | row = new FSpotPhotoRow (); | ||
1516 | 122 | row.photo_id = stmt.column_int64 (offset + 0); | ||
1517 | 123 | row.time = (time_t) stmt.column_int64 (offset + 1); | ||
1518 | 124 | |||
1519 | 125 | string? base_path = stmt.column_text (offset + 2); | ||
1520 | 126 | string? filename = stmt.column_text (offset + 3); | ||
1521 | 127 | if (base_path != null && filename != null) { | ||
1522 | 128 | row.base_path = File.new_for_uri (base_path); | ||
1523 | 129 | row.filename = filename; | ||
1524 | 130 | } | ||
1525 | 131 | |||
1526 | 132 | row.description = stmt.column_text (offset + 4); | ||
1527 | 133 | row.roll_id = stmt.column_int64 (offset + 5); | ||
1528 | 134 | row.default_version_id = stmt.column_int64 (offset + 6); | ||
1529 | 135 | row.rating = 0; | ||
1530 | 136 | row.md5_sum = ""; | ||
1531 | 137 | } | ||
1532 | 138 | } | ||
1533 | 139 | |||
1534 | 140 | // Photos table behavior for v7-10 | ||
1535 | 141 | // v7 merged directory_path and name into a single URI value with a file:// | ||
1536 | 142 | // prefix; presumaly this is meant to be able to handle remote files using a | ||
1537 | 143 | // different URI prefix such as remote files | ||
1538 | 144 | public class FSpotPhotosV7Behavior : FSpotTableBehavior<FSpotPhotoRow>, Object { | ||
1539 | 145 | private static FSpotPhotosV7Behavior instance; | ||
1540 | 146 | |||
1541 | 147 | private FSpotPhotosV7Behavior () { | ||
1542 | 148 | } | ||
1543 | 149 | |||
1544 | 150 | public static FSpotPhotosV7Behavior get_instance () { | ||
1545 | 151 | if (instance == null) | ||
1546 | 152 | instance = new FSpotPhotosV7Behavior (); | ||
1547 | 153 | return instance; | ||
1548 | 154 | } | ||
1549 | 155 | |||
1550 | 156 | public string get_table_name () { | ||
1551 | 157 | return FSpotPhotosTable.TABLE_NAME; | ||
1552 | 158 | } | ||
1553 | 159 | |||
1554 | 160 | public string[] list_columns () { | ||
1555 | 161 | return { "id", "time", "uri", "description", "roll_id", | ||
1556 | 162 | "default_version_id" | ||
1557 | 163 | }; | ||
1558 | 164 | } | ||
1559 | 165 | |||
1560 | 166 | public void build_row (Sqlite.Statement stmt, out FSpotPhotoRow row, int offset = 0) { | ||
1561 | 167 | row = new FSpotPhotoRow (); | ||
1562 | 168 | row.photo_id = stmt.column_int64 (offset + 0); | ||
1563 | 169 | row.time = (time_t) stmt.column_int64 (offset + 1); | ||
1564 | 170 | |||
1565 | 171 | string? full_path = stmt.column_text (offset + 2); | ||
1566 | 172 | if (full_path != null) { | ||
1567 | 173 | File uri = File.new_for_uri (full_path); | ||
1568 | 174 | row.base_path = uri.get_parent (); | ||
1569 | 175 | row.filename = uri.get_basename (); | ||
1570 | 176 | } | ||
1571 | 177 | |||
1572 | 178 | row.description = stmt.column_text (offset + 3); | ||
1573 | 179 | row.roll_id = stmt.column_int64 (offset + 4); | ||
1574 | 180 | row.default_version_id = stmt.column_int64 (offset + 5); | ||
1575 | 181 | row.rating = 0; | ||
1576 | 182 | row.md5_sum = ""; | ||
1577 | 183 | } | ||
1578 | 184 | } | ||
1579 | 185 | |||
1580 | 186 | // Photos table behavior for v11-15 | ||
1581 | 187 | // v11 introduced the concept of rating so add this to the list of fields | ||
1582 | 188 | public class FSpotPhotosV11Behavior : FSpotTableBehavior<FSpotPhotoRow>, Object { | ||
1583 | 189 | private static FSpotPhotosV11Behavior instance; | ||
1584 | 190 | |||
1585 | 191 | private FSpotPhotosV11Behavior () { | ||
1586 | 192 | } | ||
1587 | 193 | |||
1588 | 194 | public static FSpotPhotosV11Behavior get_instance () { | ||
1589 | 195 | if (instance == null) | ||
1590 | 196 | instance = new FSpotPhotosV11Behavior (); | ||
1591 | 197 | return instance; | ||
1592 | 198 | } | ||
1593 | 199 | |||
1594 | 200 | public string get_table_name () { | ||
1595 | 201 | return FSpotPhotosTable.TABLE_NAME; | ||
1596 | 202 | } | ||
1597 | 203 | |||
1598 | 204 | public string[] list_columns () { | ||
1599 | 205 | return { "id", "time", "uri", "description", "roll_id", | ||
1600 | 206 | "default_version_id", "rating" | ||
1601 | 207 | }; | ||
1602 | 208 | } | ||
1603 | 209 | |||
1604 | 210 | public void build_row (Sqlite.Statement stmt, out FSpotPhotoRow row, int offset = 0) { | ||
1605 | 211 | row = new FSpotPhotoRow (); | ||
1606 | 212 | row.photo_id = stmt.column_int64 (offset + 0); | ||
1607 | 213 | row.time = (time_t) stmt.column_int64 (offset + 1); | ||
1608 | 214 | |||
1609 | 215 | string? full_path = stmt.column_text (offset + 2); | ||
1610 | 216 | if (full_path != null) { | ||
1611 | 217 | File uri = File.new_for_uri (full_path); | ||
1612 | 218 | row.base_path = uri.get_parent (); | ||
1613 | 219 | row.filename = uri.get_basename (); | ||
1614 | 220 | } | ||
1615 | 221 | |||
1616 | 222 | row.description = stmt.column_text (offset + 3); | ||
1617 | 223 | row.roll_id = stmt.column_int64 (offset + 4); | ||
1618 | 224 | row.default_version_id = stmt.column_int64 (offset + 5); | ||
1619 | 225 | row.rating = stmt.column_int (offset + 6); | ||
1620 | 226 | row.md5_sum = ""; | ||
1621 | 227 | } | ||
1622 | 228 | } | ||
1623 | 229 | |||
1624 | 230 | // Photos table behavior for v16 | ||
1625 | 231 | // v16 introduced the MD5 sum so add this to the list of fields | ||
1626 | 232 | public class FSpotPhotosV16Behavior : FSpotTableBehavior<FSpotPhotoRow>, Object { | ||
1627 | 233 | private static FSpotPhotosV16Behavior instance; | ||
1628 | 234 | |||
1629 | 235 | private FSpotPhotosV16Behavior () { | ||
1630 | 236 | } | ||
1631 | 237 | |||
1632 | 238 | public static FSpotPhotosV16Behavior get_instance () { | ||
1633 | 239 | if (instance == null) | ||
1634 | 240 | instance = new FSpotPhotosV16Behavior (); | ||
1635 | 241 | return instance; | ||
1636 | 242 | } | ||
1637 | 243 | |||
1638 | 244 | public string get_table_name () { | ||
1639 | 245 | return FSpotPhotosTable.TABLE_NAME; | ||
1640 | 246 | } | ||
1641 | 247 | |||
1642 | 248 | public string[] list_columns () { | ||
1643 | 249 | return { "id", "time", "uri", "description", "roll_id", | ||
1644 | 250 | "default_version_id", "rating", "md5_sum" | ||
1645 | 251 | }; | ||
1646 | 252 | } | ||
1647 | 253 | |||
1648 | 254 | public void build_row (Sqlite.Statement stmt, out FSpotPhotoRow row, int offset = 0) { | ||
1649 | 255 | row = new FSpotPhotoRow (); | ||
1650 | 256 | row.photo_id = stmt.column_int64 (offset + 0); | ||
1651 | 257 | row.time = (time_t) stmt.column_int64 (offset + 1); | ||
1652 | 258 | |||
1653 | 259 | string? full_path = stmt.column_text (offset + 2); | ||
1654 | 260 | if (full_path != null) { | ||
1655 | 261 | File uri = File.new_for_uri (full_path); | ||
1656 | 262 | row.base_path = uri.get_parent (); | ||
1657 | 263 | row.filename = uri.get_basename (); | ||
1658 | 264 | } | ||
1659 | 265 | |||
1660 | 266 | row.description = stmt.column_text (offset + 3); | ||
1661 | 267 | row.roll_id = stmt.column_int64 (offset + 4); | ||
1662 | 268 | row.default_version_id = stmt.column_int64 (offset + 5); | ||
1663 | 269 | row.rating = stmt.column_int (offset + 6); | ||
1664 | 270 | row.md5_sum = stmt.column_text (offset + 7); | ||
1665 | 271 | } | ||
1666 | 272 | } | ||
1667 | 273 | |||
1668 | 274 | // Photos table behavior for v17 | ||
1669 | 275 | // v17 split the URI into base_uri and filename (reverting back to the original | ||
1670 | 276 | // design introduced in v0, albeit with a URI rather than a file system path) | ||
1671 | 277 | public class FSpotPhotosV17Behavior : FSpotTableBehavior<FSpotPhotoRow>, Object { | ||
1672 | 278 | private static FSpotPhotosV17Behavior instance; | ||
1673 | 279 | |||
1674 | 280 | private FSpotPhotosV17Behavior () { | ||
1675 | 281 | } | ||
1676 | 282 | |||
1677 | 283 | public static FSpotPhotosV17Behavior get_instance () { | ||
1678 | 284 | if (instance == null) | ||
1679 | 285 | instance = new FSpotPhotosV17Behavior (); | ||
1680 | 286 | return instance; | ||
1681 | 287 | } | ||
1682 | 288 | |||
1683 | 289 | public string get_table_name () { | ||
1684 | 290 | return FSpotPhotosTable.TABLE_NAME; | ||
1685 | 291 | } | ||
1686 | 292 | |||
1687 | 293 | public string[] list_columns () { | ||
1688 | 294 | return { "id", "time", "base_uri", "filename", "description", "roll_id", | ||
1689 | 295 | "default_version_id", "rating", "md5_sum" | ||
1690 | 296 | }; | ||
1691 | 297 | } | ||
1692 | 298 | |||
1693 | 299 | public void build_row (Sqlite.Statement stmt, out FSpotPhotoRow row, int offset = 0) { | ||
1694 | 300 | row = new FSpotPhotoRow (); | ||
1695 | 301 | row.photo_id = stmt.column_int64 (offset + 0); | ||
1696 | 302 | row.time = (time_t) stmt.column_int64 (offset + 1); | ||
1697 | 303 | |||
1698 | 304 | string? base_path = stmt.column_text (offset + 2); | ||
1699 | 305 | string? filename = stmt.column_text (offset + 3); | ||
1700 | 306 | if (base_path != null && filename != null) { | ||
1701 | 307 | row.base_path = File.new_for_uri (base_path); | ||
1702 | 308 | row.filename = filename; | ||
1703 | 309 | } | ||
1704 | 310 | |||
1705 | 311 | row.description = stmt.column_text (offset + 4); | ||
1706 | 312 | row.roll_id = stmt.column_int64 (offset + 5); | ||
1707 | 313 | row.default_version_id = stmt.column_int64 (offset + 6); | ||
1708 | 314 | row.rating = stmt.column_int (offset + 7); | ||
1709 | 315 | row.md5_sum = stmt.column_text (offset + 8); | ||
1710 | 316 | } | ||
1711 | 317 | } | ||
1712 | 318 | |||
1713 | 319 | // v18: no more MD5 hash in the photos table: moved to photo_versions table | ||
1714 | 320 | public class FSpotPhotosV18Behavior : FSpotTableBehavior<FSpotPhotoRow>, Object { | ||
1715 | 321 | private static FSpotPhotosV18Behavior instance; | ||
1716 | 322 | |||
1717 | 323 | private FSpotPhotosV18Behavior () { | ||
1718 | 324 | } | ||
1719 | 325 | |||
1720 | 326 | public static FSpotPhotosV18Behavior get_instance () { | ||
1721 | 327 | if (instance == null) | ||
1722 | 328 | instance = new FSpotPhotosV18Behavior (); | ||
1723 | 329 | return instance; | ||
1724 | 330 | } | ||
1725 | 331 | |||
1726 | 332 | public string get_table_name () { | ||
1727 | 333 | return FSpotPhotosTable.TABLE_NAME; | ||
1728 | 334 | } | ||
1729 | 335 | |||
1730 | 336 | public string[] list_columns () { | ||
1731 | 337 | return { "id", "time", "base_uri", "filename", "description", "roll_id", | ||
1732 | 338 | "default_version_id", "rating" | ||
1733 | 339 | }; | ||
1734 | 340 | } | ||
1735 | 341 | |||
1736 | 342 | public void build_row (Sqlite.Statement stmt, out FSpotPhotoRow row, int offset = 0) { | ||
1737 | 343 | row = new FSpotPhotoRow (); | ||
1738 | 344 | row.photo_id = stmt.column_int64 (offset + 0); | ||
1739 | 345 | row.time = (time_t) stmt.column_int64 (offset + 1); | ||
1740 | 346 | |||
1741 | 347 | string? base_path = stmt.column_text (offset + 2); | ||
1742 | 348 | string? filename = stmt.column_text (offset + 3); | ||
1743 | 349 | if (base_path != null && filename != null) { | ||
1744 | 350 | row.base_path = File.new_for_uri (base_path); | ||
1745 | 351 | row.filename = filename; | ||
1746 | 352 | } | ||
1747 | 353 | |||
1748 | 354 | row.description = stmt.column_text (offset + 4); | ||
1749 | 355 | row.roll_id = stmt.column_int64 (offset + 5); | ||
1750 | 356 | row.default_version_id = stmt.column_int64 (offset + 6); | ||
1751 | 357 | row.rating = stmt.column_int (offset + 7); | ||
1752 | 358 | row.md5_sum = ""; | ||
1753 | 359 | } | ||
1754 | 360 | } | ||
1755 | 361 | |||
1756 | 362 | } | ||
1757 | 363 | |||
1758 | 364 | 0 | ||
1759 | === removed file 'plugins/shotwell-data-imports/FSpotRollsTable.vala' | |||
1760 | --- plugins/shotwell-data-imports/FSpotRollsTable.vala 2014-08-08 21:13:09 +0000 | |||
1761 | +++ plugins/shotwell-data-imports/FSpotRollsTable.vala 1970-01-01 00:00:00 +0000 | |||
1762 | @@ -1,111 +0,0 @@ | |||
1763 | 1 | /* Copyright 2011-2013 Yorba Foundation | ||
1764 | 2 | * | ||
1765 | 3 | * This software is licensed under the GNU Lesser General Public License | ||
1766 | 4 | * (version 2.1 or later). See the COPYING file in this distribution. | ||
1767 | 5 | */ | ||
1768 | 6 | |||
1769 | 7 | namespace DataImports.FSpot.Db { | ||
1770 | 8 | |||
1771 | 9 | /** | ||
1772 | 10 | * The value object for the "rolls" table, representing a single database row. | ||
1773 | 11 | */ | ||
1774 | 12 | public class FSpotRollRow : Object { | ||
1775 | 13 | public int64 id; | ||
1776 | 14 | public time_t time; | ||
1777 | 15 | } | ||
1778 | 16 | |||
1779 | 17 | /** | ||
1780 | 18 | * This class represents the F-Spot rolls table. | ||
1781 | 19 | */ | ||
1782 | 20 | public class FSpotRollsTable : FSpotDatabaseTable<FSpotRollRow> { | ||
1783 | 21 | public static const string TABLE_NAME = "Rolls"; | ||
1784 | 22 | public static const string TABLE_NAME_PRE_V5 = "Imports"; | ||
1785 | 23 | |||
1786 | 24 | public FSpotRollsTable (Sqlite.Database db, FSpotDatabaseBehavior db_behavior) { | ||
1787 | 25 | base (db); | ||
1788 | 26 | set_behavior (db_behavior.get_rolls_behavior ()); | ||
1789 | 27 | } | ||
1790 | 28 | |||
1791 | 29 | public FSpotRollRow? get_by_id (int64 roll_id) throws DatabaseError { | ||
1792 | 30 | Sqlite.Statement stmt; | ||
1793 | 31 | FSpotRollRow? row = null; | ||
1794 | 32 | string column_list = get_joined_column_list (); | ||
1795 | 33 | string sql = "SELECT %s FROM %s WHERE id=?".printf (column_list, table_name); | ||
1796 | 34 | |||
1797 | 35 | int res = fspot_db.prepare_v2 (sql, -1, out stmt); | ||
1798 | 36 | if (res != Sqlite.OK) | ||
1799 | 37 | throw_error ("Statement failed: %s".printf (sql), res); | ||
1800 | 38 | |||
1801 | 39 | res = stmt.bind_int64 (1, roll_id); | ||
1802 | 40 | if (res != Sqlite.OK) | ||
1803 | 41 | throw_error ("Bind failed for roll_id", res); | ||
1804 | 42 | |||
1805 | 43 | res = stmt.step (); | ||
1806 | 44 | if (res == Sqlite.ROW) | ||
1807 | 45 | behavior.build_row (stmt, out row); | ||
1808 | 46 | else if (res == Sqlite.DONE) | ||
1809 | 47 | message ("Could not find roll row with ID %d", (int)roll_id); | ||
1810 | 48 | |||
1811 | 49 | return row; | ||
1812 | 50 | } | ||
1813 | 51 | } | ||
1814 | 52 | |||
1815 | 53 | // Rolls table behavior for v0-4 | ||
1816 | 54 | public class FSpotRollsV0Behavior : FSpotTableBehavior<FSpotRollRow>, Object { | ||
1817 | 55 | private static FSpotRollsV0Behavior instance; | ||
1818 | 56 | |||
1819 | 57 | private FSpotRollsV0Behavior () { | ||
1820 | 58 | } | ||
1821 | 59 | |||
1822 | 60 | public static FSpotRollsV0Behavior get_instance () { | ||
1823 | 61 | if (instance == null) | ||
1824 | 62 | instance = new FSpotRollsV0Behavior (); | ||
1825 | 63 | return instance; | ||
1826 | 64 | } | ||
1827 | 65 | |||
1828 | 66 | public string get_table_name () { | ||
1829 | 67 | return FSpotRollsTable.TABLE_NAME_PRE_V5; | ||
1830 | 68 | } | ||
1831 | 69 | |||
1832 | 70 | public string[] list_columns () { | ||
1833 | 71 | return { "id", "time" }; | ||
1834 | 72 | } | ||
1835 | 73 | |||
1836 | 74 | public void build_row (Sqlite.Statement stmt, out FSpotRollRow row, int offset = 0) { | ||
1837 | 75 | row = new FSpotRollRow (); | ||
1838 | 76 | row.id = stmt.column_int64 (offset + 0); | ||
1839 | 77 | row.time = (time_t) stmt.column_int64 (offset + 1); | ||
1840 | 78 | } | ||
1841 | 79 | } | ||
1842 | 80 | |||
1843 | 81 | // Rolls table behavior for v5+ | ||
1844 | 82 | // Table name changed from "imports" to "rolls" | ||
1845 | 83 | public class FSpotRollsV5Behavior : FSpotTableBehavior<FSpotRollRow>, Object { | ||
1846 | 84 | private static FSpotRollsV5Behavior instance; | ||
1847 | 85 | |||
1848 | 86 | private FSpotRollsV5Behavior () { | ||
1849 | 87 | } | ||
1850 | 88 | |||
1851 | 89 | public static FSpotRollsV5Behavior get_instance () { | ||
1852 | 90 | if (instance == null) | ||
1853 | 91 | instance = new FSpotRollsV5Behavior (); | ||
1854 | 92 | return instance; | ||
1855 | 93 | } | ||
1856 | 94 | |||
1857 | 95 | public string get_table_name () { | ||
1858 | 96 | return FSpotRollsTable.TABLE_NAME; | ||
1859 | 97 | } | ||
1860 | 98 | |||
1861 | 99 | public string[] list_columns () { | ||
1862 | 100 | return { "id", "time" }; | ||
1863 | 101 | } | ||
1864 | 102 | |||
1865 | 103 | public void build_row (Sqlite.Statement stmt, out FSpotRollRow row, int offset = 0) { | ||
1866 | 104 | row = new FSpotRollRow (); | ||
1867 | 105 | row.id = stmt.column_int64 (offset + 0); | ||
1868 | 106 | row.time = (time_t) stmt.column_int64 (offset + 1); | ||
1869 | 107 | } | ||
1870 | 108 | } | ||
1871 | 109 | |||
1872 | 110 | } | ||
1873 | 111 | |||
1874 | 112 | 0 | ||
1875 | === removed file 'plugins/shotwell-data-imports/FSpotTableBehavior.vala' | |||
1876 | --- plugins/shotwell-data-imports/FSpotTableBehavior.vala 2014-08-08 21:13:09 +0000 | |||
1877 | +++ plugins/shotwell-data-imports/FSpotTableBehavior.vala 1970-01-01 00:00:00 +0000 | |||
1878 | @@ -1,28 +0,0 @@ | |||
1879 | 1 | /* Copyright 2011-2013 Yorba Foundation | ||
1880 | 2 | * | ||
1881 | 3 | * This software is licensed under the GNU Lesser General Public License | ||
1882 | 4 | * (version 2.1 or later). See the COPYING file in this distribution. | ||
1883 | 5 | */ | ||
1884 | 6 | |||
1885 | 7 | namespace DataImports.FSpot.Db { | ||
1886 | 8 | |||
1887 | 9 | /** | ||
1888 | 10 | * This class defines a generic table behavior. In practice, it implements | ||
1889 | 11 | * the concept of a DAO (Data Access Object) in ORM terms and is responsible | ||
1890 | 12 | * for transforming the data extracted from a relational statement into a | ||
1891 | 13 | * lightweight value object. | ||
1892 | 14 | * | ||
1893 | 15 | * The type T defined in the generic is the value object type a behavior | ||
1894 | 16 | * implementation is designed to handle. Value object types are designed to | ||
1895 | 17 | * contain the data for a single database row. | ||
1896 | 18 | */ | ||
1897 | 19 | public interface FSpotTableBehavior<T> : Object { | ||
1898 | 20 | public abstract string get_table_name (); | ||
1899 | 21 | |||
1900 | 22 | public abstract string[] list_columns (); | ||
1901 | 23 | |||
1902 | 24 | public abstract void build_row (Sqlite.Statement stmt, out T row, int offset = 0); | ||
1903 | 25 | } | ||
1904 | 26 | |||
1905 | 27 | } | ||
1906 | 28 | |||
1907 | 29 | 0 | ||
1908 | === removed file 'plugins/shotwell-data-imports/FSpotTagsTable.vala' | |||
1909 | --- plugins/shotwell-data-imports/FSpotTagsTable.vala 2014-08-08 21:13:09 +0000 | |||
1910 | +++ plugins/shotwell-data-imports/FSpotTagsTable.vala 1970-01-01 00:00:00 +0000 | |||
1911 | @@ -1,129 +0,0 @@ | |||
1912 | 1 | /* Copyright 2011-2013 Yorba Foundation | ||
1913 | 2 | * | ||
1914 | 3 | * This software is licensed under the GNU Lesser General Public License | ||
1915 | 4 | * (version 2.1 or later). See the COPYING file in this distribution. | ||
1916 | 5 | */ | ||
1917 | 6 | |||
1918 | 7 | namespace DataImports.FSpot.Db { | ||
1919 | 8 | |||
1920 | 9 | /** | ||
1921 | 10 | * The value object for the "tags" table, representing a single database row. | ||
1922 | 11 | */ | ||
1923 | 12 | public class FSpotTagRow : Object { | ||
1924 | 13 | public int64 tag_id; | ||
1925 | 14 | public string name; | ||
1926 | 15 | public int64 category_id; | ||
1927 | 16 | public bool is_category; | ||
1928 | 17 | public int sort_priority; | ||
1929 | 18 | public string stock_icon; // only store stock icons | ||
1930 | 19 | } | ||
1931 | 20 | |||
1932 | 21 | /** | ||
1933 | 22 | * This class represents the F-Spot tags table. | ||
1934 | 23 | */ | ||
1935 | 24 | public class FSpotTagsTable : FSpotDatabaseTable<FSpotTagRow> { | ||
1936 | 25 | public static const string TABLE_NAME = "Tags"; | ||
1937 | 26 | |||
1938 | 27 | public static const string PREFIX_STOCK_ICON = "stock_icon:"; | ||
1939 | 28 | public static const string STOCK_ICON_FAV = "stock_icon:emblem-favorite"; | ||
1940 | 29 | public static const string STOCK_ICON_PEOPLE = "stock_icon:emblem-people"; | ||
1941 | 30 | public static const string STOCK_ICON_PLACES = "stock_icon:emblem-places"; | ||
1942 | 31 | public static const string STOCK_ICON_EVENTS = "stock_icon:emblem-event"; | ||
1943 | 32 | |||
1944 | 33 | private FSpotTableBehavior<FSpotPhotoTagRow> photo_tags_behavior; | ||
1945 | 34 | |||
1946 | 35 | public FSpotTagsTable (Sqlite.Database db, FSpotDatabaseBehavior db_behavior) { | ||
1947 | 36 | base (db); | ||
1948 | 37 | set_behavior (db_behavior.get_tags_behavior ()); | ||
1949 | 38 | photo_tags_behavior = db_behavior.get_photo_tags_behavior (); | ||
1950 | 39 | } | ||
1951 | 40 | |||
1952 | 41 | public FSpotTagRow? get_by_id (int64 tag_id) throws DatabaseError { | ||
1953 | 42 | Sqlite.Statement stmt; | ||
1954 | 43 | FSpotTagRow? row = null; | ||
1955 | 44 | string column_list = get_joined_column_list (); | ||
1956 | 45 | string sql = "SELECT %s FROM %s WHERE id=?".printf (column_list, table_name); | ||
1957 | 46 | |||
1958 | 47 | int res = fspot_db.prepare_v2 (sql, -1, out stmt); | ||
1959 | 48 | if (res != Sqlite.OK) | ||
1960 | 49 | throw_error ("Statement failed: %s".printf (sql), res); | ||
1961 | 50 | |||
1962 | 51 | res = stmt.bind_int64 (1, tag_id); | ||
1963 | 52 | assert (res == Sqlite.OK); | ||
1964 | 53 | |||
1965 | 54 | res = stmt.step (); | ||
1966 | 55 | if (res == Sqlite.ROW) | ||
1967 | 56 | behavior.build_row (stmt, out row); | ||
1968 | 57 | else if (res == Sqlite.DONE) | ||
1969 | 58 | message ("Could not find tag row with ID %d", (int)tag_id); | ||
1970 | 59 | |||
1971 | 60 | return row; | ||
1972 | 61 | } | ||
1973 | 62 | |||
1974 | 63 | public Gee.ArrayList<FSpotTagRow> get_by_photo_id (int64 photo_id) throws DatabaseError { | ||
1975 | 64 | Gee.ArrayList<FSpotTagRow> rows = new Gee.ArrayList < FSpotTagRow?> (); | ||
1976 | 65 | |||
1977 | 66 | Sqlite.Statement stmt; | ||
1978 | 67 | |||
1979 | 68 | string column_list = get_joined_column_list (true); | ||
1980 | 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 ( | ||
1981 | 70 | column_list, table_name, photo_tags_behavior.get_table_name () | ||
1982 | 71 | ); | ||
1983 | 72 | |||
1984 | 73 | int res = fspot_db.prepare_v2 (sql, -1, out stmt); | ||
1985 | 74 | if (res != Sqlite.OK) | ||
1986 | 75 | throw_error ("Statement failed: %s".printf (sql), res); | ||
1987 | 76 | |||
1988 | 77 | res = stmt.bind_int64 (1, photo_id); | ||
1989 | 78 | if (res != Sqlite.OK) | ||
1990 | 79 | throw_error ("Bind failed for photo_id", res); | ||
1991 | 80 | |||
1992 | 81 | res = stmt.step (); | ||
1993 | 82 | while (res == Sqlite.ROW) { | ||
1994 | 83 | FSpotTagRow row; | ||
1995 | 84 | behavior.build_row (stmt, out row); | ||
1996 | 85 | rows.add (row); | ||
1997 | 86 | res = stmt.step (); | ||
1998 | 87 | } | ||
1999 | 88 | |||
2000 | 89 | return rows; | ||
2001 | 90 | } | ||
2002 | 91 | } | ||
2003 | 92 | |||
2004 | 93 | public class FSpotTagsV0Behavior : FSpotTableBehavior<FSpotTagRow>, Object { | ||
2005 | 94 | private static FSpotTagsV0Behavior instance; | ||
2006 | 95 | |||
2007 | 96 | private FSpotTagsV0Behavior () { | ||
2008 | 97 | } | ||
2009 | 98 | |||
2010 | 99 | public static FSpotTagsV0Behavior get_instance () { | ||
2011 | 100 | if (instance == null) | ||
2012 | 101 | instance = new FSpotTagsV0Behavior (); | ||
2013 | 102 | return instance; | ||
2014 | 103 | } | ||
2015 | 104 | |||
2016 | 105 | public string get_table_name () { | ||
2017 | 106 | return FSpotTagsTable.TABLE_NAME; | ||
2018 | 107 | } | ||
2019 | 108 | |||
2020 | 109 | public string[] list_columns () { | ||
2021 | 110 | return { "id", "name", "category_id", "is_category", "sort_priority", "icon" }; | ||
2022 | 111 | } | ||
2023 | 112 | |||
2024 | 113 | public void build_row (Sqlite.Statement stmt, out FSpotTagRow row, int offset = 0) { | ||
2025 | 114 | row = new FSpotTagRow (); | ||
2026 | 115 | row.tag_id = stmt.column_int64 (offset + 0); | ||
2027 | 116 | row.name = stmt.column_text (offset + 1); | ||
2028 | 117 | row.category_id = stmt.column_int64 (offset + 2); | ||
2029 | 118 | row.is_category = (stmt.column_int (offset + 3) > 0); | ||
2030 | 119 | row.sort_priority = stmt.column_int (offset + 4); | ||
2031 | 120 | string icon_str = stmt.column_text (offset + 5); | ||
2032 | 121 | if (icon_str != null && icon_str.has_prefix (FSpotTagsTable.PREFIX_STOCK_ICON)) | ||
2033 | 122 | row.stock_icon = icon_str; | ||
2034 | 123 | else | ||
2035 | 124 | row.stock_icon = ""; | ||
2036 | 125 | } | ||
2037 | 126 | } | ||
2038 | 127 | |||
2039 | 128 | } | ||
2040 | 129 | |||
2041 | 130 | 0 | ||
2042 | === removed file 'plugins/shotwell-data-imports/Makefile' | |||
2043 | --- plugins/shotwell-data-imports/Makefile 2013-04-25 00:53:04 +0000 | |||
2044 | +++ plugins/shotwell-data-imports/Makefile 1970-01-01 00:00:00 +0000 | |||
2045 | @@ -1,30 +0,0 @@ | |||
2046 | 1 | |||
2047 | 2 | PLUGIN := shotwell-data-imports | ||
2048 | 3 | |||
2049 | 4 | PLUGIN_PKGS := \ | ||
2050 | 5 | gtk+-3.0 \ | ||
2051 | 6 | gexiv2 \ | ||
2052 | 7 | gee-0.8 \ | ||
2053 | 8 | sqlite3 | ||
2054 | 9 | |||
2055 | 10 | SRC_FILES := \ | ||
2056 | 11 | shotwell-data-imports.vala \ | ||
2057 | 12 | ../common/VersionNumber.vala \ | ||
2058 | 13 | ../common/SqliteSupport.vala \ | ||
2059 | 14 | FSpotImporter.vala \ | ||
2060 | 15 | FSpotDatabaseBehavior.vala \ | ||
2061 | 16 | FSpotDatabase.vala \ | ||
2062 | 17 | FSpotDatabaseTable.vala \ | ||
2063 | 18 | FSpotTableBehavior.vala \ | ||
2064 | 19 | FSpotMetaTable.vala \ | ||
2065 | 20 | FSpotPhotosTable.vala \ | ||
2066 | 21 | FSpotPhotoTagsTable.vala \ | ||
2067 | 22 | FSpotPhotoVersionsTable.vala \ | ||
2068 | 23 | FSpotRollsTable.vala \ | ||
2069 | 24 | FSpotTagsTable.vala | ||
2070 | 25 | |||
2071 | 26 | RC_FILES := \ | ||
2072 | 27 | f-spot-24.png | ||
2073 | 28 | |||
2074 | 29 | include ../Makefile.plugin.mk | ||
2075 | 30 | |||
2076 | 31 | 0 | ||
2077 | === removed file 'plugins/shotwell-data-imports/f-spot-24.png' | |||
2078 | 32 | Binary 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 | 1 | Binary 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 |
2079 | === removed file 'plugins/shotwell-data-imports/shotwell-data-imports.vala' | |||
2080 | --- plugins/shotwell-data-imports/shotwell-data-imports.vala 2014-08-08 21:13:09 +0000 | |||
2081 | +++ plugins/shotwell-data-imports/shotwell-data-imports.vala 1970-01-01 00:00:00 +0000 | |||
2082 | @@ -1,46 +0,0 @@ | |||
2083 | 1 | /* Copyright 2011-2013 Yorba Foundation | ||
2084 | 2 | * | ||
2085 | 3 | * This software is licensed under the GNU Lesser General Public License | ||
2086 | 4 | * (version 2.1 or later). See the COPYING file in this distribution. | ||
2087 | 5 | */ | ||
2088 | 6 | |||
2089 | 7 | extern const string _VERSION; | ||
2090 | 8 | |||
2091 | 9 | // "core services" are: F-Spot | ||
2092 | 10 | private class ShotwellDataImportsCoreServices : Object, Spit.Module { | ||
2093 | 11 | private Spit.Pluggable[] pluggables = new Spit.Pluggable[0]; | ||
2094 | 12 | |||
2095 | 13 | // we need to get a module file handle because our pluggables have to load resources from the | ||
2096 | 14 | // module file directory | ||
2097 | 15 | public ShotwellDataImportsCoreServices (GLib.File module_file) { | ||
2098 | 16 | GLib.File resource_directory = module_file.get_parent (); | ||
2099 | 17 | |||
2100 | 18 | pluggables += new FSpotService (resource_directory); | ||
2101 | 19 | } | ||
2102 | 20 | |||
2103 | 21 | public unowned string get_module_name () { | ||
2104 | 22 | return _ ("Core Data Import Services"); | ||
2105 | 23 | } | ||
2106 | 24 | |||
2107 | 25 | public unowned string get_version () { | ||
2108 | 26 | return _VERSION; | ||
2109 | 27 | } | ||
2110 | 28 | |||
2111 | 29 | public unowned string get_id () { | ||
2112 | 30 | return "org.yorba.shotwell.data_imports.core_services"; | ||
2113 | 31 | } | ||
2114 | 32 | |||
2115 | 33 | public unowned Spit.Pluggable[]? get_pluggables () { | ||
2116 | 34 | return pluggables; | ||
2117 | 35 | } | ||
2118 | 36 | } | ||
2119 | 37 | |||
2120 | 38 | // This entry point is required for all SPIT modules. | ||
2121 | 39 | public Spit.Module? spit_entry_point (Spit.EntryPointParams *params) { | ||
2122 | 40 | params->module_spit_interface = Spit.negotiate_interfaces (params->host_min_spit_interface, | ||
2123 | 41 | params->host_max_spit_interface, Spit.CURRENT_INTERFACE); | ||
2124 | 42 | |||
2125 | 43 | return (params->module_spit_interface != Spit.UNSUPPORTED_INTERFACE) | ||
2126 | 44 | ? new ShotwellDataImportsCoreServices (params->module_file) : null; | ||
2127 | 45 | } | ||
2128 | 46 | |||
2129 | 47 | 0 | ||
2130 | === modified file 'src/Dialogs.vala' | |||
2131 | --- src/Dialogs.vala 2014-08-20 20:14:47 +0000 | |||
2132 | +++ src/Dialogs.vala 2014-08-28 06:03:26 +0000 | |||
2133 | @@ -1884,12 +1884,10 @@ | |||
2134 | 1884 | Gtk.Box import_content; | 1884 | Gtk.Box import_content; |
2135 | 1885 | Gtk.Box import_action_checkbox_packer; | 1885 | Gtk.Box import_action_checkbox_packer; |
2136 | 1886 | Gtk.Box external_import_action_checkbox_packer; | 1886 | Gtk.Box external_import_action_checkbox_packer; |
2137 | 1887 | Spit.DataImports.WelcomeImportMetaHost import_meta_host; | ||
2138 | 1888 | bool import_content_already_installed = false; | 1887 | bool import_content_already_installed = false; |
2139 | 1889 | bool ok_clicked = false; | 1888 | bool ok_clicked = false; |
2140 | 1890 | 1889 | ||
2141 | 1891 | public WelcomeDialog (Gtk.Window owner) { | 1890 | public WelcomeDialog (Gtk.Window owner) { |
2142 | 1892 | import_meta_host = new Spit.DataImports.WelcomeImportMetaHost (this); | ||
2143 | 1893 | bool show_system_pictures_import = is_system_pictures_import_possible (); | 1891 | bool show_system_pictures_import = is_system_pictures_import_possible (); |
2144 | 1894 | Gtk.Widget ok_button = add_button (_ ("_Close"), Gtk.ResponseType.OK); | 1892 | Gtk.Widget ok_button = add_button (_ ("_Close"), Gtk.ResponseType.OK); |
2145 | 1895 | set_title (_ ("Welcome!")); | 1893 | set_title (_ ("Welcome!")); |
2146 | @@ -1966,8 +1964,6 @@ | |||
2147 | 1966 | ok_button.grab_focus (); | 1964 | ok_button.grab_focus (); |
2148 | 1967 | 1965 | ||
2149 | 1968 | install_import_content (); | 1966 | install_import_content (); |
2150 | 1969 | |||
2151 | 1970 | import_meta_host.start (); | ||
2152 | 1971 | } | 1967 | } |
2153 | 1972 | 1968 | ||
2154 | 1973 | private void install_import_content () { | 1969 | private void install_import_content () { |
2155 | @@ -2498,4 +2494,4 @@ | |||
2156 | 2498 | progress.close (); | 2494 | progress.close (); |
2157 | 2499 | 2495 | ||
2158 | 2500 | AppWindow.get_instance ().set_normal_cursor (); | 2496 | AppWindow.get_instance ().set_normal_cursor (); |
2159 | 2501 | } | ||
2160 | 2502 | \ No newline at end of file | 2497 | \ No newline at end of file |
2161 | 2498 | } | ||
2162 | 2503 | 2499 | ||
2163 | === removed directory 'src/data_imports' | |||
2164 | === removed file 'src/data_imports/DataImportJob.vala' | |||
2165 | --- src/data_imports/DataImportJob.vala 2014-08-08 21:13:09 +0000 | |||
2166 | +++ src/data_imports/DataImportJob.vala 1970-01-01 00:00:00 +0000 | |||
2167 | @@ -1,177 +0,0 @@ | |||
2168 | 1 | /* Copyright 2009-2013 Yorba Foundation | ||
2169 | 2 | * | ||
2170 | 3 | * This software is licensed under the GNU LGPL (version 2.1 or later). | ||
2171 | 4 | * See the COPYING file in this distribution. | ||
2172 | 5 | */ | ||
2173 | 6 | |||
2174 | 7 | namespace Spit.DataImports { | ||
2175 | 8 | |||
2176 | 9 | /** | ||
2177 | 10 | * A specialized import job implementation for alien databases. | ||
2178 | 11 | */ | ||
2179 | 12 | public class DataImportJob : BatchImportJob { | ||
2180 | 13 | private DataImportSource import_source; | ||
2181 | 14 | private File? src_file; | ||
2182 | 15 | private uint64 filesize; | ||
2183 | 16 | private time_t exposure_time; | ||
2184 | 17 | private DataImportJob? associated = null; | ||
2185 | 18 | private HierarchicalTagIndex? detected_htags = null; | ||
2186 | 19 | |||
2187 | 20 | public DataImportJob (DataImportSource import_source) { | ||
2188 | 21 | this.import_source = import_source; | ||
2189 | 22 | |||
2190 | 23 | // stash everything called in prepare (), as it may/will be called from a separate thread | ||
2191 | 24 | src_file = import_source.get_file (); | ||
2192 | 25 | filesize = import_source.get_filesize (); | ||
2193 | 26 | exposure_time = import_source.get_exposure_time (); | ||
2194 | 27 | } | ||
2195 | 28 | |||
2196 | 29 | private HierarchicalTagIndex? build_exclusion_index (ImportableTag[] src_tags) { | ||
2197 | 30 | Gee.Set<string> detected_htags = new Gee.HashSet<string> (); | ||
2198 | 31 | |||
2199 | 32 | foreach (ImportableTag src_tag in src_tags) { | ||
2200 | 33 | string? prepped = HierarchicalTagUtilities.join_path_components ( | ||
2201 | 34 | Tag.prep_tag_names ( | ||
2202 | 35 | build_path_components (src_tag) | ||
2203 | 36 | ) | ||
2204 | 37 | ); | ||
2205 | 38 | |||
2206 | 39 | if (prepped != null && prepped.has_prefix (Tag.PATH_SEPARATOR_STRING)) { | ||
2207 | 40 | detected_htags.add (prepped); | ||
2208 | 41 | |||
2209 | 42 | Gee.List<string> parents = HierarchicalTagUtilities.enumerate_parent_paths (prepped); | ||
2210 | 43 | foreach (string parent in parents) | ||
2211 | 44 | detected_htags.add (parent); | ||
2212 | 45 | } | ||
2213 | 46 | } | ||
2214 | 47 | |||
2215 | 48 | return (detected_htags.size > 0) ? HierarchicalTagIndex.from_paths (detected_htags) : null; | ||
2216 | 49 | } | ||
2217 | 50 | |||
2218 | 51 | public time_t get_exposure_time () { | ||
2219 | 52 | return exposure_time; | ||
2220 | 53 | } | ||
2221 | 54 | |||
2222 | 55 | public override string get_dest_identifier () { | ||
2223 | 56 | return import_source.get_filename (); | ||
2224 | 57 | } | ||
2225 | 58 | |||
2226 | 59 | public override string get_source_identifier () { | ||
2227 | 60 | return import_source.get_filename (); | ||
2228 | 61 | } | ||
2229 | 62 | |||
2230 | 63 | public override bool is_directory () { | ||
2231 | 64 | return false; | ||
2232 | 65 | } | ||
2233 | 66 | |||
2234 | 67 | public override string get_basename () { | ||
2235 | 68 | return src_file.get_basename (); | ||
2236 | 69 | } | ||
2237 | 70 | |||
2238 | 71 | public override string get_path () { | ||
2239 | 72 | return src_file.get_parent ().get_path (); | ||
2240 | 73 | } | ||
2241 | 74 | |||
2242 | 75 | public override void set_associated (BatchImportJob associated) { | ||
2243 | 76 | this.associated = associated as DataImportJob; | ||
2244 | 77 | } | ||
2245 | 78 | |||
2246 | 79 | public override bool determine_file_size (out uint64 filesize, out File file) { | ||
2247 | 80 | file = null; | ||
2248 | 81 | filesize = this.filesize; | ||
2249 | 82 | |||
2250 | 83 | return true; | ||
2251 | 84 | } | ||
2252 | 85 | |||
2253 | 86 | public override bool prepare (out File file_to_import, out bool copy_to_library) throws Error { | ||
2254 | 87 | file_to_import = src_file; | ||
2255 | 88 | copy_to_library = false; | ||
2256 | 89 | |||
2257 | 90 | detected_htags = build_exclusion_index (import_source.get_photo ().get_tags ()); | ||
2258 | 91 | |||
2259 | 92 | return true; | ||
2260 | 93 | } | ||
2261 | 94 | |||
2262 | 95 | public override bool complete (MediaSource source, BatchImportRoll import_roll) throws Error { | ||
2263 | 96 | LibraryPhoto? photo = source as LibraryPhoto; | ||
2264 | 97 | if (photo == null) | ||
2265 | 98 | return false; | ||
2266 | 99 | |||
2267 | 100 | ImportableMediaItem src_photo = import_source.get_photo (); | ||
2268 | 101 | |||
2269 | 102 | // tags | ||
2270 | 103 | if (detected_htags != null) { | ||
2271 | 104 | Gee.Collection<string> paths = detected_htags.get_all_paths (); | ||
2272 | 105 | |||
2273 | 106 | foreach (string path in paths) | ||
2274 | 107 | Tag.for_path (path); | ||
2275 | 108 | } | ||
2276 | 109 | |||
2277 | 110 | ImportableTag[] src_tags = src_photo.get_tags (); | ||
2278 | 111 | foreach (ImportableTag src_tag in src_tags) { | ||
2279 | 112 | string? prepped = HierarchicalTagUtilities.join_path_components ( | ||
2280 | 113 | Tag.prep_tag_names ( | ||
2281 | 114 | build_path_components (src_tag) | ||
2282 | 115 | ) | ||
2283 | 116 | ); | ||
2284 | 117 | if (prepped != null) { | ||
2285 | 118 | if (HierarchicalTagUtilities.enumerate_path_components (prepped).size == 1) { | ||
2286 | 119 | if (prepped.has_prefix (Tag.PATH_SEPARATOR_STRING)) | ||
2287 | 120 | prepped = HierarchicalTagUtilities.hierarchical_to_flat (prepped); | ||
2288 | 121 | } else { | ||
2289 | 122 | Gee.List<string> parents = | ||
2290 | 123 | HierarchicalTagUtilities.enumerate_parent_paths (prepped); | ||
2291 | 124 | |||
2292 | 125 | assert (parents.size > 0); | ||
2293 | 126 | |||
2294 | 127 | string top_level_parent = parents.get (0); | ||
2295 | 128 | string flat_top_level_parent = | ||
2296 | 129 | HierarchicalTagUtilities.hierarchical_to_flat (top_level_parent); | ||
2297 | 130 | |||
2298 | 131 | if (Tag.global.exists (flat_top_level_parent)) | ||
2299 | 132 | Tag.for_path (flat_top_level_parent).promote (); | ||
2300 | 133 | } | ||
2301 | 134 | |||
2302 | 135 | Tag.for_path (prepped).attach (photo); | ||
2303 | 136 | } | ||
2304 | 137 | } | ||
2305 | 138 | // event | ||
2306 | 139 | ImportableEvent? src_event = src_photo.get_event (); | ||
2307 | 140 | if (src_event != null) { | ||
2308 | 141 | string? prepped = prepare_input_text (src_event.get_name (), | ||
2309 | 142 | PrepareInputTextOptions.DEFAULT, -1); | ||
2310 | 143 | if (prepped != null) | ||
2311 | 144 | Event.generate_single_event (photo, import_roll.generated_events, prepped); | ||
2312 | 145 | } | ||
2313 | 146 | // rating | ||
2314 | 147 | Rating dst_rating; | ||
2315 | 148 | ImportableRating src_rating = src_photo.get_rating (); | ||
2316 | 149 | if (src_rating.is_rejected ()) | ||
2317 | 150 | dst_rating = Rating.REJECTED; | ||
2318 | 151 | else if (src_rating.is_unrated ()) | ||
2319 | 152 | dst_rating = Rating.UNRATED; | ||
2320 | 153 | else | ||
2321 | 154 | dst_rating = Rating.unserialize (src_rating.get_value ()); | ||
2322 | 155 | photo.set_rating (dst_rating); | ||
2323 | 156 | // title | ||
2324 | 157 | string? title = src_photo.get_title (); | ||
2325 | 158 | if (title != null) | ||
2326 | 159 | photo.set_title (title); | ||
2327 | 160 | // import ID | ||
2328 | 161 | photo.set_import_id (import_roll.import_id); | ||
2329 | 162 | |||
2330 | 163 | return true; | ||
2331 | 164 | } | ||
2332 | 165 | |||
2333 | 166 | private string[] build_path_components (ImportableTag tag) { | ||
2334 | 167 | // use a linked list as we are always inserting in head position | ||
2335 | 168 | Gee.List<string> components = new Gee.LinkedList<string> (); | ||
2336 | 169 | for (ImportableTag current_tag = tag; current_tag != null; current_tag = current_tag.get_parent ()) { | ||
2337 | 170 | components.insert (0, HierarchicalTagUtilities.make_flat_tag_safe (current_tag.get_name ())); | ||
2338 | 171 | } | ||
2339 | 172 | return components.to_array (); | ||
2340 | 173 | } | ||
2341 | 174 | } | ||
2342 | 175 | |||
2343 | 176 | } | ||
2344 | 177 | |||
2345 | 178 | 0 | ||
2346 | === removed file 'src/data_imports/DataImportSource.vala' | |||
2347 | --- src/data_imports/DataImportSource.vala 2014-08-08 21:13:09 +0000 | |||
2348 | +++ src/data_imports/DataImportSource.vala 1970-01-01 00:00:00 +0000 | |||
2349 | @@ -1,135 +0,0 @@ | |||
2350 | 1 | /* Copyright 2011-2013 Yorba Foundation | ||
2351 | 2 | * | ||
2352 | 3 | * This software is licensed under the GNU Lesser General Public License | ||
2353 | 4 | * (version 2.1 or later). See the COPYING file in this distribution. | ||
2354 | 5 | */ | ||
2355 | 6 | |||
2356 | 7 | namespace Spit.DataImports { | ||
2357 | 8 | |||
2358 | 9 | /** | ||
2359 | 10 | * Photo source implementation for alien databases. This class is responsible | ||
2360 | 11 | * for extracting meta-data out of a source photo to support the import | ||
2361 | 12 | * process. | ||
2362 | 13 | * | ||
2363 | 14 | * This class does not extend PhotoSource in order to minimise the API to the | ||
2364 | 15 | * absolute minimum required to run the import job. | ||
2365 | 16 | */ | ||
2366 | 17 | public class DataImportSource { | ||
2367 | 18 | private bool backing_file_found; | ||
2368 | 19 | private ImportableMediaItem db_photo; | ||
2369 | 20 | private string? title = null; | ||
2370 | 21 | private string? preview_md5 = null; | ||
2371 | 22 | private uint64 file_size; | ||
2372 | 23 | private time_t modification_time; | ||
2373 | 24 | private MetadataDateTime? exposure_time; | ||
2374 | 25 | |||
2375 | 26 | public DataImportSource (ImportableMediaItem db_photo) { | ||
2376 | 27 | this.db_photo = db_photo; | ||
2377 | 28 | |||
2378 | 29 | // A well-behaved plugin will ensure that the path and file name are | ||
2379 | 30 | // not null but we check just in case | ||
2380 | 31 | string folder_path = db_photo.get_folder_path (); | ||
2381 | 32 | string filename = db_photo.get_filename (); | ||
2382 | 33 | File? photo = null; | ||
2383 | 34 | if (folder_path != null && filename != null) { | ||
2384 | 35 | photo = File.new_for_path (db_photo.get_folder_path ()). | ||
2385 | 36 | get_child (db_photo.get_filename ()); | ||
2386 | 37 | |||
2387 | 38 | backing_file_found = photo.query_exists (); | ||
2388 | 39 | } else { | ||
2389 | 40 | backing_file_found = false; | ||
2390 | 41 | } | ||
2391 | 42 | |||
2392 | 43 | if (photo != null && backing_file_found) { | ||
2393 | 44 | PhotoMetadata? metadata = new PhotoMetadata (); | ||
2394 | 45 | try { | ||
2395 | 46 | metadata.read_from_file (photo); | ||
2396 | 47 | } catch (Error e) { | ||
2397 | 48 | warning ("Could not get file metadata for %s: %s", get_filename (), e.message); | ||
2398 | 49 | metadata = null; | ||
2399 | 50 | } | ||
2400 | 51 | |||
2401 | 52 | title = (metadata != null) ? metadata.get_title () : null; | ||
2402 | 53 | exposure_time = (metadata != null) ? metadata.get_exposure_date_time () : null; | ||
2403 | 54 | PhotoPreview ? preview = metadata != null ? metadata.get_preview (0) : null; | ||
2404 | 55 | if (preview != null) { | ||
2405 | 56 | try { | ||
2406 | 57 | uint8[] preview_raw = preview.flatten (); | ||
2407 | 58 | preview_md5 = md5_binary (preview_raw, preview_raw.length); | ||
2408 | 59 | } catch (Error e) { | ||
2409 | 60 | warning ("Could not get raw preview for %s: %s", get_filename (), e.message); | ||
2410 | 61 | } | ||
2411 | 62 | } | ||
2412 | 63 | #if TRACE_MD5 | ||
2413 | 64 | debug ("Photo MD5 %s: preview=%s", get_filename (), preview_md5); | ||
2414 | 65 | #endif | ||
2415 | 66 | |||
2416 | 67 | try { | ||
2417 | 68 | file_size = query_total_file_size (photo); | ||
2418 | 69 | } catch (Error e) { | ||
2419 | 70 | warning ("Could not get file size for %s: %s", get_filename (), e.message); | ||
2420 | 71 | } | ||
2421 | 72 | try { | ||
2422 | 73 | modification_time = query_file_modified (photo); | ||
2423 | 74 | } catch (Error e) { | ||
2424 | 75 | warning ("Could not get modification time for %s: %s", get_filename (), e.message); | ||
2425 | 76 | } | ||
2426 | 77 | } else { | ||
2427 | 78 | debug ("Photo file %s not found".printf (photo.get_path ())); | ||
2428 | 79 | } | ||
2429 | 80 | } | ||
2430 | 81 | |||
2431 | 82 | public string get_filename () { | ||
2432 | 83 | return db_photo.get_filename (); | ||
2433 | 84 | } | ||
2434 | 85 | |||
2435 | 86 | public string get_fulldir () { | ||
2436 | 87 | return db_photo.get_folder_path (); | ||
2437 | 88 | } | ||
2438 | 89 | |||
2439 | 90 | public File get_file () { | ||
2440 | 91 | return File.new_for_path (get_fulldir ()).get_child (get_filename ()); | ||
2441 | 92 | } | ||
2442 | 93 | |||
2443 | 94 | public string get_name () { | ||
2444 | 95 | return !is_string_empty (title) ? title : get_filename (); | ||
2445 | 96 | } | ||
2446 | 97 | |||
2447 | 98 | public string? get_title () { | ||
2448 | 99 | return title; | ||
2449 | 100 | } | ||
2450 | 101 | |||
2451 | 102 | public PhotoFileFormat get_file_format () { | ||
2452 | 103 | return PhotoFileFormat.get_by_basename_extension (get_filename ()); | ||
2453 | 104 | } | ||
2454 | 105 | |||
2455 | 106 | public string to_string () { | ||
2456 | 107 | return get_name (); | ||
2457 | 108 | } | ||
2458 | 109 | |||
2459 | 110 | public time_t get_exposure_time () { | ||
2460 | 111 | return (exposure_time != null) ? exposure_time.get_timestamp () : modification_time; | ||
2461 | 112 | } | ||
2462 | 113 | |||
2463 | 114 | public uint64 get_filesize () { | ||
2464 | 115 | return file_size; | ||
2465 | 116 | } | ||
2466 | 117 | |||
2467 | 118 | public ImportableMediaItem get_photo () { | ||
2468 | 119 | return db_photo; | ||
2469 | 120 | } | ||
2470 | 121 | |||
2471 | 122 | public bool is_already_imported () { | ||
2472 | 123 | // ignore trashed duplicates | ||
2473 | 124 | return (preview_md5 != null) | ||
2474 | 125 | ? LibraryPhoto.has_nontrash_duplicate (null, preview_md5, null, get_file_format ()) | ||
2475 | 126 | : false; | ||
2476 | 127 | } | ||
2477 | 128 | |||
2478 | 129 | public bool was_backing_file_found () { | ||
2479 | 130 | return backing_file_found; | ||
2480 | 131 | } | ||
2481 | 132 | } | ||
2482 | 133 | |||
2483 | 134 | } | ||
2484 | 135 | |||
2485 | 136 | 0 | ||
2486 | === removed file 'src/data_imports/DataImports.vala' | |||
2487 | --- src/data_imports/DataImports.vala 2014-08-08 21:13:09 +0000 | |||
2488 | +++ src/data_imports/DataImports.vala 1970-01-01 00:00:00 +0000 | |||
2489 | @@ -1,30 +0,0 @@ | |||
2490 | 1 | /* Copyright 2011-2013 Yorba Foundation | ||
2491 | 2 | * | ||
2492 | 3 | * This software is licensed under the GNU Lesser General Public License | ||
2493 | 4 | * (version 2.1 or later). See the COPYING file in this distribution. | ||
2494 | 5 | */ | ||
2495 | 6 | |||
2496 | 7 | /* This file is the master unit file for the DataImports unit. It should be edited to include | ||
2497 | 8 | * whatever code is deemed necessary. | ||
2498 | 9 | * | ||
2499 | 10 | * The init () and terminate () methods are mandatory. | ||
2500 | 11 | * | ||
2501 | 12 | * If the unit needs to be configured prior to initialization, add the proper parameters to | ||
2502 | 13 | * the preconfigure () method, implement it, and ensure in init () that it's been called. | ||
2503 | 14 | */ | ||
2504 | 15 | |||
2505 | 16 | namespace DataImports { | ||
2506 | 17 | |||
2507 | 18 | public void init () throws Error { | ||
2508 | 19 | string[] core_ids = new string[0]; | ||
2509 | 20 | core_ids += "org.yorba.shotwell.dataimports.fspot"; | ||
2510 | 21 | |||
2511 | 22 | Plugins.register_extension_point (typeof (Spit.DataImports.Service), _ ("Data Imports"), | ||
2512 | 23 | Resources.IMPORT, core_ids); | ||
2513 | 24 | } | ||
2514 | 25 | |||
2515 | 26 | public void terminate () { | ||
2516 | 27 | } | ||
2517 | 28 | |||
2518 | 29 | } | ||
2519 | 30 | |||
2520 | 31 | 0 | ||
2521 | === removed file 'src/data_imports/DataImportsPluginHost.vala' | |||
2522 | --- src/data_imports/DataImportsPluginHost.vala 2014-08-08 21:13:09 +0000 | |||
2523 | +++ src/data_imports/DataImportsPluginHost.vala 1970-01-01 00:00:00 +0000 | |||
2524 | @@ -1,483 +0,0 @@ | |||
2525 | 1 | /* Copyright 2011-2013 Yorba Foundation | ||
2526 | 2 | * | ||
2527 | 3 | * This software is licensed under the GNU Lesser General Public License | ||
2528 | 4 | * (version 2.1 or later). See the COPYING file in this distribution. | ||
2529 | 5 | */ | ||
2530 | 6 | |||
2531 | 7 | namespace Spit.DataImports { | ||
2532 | 8 | |||
2533 | 9 | private class CoreImporter { | ||
2534 | 10 | private weak Spit.DataImports.PluginHost host; | ||
2535 | 11 | public int imported_items_count = 0; | ||
2536 | 12 | public BatchImportRoll? current_import_roll = null; | ||
2537 | 13 | |||
2538 | 14 | public CoreImporter (Spit.DataImports.PluginHost host) { | ||
2539 | 15 | this.host = host; | ||
2540 | 16 | } | ||
2541 | 17 | |||
2542 | 18 | public void prepare_media_items_for_import ( | ||
2543 | 19 | ImportableMediaItem[] items, | ||
2544 | 20 | double progress, | ||
2545 | 21 | double host_progress_delta = 0.0, | ||
2546 | 22 | string? progress_message = null | ||
2547 | 23 | ) { | ||
2548 | 24 | host.update_import_progress_pane (progress, progress_message); | ||
2549 | 25 | // | ||
2550 | 26 | SortedList<DataImportJob> jobs = | ||
2551 | 27 | new SortedList<DataImportJob> (import_job_comparator); | ||
2552 | 28 | Gee.ArrayList<DataImportJob> already_imported = | ||
2553 | 29 | new Gee.ArrayList<DataImportJob> (); | ||
2554 | 30 | Gee.ArrayList<DataImportJob> failed = | ||
2555 | 31 | new Gee.ArrayList<DataImportJob> (); | ||
2556 | 32 | |||
2557 | 33 | int item_idx = 0; | ||
2558 | 34 | double item_progress_delta = host_progress_delta / items.length; | ||
2559 | 35 | foreach (ImportableMediaItem src_item in items) { | ||
2560 | 36 | DataImportSource import_source = new DataImportSource (src_item); | ||
2561 | 37 | |||
2562 | 38 | if (!import_source.was_backing_file_found ()) { | ||
2563 | 39 | message ("Skipping import of %s: backing file not found", | ||
2564 | 40 | import_source.get_filename ()); | ||
2565 | 41 | failed.add (new DataImportJob (import_source)); | ||
2566 | 42 | |||
2567 | 43 | continue; | ||
2568 | 44 | } | ||
2569 | 45 | |||
2570 | 46 | if (import_source.is_already_imported ()) { | ||
2571 | 47 | message ("Skipping import of %s: checksum detected in library", | ||
2572 | 48 | import_source.get_filename ()); | ||
2573 | 49 | already_imported.add (new DataImportJob (import_source)); | ||
2574 | 50 | |||
2575 | 51 | continue; | ||
2576 | 52 | } | ||
2577 | 53 | |||
2578 | 54 | jobs.add (new DataImportJob (import_source)); | ||
2579 | 55 | item_idx++; | ||
2580 | 56 | host.update_import_progress_pane (progress + item_idx * item_progress_delta); | ||
2581 | 57 | } | ||
2582 | 58 | |||
2583 | 59 | if (jobs.size > 0) { | ||
2584 | 60 | // If there it no current import roll, create one to ensure that all | ||
2585 | 61 | // imported items end up in the same roll even if this method is called | ||
2586 | 62 | // several times | ||
2587 | 63 | if (current_import_roll == null) | ||
2588 | 64 | current_import_roll = new BatchImportRoll (); | ||
2589 | 65 | string db_name = _ ("%s Database").printf (host.get_data_importer ().get_service ().get_pluggable_name ()); | ||
2590 | 66 | BatchImport batch_import = new BatchImport (jobs, db_name, data_import_reporter, | ||
2591 | 67 | failed, already_imported, null, current_import_roll); | ||
2592 | 68 | |||
2593 | 69 | LibraryWindow.get_app ().enqueue_batch_import (batch_import, true); | ||
2594 | 70 | imported_items_count += jobs.size; | ||
2595 | 71 | } | ||
2596 | 72 | |||
2597 | 73 | host.update_import_progress_pane (progress + host_progress_delta); | ||
2598 | 74 | } | ||
2599 | 75 | |||
2600 | 76 | public void finalize_import () { | ||
2601 | 77 | // Send an empty job to the queue to mark the end of the import | ||
2602 | 78 | string db_name = _ ("%s Database").printf (host.get_data_importer ().get_service ().get_pluggable_name ()); | ||
2603 | 79 | BatchImport batch_import = new BatchImport ( | ||
2604 | 80 | new Gee.ArrayList<BatchImportJob> (), db_name, data_import_reporter, null, null, null, current_import_roll | ||
2605 | 81 | ); | ||
2606 | 82 | LibraryWindow.get_app ().enqueue_batch_import (batch_import, true); | ||
2607 | 83 | current_import_roll = null; | ||
2608 | 84 | } | ||
2609 | 85 | } | ||
2610 | 86 | |||
2611 | 87 | public class ConcreteDataImportsHost : Plugins.StandardHostInterface, | ||
2612 | 88 | Spit.DataImports.PluginHost { | ||
2613 | 89 | |||
2614 | 90 | private Spit.DataImports.DataImporter active_importer = null; | ||
2615 | 91 | private weak DataImportsUI.DataImportsDialog dialog = null; | ||
2616 | 92 | private DataImportsUI.ProgressPane? progress_pane = null; | ||
2617 | 93 | private bool importing_halted = false; | ||
2618 | 94 | private CoreImporter core_importer; | ||
2619 | 95 | |||
2620 | 96 | public ConcreteDataImportsHost (Service service, DataImportsUI.DataImportsDialog dialog) { | ||
2621 | 97 | base (service, "data_imports"); | ||
2622 | 98 | this.dialog = dialog; | ||
2623 | 99 | |||
2624 | 100 | this.active_importer = service.create_data_importer (this); | ||
2625 | 101 | this.core_importer = new CoreImporter (this); | ||
2626 | 102 | } | ||
2627 | 103 | |||
2628 | 104 | public DataImporter get_data_importer () { | ||
2629 | 105 | return active_importer; | ||
2630 | 106 | } | ||
2631 | 107 | |||
2632 | 108 | public void start_importing () { | ||
2633 | 109 | if (get_data_importer ().is_running ()) | ||
2634 | 110 | return; | ||
2635 | 111 | |||
2636 | 112 | debug ("ConcreteDataImportsHost.start_importing( ): invoked."); | ||
2637 | 113 | |||
2638 | 114 | get_data_importer ().start (); | ||
2639 | 115 | } | ||
2640 | 116 | |||
2641 | 117 | public void stop_importing () { | ||
2642 | 118 | debug ("ConcreteDataImportsHost.stop_importing( ): invoked."); | ||
2643 | 119 | |||
2644 | 120 | if (get_data_importer ().is_running ()) | ||
2645 | 121 | get_data_importer ().stop (); | ||
2646 | 122 | |||
2647 | 123 | clean_up (); | ||
2648 | 124 | |||
2649 | 125 | importing_halted = true; | ||
2650 | 126 | } | ||
2651 | 127 | |||
2652 | 128 | private void clean_up () { | ||
2653 | 129 | progress_pane = null; | ||
2654 | 130 | } | ||
2655 | 131 | |||
2656 | 132 | public void set_button_mode (Spit.DataImports.PluginHost.ButtonMode mode) { | ||
2657 | 133 | if (mode == Spit.DataImports.PluginHost.ButtonMode.CLOSE) | ||
2658 | 134 | dialog.set_close_button_mode (); | ||
2659 | 135 | else if (mode == Spit.DataImports.PluginHost.ButtonMode.CANCEL) | ||
2660 | 136 | dialog.set_cancel_button_mode (); | ||
2661 | 137 | else | ||
2662 | 138 | error ("unrecognized button mode enumeration value"); | ||
2663 | 139 | } | ||
2664 | 140 | |||
2665 | 141 | // Pane handling methods | ||
2666 | 142 | |||
2667 | 143 | public void post_error (Error err) { | ||
2668 | 144 | post_error_message (err.message); | ||
2669 | 145 | } | ||
2670 | 146 | |||
2671 | 147 | public void post_error_message (string message) { | ||
2672 | 148 | string msg = _ ("Importing from %s can't continue because an error occurred:").printf ( | ||
2673 | 149 | active_importer.get_service ().get_pluggable_name ()); | ||
2674 | 150 | msg += GLib.Markup.printf_escaped ("\n\n<i>%s</i>\n\n", message); | ||
2675 | 151 | msg += _ ("To try importing from another service, select one from the above menu."); | ||
2676 | 152 | |||
2677 | 153 | dialog.install_pane (new DataImportsUI.StaticMessagePane.with_pango (msg)); | ||
2678 | 154 | dialog.set_close_button_mode (); | ||
2679 | 155 | dialog.unlock_service (); | ||
2680 | 156 | |||
2681 | 157 | get_data_importer ().stop (); | ||
2682 | 158 | |||
2683 | 159 | // post_error_message( ) tells the active_importer to stop importing and displays a | ||
2684 | 160 | // non-removable error pane that effectively ends the publishing interaction, | ||
2685 | 161 | // so no problem calling clean_up( ) here. | ||
2686 | 162 | clean_up (); | ||
2687 | 163 | } | ||
2688 | 164 | |||
2689 | 165 | public void install_dialog_pane (Spit.DataImports.DialogPane pane, | ||
2690 | 166 | Spit.DataImports.PluginHost.ButtonMode button_mode = Spit.DataImports.PluginHost.ButtonMode.CANCEL) { | ||
2691 | 167 | debug ("DataImports.PluginHost: install_dialog_pane( ): invoked."); | ||
2692 | 168 | |||
2693 | 169 | if (get_data_importer () == null || (!get_data_importer ().is_running ())) | ||
2694 | 170 | return; | ||
2695 | 171 | |||
2696 | 172 | dialog.install_pane (pane); | ||
2697 | 173 | |||
2698 | 174 | set_button_mode (button_mode); | ||
2699 | 175 | } | ||
2700 | 176 | |||
2701 | 177 | public void install_static_message_pane (string message, | ||
2702 | 178 | Spit.DataImports.PluginHost.ButtonMode button_mode = Spit.DataImports.PluginHost.ButtonMode.CANCEL) { | ||
2703 | 179 | |||
2704 | 180 | set_button_mode (button_mode); | ||
2705 | 181 | |||
2706 | 182 | dialog.install_pane (new DataImportsUI.StaticMessagePane.with_pango (message)); | ||
2707 | 183 | } | ||
2708 | 184 | |||
2709 | 185 | public void install_library_selection_pane ( | ||
2710 | 186 | string welcome_message, | ||
2711 | 187 | ImportableLibrary[] discovered_libraries, | ||
2712 | 188 | string? file_select_label | ||
2713 | 189 | ) { | ||
2714 | 190 | if (discovered_libraries.length == 0 && file_select_label == null) | ||
2715 | 191 | post_error_message ("Libraries or file option needed"); | ||
2716 | 192 | else | ||
2717 | 193 | dialog.install_pane (new DataImportsUI.LibrarySelectionPane ( | ||
2718 | 194 | this, | ||
2719 | 195 | welcome_message, | ||
2720 | 196 | discovered_libraries, | ||
2721 | 197 | file_select_label | ||
2722 | 198 | )); | ||
2723 | 199 | set_button_mode (Spit.DataImports.PluginHost.ButtonMode.CLOSE); | ||
2724 | 200 | } | ||
2725 | 201 | |||
2726 | 202 | public void install_import_progress_pane ( | ||
2727 | 203 | string message | ||
2728 | 204 | ) { | ||
2729 | 205 | progress_pane = new DataImportsUI.ProgressPane (message); | ||
2730 | 206 | dialog.install_pane (progress_pane); | ||
2731 | 207 | set_button_mode (Spit.DataImports.PluginHost.ButtonMode.CANCEL); | ||
2732 | 208 | // initialize the import | ||
2733 | 209 | core_importer.imported_items_count = 0; | ||
2734 | 210 | core_importer.current_import_roll = null; | ||
2735 | 211 | } | ||
2736 | 212 | |||
2737 | 213 | public void update_import_progress_pane ( | ||
2738 | 214 | double progress, | ||
2739 | 215 | string? progress_message = null | ||
2740 | 216 | ) { | ||
2741 | 217 | if (progress_pane != null) { | ||
2742 | 218 | progress_pane.update_progress (progress, progress_message); | ||
2743 | 219 | } | ||
2744 | 220 | } | ||
2745 | 221 | |||
2746 | 222 | public void prepare_media_items_for_import ( | ||
2747 | 223 | ImportableMediaItem[] items, | ||
2748 | 224 | double progress, | ||
2749 | 225 | double host_progress_delta = 0.0, | ||
2750 | 226 | string? progress_message = null | ||
2751 | 227 | ) { | ||
2752 | 228 | core_importer.prepare_media_items_for_import (items, progress, host_progress_delta, progress_message); | ||
2753 | 229 | } | ||
2754 | 230 | |||
2755 | 231 | public void finalize_import ( | ||
2756 | 232 | ImportedItemsCountCallback report_imported_items_count, | ||
2757 | 233 | string? finalize_message = null | ||
2758 | 234 | ) { | ||
2759 | 235 | update_import_progress_pane (1.0, finalize_message); | ||
2760 | 236 | set_button_mode (Spit.DataImports.PluginHost.ButtonMode.CLOSE); | ||
2761 | 237 | core_importer.finalize_import (); | ||
2762 | 238 | report_imported_items_count (core_importer.imported_items_count); | ||
2763 | 239 | if (core_importer.imported_items_count > 0) | ||
2764 | 240 | LibraryWindow.get_app ().switch_to_import_queue_page (); | ||
2765 | 241 | } | ||
2766 | 242 | } | ||
2767 | 243 | |||
2768 | 244 | public class WelcomeDataImportsHost : Plugins.StandardHostInterface, | ||
2769 | 245 | Spit.DataImports.PluginHost { | ||
2770 | 246 | |||
2771 | 247 | private weak WelcomeImportMetaHost meta_host; | ||
2772 | 248 | private Spit.DataImports.DataImporter active_importer = null; | ||
2773 | 249 | private bool importing_halted = false; | ||
2774 | 250 | private CoreImporter core_importer; | ||
2775 | 251 | |||
2776 | 252 | public WelcomeDataImportsHost (Service service, WelcomeImportMetaHost meta_host) { | ||
2777 | 253 | base (service, "data_imports"); | ||
2778 | 254 | |||
2779 | 255 | this.active_importer = service.create_data_importer (this); | ||
2780 | 256 | this.core_importer = new CoreImporter (this); | ||
2781 | 257 | this.meta_host = meta_host; | ||
2782 | 258 | } | ||
2783 | 259 | |||
2784 | 260 | public DataImporter get_data_importer () { | ||
2785 | 261 | return active_importer; | ||
2786 | 262 | } | ||
2787 | 263 | |||
2788 | 264 | public void start_importing () { | ||
2789 | 265 | if (get_data_importer ().is_running ()) | ||
2790 | 266 | return; | ||
2791 | 267 | |||
2792 | 268 | debug ("WelcomeDataImportsHost.start_importing( ): invoked."); | ||
2793 | 269 | |||
2794 | 270 | get_data_importer ().start (); | ||
2795 | 271 | } | ||
2796 | 272 | |||
2797 | 273 | public void stop_importing () { | ||
2798 | 274 | debug ("WelcomeDataImportsHost.stop_importing( ): invoked."); | ||
2799 | 275 | |||
2800 | 276 | if (get_data_importer ().is_running ()) | ||
2801 | 277 | get_data_importer ().stop (); | ||
2802 | 278 | |||
2803 | 279 | clean_up (); | ||
2804 | 280 | |||
2805 | 281 | importing_halted = true; | ||
2806 | 282 | } | ||
2807 | 283 | |||
2808 | 284 | private void clean_up () { | ||
2809 | 285 | } | ||
2810 | 286 | |||
2811 | 287 | // Pane handling methods | ||
2812 | 288 | |||
2813 | 289 | public void post_error (Error err) { | ||
2814 | 290 | post_error_message (err.message); | ||
2815 | 291 | } | ||
2816 | 292 | |||
2817 | 293 | public void post_error_message (string message) { | ||
2818 | 294 | string msg = _ ("Importing from %s can't continue because an error occurred:").printf ( | ||
2819 | 295 | active_importer.get_service ().get_pluggable_name ()); | ||
2820 | 296 | |||
2821 | 297 | debug (msg); | ||
2822 | 298 | |||
2823 | 299 | get_data_importer ().stop (); | ||
2824 | 300 | |||
2825 | 301 | // post_error_message( ) tells the active_importer to stop importing and displays a | ||
2826 | 302 | // non-removable error pane that effectively ends the publishing interaction, | ||
2827 | 303 | // so no problem calling clean_up( ) here. | ||
2828 | 304 | clean_up (); | ||
2829 | 305 | } | ||
2830 | 306 | |||
2831 | 307 | public void install_dialog_pane (Spit.DataImports.DialogPane pane, | ||
2832 | 308 | Spit.DataImports.PluginHost.ButtonMode button_mode = Spit.DataImports.PluginHost.ButtonMode.CANCEL) { | ||
2833 | 309 | // do nothing | ||
2834 | 310 | } | ||
2835 | 311 | |||
2836 | 312 | public void install_static_message_pane (string message, | ||
2837 | 313 | Spit.DataImports.PluginHost.ButtonMode button_mode = Spit.DataImports.PluginHost.ButtonMode.CANCEL) { | ||
2838 | 314 | // do nothing | ||
2839 | 315 | } | ||
2840 | 316 | |||
2841 | 317 | public void install_library_selection_pane ( | ||
2842 | 318 | string welcome_message, | ||
2843 | 319 | ImportableLibrary[] discovered_libraries, | ||
2844 | 320 | string? file_select_label | ||
2845 | 321 | ) { | ||
2846 | 322 | debug ("WelcomeDataImportsHost: Installing library selection pane for %s".printf (get_data_importer ().get_service ().get_pluggable_name ())); | ||
2847 | 323 | if (discovered_libraries.length > 0) { | ||
2848 | 324 | meta_host.install_service_entry (new WelcomeImportServiceEntry ( | ||
2849 | 325 | this, | ||
2850 | 326 | get_data_importer ().get_service ().get_pluggable_name (), | ||
2851 | 327 | discovered_libraries | ||
2852 | 328 | )); | ||
2853 | 329 | } | ||
2854 | 330 | } | ||
2855 | 331 | |||
2856 | 332 | public void install_import_progress_pane ( | ||
2857 | 333 | string message | ||
2858 | 334 | ) { | ||
2859 | 335 | // empty implementation | ||
2860 | 336 | } | ||
2861 | 337 | |||
2862 | 338 | public void update_import_progress_pane ( | ||
2863 | 339 | double progress, | ||
2864 | 340 | string? progress_message = null | ||
2865 | 341 | ) { | ||
2866 | 342 | // empty implementation | ||
2867 | 343 | } | ||
2868 | 344 | |||
2869 | 345 | public void prepare_media_items_for_import ( | ||
2870 | 346 | ImportableMediaItem[] items, | ||
2871 | 347 | double progress, | ||
2872 | 348 | double host_progress_delta = 0.0, | ||
2873 | 349 | string? progress_message = null | ||
2874 | 350 | ) { | ||
2875 | 351 | core_importer.prepare_media_items_for_import (items, progress, host_progress_delta, progress_message); | ||
2876 | 352 | } | ||
2877 | 353 | |||
2878 | 354 | public void finalize_import ( | ||
2879 | 355 | ImportedItemsCountCallback report_imported_items_count, | ||
2880 | 356 | string? finalize_message = null | ||
2881 | 357 | ) { | ||
2882 | 358 | core_importer.finalize_import (); | ||
2883 | 359 | report_imported_items_count (core_importer.imported_items_count); | ||
2884 | 360 | meta_host.finalize_import (this); | ||
2885 | 361 | } | ||
2886 | 362 | } | ||
2887 | 363 | |||
2888 | 364 | |||
2889 | 365 | //public delegate void WelcomeImporterCallback (); | ||
2890 | 366 | |||
2891 | 367 | public class WelcomeImportServiceEntry : GLib.Object, WelcomeServiceEntry { | ||
2892 | 368 | private string pluggable_name; | ||
2893 | 369 | private ImportableLibrary[] discovered_libraries; | ||
2894 | 370 | private Spit.DataImports.PluginHost host; | ||
2895 | 371 | |||
2896 | 372 | public WelcomeImportServiceEntry ( | ||
2897 | 373 | Spit.DataImports.PluginHost host, | ||
2898 | 374 | string pluggable_name, ImportableLibrary[] discovered_libraries) { | ||
2899 | 375 | |||
2900 | 376 | this.host = host; | ||
2901 | 377 | this.pluggable_name = pluggable_name; | ||
2902 | 378 | this.discovered_libraries = discovered_libraries; | ||
2903 | 379 | } | ||
2904 | 380 | |||
2905 | 381 | public string get_service_name () { | ||
2906 | 382 | return pluggable_name; | ||
2907 | 383 | } | ||
2908 | 384 | |||
2909 | 385 | public void execute () { | ||
2910 | 386 | foreach (ImportableLibrary library in discovered_libraries) { | ||
2911 | 387 | host.get_data_importer ().on_library_selected (library); | ||
2912 | 388 | } | ||
2913 | 389 | } | ||
2914 | 390 | } | ||
2915 | 391 | |||
2916 | 392 | public class WelcomeImportMetaHost : GLib.Object { | ||
2917 | 393 | private WelcomeDialog dialog; | ||
2918 | 394 | |||
2919 | 395 | public WelcomeImportMetaHost (WelcomeDialog dialog) { | ||
2920 | 396 | this.dialog = dialog; | ||
2921 | 397 | } | ||
2922 | 398 | |||
2923 | 399 | public void start () { | ||
2924 | 400 | Service[] services = load_all_services (); | ||
2925 | 401 | foreach (Service service in services) { | ||
2926 | 402 | WelcomeDataImportsHost host = new WelcomeDataImportsHost (service, this); | ||
2927 | 403 | host.start_importing (); | ||
2928 | 404 | } | ||
2929 | 405 | } | ||
2930 | 406 | |||
2931 | 407 | public void finalize_import (WelcomeDataImportsHost host) { | ||
2932 | 408 | host.stop_importing (); | ||
2933 | 409 | } | ||
2934 | 410 | |||
2935 | 411 | public void install_service_entry (WelcomeServiceEntry entry) { | ||
2936 | 412 | debug ("WelcomeImportMetaHost: Installing service entry for %s".printf (entry.get_service_name ())); | ||
2937 | 413 | dialog.install_service_entry (entry); | ||
2938 | 414 | } | ||
2939 | 415 | } | ||
2940 | 416 | |||
2941 | 417 | public static Spit.DataImports.Service[] load_all_services () { | ||
2942 | 418 | return load_services (true); | ||
2943 | 419 | } | ||
2944 | 420 | |||
2945 | 421 | public static Spit.DataImports.Service[] load_services (bool load_all = false) { | ||
2946 | 422 | Spit.DataImports.Service[] loaded_services = new Spit.DataImports.Service[0]; | ||
2947 | 423 | |||
2948 | 424 | // load publishing services from plug-ins | ||
2949 | 425 | Gee.Collection<Spit.Pluggable> pluggables = Plugins.get_pluggables_for_type ( | ||
2950 | 426 | typeof (Spit.DataImports.Service), null, load_all); | ||
2951 | 427 | // TODO: include sorting function to ensure consistent order | ||
2952 | 428 | |||
2953 | 429 | debug ("DataImportsDialog: discovered %d pluggable data import services.", pluggables.size); | ||
2954 | 430 | |||
2955 | 431 | foreach (Spit.Pluggable pluggable in pluggables) { | ||
2956 | 432 | int pluggable_interface = pluggable.get_pluggable_interface ( | ||
2957 | 433 | Spit.DataImports.CURRENT_INTERFACE, Spit.DataImports.CURRENT_INTERFACE); | ||
2958 | 434 | if (pluggable_interface != Spit.DataImports.CURRENT_INTERFACE) { | ||
2959 | 435 | warning ("Unable to load data import plugin %s: reported interface %d.", | ||
2960 | 436 | Plugins.get_pluggable_module_id (pluggable), pluggable_interface); | ||
2961 | 437 | |||
2962 | 438 | continue; | ||
2963 | 439 | } | ||
2964 | 440 | |||
2965 | 441 | Spit.DataImports.Service service = | ||
2966 | 442 | (Spit.DataImports.Service) pluggable; | ||
2967 | 443 | |||
2968 | 444 | debug ("DataImportsDialog: discovered pluggable data import service '%s'.", | ||
2969 | 445 | service.get_pluggable_name ()); | ||
2970 | 446 | |||
2971 | 447 | loaded_services += service; | ||
2972 | 448 | } | ||
2973 | 449 | |||
2974 | 450 | // Sort import services by name. | ||
2975 | 451 | // TODO: extract to a function to sort it on initial request | ||
2976 | 452 | Posix.qsort (loaded_services, loaded_services.length, sizeof (Spit.DataImports.Service), | ||
2977 | 453 | (a, b) => { | ||
2978 | 454 | return utf8_cs_compare ((* ((Spit.DataImports.Service **) a))->get_pluggable_name (), | ||
2979 | 455 | (* ((Spit.DataImports.Service **) b))->get_pluggable_name ()); | ||
2980 | 456 | }); | ||
2981 | 457 | |||
2982 | 458 | return loaded_services; | ||
2983 | 459 | } | ||
2984 | 460 | |||
2985 | 461 | private ImportManifest? meta_manifest = null; | ||
2986 | 462 | |||
2987 | 463 | private void data_import_reporter (ImportManifest manifest, BatchImportRoll import_roll) { | ||
2988 | 464 | if (manifest.all.size > 0) { | ||
2989 | 465 | if (meta_manifest == null) | ||
2990 | 466 | meta_manifest = new ImportManifest (); | ||
2991 | 467 | foreach (BatchImportResult result in manifest.all) { | ||
2992 | 468 | meta_manifest.add_result (result); | ||
2993 | 469 | } | ||
2994 | 470 | } else { | ||
2995 | 471 | DataImportsUI.DataImportsDialog.terminate_instance (); | ||
2996 | 472 | ImportUI.report_manifest (meta_manifest, true); | ||
2997 | 473 | meta_manifest = null; | ||
2998 | 474 | } | ||
2999 | 475 | } | ||
3000 | 476 | |||
3001 | 477 | private int64 import_job_comparator (void *a, void *b) { | ||
3002 | 478 | return ((DataImportJob *) a)->get_exposure_time () | ||
3003 | 479 | - ((DataImportJob *) b)->get_exposure_time (); | ||
3004 | 480 | } | ||
3005 | 481 | |||
3006 | 482 | } | ||
3007 | 483 | |||
3008 | 484 | 0 | ||
3009 | === removed file 'src/data_imports/DataImportsUI.vala' | |||
3010 | --- src/data_imports/DataImportsUI.vala 2014-08-08 21:13:09 +0000 | |||
3011 | +++ src/data_imports/DataImportsUI.vala 1970-01-01 00:00:00 +0000 | |||
3012 | @@ -1,445 +0,0 @@ | |||
3013 | 1 | /* Copyright 2011-2013 Yorba Foundation | ||
3014 | 2 | * | ||
3015 | 3 | * This software is licensed under the GNU Lesser General Public License | ||
3016 | 4 | * (version 2.1 or later). See the COPYING file in this distribution. | ||
3017 | 5 | */ | ||
3018 | 6 | |||
3019 | 7 | namespace DataImportsUI { | ||
3020 | 8 | |||
3021 | 9 | internal const string NO_PLUGINS_ENABLED_MESSAGE = | ||
3022 | 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."); | ||
3023 | 11 | |||
3024 | 12 | public class ConcreteDialogPane : Spit.DataImports.DialogPane, GLib.Object { | ||
3025 | 13 | private Gtk.Box pane_widget; | ||
3026 | 14 | |||
3027 | 15 | public ConcreteDialogPane () { | ||
3028 | 16 | pane_widget = new Gtk.Box (Gtk.Orientation.VERTICAL, 8); | ||
3029 | 17 | } | ||
3030 | 18 | |||
3031 | 19 | public Gtk.Widget get_widget () { | ||
3032 | 20 | return pane_widget; | ||
3033 | 21 | } | ||
3034 | 22 | |||
3035 | 23 | public Spit.DataImports.DialogPane.GeometryOptions get_preferred_geometry () { | ||
3036 | 24 | return Spit.DataImports.DialogPane.GeometryOptions.NONE; | ||
3037 | 25 | } | ||
3038 | 26 | |||
3039 | 27 | public void on_pane_installed () { | ||
3040 | 28 | } | ||
3041 | 29 | |||
3042 | 30 | public void on_pane_uninstalled () { | ||
3043 | 31 | } | ||
3044 | 32 | } | ||
3045 | 33 | |||
3046 | 34 | public class StaticMessagePane : ConcreteDialogPane { | ||
3047 | 35 | public StaticMessagePane (string message_string) { | ||
3048 | 36 | Gtk.Label message_label = new Gtk.Label (message_string); | ||
3049 | 37 | (get_widget () as Gtk.Box).pack_start (message_label, true, true, 0); | ||
3050 | 38 | } | ||
3051 | 39 | |||
3052 | 40 | public StaticMessagePane.with_pango (string msg) { | ||
3053 | 41 | Gtk.Label label = new Gtk.Label (null); | ||
3054 | 42 | label.set_markup (msg); | ||
3055 | 43 | label.set_line_wrap (true); | ||
3056 | 44 | |||
3057 | 45 | (get_widget () as Gtk.Box).pack_start (label, true, true, 0); | ||
3058 | 46 | } | ||
3059 | 47 | } | ||
3060 | 48 | |||
3061 | 49 | public class LibrarySelectionPane : ConcreteDialogPane { | ||
3062 | 50 | private weak Spit.DataImports.PluginHost host; | ||
3063 | 51 | private Spit.DataImports.ImportableLibrary? selected_library = null; | ||
3064 | 52 | private File? selected_file = null; | ||
3065 | 53 | private Gtk.Button import_button; | ||
3066 | 54 | private Gtk.RadioButton? file_radio = null; | ||
3067 | 55 | |||
3068 | 56 | public LibrarySelectionPane ( | ||
3069 | 57 | Spit.DataImports.PluginHost host, | ||
3070 | 58 | string welcome_message, | ||
3071 | 59 | Spit.DataImports.ImportableLibrary[] discovered_libraries, | ||
3072 | 60 | string? file_select_label | ||
3073 | 61 | ) { | ||
3074 | 62 | assert (discovered_libraries.length > 0 || on_file_selected != null); | ||
3075 | 63 | |||
3076 | 64 | this.host = host; | ||
3077 | 65 | |||
3078 | 66 | Gtk.Box content_box = new Gtk.Box (Gtk.Orientation.VERTICAL, 8); | ||
3079 | 67 | content_box.set_margin_left (30); | ||
3080 | 68 | content_box.set_margin_right (30); | ||
3081 | 69 | Gtk.Label welcome_label = new Gtk.Label (null); | ||
3082 | 70 | welcome_label.set_markup (welcome_message); | ||
3083 | 71 | welcome_label.set_line_wrap (true); | ||
3084 | 72 | welcome_label.set_halign (Gtk.Align.START); | ||
3085 | 73 | content_box.pack_start (welcome_label, true, true, 6); | ||
3086 | 74 | |||
3087 | 75 | // margins for buttons | ||
3088 | 76 | int radio_margin_left = 20; | ||
3089 | 77 | int radio_margin_right = 20; | ||
3090 | 78 | int chooser_margin_left = radio_margin_left; | ||
3091 | 79 | int chooser_margin_right = radio_margin_right; | ||
3092 | 80 | |||
3093 | 81 | Gtk.RadioButton lib_radio = null; | ||
3094 | 82 | if (discovered_libraries.length > 0) { | ||
3095 | 83 | chooser_margin_left = radio_margin_left + 20; | ||
3096 | 84 | foreach (Spit.DataImports.ImportableLibrary library in discovered_libraries) { | ||
3097 | 85 | string lib_radio_label = library.get_display_name (); | ||
3098 | 86 | lib_radio = create_radio_button ( | ||
3099 | 87 | content_box, lib_radio, library, lib_radio_label, | ||
3100 | 88 | radio_margin_left, radio_margin_right | ||
3101 | 89 | ); | ||
3102 | 90 | } | ||
3103 | 91 | if (file_select_label != null) { | ||
3104 | 92 | lib_radio = create_radio_button ( | ||
3105 | 93 | content_box, lib_radio, null, file_select_label, | ||
3106 | 94 | radio_margin_left, radio_margin_right | ||
3107 | 95 | ); | ||
3108 | 96 | file_radio = lib_radio; | ||
3109 | 97 | } | ||
3110 | 98 | } | ||
3111 | 99 | if (file_select_label != null) { | ||
3112 | 100 | Gtk.FileChooserButton file_chooser = new Gtk.FileChooserButton (_ ("Database file:"), Gtk.FileChooserAction.OPEN); | ||
3113 | 101 | file_chooser.selection_changed.connect ( () => { | ||
3114 | 102 | selected_file = file_chooser.get_file (); | ||
3115 | 103 | if (file_radio != null) | ||
3116 | 104 | file_radio.active = true; | ||
3117 | 105 | set_import_button_sensitivity (); | ||
3118 | 106 | }); | ||
3119 | 107 | file_chooser.set_margin_left (chooser_margin_left); | ||
3120 | 108 | file_chooser.set_margin_right (chooser_margin_right); | ||
3121 | 109 | content_box.pack_start (file_chooser, false, false, 6); | ||
3122 | 110 | } | ||
3123 | 111 | |||
3124 | 112 | import_button = new Gtk.Button.with_mnemonic (_ ("_Import")); | ||
3125 | 113 | import_button.clicked.connect ( () => { | ||
3126 | 114 | if (selected_library != null) | ||
3127 | 115 | on_library_selected (selected_library); | ||
3128 | 116 | else if (selected_file != null) | ||
3129 | 117 | on_file_selected (selected_file); | ||
3130 | 118 | else | ||
3131 | 119 | debug ("LibrarySelectionPane: Library or file should be selected."); | ||
3132 | 120 | }); | ||
3133 | 121 | Gtk.ButtonBox button_box = new Gtk.ButtonBox (Gtk.Orientation.HORIZONTAL); | ||
3134 | 122 | button_box.layout_style = Gtk.ButtonBoxStyle.CENTER; | ||
3135 | 123 | button_box.add (import_button); | ||
3136 | 124 | content_box.pack_end (button_box, true, false, 6); | ||
3137 | 125 | |||
3138 | 126 | (get_widget () as Gtk.Box).pack_start (content_box, true, true, 0); | ||
3139 | 127 | |||
3140 | 128 | set_import_button_sensitivity (); | ||
3141 | 129 | } | ||
3142 | 130 | |||
3143 | 131 | private Gtk.RadioButton create_radio_button ( | ||
3144 | 132 | Gtk.Box box, Gtk.RadioButton? group, Spit.DataImports.ImportableLibrary? library, string label, | ||
3145 | 133 | int margin_left, int margin_right | ||
3146 | 134 | ) { | ||
3147 | 135 | var button = new Gtk.RadioButton.with_label_from_widget (group, label); | ||
3148 | 136 | if (group == null) { // first radio button is active | ||
3149 | 137 | button.active = true; | ||
3150 | 138 | selected_library = library; | ||
3151 | 139 | } | ||
3152 | 140 | button.toggled.connect ( () => { | ||
3153 | 141 | if (button.active) { | ||
3154 | 142 | this.selected_library = library; | ||
3155 | 143 | set_import_button_sensitivity (); | ||
3156 | 144 | } | ||
3157 | 145 | |||
3158 | 146 | }); | ||
3159 | 147 | button.set_margin_left (margin_left); | ||
3160 | 148 | button.set_margin_right (margin_right); | ||
3161 | 149 | box.pack_start (button, false, false, 6); | ||
3162 | 150 | return button; | ||
3163 | 151 | } | ||
3164 | 152 | |||
3165 | 153 | private void set_import_button_sensitivity () { | ||
3166 | 154 | import_button.set_sensitive (selected_library != null || selected_file != null); | ||
3167 | 155 | } | ||
3168 | 156 | |||
3169 | 157 | private void on_library_selected (Spit.DataImports.ImportableLibrary library) { | ||
3170 | 158 | host.get_data_importer ().on_library_selected (library); | ||
3171 | 159 | } | ||
3172 | 160 | |||
3173 | 161 | private void on_file_selected (File file) { | ||
3174 | 162 | host.get_data_importer ().on_file_selected (file); | ||
3175 | 163 | } | ||
3176 | 164 | } | ||
3177 | 165 | |||
3178 | 166 | public class ProgressPane : ConcreteDialogPane { | ||
3179 | 167 | private Gtk.Label message_label; | ||
3180 | 168 | private Gtk.Label progress_label; | ||
3181 | 169 | private Gtk.ProgressBar progress_bar; | ||
3182 | 170 | |||
3183 | 171 | public ProgressPane (string message) { | ||
3184 | 172 | Gtk.Box content_box = new Gtk.Box (Gtk.Orientation.VERTICAL, 8); | ||
3185 | 173 | message_label = new Gtk.Label (message); | ||
3186 | 174 | content_box.pack_start (message_label, true, true, 6); | ||
3187 | 175 | progress_bar = new Gtk.ProgressBar (); | ||
3188 | 176 | content_box.pack_start (progress_bar, false, true, 6); | ||
3189 | 177 | progress_label = new Gtk.Label (""); | ||
3190 | 178 | content_box.pack_start (progress_label, false, true, 6); | ||
3191 | 179 | |||
3192 | 180 | (get_widget () as Gtk.Container).add (content_box); | ||
3193 | 181 | } | ||
3194 | 182 | |||
3195 | 183 | public void update_progress (double progress, string? progress_message) { | ||
3196 | 184 | progress_bar.set_fraction (progress); | ||
3197 | 185 | if (progress_message != null) | ||
3198 | 186 | progress_label.set_label (progress_message); | ||
3199 | 187 | spin_event_loop (); | ||
3200 | 188 | } | ||
3201 | 189 | } | ||
3202 | 190 | |||
3203 | 191 | public class DataImportsDialog : Gtk.Dialog { | ||
3204 | 192 | private const int LARGE_WINDOW_WIDTH = 860; | ||
3205 | 193 | private const int LARGE_WINDOW_HEIGHT = 688; | ||
3206 | 194 | private const int COLOSSAL_WINDOW_WIDTH = 1024; | ||
3207 | 195 | private const int COLOSSAL_WINDOW_HEIGHT = 688; | ||
3208 | 196 | private const int STANDARD_WINDOW_WIDTH = 600; | ||
3209 | 197 | private const int STANDARD_WINDOW_HEIGHT = 510; | ||
3210 | 198 | private const int BORDER_REGION_WIDTH = 16; | ||
3211 | 199 | private const int BORDER_REGION_HEIGHT = 100; | ||
3212 | 200 | |||
3213 | 201 | public const int STANDARD_CONTENT_LABEL_WIDTH = 500; | ||
3214 | 202 | public const int STANDARD_ACTION_BUTTON_WIDTH = 128; | ||
3215 | 203 | |||
3216 | 204 | private Gtk.ComboBoxText service_selector_box; | ||
3217 | 205 | private Gtk.Label service_selector_box_label; | ||
3218 | 206 | private Gtk.Box central_area_layouter; | ||
3219 | 207 | private Gtk.Button close_cancel_button; | ||
3220 | 208 | private Spit.DataImports.DialogPane active_pane; | ||
3221 | 209 | private Spit.DataImports.ConcreteDataImportsHost host; | ||
3222 | 210 | |||
3223 | 211 | protected DataImportsDialog () { | ||
3224 | 212 | |||
3225 | 213 | resizable = false; | ||
3226 | 214 | delete_event.connect (on_window_close); | ||
3227 | 215 | |||
3228 | 216 | string title = _ ("Import From Application"); | ||
3229 | 217 | string label = _ ("Import media _from:"); | ||
3230 | 218 | |||
3231 | 219 | set_title (title); | ||
3232 | 220 | |||
3233 | 221 | Spit.DataImports.Service[] loaded_services = Spit.DataImports.load_services (); | ||
3234 | 222 | |||
3235 | 223 | if (loaded_services.length > 0) { | ||
3236 | 224 | // Install the service selector part only if there is at least one | ||
3237 | 225 | // service to select from | ||
3238 | 226 | service_selector_box = new Gtk.ComboBoxText (); | ||
3239 | 227 | service_selector_box.set_active (0); | ||
3240 | 228 | service_selector_box_label = new Gtk.Label.with_mnemonic (label); | ||
3241 | 229 | service_selector_box_label.set_mnemonic_widget (service_selector_box); | ||
3242 | 230 | service_selector_box_label.set_alignment (0.0f, 0.5f); | ||
3243 | 231 | |||
3244 | 232 | // get the name of the service the user last used | ||
3245 | 233 | string? last_used_service = Config.Facade.get_instance ().get_last_used_dataimports_service (); | ||
3246 | 234 | |||
3247 | 235 | int ticker = 0; | ||
3248 | 236 | int last_used_index = -1; | ||
3249 | 237 | foreach (Spit.DataImports.Service service in loaded_services) { | ||
3250 | 238 | string curr_service_id = service.get_id (); | ||
3251 | 239 | if (last_used_service != null && last_used_service == curr_service_id) | ||
3252 | 240 | last_used_index = ticker; | ||
3253 | 241 | |||
3254 | 242 | service_selector_box.append_text (service.get_pluggable_name ()); | ||
3255 | 243 | ticker++; | ||
3256 | 244 | } | ||
3257 | 245 | if (last_used_index >= 0) | ||
3258 | 246 | service_selector_box.set_active (last_used_index); | ||
3259 | 247 | else | ||
3260 | 248 | service_selector_box.set_active (0); | ||
3261 | 249 | |||
3262 | 250 | service_selector_box.changed.connect (on_service_changed); | ||
3263 | 251 | |||
3264 | 252 | /* the wrapper is not an extraneous widget -- it's necessary to prevent the service | ||
3265 | 253 | selection box from growing and shrinking whenever its parent's size changes. | ||
3266 | 254 | When wrapped inside a Gtk.Alignment, the Alignment grows and shrinks instead of | ||
3267 | 255 | the service selection box. */ | ||
3268 | 256 | Gtk.Alignment service_selector_box_wrapper = new Gtk.Alignment (1.0f, 0.5f, 0.0f, 0.0f); | ||
3269 | 257 | service_selector_box_wrapper.add (service_selector_box); | ||
3270 | 258 | |||
3271 | 259 | Gtk.Box service_selector_layouter = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 8); | ||
3272 | 260 | service_selector_layouter.set_border_width (12); | ||
3273 | 261 | service_selector_layouter.add (service_selector_box_label); | ||
3274 | 262 | service_selector_layouter.pack_start (service_selector_box_wrapper, true, true, 0); | ||
3275 | 263 | |||
3276 | 264 | /* 'service area' is the selector assembly plus the horizontal rule dividing it from the | ||
3277 | 265 | rest of the dialog */ | ||
3278 | 266 | Gtk.Box service_area_layouter = new Gtk.Box (Gtk.Orientation.VERTICAL, 0); | ||
3279 | 267 | service_area_layouter.pack_start (service_selector_layouter, true, true, 0); | ||
3280 | 268 | Gtk.Separator service_central_separator = new Gtk.Separator (Gtk.Orientation.HORIZONTAL); | ||
3281 | 269 | service_area_layouter.add (service_central_separator); | ||
3282 | 270 | |||
3283 | 271 | Gtk.Alignment service_area_wrapper = new Gtk.Alignment (0.0f, 0.0f, 1.0f, 0.0f); | ||
3284 | 272 | service_area_wrapper.add (service_area_layouter); | ||
3285 | 273 | |||
3286 | 274 | ((Gtk.Box) get_content_area ()).pack_start (service_area_wrapper, false, false, 0); | ||
3287 | 275 | } | ||
3288 | 276 | |||
3289 | 277 | // Intall the central area in all cases | ||
3290 | 278 | central_area_layouter = new Gtk.Box (Gtk.Orientation.VERTICAL, 0); | ||
3291 | 279 | ((Gtk.Box) get_content_area ()).pack_start (central_area_layouter, true, true, 0); | ||
3292 | 280 | |||
3293 | 281 | close_cancel_button = new Gtk.Button.with_mnemonic ("_Cancel"); | ||
3294 | 282 | close_cancel_button.set_can_default (true); | ||
3295 | 283 | close_cancel_button.clicked.connect (on_close_cancel_clicked); | ||
3296 | 284 | ((Gtk.Box) get_action_area ()).add (close_cancel_button); | ||
3297 | 285 | |||
3298 | 286 | set_standard_window_mode (); | ||
3299 | 287 | |||
3300 | 288 | if (loaded_services.length > 0) { | ||
3301 | 289 | // trigger the selected service if at least one service is available | ||
3302 | 290 | on_service_changed (); | ||
3303 | 291 | } else { | ||
3304 | 292 | // otherwise, install a message pane advising the user what to do | ||
3305 | 293 | install_pane (new StaticMessagePane.with_pango (NO_PLUGINS_ENABLED_MESSAGE)); | ||
3306 | 294 | set_close_button_mode (); | ||
3307 | 295 | } | ||
3308 | 296 | |||
3309 | 297 | show_all (); | ||
3310 | 298 | } | ||
3311 | 299 | |||
3312 | 300 | public static DataImportsDialog get_or_create_instance () { | ||
3313 | 301 | if (instance == null) { | ||
3314 | 302 | instance = new DataImportsDialog (); | ||
3315 | 303 | } | ||
3316 | 304 | return instance; | ||
3317 | 305 | } | ||
3318 | 306 | |||
3319 | 307 | public static void terminate_instance () { | ||
3320 | 308 | if (instance != null) { | ||
3321 | 309 | instance.terminate (); | ||
3322 | 310 | } | ||
3323 | 311 | instance = null; | ||
3324 | 312 | } | ||
3325 | 313 | |||
3326 | 314 | private bool on_window_close (Gdk.EventAny evt) { | ||
3327 | 315 | debug ("DataImportsDialog: on_window_close( ): invoked."); | ||
3328 | 316 | terminate (); | ||
3329 | 317 | |||
3330 | 318 | return true; | ||
3331 | 319 | } | ||
3332 | 320 | |||
3333 | 321 | private void on_service_changed () { | ||
3334 | 322 | debug ("DataImportsDialog: on_service_changed invoked."); | ||
3335 | 323 | string service_name = service_selector_box.get_active_text (); | ||
3336 | 324 | |||
3337 | 325 | Spit.DataImports.Service? selected_service = null; | ||
3338 | 326 | Spit.DataImports.Service[] services = Spit.DataImports.load_all_services (); | ||
3339 | 327 | foreach (Spit.DataImports.Service service in services) { | ||
3340 | 328 | if (service.get_pluggable_name () == service_name) { | ||
3341 | 329 | selected_service = service; | ||
3342 | 330 | break; | ||
3343 | 331 | } | ||
3344 | 332 | } | ||
3345 | 333 | assert (selected_service != null); | ||
3346 | 334 | |||
3347 | 335 | Config.Facade.get_instance ().set_last_used_dataimports_service (selected_service.get_id ()); | ||
3348 | 336 | |||
3349 | 337 | host = new Spit.DataImports.ConcreteDataImportsHost (selected_service, this); | ||
3350 | 338 | host.start_importing (); | ||
3351 | 339 | } | ||
3352 | 340 | |||
3353 | 341 | private void on_close_cancel_clicked () { | ||
3354 | 342 | debug ("DataImportsDialog: on_close_cancel_clicked( ): invoked."); | ||
3355 | 343 | |||
3356 | 344 | terminate (); | ||
3357 | 345 | } | ||
3358 | 346 | |||
3359 | 347 | private void terminate () { | ||
3360 | 348 | debug ("DataImportsDialog: terminate( ): invoked."); | ||
3361 | 349 | |||
3362 | 350 | if (host != null) { | ||
3363 | 351 | host.stop_importing (); | ||
3364 | 352 | host = null; | ||
3365 | 353 | } | ||
3366 | 354 | |||
3367 | 355 | hide (); | ||
3368 | 356 | destroy (); | ||
3369 | 357 | instance = null; | ||
3370 | 358 | } | ||
3371 | 359 | |||
3372 | 360 | private void set_large_window_mode () { | ||
3373 | 361 | set_size_request (LARGE_WINDOW_WIDTH, LARGE_WINDOW_HEIGHT); | ||
3374 | 362 | central_area_layouter.set_size_request (LARGE_WINDOW_WIDTH - BORDER_REGION_WIDTH, | ||
3375 | 363 | LARGE_WINDOW_HEIGHT - BORDER_REGION_HEIGHT); | ||
3376 | 364 | resizable = false; | ||
3377 | 365 | } | ||
3378 | 366 | |||
3379 | 367 | private void set_colossal_window_mode () { | ||
3380 | 368 | set_size_request (COLOSSAL_WINDOW_WIDTH, COLOSSAL_WINDOW_HEIGHT); | ||
3381 | 369 | central_area_layouter.set_size_request (COLOSSAL_WINDOW_WIDTH - BORDER_REGION_WIDTH, | ||
3382 | 370 | COLOSSAL_WINDOW_HEIGHT - BORDER_REGION_HEIGHT); | ||
3383 | 371 | resizable = false; | ||
3384 | 372 | } | ||
3385 | 373 | |||
3386 | 374 | private void set_standard_window_mode () { | ||
3387 | 375 | set_size_request (STANDARD_WINDOW_WIDTH, STANDARD_WINDOW_HEIGHT); | ||
3388 | 376 | central_area_layouter.set_size_request (STANDARD_WINDOW_WIDTH - BORDER_REGION_WIDTH, | ||
3389 | 377 | STANDARD_WINDOW_HEIGHT - BORDER_REGION_HEIGHT); | ||
3390 | 378 | resizable = false; | ||
3391 | 379 | } | ||
3392 | 380 | |||
3393 | 381 | private void set_free_sizable_window_mode () { | ||
3394 | 382 | resizable = true; | ||
3395 | 383 | } | ||
3396 | 384 | |||
3397 | 385 | private void clear_free_sizable_window_mode () { | ||
3398 | 386 | resizable = false; | ||
3399 | 387 | } | ||
3400 | 388 | |||
3401 | 389 | public Spit.DataImports.DialogPane get_active_pane () { | ||
3402 | 390 | return active_pane; | ||
3403 | 391 | } | ||
3404 | 392 | |||
3405 | 393 | public void set_close_button_mode () { | ||
3406 | 394 | close_cancel_button.set_label (_ ("_Close")); | ||
3407 | 395 | set_default (close_cancel_button); | ||
3408 | 396 | } | ||
3409 | 397 | |||
3410 | 398 | public void set_cancel_button_mode () { | ||
3411 | 399 | close_cancel_button.set_label (_ ("_Cancel")); | ||
3412 | 400 | } | ||
3413 | 401 | |||
3414 | 402 | public void lock_service () { | ||
3415 | 403 | service_selector_box.set_sensitive (false); | ||
3416 | 404 | } | ||
3417 | 405 | |||
3418 | 406 | public void unlock_service () { | ||
3419 | 407 | service_selector_box.set_sensitive (true); | ||
3420 | 408 | } | ||
3421 | 409 | |||
3422 | 410 | public void install_pane (Spit.DataImports.DialogPane pane) { | ||
3423 | 411 | debug ("DataImportsDialog: install_pane( ): invoked."); | ||
3424 | 412 | |||
3425 | 413 | if (active_pane != null) { | ||
3426 | 414 | debug ("DataImportsDialog: install_pane( ): a pane is already installed; removing it."); | ||
3427 | 415 | |||
3428 | 416 | active_pane.on_pane_uninstalled (); | ||
3429 | 417 | central_area_layouter.remove (active_pane.get_widget ()); | ||
3430 | 418 | } | ||
3431 | 419 | |||
3432 | 420 | central_area_layouter.pack_start (pane.get_widget (), true, true, 0); | ||
3433 | 421 | show_all (); | ||
3434 | 422 | |||
3435 | 423 | Spit.DataImports.DialogPane.GeometryOptions geometry_options = | ||
3436 | 424 | pane.get_preferred_geometry (); | ||
3437 | 425 | if ((geometry_options & Spit.Publishing.DialogPane.GeometryOptions.EXTENDED_SIZE) != 0) | ||
3438 | 426 | set_large_window_mode (); | ||
3439 | 427 | else if ((geometry_options & Spit.Publishing.DialogPane.GeometryOptions.COLOSSAL_SIZE) != 0) | ||
3440 | 428 | set_colossal_window_mode (); | ||
3441 | 429 | else | ||
3442 | 430 | set_standard_window_mode (); | ||
3443 | 431 | |||
3444 | 432 | if ((geometry_options & Spit.Publishing.DialogPane.GeometryOptions.RESIZABLE) != 0) | ||
3445 | 433 | set_free_sizable_window_mode (); | ||
3446 | 434 | else | ||
3447 | 435 | clear_free_sizable_window_mode (); | ||
3448 | 436 | |||
3449 | 437 | active_pane = pane; | ||
3450 | 438 | pane.on_pane_installed (); | ||
3451 | 439 | } | ||
3452 | 440 | |||
3453 | 441 | private static DataImportsDialog? instance; | ||
3454 | 442 | } | ||
3455 | 443 | |||
3456 | 444 | } | ||
3457 | 445 | |||
3458 | 446 | 0 | ||
3459 | === removed directory 'src/data_imports/mk' | |||
3460 | === removed file 'src/data_imports/mk/data_imports.mk' | |||
3461 | --- src/data_imports/mk/data_imports.mk 2012-02-02 22:56:06 +0000 | |||
3462 | +++ src/data_imports/mk/data_imports.mk 1970-01-01 00:00:00 +0000 | |||
3463 | @@ -1,31 +0,0 @@ | |||
3464 | 1 | |||
3465 | 2 | # UNIT_NAME is the Vala namespace. A file named UNIT_NAME.vala must be in this directory with | ||
3466 | 3 | # a init() and terminate() function declared in the namespace. | ||
3467 | 4 | UNIT_NAME := DataImports | ||
3468 | 5 | |||
3469 | 6 | # UNIT_DIR should match the subdirectory the files are located in. Generally UNIT_NAME in all | ||
3470 | 7 | # lowercase. The name of this file should be UNIT_DIR.mk. | ||
3471 | 8 | UNIT_DIR := data_imports | ||
3472 | 9 | |||
3473 | 10 | # All Vala files in the unit should be listed here with no subdirectory prefix. | ||
3474 | 11 | # | ||
3475 | 12 | # NOTE: Do *not* include the unit's master file, i.e. UNIT_NAME.vala. | ||
3476 | 13 | UNIT_FILES := \ | ||
3477 | 14 | DataImportsPluginHost.vala \ | ||
3478 | 15 | DataImportsUI.vala \ | ||
3479 | 16 | DataImportJob.vala \ | ||
3480 | 17 | DataImportSource.vala | ||
3481 | 18 | |||
3482 | 19 | # Any unit this unit relies upon (and should be initialized before it's initialized) should | ||
3483 | 20 | # be listed here using its Vala namespace. | ||
3484 | 21 | # | ||
3485 | 22 | # NOTE: All units are assumed to rely upon the unit-unit. Do not include that here. | ||
3486 | 23 | UNIT_USES := | ||
3487 | 24 | |||
3488 | 25 | # List any additional files that are used in the build process as a part of this unit that should | ||
3489 | 26 | # be packaged in the tarball. File names should be relative to the unit's home directory. | ||
3490 | 27 | UNIT_RC := | ||
3491 | 28 | |||
3492 | 29 | # unitize.mk must be called at the end of each UNIT_DIR.mk file. | ||
3493 | 30 | include unitize.mk | ||
3494 | 31 | |||
3495 | 32 | 0 | ||
3496 | === modified file 'src/library/LibraryWindow.vala' | |||
3497 | --- src/library/LibraryWindow.vala 2014-08-28 03:37:44 +0000 | |||
3498 | +++ src/library/LibraryWindow.vala 2014-08-28 06:03:26 +0000 | |||
3499 | @@ -288,13 +288,6 @@ | |||
3500 | 288 | import.tooltip = _ ("Import photos from disk to library"); | 288 | import.tooltip = _ ("Import photos from disk to library"); |
3501 | 289 | actions += import; | 289 | actions += import; |
3502 | 290 | 290 | ||
3503 | 291 | Gtk.ActionEntry import_from_external = { | ||
3504 | 292 | "ExternalLibraryImport", Resources.IMPORT, TRANSLATABLE, | ||
3505 | 293 | null, TRANSLATABLE, on_external_library_import | ||
3506 | 294 | }; | ||
3507 | 295 | import_from_external.label = _ ("Import From _Application..."); | ||
3508 | 296 | actions += import_from_external; | ||
3509 | 297 | |||
3510 | 298 | Gtk.ActionEntry sort = { "CommonSortEvents", null, TRANSLATABLE, null, null, null }; | 291 | Gtk.ActionEntry sort = { "CommonSortEvents", null, TRANSLATABLE, null, null, null }; |
3511 | 299 | sort.label = _ ("Sort _Events"); | 292 | sort.label = _ ("Sort _Events"); |
3512 | 300 | actions += sort; | 293 | actions += sort; |
3513 | @@ -667,12 +660,6 @@ | |||
3514 | 667 | import_dialog.destroy (); | 660 | import_dialog.destroy (); |
3515 | 668 | } | 661 | } |
3516 | 669 | 662 | ||
3517 | 670 | private void on_external_library_import () { | ||
3518 | 671 | Gtk.Dialog import_dialog = DataImportsUI.DataImportsDialog.get_or_create_instance (); | ||
3519 | 672 | |||
3520 | 673 | import_dialog.run (); | ||
3521 | 674 | } | ||
3522 | 675 | |||
3523 | 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) { |
3524 | 677 | base.update_common_action_availability (old_page, new_page); | 664 | base.update_common_action_availability (old_page, new_page); |
3525 | 678 | 665 | ||
3526 | 679 | 666 | ||
3527 | === modified file 'src/library/mk/library.mk' | |||
3528 | --- src/library/mk/library.mk 2014-08-28 03:37:44 +0000 | |||
3529 | +++ src/library/mk/library.mk 2014-08-28 06:03:26 +0000 | |||
3530 | @@ -41,8 +41,7 @@ | |||
3531 | 41 | Events \ | 41 | Events \ |
3532 | 42 | Tags \ | 42 | Tags \ |
3533 | 43 | Camera \ | 43 | Camera \ |
3536 | 44 | Searches \ | 44 | Searches |
3535 | 45 | DataImports | ||
3537 | 46 | 45 | ||
3538 | 47 | # List any additional files that are used in the build process as a part of this unit that should | 46 | # List any additional files that are used in the build process as a part of this unit that should |
3539 | 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. |
3540 | 49 | 48 | ||
3541 | === removed file 'src/plugins/DataImportsInterfaces.vala' | |||
3542 | --- src/plugins/DataImportsInterfaces.vala 2014-08-08 21:13:09 +0000 | |||
3543 | +++ src/plugins/DataImportsInterfaces.vala 1970-01-01 00:00:00 +0000 | |||
3544 | @@ -1,489 +0,0 @@ | |||
3545 | 1 | /* Copyright 2011-2013 Yorba Foundation | ||
3546 | 2 | * | ||
3547 | 3 | * This software is licensed under the GNU Lesser General Public License | ||
3548 | 4 | * (version 2.1 or later). See the COPYING file in this distribution. | ||
3549 | 5 | */ | ||
3550 | 6 | |||
3551 | 7 | /** | ||
3552 | 8 | * Shotwell Pluggable Data Imports API | ||
3553 | 9 | * | ||
3554 | 10 | * The Shotwell Pluggable Data Imports API allows you to write plugins that import | ||
3555 | 11 | * information from other media library databases to help migration to Shotwell. | ||
3556 | 12 | * The Shotwell distribution includes import support for F-Spot. | ||
3557 | 13 | * To enable Shotwell to import from additional libaries, developers like you write | ||
3558 | 14 | * data import plugins, dynamically-loadable shared objects that are linked into the | ||
3559 | 15 | * Shotwell process at runtime. Data import plugins are just one of several kinds of | ||
3560 | 16 | * plugins supported by {@link Spit}, the Shotwell Pluggable Interfaces Technology. | ||
3561 | 17 | */ | ||
3562 | 18 | namespace Spit.DataImports { | ||
3563 | 19 | |||
3564 | 20 | /** | ||
3565 | 21 | * The current version of the Pluggable Data Import API | ||
3566 | 22 | */ | ||
3567 | 23 | public const int CURRENT_INTERFACE = 0; | ||
3568 | 24 | |||
3569 | 25 | /** | ||
3570 | 26 | * The error domain for alien databases | ||
3571 | 27 | */ | ||
3572 | 28 | public errordomain DataImportError { | ||
3573 | 29 | /** | ||
3574 | 30 | * Indicates that the version of the external database being imported is | ||
3575 | 31 | * not supported by this version of the plugin. | ||
3576 | 32 | * | ||
3577 | 33 | * This occurs for example when trying to import an F-Spot database that | ||
3578 | 34 | * has a version that is more recent than what the current plugin supports. | ||
3579 | 35 | */ | ||
3580 | 36 | UNSUPPORTED_VERSION | ||
3581 | 37 | } | ||
3582 | 38 | |||
3583 | 39 | /** | ||
3584 | 40 | * Represents a module that is able to import data from a specific database format. | ||
3585 | 41 | * | ||
3586 | 42 | * Developers of data import plugins provide a class that implements this interface. At | ||
3587 | 43 | * any given time, only one DataImporter can be running. When a data importer is running, it | ||
3588 | 44 | * has exclusive use of the shared user-interface and | ||
3589 | 45 | * configuration services provided by the {@link PluginHost}. Data importers are created in | ||
3590 | 46 | * a non-running state and do not begin running until start( ) is invoked. Data importers | ||
3591 | 47 | * run until stop( ) is invoked. | ||
3592 | 48 | */ | ||
3593 | 49 | public interface DataImporter : GLib.Object { | ||
3594 | 50 | /** | ||
3595 | 51 | * Returns a {@link Service} object describing the service to which this connects. | ||
3596 | 52 | */ | ||
3597 | 53 | public abstract Service get_service (); | ||
3598 | 54 | |||
3599 | 55 | /** | ||
3600 | 56 | * Makes this data importer enter the running state and endows it with exclusive access | ||
3601 | 57 | * to the shared services provided by the {@link PluginHost}. Through the host’s interface, | ||
3602 | 58 | * this data importer can install user interface panes and query configuration information. | ||
3603 | 59 | */ | ||
3604 | 60 | public abstract void start (); | ||
3605 | 61 | |||
3606 | 62 | /** | ||
3607 | 63 | * Returns true if this data importer is in the running state; false otherwise. | ||
3608 | 64 | */ | ||
3609 | 65 | public abstract bool is_running (); | ||
3610 | 66 | |||
3611 | 67 | /** | ||
3612 | 68 | * Causes this data importer to enter a non-running state. This data importer should stop all | ||
3613 | 69 | * data access operations and cease use of the shared services provided by the {@link PluginHost}. | ||
3614 | 70 | */ | ||
3615 | 71 | public abstract void stop (); | ||
3616 | 72 | |||
3617 | 73 | /** | ||
3618 | 74 | * Causes this data importer to enter start the import of a library. | ||
3619 | 75 | */ | ||
3620 | 76 | public abstract void on_library_selected (ImportableLibrary library); | ||
3621 | 77 | |||
3622 | 78 | /** | ||
3623 | 79 | * Causes this data importer to enter start the import of a library file. | ||
3624 | 80 | */ | ||
3625 | 81 | public abstract void on_file_selected (File file); | ||
3626 | 82 | |||
3627 | 83 | // | ||
3628 | 84 | // For future expansion. | ||
3629 | 85 | // | ||
3630 | 86 | protected virtual void reserved0 () {} | ||
3631 | 87 | protected virtual void reserved1 () {} | ||
3632 | 88 | protected virtual void reserved2 () {} | ||
3633 | 89 | protected virtual void reserved3 () {} | ||
3634 | 90 | protected virtual void reserved4 () {} | ||
3635 | 91 | protected virtual void reserved5 () {} | ||
3636 | 92 | protected virtual void reserved6 () {} | ||
3637 | 93 | protected virtual void reserved7 () {} | ||
3638 | 94 | } | ||
3639 | 95 | |||
3640 | 96 | /** | ||
3641 | 97 | * Represents a library of importable media items. | ||
3642 | 98 | * | ||
3643 | 99 | * Developers of data import plugins provide a class that implements this interface. | ||
3644 | 100 | */ | ||
3645 | 101 | public interface ImportableLibrary : GLib.Object { | ||
3646 | 102 | public abstract string get_display_name (); | ||
3647 | 103 | } | ||
3648 | 104 | |||
3649 | 105 | /** | ||
3650 | 106 | * Represents an importable media item such as a photo or a video file. | ||
3651 | 107 | * | ||
3652 | 108 | * Developers of data import plugins provide a class that implements this interface. | ||
3653 | 109 | */ | ||
3654 | 110 | public interface ImportableMediaItem : GLib.Object { | ||
3655 | 111 | public abstract ImportableTag[] get_tags (); | ||
3656 | 112 | |||
3657 | 113 | public abstract ImportableEvent? get_event (); | ||
3658 | 114 | |||
3659 | 115 | public abstract ImportableRating get_rating (); | ||
3660 | 116 | |||
3661 | 117 | public abstract string? get_title (); | ||
3662 | 118 | |||
3663 | 119 | public abstract string get_folder_path (); | ||
3664 | 120 | |||
3665 | 121 | public abstract string get_filename (); | ||
3666 | 122 | } | ||
3667 | 123 | |||
3668 | 124 | /** | ||
3669 | 125 | * Represents an importable tag. | ||
3670 | 126 | * | ||
3671 | 127 | * Developers of data import plugins provide a class that implements this interface. | ||
3672 | 128 | */ | ||
3673 | 129 | public interface ImportableTag : GLib.Object { | ||
3674 | 130 | public abstract string get_name (); | ||
3675 | 131 | |||
3676 | 132 | public abstract ImportableTag? get_parent (); | ||
3677 | 133 | } | ||
3678 | 134 | |||
3679 | 135 | /** | ||
3680 | 136 | * Represents an importable event. | ||
3681 | 137 | * | ||
3682 | 138 | * Developers of data import plugins provide a class that implements this interface. | ||
3683 | 139 | */ | ||
3684 | 140 | public interface ImportableEvent : GLib.Object { | ||
3685 | 141 | public abstract string get_name (); | ||
3686 | 142 | } | ||
3687 | 143 | |||
3688 | 144 | /** | ||
3689 | 145 | * Represents an importable rating value. | ||
3690 | 146 | * | ||
3691 | 147 | * Developers of data import plugins provide a class that implements this interface. | ||
3692 | 148 | * Note that the value returned by the get_value method should be a value between | ||
3693 | 149 | * 1 and 5, unless the rating object is unrated or rejected, in which case the | ||
3694 | 150 | * value is unspecified. | ||
3695 | 151 | */ | ||
3696 | 152 | public interface ImportableRating : GLib.Object { | ||
3697 | 153 | public abstract bool is_unrated (); | ||
3698 | 154 | |||
3699 | 155 | public abstract bool is_rejected (); | ||
3700 | 156 | |||
3701 | 157 | public abstract int get_value (); | ||
3702 | 158 | } | ||
3703 | 159 | |||
3704 | 160 | /** | ||
3705 | 161 | * Encapsulates a pane that can be installed in the on-screen import dialog box to | ||
3706 | 162 | * communicate status to and to get information from the user. | ||
3707 | 163 | * | ||
3708 | 164 | */ | ||
3709 | 165 | public interface DialogPane : GLib.Object { | ||
3710 | 166 | |||
3711 | 167 | /** | ||
3712 | 168 | * Describes how the on-screen publishing dialog box should look and behave when an associated | ||
3713 | 169 | * pane is installed in the on-screen publishing dialog box. | ||
3714 | 170 | */ | ||
3715 | 171 | public enum GeometryOptions { | ||
3716 | 172 | |||
3717 | 173 | /** | ||
3718 | 174 | * When the associated pane is installed, the on-screen publishing dialog box will be | ||
3719 | 175 | * sized normally and will not allow the user to change its size. | ||
3720 | 176 | */ | ||
3721 | 177 | NONE = 0, | ||
3722 | 178 | |||
3723 | 179 | /** | ||
3724 | 180 | * If this bit is set, when the associated pane is installed, the on-screen publishing | ||
3725 | 181 | * dialog box will grow to a larger size. | ||
3726 | 182 | */ | ||
3727 | 183 | EXTENDED_SIZE = 1 << 0, | ||
3728 | 184 | |||
3729 | 185 | /** | ||
3730 | 186 | * If this bit is set, when the associated pane is installed, the on-screen publishing | ||
3731 | 187 | * dialog box will allow the user to change its size. | ||
3732 | 188 | */ | ||
3733 | 189 | RESIZABLE = 1 << 1, | ||
3734 | 190 | |||
3735 | 191 | /** | ||
3736 | 192 | * If this bit is set, when the associated pane is installed, the on-screen publishing | ||
3737 | 193 | * dialog box will grow to accommodate a full-width 1024 pixel web page. If both | ||
3738 | 194 | * EXTENDED_SIZE and COLOSSAL_SIZE are set, EXTENDED_SIZE takes precedence. | ||
3739 | 195 | */ | ||
3740 | 196 | COLOSSAL_SIZE = 1 << 2; | ||
3741 | 197 | } | ||
3742 | 198 | |||
3743 | 199 | /** | ||
3744 | 200 | * Returns the Gtk.Widget that is this pane's on-screen representation. | ||
3745 | 201 | */ | ||
3746 | 202 | public abstract Gtk.Widget get_widget (); | ||
3747 | 203 | |||
3748 | 204 | /** | ||
3749 | 205 | * Returns a {@link GeometryOptions} bitfield describing how the on-screen publishing dialog | ||
3750 | 206 | * box should look and behave when this pane is installed. | ||
3751 | 207 | */ | ||
3752 | 208 | public abstract GeometryOptions get_preferred_geometry (); | ||
3753 | 209 | |||
3754 | 210 | /** | ||
3755 | 211 | * Invoked automatically by Shotwell when this pane has been installed into the on-screen | ||
3756 | 212 | * publishing dialog box and become visible to the user. | ||
3757 | 213 | */ | ||
3758 | 214 | public abstract void on_pane_installed (); | ||
3759 | 215 | |||
3760 | 216 | /** | ||
3761 | 217 | * Invoked automatically by Shotwell when this pane has been removed from the on-screen | ||
3762 | 218 | * publishing dialog box and is no longer visible to the user. | ||
3763 | 219 | */ | ||
3764 | 220 | public abstract void on_pane_uninstalled (); | ||
3765 | 221 | |||
3766 | 222 | // | ||
3767 | 223 | // For future expansion. | ||
3768 | 224 | // | ||
3769 | 225 | protected virtual void reserved0 () {} | ||
3770 | 226 | protected virtual void reserved1 () {} | ||
3771 | 227 | protected virtual void reserved2 () {} | ||
3772 | 228 | protected virtual void reserved3 () {} | ||
3773 | 229 | protected virtual void reserved4 () {} | ||
3774 | 230 | protected virtual void reserved5 () {} | ||
3775 | 231 | protected virtual void reserved6 () {} | ||
3776 | 232 | protected virtual void reserved7 () {} | ||
3777 | 233 | } | ||
3778 | 234 | |||
3779 | 235 | /** | ||
3780 | 236 | * Called by the data imports system at the end of an import batch to report | ||
3781 | 237 | * to the plugin the number of items that were really imported. This enables | ||
3782 | 238 | * the plugin to display a final message to the user. However, the plugin | ||
3783 | 239 | * should not rely on this callback being called in order to clean up. | ||
3784 | 240 | */ | ||
3785 | 241 | public delegate void ImportedItemsCountCallback (int imported_items_count); | ||
3786 | 242 | |||
3787 | 243 | /** | ||
3788 | 244 | * Manages and provides services for data import plugins. | ||
3789 | 245 | * | ||
3790 | 246 | * Implemented inside Shotwell, the PluginHost provides an interface through which the | ||
3791 | 247 | * developers of data import plugins can query and make changes to the import | ||
3792 | 248 | * environment. Plugins can use the services of the PluginHost only when their | ||
3793 | 249 | * {@link DataImporter} is in the running state. This ensures that non-running data importers | ||
3794 | 250 | * don’t destructively interfere with the actively running importer. | ||
3795 | 251 | */ | ||
3796 | 252 | public interface PluginHost : GLib.Object, Spit.HostInterface { | ||
3797 | 253 | |||
3798 | 254 | /** | ||
3799 | 255 | * Specifies the label text on the push button control that appears in the | ||
3800 | 256 | * lower-right-hand corner of the on-screen publishing dialog box. | ||
3801 | 257 | */ | ||
3802 | 258 | public enum ButtonMode { | ||
3803 | 259 | CLOSE = 0, | ||
3804 | 260 | CANCEL = 1 | ||
3805 | 261 | } | ||
3806 | 262 | |||
3807 | 263 | /** | ||
3808 | 264 | * Notifies the user that an unrecoverable import error has occurred and halts | ||
3809 | 265 | * the import process. | ||
3810 | 266 | * | ||
3811 | 267 | * @param err An error object that describes the kind of error that occurred. | ||
3812 | 268 | */ | ||
3813 | 269 | public abstract void post_error (Error err); | ||
3814 | 270 | |||
3815 | 271 | /** | ||
3816 | 272 | * Notifies the user that an unrecoverable import error has occurred and halts | ||
3817 | 273 | * the import process. | ||
3818 | 274 | * | ||
3819 | 275 | * @param msg A message that describes the kind of error that occurred. | ||
3820 | 276 | */ | ||
3821 | 277 | public abstract void post_error_message (string msg); | ||
3822 | 278 | |||
3823 | 279 | /** | ||
3824 | 280 | * Starts the import process. | ||
3825 | 281 | * | ||
3826 | 282 | * Calling this method starts the import activity for this host. | ||
3827 | 283 | */ | ||
3828 | 284 | public abstract void start_importing (); | ||
3829 | 285 | |||
3830 | 286 | /** | ||
3831 | 287 | * Halts the import process. | ||
3832 | 288 | * | ||
3833 | 289 | * Calling this method stops all import activity and hides the on-screen import | ||
3834 | 290 | * dialog box. | ||
3835 | 291 | */ | ||
3836 | 292 | public abstract void stop_importing (); | ||
3837 | 293 | |||
3838 | 294 | /** | ||
3839 | 295 | * Returns a reference to the {@link DataImporter} object that this is currently hosting. | ||
3840 | 296 | */ | ||
3841 | 297 | public abstract DataImporter get_data_importer (); | ||
3842 | 298 | |||
3843 | 299 | /** | ||
3844 | 300 | * Attempts to install a pane in the on-screen data import dialog box, making the pane visible | ||
3845 | 301 | * and allowing it to interact with the user. | ||
3846 | 302 | * | ||
3847 | 303 | * If an error has posted, the {@link PluginHost} will not honor this request. | ||
3848 | 304 | * | ||
3849 | 305 | * @param pane the pane to install | ||
3850 | 306 | * | ||
3851 | 307 | * @param mode allows you to set the text displayed on the close/cancel button in the | ||
3852 | 308 | * lower-right-hand corner of the on-screen data import dialog box when pane is installed. | ||
3853 | 309 | * If mode is ButtonMode.CLOSE, the button will have the title "Close." If mode is | ||
3854 | 310 | * ButtonMode.CANCEL, the button will be titled "Cancel." You should set mode depending on | ||
3855 | 311 | * whether a cancellable action is in progress. For example, if your importer is in the | ||
3856 | 312 | * middle of processing 3 of 8 videos, then mode should be ButtonMode.CANCEL. However, if | ||
3857 | 313 | * the processing operation has completed and the success pane is displayed, then mode | ||
3858 | 314 | * should be ButtonMode.CLOSE, because all cancellable actions have already | ||
3859 | 315 | * occurred. | ||
3860 | 316 | */ | ||
3861 | 317 | public abstract void install_dialog_pane (Spit.DataImports.DialogPane pane, | ||
3862 | 318 | ButtonMode mode = ButtonMode.CANCEL); | ||
3863 | 319 | |||
3864 | 320 | /** | ||
3865 | 321 | * Attempts to install a pane in the on-screen data import dialog box that contains | ||
3866 | 322 | * static text. | ||
3867 | 323 | * | ||
3868 | 324 | * The text appears centered in the data import dialog box and is drawn in | ||
3869 | 325 | * the system font. This is a convenience method only; similar results could be | ||
3870 | 326 | * achieved by manually constructing a Gtk.Label widget, wrapping it inside a | ||
3871 | 327 | * {@link DialogPane}, and installing it manually with a call to | ||
3872 | 328 | * install_dialog_pane( ). To provide visual consistency across data import services, | ||
3873 | 329 | * however, always use this convenience method instead of constructing label panes when | ||
3874 | 330 | * you need to display static text to the user. | ||
3875 | 331 | * | ||
3876 | 332 | * If an error has posted, the {@link PluginHost} will not honor this request. | ||
3877 | 333 | * | ||
3878 | 334 | * @param message the text to show in the pane | ||
3879 | 335 | * | ||
3880 | 336 | * @param mode allows you to set the text displayed on the close/cancel button in the | ||
3881 | 337 | * lower-right-hand corner of the on-screen data import dialog box when pane is installed. | ||
3882 | 338 | * If mode is ButtonMode.CLOSE, the button will have the title "Close." If mode is | ||
3883 | 339 | * ButtonMode.CANCEL, the button will be titled "Cancel." You should set mode depending on | ||
3884 | 340 | * whether a cancellable action is in progress. For example, if your importer is in the | ||
3885 | 341 | * middle of processing 3 of 8 videos, then mode should be ButtonMode.CANCEL. However, if | ||
3886 | 342 | * the processing operation has completed and the success pane is displayed, then mode | ||
3887 | 343 | * should be ButtonMode.CLOSE, because all cancellable actions have already | ||
3888 | 344 | * occurred. | ||
3889 | 345 | */ | ||
3890 | 346 | public abstract void install_static_message_pane (string message, | ||
3891 | 347 | ButtonMode mode = ButtonMode.CANCEL); | ||
3892 | 348 | |||
3893 | 349 | /** | ||
3894 | 350 | * Attempts to install a library selection pane that presents a list of | ||
3895 | 351 | * discovered libraries to the user. | ||
3896 | 352 | * | ||
3897 | 353 | * When the user clicks the “OK” button, you’ll be notified of the user’s action through | ||
3898 | 354 | * the 'on_library_selected' callback if a discovered library was selected or through | ||
3899 | 355 | * the 'on_file_selected' callback if a file was selected. | ||
3900 | 356 | * | ||
3901 | 357 | * If an error has posted, the {@link PluginHost} will not honor this request. | ||
3902 | 358 | * | ||
3903 | 359 | * @param welcome_message the text to be displayed above the list of discovered | ||
3904 | 360 | * libraries. | ||
3905 | 361 | * | ||
3906 | 362 | * @param discovered_libraries the list of importable libraries that the plugin | ||
3907 | 363 | * has discovered in well known locations. | ||
3908 | 364 | * | ||
3909 | 365 | * @param file_select_label the label to display for the file selection | ||
3910 | 366 | * option. If this label is null, the | ||
3911 | 367 | * user will not be presented with a file selection option. | ||
3912 | 368 | */ | ||
3913 | 369 | public abstract void install_library_selection_pane ( | ||
3914 | 370 | string welcome_message, | ||
3915 | 371 | ImportableLibrary[] discovered_libraries, | ||
3916 | 372 | string? file_select_label | ||
3917 | 373 | ); | ||
3918 | 374 | |||
3919 | 375 | /** | ||
3920 | 376 | * Attempts to install a progress pane that provides the user with feedback | ||
3921 | 377 | * on import preparation. | ||
3922 | 378 | * | ||
3923 | 379 | * If an error has posted, the {@link PluginHost} will not honor this request. | ||
3924 | 380 | * | ||
3925 | 381 | * @param message the text to be displayed above the progress bar. | ||
3926 | 382 | */ | ||
3927 | 383 | public abstract void install_import_progress_pane ( | ||
3928 | 384 | string message | ||
3929 | 385 | ); | ||
3930 | 386 | |||
3931 | 387 | /** | ||
3932 | 388 | * Update the progress bar installed by install_import_progress_pane. | ||
3933 | 389 | * | ||
3934 | 390 | * If an error has posted, the {@link PluginHost} will not honor this request. | ||
3935 | 391 | * | ||
3936 | 392 | * @param progress a value between 0.0 and 1.0 identifying progress for the | ||
3937 | 393 | * plugin. | ||
3938 | 394 | * | ||
3939 | 395 | * @param progress_label the text to be displayed below the progress bar. If that | ||
3940 | 396 | * parameter is null, the message will be left unchanged. | ||
3941 | 397 | */ | ||
3942 | 398 | public abstract void update_import_progress_pane ( | ||
3943 | 399 | double progress, | ||
3944 | 400 | string? progress_message = null | ||
3945 | 401 | ); | ||
3946 | 402 | |||
3947 | 403 | /** | ||
3948 | 404 | * Sends an importable media item to the host in order to prepare it for import | ||
3949 | 405 | * and update the progress bar installed by install_import_progress_pane. | ||
3950 | 406 | * | ||
3951 | 407 | * If an error has posted, the {@link PluginHost} will not honor this request. | ||
3952 | 408 | * | ||
3953 | 409 | * @param item the importable media item to prepare for import. | ||
3954 | 410 | * | ||
3955 | 411 | * @param progress a value between 0.0 and 1.0 identifying progress for the | ||
3956 | 412 | * plugin. | ||
3957 | 413 | * | ||
3958 | 414 | * @param host_progress_delta the amount of progress the host should update | ||
3959 | 415 | * the progress bar during import preparation. Plugins should ensure that | ||
3960 | 416 | * a proportion of progress for each media item is set aside for the host | ||
3961 | 417 | * in oder to ensure a smoother update to the progress bar. | ||
3962 | 418 | * | ||
3963 | 419 | * @param progress_message the text to be displayed below the progress bar. If that | ||
3964 | 420 | * parameter is null, the message will be left unchanged. | ||
3965 | 421 | */ | ||
3966 | 422 | public abstract void prepare_media_items_for_import ( | ||
3967 | 423 | ImportableMediaItem[] items, | ||
3968 | 424 | double progress, | ||
3969 | 425 | double host_progress_delta = 0.0, | ||
3970 | 426 | string? progress_message = null | ||
3971 | 427 | ); | ||
3972 | 428 | |||
3973 | 429 | /** | ||
3974 | 430 | * Finalize the import sequence for the plugin. This tells the host that | ||
3975 | 431 | * all media items have been processed and that the plugin has finished all | ||
3976 | 432 | * import work. Once this method has been called, all resources used by the | ||
3977 | 433 | * plugin for import should be released and the plugin should be back to the | ||
3978 | 434 | * state it had just after running the start method. The host will then display | ||
3979 | 435 | * the final message and show progress as fully complete. In a standard import | ||
3980 | 436 | * scenario, the user is expected to click the Close button to dismiss the | ||
3981 | 437 | * dialog. On first run, the host may call the LibrarySelectedCallback again | ||
3982 | 438 | * to import another library handled by the same plugin. | ||
3983 | 439 | * | ||
3984 | 440 | * If an error has posted, the {@link PluginHost} will not honor this request. | ||
3985 | 441 | * | ||
3986 | 442 | * @param finalize_message the text to be displayed below the progress bar. If that | ||
3987 | 443 | * parameter is null, the message will be left unchanged. | ||
3988 | 444 | */ | ||
3989 | 445 | public abstract void finalize_import ( | ||
3990 | 446 | ImportedItemsCountCallback report_imported_items_count, | ||
3991 | 447 | string? finalize_message = null | ||
3992 | 448 | ); | ||
3993 | 449 | |||
3994 | 450 | // | ||
3995 | 451 | // For future expansion. | ||
3996 | 452 | // | ||
3997 | 453 | protected virtual void reserved0 () {} | ||
3998 | 454 | protected virtual void reserved1 () {} | ||
3999 | 455 | protected virtual void reserved2 () {} | ||
4000 | 456 | protected virtual void reserved3 () {} | ||
4001 | 457 | protected virtual void reserved4 () {} | ||
4002 | 458 | protected virtual void reserved5 () {} | ||
4003 | 459 | protected virtual void reserved6 () {} | ||
4004 | 460 | protected virtual void reserved7 () {} | ||
4005 | 461 | } | ||
4006 | 462 | |||
4007 | 463 | /** | ||
4008 | 464 | * Describes the features and capabilities of a data import service. | ||
4009 | 465 | * | ||
4010 | 466 | * Developers of data import plugins provide a class that implements this interface. | ||
4011 | 467 | */ | ||
4012 | 468 | public interface Service : Object, Spit.Pluggable { | ||
4013 | 469 | /** | ||
4014 | 470 | * A factory method that instantiates and returns a new {@link DataImporter} object | ||
4015 | 471 | * that this Service describes. | ||
4016 | 472 | */ | ||
4017 | 473 | public abstract Spit.DataImports.DataImporter create_data_importer (Spit.DataImports.PluginHost host); | ||
4018 | 474 | |||
4019 | 475 | // | ||
4020 | 476 | // For future expansion. | ||
4021 | 477 | // | ||
4022 | 478 | protected virtual void reserved0 () {} | ||
4023 | 479 | protected virtual void reserved1 () {} | ||
4024 | 480 | protected virtual void reserved2 () {} | ||
4025 | 481 | protected virtual void reserved3 () {} | ||
4026 | 482 | protected virtual void reserved4 () {} | ||
4027 | 483 | protected virtual void reserved5 () {} | ||
4028 | 484 | protected virtual void reserved6 () {} | ||
4029 | 485 | protected virtual void reserved7 () {} | ||
4030 | 486 | } | ||
4031 | 487 | |||
4032 | 488 | } | ||
4033 | 489 | |||
4034 | 490 | 0 | ||
4035 | === modified file 'src/plugins/mk/interfaces.mk' | |||
4036 | --- src/plugins/mk/interfaces.mk 2013-04-25 00:53:04 +0000 | |||
4037 | +++ src/plugins/mk/interfaces.mk 2014-08-28 06:03:26 +0000 | |||
4038 | @@ -2,8 +2,7 @@ | |||
4039 | 2 | PLUGIN_INTERFACES := \ | 2 | PLUGIN_INTERFACES := \ |
4040 | 3 | src/plugins/SpitInterfaces.vala \ | 3 | src/plugins/SpitInterfaces.vala \ |
4041 | 4 | src/plugins/TransitionsInterfaces.vala \ | 4 | src/plugins/TransitionsInterfaces.vala \ |
4044 | 5 | src/plugins/PublishingInterfaces.vala \ | 5 | src/plugins/PublishingInterfaces.vala |
4043 | 6 | src/plugins/DataImportsInterfaces.vala | ||
4045 | 7 | 6 | ||
4046 | 8 | PLUGIN_PKG_REQS := \ | 7 | PLUGIN_PKG_REQS := \ |
4047 | 9 | gobject-2.0 \ | 8 | gobject-2.0 \ |
4048 | 10 | 9 | ||
4049 | === modified file 'src/plugins/mk/plugins.mk' | |||
4050 | --- src/plugins/mk/plugins.mk 2012-02-02 22:56:06 +0000 | |||
4051 | +++ src/plugins/mk/plugins.mk 2014-08-28 06:03:26 +0000 | |||
4052 | @@ -15,8 +15,7 @@ | |||
4053 | 15 | SpitInterfaces.vala \ | 15 | SpitInterfaces.vala \ |
4054 | 16 | TransitionsInterfaces.vala \ | 16 | TransitionsInterfaces.vala \ |
4055 | 17 | StandardHostInterface.vala \ | 17 | StandardHostInterface.vala \ |
4058 | 18 | ManifestWidget.vala \ | 18 | ManifestWidget.vala |
4057 | 19 | DataImportsInterfaces.vala | ||
4059 | 20 | 19 | ||
4060 | 21 | # Any unit this unit relies upon (and should be initialized before it's initialized) should | 20 | # Any unit this unit relies upon (and should be initialized before it's initialized) should |
4061 | 22 | # be listed here using its Vala namespace. | 21 | # be listed here using its Vala namespace. |
4062 | 23 | 22 | ||
4063 | === modified file 'src/tags/HierarchicalTagUtilities.vala' | |||
4064 | --- src/tags/HierarchicalTagUtilities.vala 2014-08-08 21:13:09 +0000 | |||
4065 | +++ src/tags/HierarchicalTagUtilities.vala 2014-08-28 06:03:26 +0000 | |||
4066 | @@ -78,18 +78,6 @@ | |||
4067 | 78 | return components; | 78 | return components; |
4068 | 79 | } | 79 | } |
4069 | 80 | 80 | ||
4070 | 81 | /** | ||
4071 | 82 | * given a list of path elements, create a fully qualified path string. | ||
4072 | 83 | * For example if 'path_elements' is the list { "Animals", "Mammals", "Elephant" } | ||
4073 | 84 | * the path "/Animals/Mammals/Elephant" will be returned | ||
4074 | 85 | */ | ||
4075 | 86 | public static string? join_path_components (string[] path_components) { | ||
4076 | 87 | if (path_components.length <= 0) | ||
4077 | 88 | return null; | ||
4078 | 89 | string tmp = string.joinv (Tag.PATH_SEPARATOR_STRING, path_components); | ||
4079 | 90 | return string.joinv (Tag.PATH_SEPARATOR_STRING, { "", tmp }); | ||
4080 | 91 | } | ||
4081 | 92 | |||
4082 | 93 | public static string get_basename (string in_path) { | 81 | public static string get_basename (string in_path) { |
4083 | 94 | string path = flat_to_hierarchical (in_path); | 82 | string path = flat_to_hierarchical (in_path); |
4084 | 95 | 83 | ||
4085 | 96 | 84 | ||
4086 | === modified file 'units.mk' | |||
4087 | --- units.mk 2014-08-28 03:37:44 +0000 | |||
4088 | +++ units.mk 2014-08-28 06:03:26 +0000 | |||
4089 | @@ -24,8 +24,7 @@ | |||
4090 | 24 | tags \ | 24 | tags \ |
4091 | 25 | camera \ | 25 | camera \ |
4092 | 26 | searches \ | 26 | searches \ |
4095 | 27 | config \ | 27 | config |
4094 | 28 | data_imports | ||
4096 | 29 | 28 | ||
4097 | 30 | # Name(s) of units that represent application entry points. These units will have init and | 29 | # Name(s) of units that represent application entry points. These units will have init and |
4098 | 31 | # termination entry points generated: Name.unitize_init() and Name.unitize_terminate(). These | 30 | # termination entry points generated: Name.unitize_init() and Name.unitize_terminate(). These |
The modifications to src/tags/ HierarchicalTag Utilities. vala were to satisfy the build failure due to an unused code warning