Commit 66c3e2c2 authored by Jim Nelson's avatar Jim Nelson

#506: Sped up opening photos by using large thumbnail is initial image. #580:...

#506: Sped up opening photos by using large thumbnail is initial image.  #580: "Copy files to library" option 
now available in File / Import.
parent 1daaf561
......@@ -214,7 +214,7 @@ endif
$(EXPANDED_C_FILES): $(VALA_STAMP)
@
$(EXPANDED_OBJ_FILES): %.o: %.c $(CONFIG_IN)
$(EXPANDED_OBJ_FILES): %.o: %.c $(CONFIG_IN) Makefile
$(CC) -c $(VALA_CFLAGS) $(CFLAGS) -o $@ $<
$(PROGRAM): $(EXPANDED_OBJ_FILES)
......
......@@ -5,11 +5,11 @@
*/
public class FullscreenWindow : Gtk.Window {
public static const int TOOLBAR_INVOCATION_MSEC = 250;
public static const int TOOLBAR_DISMISSAL_SEC = 2;
public static const int TOOLBAR_CHECK_DISMISSAL_MSEC = 500;
public const int TOOLBAR_INVOCATION_MSEC = 250;
public const int TOOLBAR_DISMISSAL_SEC = 2;
public const int TOOLBAR_CHECK_DISMISSAL_MSEC = 500;
public static const double TOOLBAR_OPACITY = 0.75;
public const double TOOLBAR_OPACITY = 0.75;
private Gdk.ModifierType ANY_BUTTON_MASK =
Gdk.ModifierType.BUTTON1_MASK | Gdk.ModifierType.BUTTON2_MASK | Gdk.ModifierType.BUTTON3_MASK;
......@@ -213,24 +213,24 @@ public class FullscreenWindow : Gtk.Window {
}
public class AppWindow : Gtk.Window {
public static const string DATA_DIR = ".shotwell";
public static const string PHOTOS_DIR = "Pictures";
public const string DATA_DIR = ".shotwell";
public const string PHOTOS_DIR = "Pictures";
public static const int SIDEBAR_MIN_WIDTH = 160;
public static const int SIDEBAR_MAX_WIDTH = 320;
public static const int PAGE_MIN_WIDTH =
public const int SIDEBAR_MIN_WIDTH = 160;
public const int SIDEBAR_MAX_WIDTH = 320;
public const int PAGE_MIN_WIDTH =
Thumbnail.MAX_SCALE + CollectionLayout.LEFT_PADDING + CollectionLayout.RIGHT_PADDING;
public static Gdk.Color BG_COLOR = parse_color("#444");
public static Gdk.Color SIDEBAR_BG_COLOR = parse_color("#EEE");
public static const long EVENT_LULL_SEC = 3 * 60 * 60;
public static const long EVENT_MAX_DURATION_SEC = 12 * 60 * 60;
public const long EVENT_LULL_SEC = 3 * 60 * 60;
public const long EVENT_MAX_DURATION_SEC = 12 * 60 * 60;
public static const int SORT_EVENTS_ORDER_ASCENDING = 0;
public static const int SORT_EVENTS_ORDER_DESCENDING = 1;
public const int SORT_EVENTS_ORDER_ASCENDING = 0;
public const int SORT_EVENTS_ORDER_DESCENDING = 1;
private static const string[] SUPPORTED_MOUNT_SCHEMES = {
private const string[] SUPPORTED_MOUNT_SCHEMES = {
"gphoto2:",
"disk:",
"file:"
......@@ -269,20 +269,20 @@ public class AppWindow : Gtk.Window {
private class FileImportJob : BatchImportJob {
private File file_or_dir;
private bool copy_to_library;
public FileImportJob(string uri) {
public FileImportJob(string uri, bool copy_to_library) {
file_or_dir = File.new_for_uri(uri);
this.copy_to_library = copy_to_library;
}
public override string get_identifier() {
return file_or_dir.get_uri();
}
public override bool prepare(out File file_to_import, out bool copy_to_library) {
// Copy the file into the photo library; this version of the app, all imports are
// copied. Later updates may allow for links and moves.
public override bool prepare(out File file_to_import, out bool copy) {
file_to_import = file_or_dir;
copy_to_library = true;
copy = copy_to_library;
return true;
}
......@@ -664,16 +664,21 @@ public class AppWindow : Gtk.Window {
}
private void on_file_import() {
Gtk.CheckButton copy_toggle = new Gtk.CheckButton.with_mnemonic(
"_Copy files to %s photo library".printf(AppWindow.PHOTOS_DIR));
copy_toggle.set_active(true);
Gtk.FileChooserDialog import_dialog = new Gtk.FileChooserDialog("Import From Folder", null,
Gtk.FileChooserAction.SELECT_FOLDER, Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
Gtk.STOCK_OK, Gtk.ResponseType.OK);
import_dialog.set_select_multiple(true);
import_dialog.set_current_folder(import_dir);
import_dialog.set_extra_widget(copy_toggle);
int response = import_dialog.run();
if (response == Gtk.ResponseType.OK) {
dispatch_import_jobs(import_dialog.get_uris(), "folders");
dispatch_import_jobs(import_dialog.get_uris(), "folders", copy_toggle.get_active());
}
import_dir = import_dialog.get_current_folder();
import_dialog.destroy();
......@@ -743,12 +748,12 @@ public class AppWindow : Gtk.Window {
import_queue_page.enqueue_and_schedule(batch_import);
}
void dispatch_import_jobs(GLib.SList<string> uris, string job_name) {
void dispatch_import_jobs(GLib.SList<string> uris, string job_name, bool copy_to_library) {
Gee.ArrayList<FileImportJob> jobs = new Gee.ArrayList<FileImportJob>();
uint64 total_bytes = 0;
foreach (string uri in uris) {
jobs.add(new FileImportJob(uri));
jobs.add(new FileImportJob(uri, copy_to_library));
try {
total_bytes += query_total_file_size(File.new_for_uri(uri));
......@@ -911,7 +916,7 @@ public class AppWindow : Gtk.Window {
foreach (string uri in uris_array) {
uris.append(uri);
}
dispatch_import_jobs(uris, "drag-and-drop");
dispatch_import_jobs(uris, "drag-and-drop", true);
Gtk.drag_finish(context, true, false, time);
}
......
......@@ -310,12 +310,17 @@ public class BatchImport {
File import = file;
if (copy_to_library) {
// never copy file if already in library directory
bool is_in_library_dir = file.has_prefix(AppWindow.get_photos_dir());
if (copy_to_library && !is_in_library_dir) {
File copied;
ImportResult result = copy_file(file, out copied);
if (result != ImportResult.SUCCESS)
return result;
debug("Copied %s into library at %s", file.get_path(), copied.get_path());
import = copied;
}
......
......@@ -701,18 +701,22 @@ public class CollectionPage : CheckerboardPage {
}
private void on_remove() {
if (get_selected_count() == 0)
return;
Gtk.MessageDialog dialog = new Gtk.MessageDialog(AppWindow.get_instance(), Gtk.DialogFlags.MODAL,
Gtk.MessageType.WARNING, Gtk.ButtonsType.CANCEL,
"Removing these photos from your library will also delete their files in your %s directory. This action cannot be undone.",
AppWindow.PHOTOS_DIR);
dialog.add_button(Gtk.STOCK_DELETE, Gtk.ResponseType.ACCEPT);
dialog.title = "Remove photos?";
Gtk.MessageType.WARNING, Gtk.ButtonsType.CANCEL,
"If you remove these photos from your library you will lose all edits you've made to "
+ "them. Shotwell can also delete the files from your drive.\n\nThis action cannot be undone.");
dialog.add_button(Gtk.STOCK_DELETE, Gtk.ResponseType.NO);
dialog.add_button("Keep files", Gtk.ResponseType.YES);
dialog.title = "Remove photos?";
Gtk.ResponseType result = (Gtk.ResponseType) dialog.run();
dialog.destroy();
if (result != Gtk.ResponseType.ACCEPT)
if (result != Gtk.ResponseType.YES && result != Gtk.ResponseType.NO)
return;
// iterate over selected photos and remove them from entire system .. this will result
......@@ -723,7 +727,7 @@ public class CollectionPage : CheckerboardPage {
photo.removed -= on_photo_removed;
photo.thumbnail_altered -= on_thumbnail_altered;
photo.remove();
photo.remove(result == Gtk.ResponseType.NO);
}
// now remove from page, outside of iterator
......
......@@ -9,7 +9,7 @@ public class DatabaseTable {
* This number should be incremented every time any database schema is altered between
* releases.
***/
public static const int SCHEMA_VERSION = 1;
public const int SCHEMA_VERSION = 1;
protected static Sqlite.Database db;
......@@ -105,7 +105,7 @@ public bool verify_databases(out string app_version) {
case Photo.Currency.GONE:
message("Unable to locate %s: Removing from photo library", photo.to_string());
photo.remove();
photo.remove(true);
break;
default:
......@@ -195,7 +195,7 @@ public class VersionTable : DatabaseTable {
}
public struct PhotoID {
public static const int64 INVALID = -1;
public const int64 INVALID = -1;
public int64 id;
......@@ -213,7 +213,7 @@ public struct PhotoID {
}
public struct ImportID {
public static const int64 INVALID = -1;
public const int64 INVALID = -1;
public int64 id;
......@@ -866,7 +866,7 @@ public class ThumbnailCacheTable : DatabaseTable {
}
public struct EventID {
public static const int64 INVALID = -1;
public const int64 INVALID = -1;
public int64 id;
......
......@@ -5,8 +5,8 @@
*/
public class DirectoryItem : LayoutItem {
public static const Gdk.InterpType INTERP = Gdk.InterpType.BILINEAR;
public static const int SCALE =
public const Gdk.InterpType INTERP = Gdk.InterpType.BILINEAR;
public const int SCALE =
ThumbnailCache.MEDIUM_SCALE + ((ThumbnailCache.BIG_SCALE - ThumbnailCache.MEDIUM_SCALE) / 2);
public EventID event_id;
......
......@@ -6,7 +6,7 @@
namespace Exif {
// "Exif"
public static const uint8[] SIGNATURE = { 0x45, 0x78, 0x69, 0x66 };
public const uint8[] SIGNATURE = { 0x45, 0x78, 0x69, 0x66 };
public Exif.Entry? find_first_entry(Data data, Exif.Tag tag, Exif.Format format) {
for (int ctr = 0; ctr < (int) Exif.Ifd.COUNT; ctr++) {
......
......@@ -20,12 +20,12 @@ public class PageLayout : Gtk.VBox {
}
public abstract class Page : Gtk.ScrolledWindow {
public static const uint KEY_CTRL_L = Gdk.keyval_from_name("Control_L");
public static const uint KEY_CTRL_R = Gdk.keyval_from_name("Control_R");
public static const uint KEY_ALT_L = Gdk.keyval_from_name("Alt_L");
public static const uint KEY_ALT_R = Gdk.keyval_from_name("Alt_R");
public static const uint KEY_SHIFT_L = Gdk.keyval_from_name("Shift_L");
public static const uint KEY_SHIFT_R = Gdk.keyval_from_name("Shift_R");
public const uint KEY_CTRL_L = Gdk.keyval_from_name("Control_L");
public const uint KEY_CTRL_R = Gdk.keyval_from_name("Control_R");
public const uint KEY_ALT_L = Gdk.keyval_from_name("Alt_L");
public const uint KEY_ALT_R = Gdk.keyval_from_name("Alt_R");
public const uint KEY_SHIFT_L = Gdk.keyval_from_name("Shift_L");
public const uint KEY_SHIFT_R = Gdk.keyval_from_name("Shift_R");
protected enum TargetType {
URI_LIST
......@@ -407,8 +407,8 @@ public abstract class Page : Gtk.ScrolledWindow {
}
public abstract class CheckerboardPage : Page {
private static const int AUTOSCROLL_PIXELS = 50;
private static const int AUTOSCROLL_TICKS_MSEC = 50;
private const int AUTOSCROLL_PIXELS = 50;
private const int AUTOSCROLL_TICKS_MSEC = 50;
private Gtk.Menu context_menu = null;
private CollectionLayout layout = new CollectionLayout();
......@@ -1156,10 +1156,8 @@ public abstract class CheckerboardPage : Page {
}
public abstract class SinglePhotoPage : Page {
public static const Gdk.InterpType FAST_INTERP = Gdk.InterpType.NEAREST;
public static const Gdk.InterpType QUALITY_INTERP = Gdk.InterpType.HYPER;
public static const int IMPROVAL_MSEC = 250;
public const Gdk.InterpType FAST_INTERP = Gdk.InterpType.NEAREST;
public const Gdk.InterpType QUALITY_INTERP = Gdk.InterpType.HYPER;
public enum UpdateReason {
NEW_PHOTO,
......@@ -1386,9 +1384,9 @@ public abstract class SinglePhotoPage : Page {
return;
}
Timeout.add(IMPROVAL_MSEC, image_improval);
Idle.add(image_improval);
// because Timeout doesn't maintain a ref to this, need to maintain one ourself
// because Idle doesn't maintain a ref to this, need to maintain one ourself
// (in case the page is destroyed between schedules)
improval_scheduled = this;
}
......
......@@ -774,7 +774,7 @@ public class Photo : Object {
return ThumbnailCache.fetch(photo_id, scale);
}
public void remove(bool remove_original = true) {
public void remove(bool remove_original) {
// signal all interested parties prior to removal from map
removed();
......@@ -830,6 +830,8 @@ public class Photo : Object {
private void remove_original_file() {
File file = get_file();
debug("Deleting original photo file %s", file.get_path());
try {
file.delete(null);
} catch (Error err) {
......
......@@ -168,7 +168,16 @@ public class PhotoPage : SinglePhotoPage {
photo = thumbnail.get_photo();
photo.altered += on_photo_altered;
// throw a resized large thumbnail up to get an image on the screen quickly,
// and when ready decode and display the full image
set_pixbuf(photo.get_thumbnail(ThumbnailCache.BIG_SCALE));
Idle.add(update_pixbuf);
}
private bool update_pixbuf() {
set_pixbuf(photo.get_pixbuf());
return false;
}
private void update_sensitivity() {
......
......@@ -9,22 +9,22 @@ extern const string _PREFIX;
extern const string _VERSION;
namespace Resources {
public static const string APP_TITLE = "Shotwell";
public static const string APP_SUBTITLE = "Photo Organizer";
public static const string APP_VERSION = _VERSION;
public static const string COPYRIGHT = "Copyright 2009 Yorba Foundation";
public const string APP_TITLE = "Shotwell";
public const string APP_SUBTITLE = "Photo Organizer";
public const string APP_VERSION = _VERSION;
public const string COPYRIGHT = "Copyright 2009 Yorba Foundation";
public static const string YORBA_URL = "http://www.yorba.org";
public static const string HELP_URL = "http://trac.yorba.org/wiki/Shotwell";
public const string YORBA_URL = "http://www.yorba.org";
public const string HELP_URL = "http://trac.yorba.org/wiki/Shotwell";
public static const string PREFIX = _PREFIX;
public const string PREFIX = _PREFIX;
public static const string[] AUTHORS = {
public const string[] AUTHORS = {
"Jim Nelson <jim@yorba.org>",
null
};
public static const string LICENSE = """
public const string LICENSE = """
Shotwell is free software; you can redistribute it and/or modify it under the
terms of the GNU Lesser General Public License as published by the Free
Software Foundation; either version 2.1 of the License, or (at your option)
......
......@@ -6,12 +6,12 @@
public class Thumbnail : LayoutItem {
// cannot use consts in ThumbnailCache for some reason
public static const int MIN_SCALE = 64;
public static const int MAX_SCALE = 360;
public static const int DEFAULT_SCALE = 128;
public const int MIN_SCALE = 64;
public const int MAX_SCALE = 360;
public const int DEFAULT_SCALE = 128;
public static const Gdk.InterpType LOW_QUALITY_INTERP = Gdk.InterpType.NEAREST;
public static const Gdk.InterpType HIGH_QUALITY_INTERP = Gdk.InterpType.BILINEAR;
public const Gdk.InterpType LOW_QUALITY_INTERP = Gdk.InterpType.NEAREST;
public const Gdk.InterpType HIGH_QUALITY_INTERP = Gdk.InterpType.BILINEAR;
private Photo photo;
private int scale;
......
......@@ -5,22 +5,22 @@
*/
public class ThumbnailCache : Object {
public static const Gdk.InterpType DEFAULT_INTERP = Gdk.InterpType.HYPER;
public static const int DEFAULT_JPEG_QUALITY = 90;
public static const int MAX_INMEMORY_DATA_SIZE = 256 * 1024;
public const Gdk.InterpType DEFAULT_INTERP = Gdk.InterpType.HYPER;
public const int DEFAULT_JPEG_QUALITY = 90;
public const int MAX_INMEMORY_DATA_SIZE = 256 * 1024;
public static const int BIG_SCALE = 360;
public static const int MEDIUM_SCALE = 128;
public static const int SMALL_SCALE = 64;
public const int BIG_SCALE = 360;
public const int MEDIUM_SCALE = 128;
public const int SMALL_SCALE = 64;
public static const int[] SCALES = { BIG_SCALE, MEDIUM_SCALE, SMALL_SCALE };
public const int[] SCALES = { BIG_SCALE, MEDIUM_SCALE, SMALL_SCALE };
public static const ulong KBYTE = 1024;
public static const ulong MBYTE = 1024 * KBYTE;
public const ulong KBYTE = 1024;
public const ulong MBYTE = 1024 * KBYTE;
public static const ulong MAX_BIG_CACHED_BYTES = 25 * MBYTE;
public static const ulong MAX_MEDIUM_CACHED_BYTES = 15 * MBYTE;
public static const ulong MAX_SMALL_CACHED_BYTES = 10 * MBYTE;
public const ulong MAX_BIG_CACHED_BYTES = 25 * MBYTE;
public const ulong MAX_MEDIUM_CACHED_BYTES = 15 * MBYTE;
public const ulong MAX_SMALL_CACHED_BYTES = 10 * MBYTE;
private static ThumbnailCache big = null;
private static ThumbnailCache medium = null;
......
......@@ -114,7 +114,7 @@ bool coord_in_rectangle(int x, int y, Gdk.Rectangle rect) {
}
namespace Jpeg {
public static const uint8 MARKER_PREFIX = 0xFF;
public const uint8 MARKER_PREFIX = 0xFF;
public enum Marker {
SOI = 0xD8,
......
......@@ -362,12 +362,12 @@ namespace GPhoto {
cprefix="GP_MIME_"
)]
namespace MIME {
public static const string RAW;
public static const string PNG;
public static const string JPEG;
public static const string TIFF;
public static const string BMP;
public static const string EXIF;
public const string RAW;
public const string PNG;
public const string JPEG;
public const string TIFF;
public const string BMP;
public const string EXIF;
}
[SimpleType]
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment