diff options
Diffstat (limited to 'src/dialogs/AdjustDateTimeDialog.vala')
| -rw-r--r-- | src/dialogs/AdjustDateTimeDialog.vala | 343 | 
1 files changed, 343 insertions, 0 deletions
| diff --git a/src/dialogs/AdjustDateTimeDialog.vala b/src/dialogs/AdjustDateTimeDialog.vala new file mode 100644 index 0000000..cf2685b --- /dev/null +++ b/src/dialogs/AdjustDateTimeDialog.vala @@ -0,0 +1,343 @@ +/* Copyright 2016 Software Freedom Conservancy Inc. + * Copyright 2017 Jens Georg <mail@jensge.org> + * + * This software is licensed under the GNU LGPL (version 2.1 or later). + * See the COPYING file in this distribution. + */ + +public class AdjustDateTimeDialog : Gtk.Dialog { +    private const int64 SECONDS_IN_DAY = 60 * 60 * 24; +    private const int64 SECONDS_IN_HOUR = 60 * 60; +    private const int64 SECONDS_IN_MINUTE = 60; +    private const int YEAR_OFFSET = 1900; +    private bool no_original_time = false; + +    private const int CALENDAR_THUMBNAIL_SCALE = 1; + +    time_t original_time; +    Gtk.Label original_time_label; +    Gtk.Calendar calendar; +    Gtk.SpinButton hour; +    Gtk.SpinButton minute; +    Gtk.SpinButton second; +    Gtk.ComboBoxText system; +    Gtk.RadioButton relativity_radio_button; +    Gtk.RadioButton batch_radio_button; +    Gtk.CheckButton modify_originals_check_button; +    Gtk.Label notification; + +    private enum TimeSystem { +        AM, +        PM, +        24HR; +    } + +    TimeSystem previous_time_system; + +    public AdjustDateTimeDialog(Dateable source, int photo_count, bool display_options = true, +        bool contains_video = false, bool only_video = false) { +        assert(source != null); + +        Object(use_header_bar: Resources.use_header_bar()); + +        set_modal(true); +        set_resizable(false); +        set_transient_for(AppWindow.get_instance()); + +        add_buttons(Resources.CANCEL_LABEL, Gtk.ResponseType.CANCEL, +                    Resources.OK_LABEL, Gtk.ResponseType.OK); +        set_title(Resources.ADJUST_DATE_TIME_LABEL); + +        calendar = new Gtk.Calendar(); +        calendar.show_heading = false; +        calendar.day_selected.connect(on_time_changed); +        calendar.month_changed.connect(on_time_changed); +        calendar.next_year.connect(on_time_changed); +        calendar.prev_year.connect(on_time_changed); + +        if (Config.Facade.get_instance().get_use_24_hour_time()) +            hour = new Gtk.SpinButton.with_range(0, 23, 1); +        else +            hour = new Gtk.SpinButton.with_range(1, 12, 1); + +        hour.output.connect(on_spin_button_output); +        hour.set_width_chars(2); +        hour.set_max_width_chars(2); + +        minute = new Gtk.SpinButton.with_range(0, 59, 1); +        minute.set_width_chars(2); +        minute.set_max_width_chars(2); +        minute.output.connect(on_spin_button_output); + +        second = new Gtk.SpinButton.with_range(0, 59, 1); +        second.set_width_chars(2); +        second.set_max_width_chars(2); +        second.output.connect(on_spin_button_output); + +        system = new Gtk.ComboBoxText(); +        system.append_text(_("AM")); +        system.append_text(_("PM")); +        system.append_text(_("24 Hr")); +        system.changed.connect(on_time_system_changed); + +        Gtk.Box clock = new Gtk.Box(Gtk.Orientation.HORIZONTAL, 3); + +        clock.pack_start(hour, false, false, 0); +        clock.pack_start(new Gtk.Label(":"), false, false, 0); // internationalize? +        clock.pack_start(minute, false, false, 0); +        clock.pack_start(new Gtk.Label(":"), false, false, 0); +        clock.pack_start(second, false, false, 0); +        clock.pack_start(system, false, false, 0); + +        set_default_response(Gtk.ResponseType.OK); + +        relativity_radio_button = new Gtk.RadioButton.with_mnemonic(null, +            _("_Shift photos/videos by the same amount")); +        relativity_radio_button.set_active(Config.Facade.get_instance().get_keep_relativity()); +        relativity_radio_button.sensitive = display_options && photo_count > 1; + +        batch_radio_button = new Gtk.RadioButton.with_mnemonic(relativity_radio_button.get_group(), +            _("Set _all photos/videos to this time")); +        batch_radio_button.set_active(!Config.Facade.get_instance().get_keep_relativity()); +        batch_radio_button.sensitive = display_options && photo_count > 1; +        batch_radio_button.toggled.connect(on_time_changed); + +        if (contains_video) { +            var text = ngettext ("_Modify original photo file", "_Modify original photo files", +                                 photo_count); +            modify_originals_check_button = new Gtk.CheckButton.with_mnemonic(text); +        } else { +            var text = ngettext ("_Modify original file", "_Modify original files", photo_count); +            modify_originals_check_button = new Gtk.CheckButton.with_mnemonic(text); +        } + +        modify_originals_check_button.set_active(Config.Facade.get_instance().get_commit_metadata_to_masters() && +            display_options); +        modify_originals_check_button.sensitive = (!only_video) && +            (!Config.Facade.get_instance().get_commit_metadata_to_masters() && display_options); + +        Gtk.Box time_content = new Gtk.Box(Gtk.Orientation.VERTICAL, 5); + +        var picker = new Gtk.Box(Gtk.Orientation.HORIZONTAL, 5); +        var combo = new Gtk.ComboBoxText(); +        for (int i = 0; i < 12; i++){ +            combo.append_text(Time.gm((i * 2764800)).format("%B")); +        } +        picker.pack_start(combo, false, false, 0); +        // Limits taken from GtkCalendar +        var spin = new Gtk.SpinButton.with_range(0, int.MAX >> 9, 1); +        picker.pack_end(spin, false, false, 0); +        spin.bind_property("value", calendar, "year", GLib.BindingFlags.BIDIRECTIONAL); +        combo.bind_property("active", calendar, "month", GLib.BindingFlags.BIDIRECTIONAL); + +        time_content.pack_start(picker, false, false, 0); +        time_content.pack_start(calendar, true, false, 0); +        time_content.pack_start(clock, true, false, 0); + +        if (display_options) { +            time_content.pack_start(relativity_radio_button, true, false, 0); +            time_content.pack_start(batch_radio_button, true, false, 0); +            time_content.pack_start(modify_originals_check_button, true, false, 0); +        } + +        Gdk.Pixbuf preview = null; +        try { +            // Instead of calling get_pixbuf() here, we use the thumbnail instead; +            // this was needed for Videos, since they don't support get_pixbuf(). +            preview = source.get_thumbnail(CALENDAR_THUMBNAIL_SCALE); +        } catch (Error err) { +            warning("Unable to fetch preview for %s", source.to_string()); +        } + +        Gtk.Box image_content = new Gtk.Box(Gtk.Orientation.VERTICAL, 0); +        image_content.set_valign(Gtk.Align.START); +        image_content.set_homogeneous(true); +        Gtk.Image image = (preview != null) ? new Gtk.Image.from_pixbuf(preview) : new Gtk.Image(); +        original_time_label = new Gtk.Label(null); +        image_content.pack_start(image, true, false, 0); +        image_content.pack_start(original_time_label, true, false, 0); + +        Gtk.Box hbox = new Gtk.Box(Gtk.Orientation.HORIZONTAL, 10); +        hbox.set_border_width(3); +        hbox.pack_start(image_content, true, false, 0); +        hbox.pack_start(time_content, true, false, 0); +        hbox.halign = Gtk.Align.CENTER; +        hbox.valign = Gtk.Align.CENTER; +        hbox.hexpand = false; +        hbox.vexpand = false; + +        ((Gtk.Box) get_content_area()).pack_start(hbox, true, false, 0); + +        notification = new Gtk.Label(""); +        notification.set_line_wrap(true); +        notification.set_justify(Gtk.Justification.CENTER); + +        ((Gtk.Box) get_content_area()).pack_start(notification, true, true, 0); + +        original_time = source.get_exposure_time(); + +        if (original_time == 0) { +            original_time = time_t(); +            no_original_time = true; +        } + +        set_time(Time.local(original_time)); +        set_original_time_label(Config.Facade.get_instance().get_use_24_hour_time()); +    } + +    private void set_time(Time time) { +        calendar.select_month(time.month, time.year + YEAR_OFFSET); +        calendar.select_day(time.day); +        calendar.notify_property("year"); +        calendar.notify_property("month"); + +        if (Config.Facade.get_instance().get_use_24_hour_time()) { +            system.set_active(TimeSystem.24HR); +            hour.set_value(time.hour); +        } else { +            int AMPM_hour = time.hour % 12; +            hour.set_value((AMPM_hour == 0) ? 12 : AMPM_hour); +            system.set_active((time.hour >= 12) ? TimeSystem.PM : TimeSystem.AM); +        } + +        minute.set_value(time.minute); +        second.set_value(time.second); + +        previous_time_system = (TimeSystem) system.get_active(); +    } + +    private void set_original_time_label(bool use_24_hr_format) { +        if (no_original_time) +            return; + +        original_time_label.set_text(_("Original: ") + +            Time.local(original_time).format(use_24_hr_format ? _("%m/%d/%Y, %H:%M:%S") : +            _("%m/%d/%Y, %I:%M:%S %p"))); +    } + +    private time_t get_time() { +        Time time = Time(); + +        time.second = (int) second.get_value(); +        time.minute = (int) minute.get_value(); + +        // convert to 24 hr +        int hour = (int) hour.get_value(); +        time.hour = (hour == 12 && system.get_active() != TimeSystem.24HR) ? 0 : hour; +        time.hour += ((system.get_active() == TimeSystem.PM) ? 12 : 0); + +        uint year, month, day; +        calendar.get_date(out year, out month, out day); +        time.year = ((int) year) - YEAR_OFFSET; +        time.month = (int) month; +        time.day = (int) day; + +        time.isdst = -1; + +        return time.mktime(); +    } + +    public bool execute(out int64 time_shift, out bool keep_relativity, +        out bool modify_originals) { +        show_all(); + +        bool response = false; + +        if (run() == Gtk.ResponseType.OK) { +            if (no_original_time) +                time_shift = (int64) get_time(); +            else +                time_shift = (int64) (get_time() - original_time); + +            keep_relativity = relativity_radio_button.get_active(); + +            if (relativity_radio_button.sensitive) +                Config.Facade.get_instance().set_keep_relativity(keep_relativity); + +            modify_originals = modify_originals_check_button.get_active(); + +            if (modify_originals_check_button.sensitive) +                Config.Facade.get_instance().set_modify_originals(modify_originals); + +            response = true; +        } else { +            time_shift = 0; +            keep_relativity = true; +            modify_originals = false; +        } + +        destroy(); + +        return response; +    } + +    private bool on_spin_button_output(Gtk.SpinButton button) { +        button.set_text("%02d".printf((int) button.get_value())); + +        on_time_changed(); + +        return true; +    } + +    private void on_time_changed() { +        int64 time_shift = ((int64) get_time() - (int64) original_time); +        calendar.notify_property("year"); +        calendar.notify_property("month"); + +        previous_time_system = (TimeSystem) system.get_active(); + +        if (time_shift == 0 || no_original_time || (batch_radio_button.get_active() && +            batch_radio_button.sensitive)) { +            notification.hide(); +        } else { +            bool forward = time_shift > 0; +            int days, hours, minutes, seconds; + +            time_shift = time_shift.abs(); + +            days = (int) (time_shift / SECONDS_IN_DAY); +            time_shift = time_shift % SECONDS_IN_DAY; +            hours = (int) (time_shift / SECONDS_IN_HOUR); +            time_shift = time_shift % SECONDS_IN_HOUR; +            minutes = (int) (time_shift / SECONDS_IN_MINUTE); +            seconds = (int) (time_shift % SECONDS_IN_MINUTE); + +            string shift_status = (forward) ? +                _("Exposure time will be shifted forward by\n%d %s, %d %s, %d %s, and %d %s.") : +                _("Exposure time will be shifted backward by\n%d %s, %d %s, %d %s, and %d %s."); + +            notification.set_text(shift_status.printf(days, ngettext("day", "days", days), +                hours, ngettext("hour", "hours", hours), minutes, +                ngettext("minute", "minutes", minutes), seconds, +                ngettext("second", "seconds", seconds))); + +            notification.show(); +        } +    } + +    private void on_time_system_changed() { +        if (previous_time_system == system.get_active()) +            return; + +        Config.Facade.get_instance().set_use_24_hour_time(system.get_active() == TimeSystem.24HR); + +        if (system.get_active() == TimeSystem.24HR) { +            int time = (hour.get_value() == 12.0) ? 0 : (int) hour.get_value(); +            time = time + ((previous_time_system == TimeSystem.PM) ? 12 : 0); + +            hour.set_range(0, 23); +            set_original_time_label(true); + +            hour.set_value(time); +        } else { +            int AMPM_hour = ((int) hour.get_value()) % 12; + +            hour.set_range(1, 12); +            set_original_time_label(false); + +            hour.set_value((AMPM_hour == 0) ? 12 : AMPM_hour); +        } + +        on_time_changed(); +    } +} | 
