summaryrefslogtreecommitdiff
path: root/src/Dialogs.vala
diff options
context:
space:
mode:
authorJörg Frings-Fürst <debian@jff-webhosting.net>2018-05-01 14:43:08 +0200
committerJörg Frings-Fürst <debian@jff-webhosting.net>2018-05-01 14:43:08 +0200
commit2b3f22361da0c1d8e6ce70d71352821758186db7 (patch)
tree5d10633b47369b3aa52a05bf889ede0dbe5ee108 /src/Dialogs.vala
parent211da5fc3048ca2b6ccee2166b0aaaade55cb84f (diff)
parentdc6c76eb04dfe3d4262a1806808f0bc0bf523238 (diff)
Merge branch 'feature/upstream' into develop
Diffstat (limited to 'src/Dialogs.vala')
-rw-r--r--src/Dialogs.vala1784
1 files changed, 0 insertions, 1784 deletions
diff --git a/src/Dialogs.vala b/src/Dialogs.vala
index d2f2cb0..2ca2678 100644
--- a/src/Dialogs.vala
+++ b/src/Dialogs.vala
@@ -134,345 +134,6 @@ public Gtk.ResponseType export_error_dialog(File dest, bool photos_remaining) {
}
-public class ExportDialog : Gtk.Dialog {
- public const int DEFAULT_SCALE = 1200;
-
- // "Unmodified" and "Current," though they appear in the "Format:" popup menu, really
- // aren't formats so much as they are operating modes that determine specific formats.
- // Hereafter we'll refer to these as "special formats."
- public const int NUM_SPECIAL_FORMATS = 2;
- public const string UNMODIFIED_FORMAT_LABEL = _("Unmodified");
- public const string CURRENT_FORMAT_LABEL = _("Current");
-
- public const ScaleConstraint[] CONSTRAINT_ARRAY = { ScaleConstraint.ORIGINAL,
- ScaleConstraint.DIMENSIONS, ScaleConstraint.WIDTH, ScaleConstraint.HEIGHT };
-
- public const Jpeg.Quality[] QUALITY_ARRAY = { Jpeg.Quality.LOW, Jpeg.Quality.MEDIUM,
- Jpeg.Quality.HIGH, Jpeg.Quality.MAXIMUM };
-
- private static ScaleConstraint current_constraint = ScaleConstraint.ORIGINAL;
- private static ExportFormatParameters current_parameters = ExportFormatParameters.current();
- private static int current_scale = DEFAULT_SCALE;
-
- private Gtk.Grid table = new Gtk.Grid();
- private Gtk.ComboBoxText quality_combo;
- private Gtk.ComboBoxText constraint_combo;
- private Gtk.ComboBoxText format_combo;
- private Gtk.Switch export_metadata;
- private Gee.ArrayList<string> format_options = new Gee.ArrayList<string>();
- private Gtk.Entry pixels_entry;
- private Gtk.Widget ok_button;
- private bool in_insert = false;
-
- public ExportDialog(string title) {
- bool use_header;
- Gtk.Settings.get_default ().get ("gtk-dialogs-use-header", out use_header);
- Object (use_header_bar: use_header ? 1 : 0);
-
- this.title = title;
- resizable = false;
-
- //get information about the export settings out of our config backend
- Config.Facade config = Config.Facade.get_instance();
- current_parameters.mode = config.get_export_export_format_mode(); //ExportFormatMode
- current_parameters.specified_format = config.get_export_photo_file_format(); //PhotoFileFormat
- current_parameters.quality = config.get_export_quality(); //quality
- current_parameters.export_metadata = config.get_export_export_metadata(); //export metadata
- current_constraint = config.get_export_constraint(); //constraint
- current_scale = config.get_export_scale(); //scale
-
- quality_combo = new Gtk.ComboBoxText();
- int ctr = 0;
- foreach (Jpeg.Quality quality in QUALITY_ARRAY) {
- quality_combo.append_text(quality.to_string());
- if (quality == current_parameters.quality)
- quality_combo.set_active(ctr);
- ctr++;
- }
-
- constraint_combo = new Gtk.ComboBoxText();
- ctr = 0;
- foreach (ScaleConstraint constraint in CONSTRAINT_ARRAY) {
- constraint_combo.append_text(constraint.to_string());
- if (constraint == current_constraint)
- constraint_combo.set_active(ctr);
- ctr++;
- }
-
- format_combo = new Gtk.ComboBoxText();
- format_add_option(UNMODIFIED_FORMAT_LABEL);
- format_add_option(CURRENT_FORMAT_LABEL);
- foreach (PhotoFileFormat format in PhotoFileFormat.get_writeable()) {
- format_add_option(format.get_properties().get_user_visible_name());
- }
-
- pixels_entry = new Gtk.Entry();
- pixels_entry.set_max_length(6);
- pixels_entry.set_text("%d".printf(current_scale));
-
- // register after preparation to avoid signals during init
- constraint_combo.changed.connect(on_constraint_changed);
- format_combo.changed.connect(on_format_changed);
- pixels_entry.changed.connect(on_pixels_changed);
- pixels_entry.insert_text.connect(on_pixels_insert_text);
- pixels_entry.activate.connect(on_activate);
-
- // layout controls
- add_label(_("_Format:"), 0, 0, format_combo);
- add_control(format_combo, 1, 0);
-
- add_label(_("_Quality:"), 0, 1, quality_combo);
- add_control(quality_combo, 1, 1);
-
- add_label(_("_Scaling constraint:"), 0, 2, constraint_combo);
- add_control(constraint_combo, 1, 2);
-
- add_label(_("_Pixels:"), 0, 3, pixels_entry);
- add_control(pixels_entry, 1, 3);
-
- export_metadata = new Gtk.Switch ();
- add_label(_("Export _metadata:"), 0, 4, export_metadata);
- add_control(export_metadata, 1, 4);
- export_metadata.active = true;
- export_metadata.halign = Gtk.Align.START;
-
- table.set_row_spacing(6);
- table.set_column_spacing(12);
- table.set_border_width(18);
-
- ((Gtk.Box) get_content_area()).add(table);
-
- // add buttons to action area
- add_button(Resources.CANCEL_LABEL, Gtk.ResponseType.CANCEL);
- ok_button = add_button(Resources.OK_LABEL, Gtk.ResponseType.OK);
- set_default_response(Gtk.ResponseType.OK);
-
- ok_button.set_can_default(true);
- ok_button.has_default = true;
- set_default(ok_button);
-
- if (current_constraint == ScaleConstraint.ORIGINAL) {
- pixels_entry.sensitive = false;
- quality_combo.sensitive = false;
- }
-
- ok_button.grab_focus();
- }
-
- private void format_add_option(string format_name) {
- format_options.add(format_name);
- format_combo.append_text(format_name);
- }
-
- private void format_set_active_text(string text) {
- int selection_ticker = 0;
-
- foreach (string current_text in format_options) {
- if (current_text == text) {
- format_combo.set_active(selection_ticker);
- return;
- }
- selection_ticker++;
- }
-
- error("format_set_active_text: text '%s' isn't in combo box", text);
- }
-
- private PhotoFileFormat get_specified_format() {
- int index = format_combo.get_active();
- if (index < NUM_SPECIAL_FORMATS)
- index = NUM_SPECIAL_FORMATS;
-
- index -= NUM_SPECIAL_FORMATS;
- PhotoFileFormat[] writeable_formats = PhotoFileFormat.get_writeable();
- return writeable_formats[index];
- }
-
- private string get_label_for_parameters(ExportFormatParameters params) {
- switch(params.mode) {
- case ExportFormatMode.UNMODIFIED:
- return UNMODIFIED_FORMAT_LABEL;
-
- case ExportFormatMode.CURRENT:
- return CURRENT_FORMAT_LABEL;
-
- case ExportFormatMode.SPECIFIED:
- return params.specified_format.get_properties().get_user_visible_name();
-
- default:
- error("get_label_for_parameters: unrecognized export format mode");
- }
- }
-
- // unlike other parameters, which should be persisted across dialog executions, the
- // format parameters must be set each time the dialog is executed -- this is why
- // it's passed qualified as ref and not as out
- public bool execute(out int scale, out ScaleConstraint constraint,
- ref ExportFormatParameters parameters) {
- show_all();
-
- // if the export format mode isn't set to last (i.e., don't use the persisted settings),
- // reset the scale constraint to original size
- if (parameters.mode != ExportFormatMode.LAST) {
- current_constraint = constraint = ScaleConstraint.ORIGINAL;
- constraint_combo.set_active(0);
- }
-
- if (parameters.mode == ExportFormatMode.LAST)
- parameters = current_parameters;
- else if (parameters.mode == ExportFormatMode.SPECIFIED && !parameters.specified_format.can_write())
- parameters.specified_format = PhotoFileFormat.get_system_default_format();
-
- format_set_active_text(get_label_for_parameters(parameters));
- on_format_changed();
-
- bool ok = (run() == Gtk.ResponseType.OK);
- if (ok) {
- int index = constraint_combo.get_active();
- assert(index >= 0);
- constraint = CONSTRAINT_ARRAY[index];
- current_constraint = constraint;
-
- scale = int.parse(pixels_entry.get_text());
- if (constraint != ScaleConstraint.ORIGINAL)
- assert(scale > 0);
- current_scale = scale;
-
- parameters.export_metadata = export_metadata.sensitive ? export_metadata.active : false;
-
- if (format_combo.get_active_text() == UNMODIFIED_FORMAT_LABEL) {
- parameters.mode = current_parameters.mode = ExportFormatMode.UNMODIFIED;
- } else if (format_combo.get_active_text() == CURRENT_FORMAT_LABEL) {
- parameters.mode = current_parameters.mode = ExportFormatMode.CURRENT;
- } else {
- parameters.mode = current_parameters.mode = ExportFormatMode.SPECIFIED;
- parameters.specified_format = current_parameters.specified_format = get_specified_format();
- if (current_parameters.specified_format == PhotoFileFormat.JFIF)
- parameters.quality = current_parameters.quality = QUALITY_ARRAY[quality_combo.get_active()];
- }
-
- //save current settings in config backend for reusing later
- Config.Facade config = Config.Facade.get_instance();
- config.set_export_export_format_mode(current_parameters.mode); //ExportFormatMode
- config.set_export_photo_file_format(current_parameters.specified_format); //PhotoFileFormat
- config.set_export_quality(current_parameters.quality); //quality
- config.set_export_export_metadata(current_parameters.export_metadata); //export metadata
- config.set_export_constraint(current_constraint); //constraint
- config.set_export_scale(current_scale); //scale
- } else {
- scale = 0;
- constraint = ScaleConstraint.ORIGINAL;
- }
-
- destroy();
-
- return ok;
- }
-
- private void add_label(string text, int x, int y, Gtk.Widget? widget = null) {
- Gtk.Label new_label = new Gtk.Label.with_mnemonic(text);
- new_label.halign = Gtk.Align.END;
- new_label.valign = Gtk.Align.CENTER;
- new_label.set_use_underline(true);
-
- if (widget != null)
- new_label.set_mnemonic_widget(widget);
-
- table.attach(new_label, x, y, 1, 1);
- }
-
- private void add_control(Gtk.Widget widget, int x, int y) {
- widget.halign = Gtk.Align.FILL;
- widget.valign = Gtk.Align.CENTER;
- widget.hexpand = true;
- widget.vexpand = true;
-
- table.attach(widget, x, y, 1, 1);
- }
-
- private void on_constraint_changed() {
- bool original = CONSTRAINT_ARRAY[constraint_combo.get_active()] == ScaleConstraint.ORIGINAL;
- bool jpeg = format_combo.get_active_text() ==
- PhotoFileFormat.JFIF.get_properties().get_user_visible_name();
- pixels_entry.sensitive = !original;
- quality_combo.sensitive = !original && jpeg;
- if (original)
- ok_button.sensitive = true;
- else
- on_pixels_changed();
- }
-
- private void on_format_changed() {
- bool original = CONSTRAINT_ARRAY[constraint_combo.get_active()] == ScaleConstraint.ORIGINAL;
-
- if (format_combo.get_active_text() == UNMODIFIED_FORMAT_LABEL) {
- // if the user wishes to export the media unmodified, then we just copy the original
- // files, so parameterizing size, quality, etc. is impossible -- these are all
- // just as they are in the original file. In this case, we set the scale constraint to
- // original and lock out all the controls
- constraint_combo.set_active(0); /* 0 == original size */
- constraint_combo.set_sensitive(false);
- quality_combo.set_sensitive(false);
- pixels_entry.sensitive = false;
- export_metadata.active = false;
- export_metadata.sensitive = false;
- } else if (format_combo.get_active_text() == CURRENT_FORMAT_LABEL) {
- // if the user wishes to export the media in its current format, we allow sizing but
- // not JPEG quality customization, because in a batch of many photos, it's not
- // guaranteed that all of them will be JPEGs or RAWs that get converted to JPEGs. Some
- // could be PNGs, and PNG has no notion of quality. So lock out the quality control.
- // If the user wants to set JPEG quality, he or she can explicitly specify the JPEG
- // format.
- constraint_combo.set_sensitive(true);
- quality_combo.set_sensitive(false);
- pixels_entry.sensitive = !original;
- export_metadata.sensitive = true;
- } else {
- // if the user has chosen a specific format, then allow JPEG quality customization if
- // the format is JPEG and the user is re-sizing the image, otherwise, disallow JPEG
- // quality customization; always allow scaling.
- constraint_combo.set_sensitive(true);
- bool jpeg = get_specified_format() == PhotoFileFormat.JFIF;
- quality_combo.sensitive = !original && jpeg;
- export_metadata.sensitive = true;
- }
- }
-
- private void on_activate() {
- response(Gtk.ResponseType.OK);
- }
-
- private void on_pixels_changed() {
- ok_button.sensitive = (pixels_entry.get_text_length() > 0) && (int.parse(pixels_entry.get_text()) > 0);
- }
-
- private void on_pixels_insert_text(string text, int length, ref int position) {
- // This is necessary because SignalHandler.block_by_func() is not properly bound
- if (in_insert)
- return;
-
- in_insert = true;
-
- if (length == -1)
- length = (int) text.length;
-
- // only permit numeric text
- string new_text = "";
- for (int ctr = 0; ctr < length; ctr++) {
- if (text[ctr].isdigit()) {
- new_text += ((char) text[ctr]).to_string();
- }
- }
-
- if (new_text.length > 0)
- pixels_entry.insert_text(new_text, (int) new_text.length, ref position);
-
- Signal.stop_emission_by_name(pixels_entry, "insert-text");
-
- in_insert = false;
- }
-}
-
namespace ImportUI {
private const int REPORT_FAILURE_COUNT = 4;
internal const string SAVE_RESULTS_BUTTON_NAME = _("Save Details…");
@@ -939,10 +600,7 @@ public abstract class TextEntryDialogMediator {
public TextEntryDialogMediator(string title, string label, string? initial_text = null,
Gee.Collection<string>? completion_list = null, string? completion_delimiter = null) {
- Gtk.Builder builder = AppWindow.create_builder();
dialog = new TextEntryDialog();
- dialog.get_content_area().add((Gtk.Box) builder.get_object("dialog-vbox2"));
- dialog.set_builder(builder);
dialog.setup(on_modify_validate, title, label, initial_text, completion_list, completion_delimiter);
}
@@ -959,10 +617,7 @@ public abstract class MultiTextEntryDialogMediator {
private MultiTextEntryDialog dialog;
public MultiTextEntryDialogMediator(string title, string label, string? initial_text = null) {
- Gtk.Builder builder = AppWindow.create_builder();
dialog = new MultiTextEntryDialog();
- dialog.get_content_area().add((Gtk.Box) builder.get_object("dialog-vbox4"));
- dialog.set_builder(builder);
dialog.setup(on_modify_validate, title, label, initial_text);
}
@@ -989,328 +644,6 @@ public string build_alert_body_text(string? primary_text, string? secondary_text
guarded_markup_escape_text(primary_text), secondary_text);
}
-// Entry completion for values separated by separators (e.g. comma in the case of tags)
-// Partly inspired by the class of the same name in gtkmm-utils by Marko Anastasov
-public class EntryMultiCompletion : Gtk.EntryCompletion {
- private string delimiter;
-
- public EntryMultiCompletion(Gee.Collection<string> completion_list, string? delimiter) {
- assert(delimiter == null || delimiter.length == 1);
- this.delimiter = delimiter;
-
- set_model(create_completion_store(completion_list));
- set_text_column(0);
- set_match_func(match_func);
- }
-
- private static Gtk.ListStore create_completion_store(Gee.Collection<string> completion_list) {
- Gtk.ListStore completion_store = new Gtk.ListStore(1, typeof(string));
- Gtk.TreeIter store_iter;
- Gee.Iterator<string> completion_iter = completion_list.iterator();
- while (completion_iter.next()) {
- completion_store.append(out store_iter);
- completion_store.set(store_iter, 0, completion_iter.get(), -1);
- }
-
- return completion_store;
- }
-
- private bool match_func(Gtk.EntryCompletion completion, string key, Gtk.TreeIter iter) {
- Gtk.TreeModel model = completion.get_model();
- string possible_match;
- model.get(iter, 0, out possible_match);
-
- // Normalize key and possible matches to allow comparison of non-ASCII characters.
- // Use a "COMPOSE" normalization to allow comparison to the position value returned by
- // Gtk.Entry, i.e. one character=one position. Using the default normalization a character
- // like "é" or "ö" would have a length of two.
- possible_match = possible_match.casefold().normalize(-1, NormalizeMode.ALL_COMPOSE);
- string normed_key = key.normalize(-1, NormalizeMode.ALL_COMPOSE);
-
- if (delimiter == null) {
- return possible_match.has_prefix(normed_key.strip());
- } else {
- if (normed_key.contains(delimiter)) {
- // check whether cursor is before last delimiter
- int offset = normed_key.char_count(normed_key.last_index_of_char(delimiter[0]));
- int position = ((Gtk.Entry) get_entry()).get_position();
- if (position <= offset)
- return false; // TODO: Autocompletion for tags not last in list
- }
-
- string last_part = get_last_part(normed_key.strip(), delimiter);
-
- if (last_part.length == 0)
- return false; // need at least one character to show matches
-
- return possible_match.has_prefix(last_part.strip());
- }
- }
-
- public override bool match_selected(Gtk.TreeModel model, Gtk.TreeIter iter) {
- string match;
- model.get(iter, 0, out match);
-
- Gtk.Entry entry = (Gtk.Entry)get_entry();
-
- string old_text = entry.get_text().normalize(-1, NormalizeMode.ALL_COMPOSE);
- if (old_text.length > 0) {
- if (old_text.contains(delimiter)) {
- old_text = old_text.substring(0, old_text.last_index_of_char(delimiter[0]) + 1) + (delimiter != " " ? " " : "");
- } else
- old_text = "";
- }
-
- string new_text = old_text + match + delimiter + (delimiter != " " ? " " : "");
- entry.set_text(new_text);
- entry.set_position((int) new_text.length);
-
- return true;
- }
-
- // Find last string after any delimiter
- private static string get_last_part(string s, string delimiter) {
- string[] split = s.split(delimiter);
-
- if((split != null) && (split[0] != null)) {
- return split[split.length - 1];
- } else {
- return "";
- }
- }
-}
-
-[GtkTemplate (ui = "/org/gnome/Shotwell/ui/set_background_dialog.ui")]
-public class SetBackgroundPhotoDialog : Gtk.Dialog {
- [GtkChild]
- private Gtk.CheckButton desktop_background_checkbox;
- [GtkChild]
- private Gtk.CheckButton screensaver_checkbox;
-
- public SetBackgroundPhotoDialog() {
- bool use_header;
- Gtk.Settings.get_default ().get ("gtk-dialogs-use-header", out use_header);
- Object(use_header_bar: use_header ? 1 : 0);
- this.set_transient_for (AppWindow.get_instance());
- }
-
- [GtkCallback]
- private void on_checkbox_clicked() {
- set_response_sensitive (Gtk.ResponseType.OK,
- desktop_background_checkbox.active ||
- screensaver_checkbox.active);
- }
-
- public bool execute(out bool desktop_background, out bool screensaver) {
- this.show_all();
- var result = this.run() == Gtk.ResponseType.OK;
- this.hide ();
-
- desktop_background = desktop_background_checkbox.active;
- screensaver = screensaver_checkbox.active;
-
- this.destroy();
- return result;
- }
-}
-
-[GtkTemplate (ui = "/org/gnome/Shotwell/ui/set_background_slideshow_dialog.ui")]
-public class SetBackgroundSlideshowDialog : Gtk.Dialog {
- [GtkChild]
- private Gtk.CheckButton desktop_background_checkbox;
- [GtkChild]
- private Gtk.CheckButton screensaver_checkbox;
- [GtkChild]
- private Gtk.Scale delay_scale;
- [GtkChild]
- private Gtk.Label delay_value_label;
-
- private int delay_value = 0;
-
- public SetBackgroundSlideshowDialog() {
- bool use_header;
- Gtk.Settings.get_default ().get ("gtk-dialogs-use-header", out use_header);
- Object(use_header_bar: use_header ? 1 : 0);
- this.set_transient_for (AppWindow.get_instance());
- }
-
- public override void constructed () {
- on_delay_scale_value_changed ();
- }
-
- [GtkCallback]
- private void on_checkbox_clicked() {
- set_response_sensitive (Gtk.ResponseType.OK,
- desktop_background_checkbox.active ||
- screensaver_checkbox.active);
- }
-
- [GtkCallback]
- private void on_delay_scale_value_changed() {
- double value = delay_scale.adjustment.value;
-
- // f(x)=x^5 allows to have fine-grained values (seconds) to the left
- // and very coarse-grained values (hours) to the right of the slider.
- // We limit maximum value to 1 day and minimum to 5 seconds.
- delay_value = (int) (Math.pow(value, 5) / Math.pow(90, 5) * 60 * 60 * 24 + 5);
-
- // convert to text and remove fractions from values > 1 minute
- string text;
- if (delay_value < 60) {
- text = ngettext("%d second", "%d seconds", delay_value).printf(delay_value);
- } else if (delay_value < 60 * 60) {
- int minutes = delay_value / 60;
- text = ngettext("%d minute", "%d minutes", minutes).printf(minutes);
- delay_value = minutes * 60;
- } else if (delay_value < 60 * 60 * 24) {
- int hours = delay_value / (60 * 60);
- text = ngettext("%d hour", "%d hours", hours).printf(hours);
- delay_value = hours * (60 * 60);
- } else {
- text = _("1 day");
- delay_value = 60 * 60 * 24;
- }
-
- delay_value_label.label = text;
- }
-
- public bool execute(out int delay_value, out bool desktop_background, out bool screensaver) {
- this.show_all();
- var result = this.run() == Gtk.ResponseType.OK;
- this.hide ();
-
- delay_value = this.delay_value;
- desktop_background = desktop_background_checkbox.active;
- screensaver = screensaver_checkbox.active;
-
- this.destroy();
- return result;
- }
-}
-
-
-public class TextEntryDialog : Gtk.Dialog {
- public delegate bool OnModifyValidateType(string text);
-
- private unowned OnModifyValidateType on_modify_validate;
- private Gtk.Entry entry;
- private Gtk.Builder builder;
- private Gtk.Button button1;
- private Gtk.Button button2;
-
- public TextEntryDialog() {
- bool use_header;
- Gtk.Settings.get_default ().get ("gtk-dialogs-use-header", out use_header);
- Object (use_header_bar: use_header ? 1 : 0);
- }
-
- public void set_builder(Gtk.Builder builder) {
- this.builder = builder;
- }
-
- public void setup(OnModifyValidateType? modify_validate, string title, string label,
- string? initial_text, Gee.Collection<string>? completion_list, string? completion_delimiter) {
- set_title(title);
- set_resizable(true);
- set_parent_window(AppWindow.get_instance().get_parent_window());
- set_transient_for(AppWindow.get_instance());
- on_modify_validate = modify_validate;
-
- Gtk.Label name_label = builder.get_object("label") as Gtk.Label;
- name_label.set_text(label);
-
- entry = builder.get_object("entry") as Gtk.Entry;
- entry.set_text(initial_text != null ? initial_text : "");
- entry.grab_focus();
- entry.changed.connect(on_entry_changed);
-
- button1 = (Gtk.Button) add_button(Resources.CANCEL_LABEL, Gtk.ResponseType.CANCEL);
- button2 = (Gtk.Button) add_button(Resources.SAVE_LABEL, Gtk.ResponseType.OK);
- set_default_response(Gtk.ResponseType.OK);
-
- if (completion_list != null) { // Textfield with autocompletion
- EntryMultiCompletion completion = new EntryMultiCompletion(completion_list,
- completion_delimiter);
- entry.set_completion(completion);
- }
-
- set_default_response(Gtk.ResponseType.OK);
- }
-
- public string? execute() {
- string? text = null;
-
- // validate entry to start with
- set_response_sensitive(Gtk.ResponseType.OK, on_modify_validate(entry.get_text()));
-
- show_all();
-
- if (run() == Gtk.ResponseType.OK)
- text = entry.get_text();
-
- entry.changed.disconnect(on_entry_changed);
- destroy();
-
- return text;
- }
-
- public void on_entry_changed() {
- set_response_sensitive(Gtk.ResponseType.OK, on_modify_validate(entry.get_text()));
- }
-}
-
-public class MultiTextEntryDialog : Gtk.Dialog {
- public delegate bool OnModifyValidateType(string text);
-
- private unowned OnModifyValidateType on_modify_validate;
- private Gtk.TextView entry;
- private Gtk.Builder builder;
- private Gtk.Button button1;
- private Gtk.Button button2;
-
- public MultiTextEntryDialog() {
- bool use_header;
- Gtk.Settings.get_default ().get ("gtk-dialogs-use-header", out use_header);
- Object (use_header_bar: use_header ? 1 : 0);
- }
-
- public void set_builder(Gtk.Builder builder) {
- this.builder = builder;
- }
-
- public void setup(OnModifyValidateType? modify_validate, string title, string label, string? initial_text) {
- set_title(title);
- set_resizable(true);
- set_default_size(500,300);
- set_parent_window(AppWindow.get_instance().get_parent_window());
- set_transient_for(AppWindow.get_instance());
- on_modify_validate = modify_validate;
-
- entry = builder.get_object("textview1") as Gtk.TextView;
- entry.set_wrap_mode (Gtk.WrapMode.WORD);
- entry.buffer = new Gtk.TextBuffer(null);
- entry.buffer.text = (initial_text != null ? initial_text : "");
-
- entry.grab_focus();
-
- button1 = (Gtk.Button) add_button(Resources.CANCEL_LABEL, Gtk.ResponseType.CANCEL);
- button2 = (Gtk.Button) add_button(Resources.SAVE_LABEL, Gtk.ResponseType.OK);
- set_default_response(Gtk.ResponseType.OK);
- }
-
- public string? execute() {
- string? text = null;
-
- show_all();
-
- if (run() == Gtk.ResponseType.OK)
- text = entry.buffer.text;
-
- destroy();
-
- return text;
- }
-}
public class EventRenameDialog : TextEntryDialogMediator {
public EventRenameDialog(string? event_name) {
@@ -1451,499 +784,6 @@ public bool remove_offline_dialog(Gtk.Window owner, int count) {
return result == Gtk.ResponseType.OK;
}
-public class ProgressDialog : Gtk.Window {
- private Gtk.ProgressBar progress_bar = new Gtk.ProgressBar();
- private Gtk.Button cancel_button = null;
- private Cancellable cancellable;
- private uint64 last_count = uint64.MAX;
- private int update_every = 1;
- private int minimum_on_screen_time_msec = 500;
- private ulong time_started;
-#if UNITY_SUPPORT
- UnityProgressBar uniprobar = UnityProgressBar.get_instance();
-#endif
-
- public ProgressDialog(Gtk.Window? owner, string text, Cancellable? cancellable = null) {
- this.cancellable = cancellable;
-
- set_title(text);
- set_resizable(false);
- if (owner != null)
- set_transient_for(owner);
- set_modal(true);
- set_type_hint(Gdk.WindowTypeHint.DIALOG);
-
- progress_bar.set_size_request(300, -1);
- progress_bar.set_show_text(true);
-
- Gtk.Box vbox_bar = new Gtk.Box(Gtk.Orientation.VERTICAL, 0);
- vbox_bar.pack_start(progress_bar, true, false, 0);
-
- if (cancellable != null) {
- cancel_button = new Gtk.Button.with_mnemonic(Resources.CANCEL_LABEL);
- cancel_button.clicked.connect(on_cancel);
- delete_event.connect(on_window_closed);
- }
-
- Gtk.Box hbox = new Gtk.Box(Gtk.Orientation.HORIZONTAL, 8);
- hbox.pack_start(vbox_bar, true, false, 0);
- if (cancel_button != null)
- hbox.pack_end(cancel_button, false, false, 0);
-
- Gtk.Label primary_text_label = new Gtk.Label("");
- primary_text_label.set_markup("<span weight=\"bold\">%s</span>".printf(text));
- primary_text_label.xalign = 0.0f;
- primary_text_label.yalign = 0.5f;
-
- Gtk.Box vbox = new Gtk.Box(Gtk.Orientation.VERTICAL, 12);
- vbox.pack_start(primary_text_label, false, false, 0);
- vbox.pack_start(hbox, true, false, 0);
- vbox.halign = Gtk.Align.CENTER;
- vbox.valign = Gtk.Align.CENTER;
- vbox.hexpand = true;
- vbox.vexpand = true;
- vbox.margin_start = 12;
- vbox.margin_end = 12;
- vbox.margin_top = 12;
- vbox.margin_bottom = 12;
-
- add(vbox);
-
- time_started = now_ms();
- }
-
- public override void realize() {
- base.realize();
-
- // if unable to cancel the progress bar, remove the close button
- if (cancellable == null)
- get_window().set_functions(Gdk.WMFunction.MOVE);
- }
-
- public void update_display_every(int update_every) {
- assert(update_every >= 1);
-
- this.update_every = update_every;
- }
-
- public void set_minimum_on_screen_time_msec(int minimum_on_screen_time_msec) {
- this.minimum_on_screen_time_msec = minimum_on_screen_time_msec;
- }
-
- public void set_fraction(int current, int total) {
- set_percentage((double) current / (double) total);
- }
-
- public void set_percentage(double pct) {
- pct = pct.clamp(0.0, 1.0);
-
- maybe_show_all(pct);
-
- progress_bar.set_fraction(pct);
- progress_bar.set_text(_("%d%%").printf((int) (pct * 100.0)));
-
-#if UNITY_SUPPORT
- //UnityProgressBar: set progress
- uniprobar.set_progress(pct);
-#endif
- }
-
- public void set_status(string text) {
- progress_bar.set_text(text);
-
-#if UNITY_SUPPORT
- //UnityProgressBar: try to draw progress bar
- uniprobar.set_visible(true);
-#endif
- show_all();
- }
-
- // This can be used as a ProgressMonitor delegate.
- public bool monitor(uint64 count, uint64 total, bool do_event_loop = true) {
- if ((last_count == uint64.MAX) || (count - last_count) >= update_every) {
- set_percentage((double) count / (double) total);
- last_count = count;
- }
-
- bool keep_going = (cancellable != null) ? !cancellable.is_cancelled() : true;
-
- // TODO: get rid of this. non-trivial, as some progress-monitor operations are blocking
- // and need to allow the event loop to spin
- //
- // Important: Since it's possible the progress dialog might be destroyed inside this call,
- // avoid referring to "this" afterwards at all costs (in case all refs have been dropped)
-
- if (do_event_loop)
- spin_event_loop();
-
- return keep_going;
- }
-
- public new void close() {
-#if UNITY_SUPPORT
- //UnityProgressBar: reset
- uniprobar.reset();
-#endif
- hide();
- destroy();
- }
-
- private bool on_window_closed() {
- on_cancel();
- return false; // return false so that the system handler will remove the window from
- // the screen
- }
-
- private void on_cancel() {
- if (cancellable != null)
- cancellable.cancel();
-
- cancel_button.sensitive = false;
- }
-
- private void maybe_show_all(double pct) {
- // Appear only after a while because some jobs may take only a
- // fraction of second to complete so there's no point in showing progress.
- if (!this.visible && now_ms() - time_started > minimum_on_screen_time_msec) {
- // calculate percents completed in one ms
- double pps = pct * 100.0 / minimum_on_screen_time_msec;
- // calculate [very rough] estimate of time to complete in ms
- double ttc = 100.0 / pps;
- // If there is still more work to do for at least MINIMUM_ON_SCREEN_TIME_MSEC,
- // finally display the dialog.
- if (ttc > minimum_on_screen_time_msec) {
-#if UNITY_SUPPORT
- //UnityProgressBar: try to draw progress bar
- uniprobar.set_visible(true);
-#endif
- show_all();
- spin_event_loop();
- }
- }
- }
-}
-
-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);
-
- bool use_header;
- Gtk.Settings.get_default ().get ("gtk-dialogs-use-header", out use_header);
- Object(use_header_bar: use_header ? 1 : 0);
-
- 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.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);
-
- 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);
-
- 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);
-
- 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();
- }
-}
-
public const int MAX_OBJECTS_DISPLAYED = 3;
public void multiple_object_error_dialog(Gee.ArrayList<DataObject> objects, string message,
string title) {
@@ -2062,630 +902,6 @@ public class ModifyTagsDialog : TagsDialog {
}
-public interface WelcomeServiceEntry : GLib.Object {
- public abstract string get_service_name();
-
- public abstract void execute();
-}
-
-public class WelcomeDialog : Gtk.Dialog {
- Gtk.CheckButton hide_button;
- Gtk.CheckButton? system_pictures_import_check = null;
- Gtk.CheckButton[] external_import_checks = new Gtk.CheckButton[0];
- WelcomeServiceEntry[] external_import_entries = new WelcomeServiceEntry[0];
- Gtk.Label secondary_text;
- Gtk.Label instruction_header;
- Gtk.Box import_content;
- Gtk.Box import_action_checkbox_packer;
- Gtk.Box external_import_action_checkbox_packer;
- Spit.DataImports.WelcomeImportMetaHost import_meta_host;
- bool import_content_already_installed = false;
- bool ok_clicked = false;
-
- public WelcomeDialog(Gtk.Window owner) {
- import_meta_host = new Spit.DataImports.WelcomeImportMetaHost(this);
- bool show_system_pictures_import = is_system_pictures_import_possible();
- Gtk.Widget ok_button = add_button(Resources.OK_LABEL, Gtk.ResponseType.OK);
- set_title(_("Welcome!"));
- set_resizable(false);
- set_type_hint(Gdk.WindowTypeHint.DIALOG);
- set_transient_for(owner);
-
- Gtk.Label primary_text = new Gtk.Label("");
- primary_text.set_markup(
- "<span size=\"large\" weight=\"bold\">%s</span>".printf(_("Welcome to Shotwell!")));
- primary_text.xalign = 0.0f;
- primary_text.yalign = 0.5f;
- secondary_text = new Gtk.Label("");
- secondary_text.set_markup("<span weight=\"normal\">%s</span>".printf(
- _("To get started, import photos in any of these ways:")));
- secondary_text.xalign = 0.0f;
- secondary_text.yalign = 0.5f;
- var image = new Gtk.Image.from_icon_name ("shotwell", Gtk.IconSize.DIALOG);
-
- Gtk.Box header_text = new Gtk.Box(Gtk.Orientation.VERTICAL, 0);
- header_text.pack_start(primary_text, false, false, 5);
- header_text.pack_start(secondary_text, false, false, 0);
-
- Gtk.Box header_content = new Gtk.Box(Gtk.Orientation.HORIZONTAL, 12);
- header_content.pack_start(image, false, false, 0);
- header_content.pack_start(header_text, false, false, 0);
-
- Gtk.Label instructions = new Gtk.Label("");
- string indent_prefix = " "; // we can't tell what the indent prefix is going to be so assume we need one
-
- string arrow_glyph = (get_direction() == Gtk.TextDirection.RTL) ? "◂" : "▸";
-
- instructions.set_markup(((indent_prefix + "&#8226; %s\n") + (indent_prefix + "&#8226; %s\n")
- + (indent_prefix + "&#8226; %s")).printf(
- _("Choose <span weight=\"bold\">File %s Import From Folder</span>").printf(arrow_glyph),
- _("Drag and drop photos onto the Shotwell window"),
- _("Connect a camera to your computer and import")));
- instructions.xalign = 0.0f;
- instructions.yalign = 0.5f;
-
- import_action_checkbox_packer = new Gtk.Box(Gtk.Orientation.VERTICAL, 2);
-
- external_import_action_checkbox_packer = new Gtk.Box(Gtk.Orientation.VERTICAL, 2);
- import_action_checkbox_packer.add(external_import_action_checkbox_packer);
-
- if (show_system_pictures_import) {
- system_pictures_import_check = new Gtk.CheckButton.with_mnemonic(
- _("_Import photos from your %s folder").printf(
- get_display_pathname(AppDirs.get_import_dir())));
- import_action_checkbox_packer.add(system_pictures_import_check);
- system_pictures_import_check.set_active(true);
- }
-
- instruction_header = new Gtk.Label(
- _("You can also import photos in any of these ways:"));
- instruction_header.xalign = 0.0f;
- instruction_header.yalign = 0.5f;
- instruction_header.set_margin_top(20);
-
- Gtk.Box content = new Gtk.Box(Gtk.Orientation.VERTICAL, 16);
- content.pack_start(header_content, true, true, 0);
- import_content = new Gtk.Box(Gtk.Orientation.VERTICAL, 2);
- content.add(import_content);
- content.pack_start(instructions, false, false, 0);
-
- hide_button = new Gtk.CheckButton.with_mnemonic(_("_Don’t show this message again"));
- hide_button.set_active(true);
- content.pack_start(hide_button, false, false, 6);
- content.halign = Gtk.Align.FILL;
- content.valign = Gtk.Align.FILL;
- content.hexpand = false;
- content.vexpand = false;
- content.margin_top = 12;
- content.margin_bottom = 0;
- content.margin_start = 12;
- content.margin_end = 12;
-
- ((Gtk.Box) get_content_area()).pack_start(content, false, false, 0);
-
- ok_button.grab_focus();
-
- install_import_content();
-
- import_meta_host.start();
- }
-
- private void install_import_content() {
- if (
- (external_import_checks.length > 0 || system_pictures_import_check != null) &&
- (import_content_already_installed == false)
- ) {
- secondary_text.set_markup("");
- import_content.add(import_action_checkbox_packer);
- import_content.add(instruction_header);
- import_content_already_installed = true;
- }
- }
-
- public void install_service_entry(WelcomeServiceEntry entry) {
- debug("WelcomeDialog: Installing service entry for %s".printf(entry.get_service_name()));
- external_import_entries += entry;
- Gtk.CheckButton entry_check = new Gtk.CheckButton.with_label(
- _("Import photos from your %s library").printf(entry.get_service_name()));
- external_import_checks += entry_check;
- entry_check.set_active(true);
- external_import_action_checkbox_packer.add(entry_check);
- install_import_content();
- }
-
- /**
- * Connected to the 'response' signal. This is part of a workaround
- * for the fact that run()-ning this dialog can interfere with displaying
- * images from a camera; please see #4997 for details.
- */
- private void on_dismiss(int resp) {
- if (resp == Gtk.ResponseType.OK) {
- ok_clicked = true;
- }
- hide();
- Gtk.main_quit();
- }
-
- public bool execute(out WelcomeServiceEntry[] selected_import_entries, out bool do_system_pictures_import) {
- // it's unsafe to call run() here - it interferes with displaying
- // images from a camera - so we process the dialog ourselves.
- response.connect(on_dismiss);
- show_all();
- show();
-
- // this will block the thread we're in until a matching call
- // to main_quit() is encountered; this happens when either the window
- // is closed or OK is clicked.
- Gtk.main();
-
- // at this point, the inner main loop will have been exited.
- // we've got the response, so we don't need this signal anymore.
- response.disconnect(on_dismiss);
-
- bool ok = ok_clicked;
- bool show_dialog = true;
-
- if (ok)
- show_dialog = !hide_button.get_active();
-
- // Use a temporary variable as += cannot be used on parameters
- WelcomeServiceEntry[] result = new WelcomeServiceEntry[0];
- for (int i = 0; i < external_import_entries.length; i++) {
- if (external_import_checks[i].get_active() == true)
- result += external_import_entries[i];
- }
- selected_import_entries = result;
- do_system_pictures_import =
- (system_pictures_import_check != null) ? system_pictures_import_check.get_active() : false;
-
- destroy();
-
- return show_dialog;
- }
-
- private static bool is_system_pictures_import_possible() {
- File system_pictures = AppDirs.get_import_dir();
- if (!system_pictures.query_exists(null))
- return false;
-
- if (!(system_pictures.query_file_type(FileQueryInfoFlags.NONE, null) == FileType.DIRECTORY))
- return false;
-
- try {
- FileEnumerator syspics_child_enum = system_pictures.enumerate_children("standard::*",
- FileQueryInfoFlags.NONE, null);
- return (syspics_child_enum.next_file(null) != null);
- } catch (Error e) {
- return false;
- }
- }
-}
-
-public class PreferencesDialog {
- private class PathFormat {
- public PathFormat(string name, string? pattern) {
- this.name = name;
- this.pattern = pattern;
- }
- public string name;
- public string? pattern;
- }
-
- private static PreferencesDialog preferences_dialog;
-
- private Gtk.Dialog dialog;
- private Gtk.Builder builder;
- private Gtk.Adjustment bg_color_adjustment;
- private Gtk.Scale bg_color_slider;
- private Gtk.ComboBox photo_editor_combo;
- private Gtk.ComboBox raw_editor_combo;
- private SortedList<AppInfo> external_raw_apps;
- private SortedList<AppInfo> external_photo_apps;
- private Gtk.FileChooserButton library_dir_button;
- private Gtk.ComboBoxText dir_pattern_combo;
- private Gtk.Entry dir_pattern_entry;
- private Gtk.Label dir_pattern_example;
- private bool allow_closing = false;
- private string? lib_dir = null;
- private Gee.ArrayList<PathFormat> path_formats = new Gee.ArrayList<PathFormat>();
- private GLib.DateTime example_date = new GLib.DateTime.local(2009, 3, 10, 18, 16, 11);
- private Gtk.CheckButton lowercase;
- private Plugins.ManifestWidgetMediator plugins_mediator = new Plugins.ManifestWidgetMediator();
- private Gtk.ComboBoxText default_raw_developer_combo;
-
- private PreferencesDialog() {
- builder = AppWindow.create_builder();
-
- dialog = builder.get_object("preferences_dialog") as Gtk.Dialog;
- bool use_header;
- Gtk.Settings.get_default ().get ("gtk-dialogs-use-header", out use_header);
- if (!use_header) {
- Gtk.Widget null_titlebar = null;
- dialog.set_titlebar (null_titlebar);
- }
- dialog.set_parent_window(AppWindow.get_instance().get_parent_window());
- dialog.set_transient_for(AppWindow.get_instance());
- dialog.delete_event.connect(on_delete);
- dialog.response.connect(on_close);
-
- bg_color_adjustment = builder.get_object("bg_color_adjustment") as Gtk.Adjustment;
- bg_color_adjustment.set_value(bg_color_adjustment.get_upper() -
- (Config.Facade.get_instance().get_bg_color().red * 65535.0));
- bg_color_adjustment.value_changed.connect(on_value_changed);
-
- bg_color_slider = builder.get_object("bg_color_slider") as Gtk.Scale;
- bg_color_slider.button_press_event.connect(on_bg_color_reset);
-
- library_dir_button = builder.get_object("library_dir_button") as Gtk.FileChooserButton;
-
- photo_editor_combo = builder.get_object("external_photo_editor_combo") as Gtk.ComboBox;
- raw_editor_combo = builder.get_object("external_raw_editor_combo") as Gtk.ComboBox;
-
- Gtk.Label pattern_help = builder.get_object("pattern_help") as Gtk.Label;
-
- // Ticket #3162 - Move dir pattern blurb into Gnome help.
- // Because specifying a particular snippet of the help requires
- // us to know where its located, we can't hardcode a URL anymore;
- // instead, we ask for the help path, and if we find it, we tell
- // yelp to read from there, otherwise, we read from system-wide.
- string help_path = Resources.get_help_path();
-
- if (help_path == null) {
- // We're installed system-wide, so use the system help.
- pattern_help.set_markup("<a href=\"" + Resources.DIR_PATTERN_URI_SYSWIDE + "\">" + _("(Help)") + "</a>");
- } else {
- // We're being run from the build directory; we'll have to handle clicks to this
- // link manually ourselves, due to a limitation of help: URIs.
- pattern_help.set_markup("<a href=\"dummy:\">" + _("(Help)") + "</a>");
- pattern_help.activate_link.connect(on_local_pattern_help);
- }
-
- dir_pattern_combo = builder.get_object("dir choser") as Gtk.ComboBoxText;
- dir_pattern_entry = builder.get_object("dir_pattern_entry") as Gtk.Entry;
- dir_pattern_example = builder.get_object("dynamic example") as Gtk.Label;
- add_to_dir_formats(_("Year%sMonth%sDay").printf(Path.DIR_SEPARATOR_S, Path.DIR_SEPARATOR_S),
- "%Y" + Path.DIR_SEPARATOR_S + "%m" + Path.DIR_SEPARATOR_S + "%d");
- add_to_dir_formats(_("Year%sMonth").printf(Path.DIR_SEPARATOR_S), "%Y" +
- Path.DIR_SEPARATOR_S + "%m");
- add_to_dir_formats(_("Year%sMonth-Day").printf(Path.DIR_SEPARATOR_S),
- "%Y" + Path.DIR_SEPARATOR_S + "%m-%d");
- add_to_dir_formats(_("Year-Month-Day"), "%Y-%m-%d");
- add_to_dir_formats(_("Custom"), null); // Custom must always be last.
- dir_pattern_combo.changed.connect(on_dir_pattern_combo_changed);
- dir_pattern_entry.changed.connect(on_dir_pattern_entry_changed);
-
- (builder.get_object("dir_structure_label") as Gtk.Label).set_mnemonic_widget(dir_pattern_combo);
-
- lowercase = builder.get_object("lowercase") as Gtk.CheckButton;
- lowercase.toggled.connect(on_lowercase_toggled);
-
- var notebook = builder.get_object("preferences-notebook") as Gtk.Notebook;
- (notebook.get_nth_page (2) as Gtk.Container).add (plugins_mediator.widget);
-
- populate_preference_options();
-
- photo_editor_combo.changed.connect(on_photo_editor_changed);
- raw_editor_combo.changed.connect(on_raw_editor_changed);
-
- Gtk.CheckButton auto_import_button = builder.get_object("autoimport") as Gtk.CheckButton;
- auto_import_button.set_active(Config.Facade.get_instance().get_auto_import_from_library());
-
- Gtk.CheckButton commit_metadata_button = builder.get_object("write_metadata") as Gtk.CheckButton;
- commit_metadata_button.set_active(Config.Facade.get_instance().get_commit_metadata_to_masters());
-
- default_raw_developer_combo = builder.get_object("default_raw_developer") as Gtk.ComboBoxText;
- default_raw_developer_combo.append_text(RawDeveloper.CAMERA.get_label());
- default_raw_developer_combo.append_text(RawDeveloper.SHOTWELL.get_label());
- set_raw_developer_combo(Config.Facade.get_instance().get_default_raw_developer());
- default_raw_developer_combo.changed.connect(on_default_raw_developer_changed);
-
- dialog.map_event.connect(map_event);
- }
-
- public void populate_preference_options() {
- populate_app_combo_box(photo_editor_combo, PhotoFileFormat.get_editable_mime_types(),
- Config.Facade.get_instance().get_external_photo_app(), out external_photo_apps);
-
- populate_app_combo_box(raw_editor_combo, PhotoFileFormat.RAW.get_mime_types(),
- Config.Facade.get_instance().get_external_raw_app(), out external_raw_apps);
-
- setup_dir_pattern(dir_pattern_combo, dir_pattern_entry);
-
- lowercase.set_active(Config.Facade.get_instance().get_use_lowercase_filenames());
- }
-
- // Ticket #3162, part II - if we're not yet installed, then we have to manually launch
- // the help viewer and specify the full path to the subsection we want...
- private bool on_local_pattern_help(string ignore) {
- try {
- Resources.launch_help(AppWindow.get_instance().get_screen(), "other-files.page");
- } catch (Error e) {
- message("Unable to launch help: %s", e.message);
- }
- return true;
- }
-
- private void populate_app_combo_box(Gtk.ComboBox combo_box, string[] mime_types,
- string current_app_executable, out SortedList<AppInfo> external_apps) {
- // get list of all applications for the given mime types
- assert(mime_types.length != 0);
- external_apps = DesktopIntegration.get_apps_for_mime_types(mime_types);
-
- if (external_apps.size == 0)
- return;
-
- // populate application ComboBox with app names and icons
- Gtk.CellRendererPixbuf pixbuf_renderer = new Gtk.CellRendererPixbuf();
- Gtk.CellRendererText text_renderer = new Gtk.CellRendererText();
- combo_box.clear();
- combo_box.pack_start(pixbuf_renderer, false);
- combo_box.pack_start(text_renderer, false);
- combo_box.add_attribute(pixbuf_renderer, "pixbuf", 0);
- combo_box.add_attribute(text_renderer, "text", 1);
-
- // TODO: need more space between icons and text
- Gtk.ListStore combo_store = new Gtk.ListStore(2, typeof(Gdk.Pixbuf), typeof(string));
- Gtk.TreeIter iter;
-
- int current_app = -1;
-
- foreach (AppInfo app in external_apps) {
- combo_store.append(out iter);
-
- Icon app_icon = app.get_icon();
- try {
- if (app_icon is FileIcon) {
- combo_store.set_value(iter, 0, scale_pixbuf(new Gdk.Pixbuf.from_file(
- ((FileIcon) app_icon).get_file().get_path()), Resources.DEFAULT_ICON_SCALE,
- Gdk.InterpType.BILINEAR, false));
- } else if (app_icon is ThemedIcon) {
- Gdk.Pixbuf icon_pixbuf =
- Gtk.IconTheme.get_default().load_icon(((ThemedIcon) app_icon).get_names()[0],
- Resources.DEFAULT_ICON_SCALE, Gtk.IconLookupFlags.FORCE_SIZE);
-
- combo_store.set_value(iter, 0, icon_pixbuf);
- }
- } catch (GLib.Error error) {
- warning("Error loading icon pixbuf: " + error.message);
- }
-
- combo_store.set_value(iter, 1, app.get_name());
-
- if (app.get_commandline() == current_app_executable)
- current_app = external_apps.index_of(app);
- }
-
- // TODO: allow users to choose unlisted applications like Nautilus's "Open with -> Other Application..."
-
- combo_box.set_model(combo_store);
-
- if (current_app != -1)
- combo_box.set_active(current_app);
- }
-
- private void setup_dir_pattern(Gtk.ComboBox combo_box, Gtk.Entry entry) {
- string? pattern = Config.Facade.get_instance().get_directory_pattern();
- bool found = false;
- if (null != pattern) {
- // Locate pre-built text.
- int i = 0;
- foreach (PathFormat pf in path_formats) {
- if (pf.pattern == pattern) {
- combo_box.set_active(i);
- found = true;
- break;
- }
- i++;
- }
- } else {
- // Custom path.
- string? s = Config.Facade.get_instance().get_directory_pattern_custom();
- if (!is_string_empty(s)) {
- combo_box.set_active(path_formats.size - 1); // Assume "custom" is last.
- found = true;
- }
- }
-
- if (!found) {
- combo_box.set_active(0);
- }
-
- on_dir_pattern_combo_changed();
- }
-
- public static void show() {
- if (preferences_dialog == null)
- preferences_dialog = new PreferencesDialog();
-
- preferences_dialog.populate_preference_options();
- preferences_dialog.dialog.show_all();
- preferences_dialog.library_dir_button.set_current_folder(AppDirs.get_import_dir().get_path());
-
- // Ticket #3001: Cause the dialog to become active if the user chooses 'Preferences'
- // from the menus a second time.
- preferences_dialog.dialog.present();
- }
-
- // For items that should only be committed when the dialog is closed, not as soon as the change
- // is made.
- private void commit_on_close() {
- Config.Facade.get_instance().commit_bg_color();
-
- Gtk.CheckButton? autoimport = builder.get_object("autoimport") as Gtk.CheckButton;
- if (autoimport != null)
- Config.Facade.get_instance().set_auto_import_from_library(autoimport.active);
-
- Gtk.CheckButton? commit_metadata = builder.get_object("write_metadata") as Gtk.CheckButton;
- if (commit_metadata != null)
- Config.Facade.get_instance().set_commit_metadata_to_masters(commit_metadata.active);
-
- if (lib_dir != null)
- AppDirs.set_import_dir(lib_dir);
-
- PathFormat pf = path_formats.get(dir_pattern_combo.get_active());
- if (null == pf.pattern) {
- Config.Facade.get_instance().set_directory_pattern_custom(dir_pattern_entry.text);
- Config.Facade.get_instance().set_directory_pattern(null);
- } else {
- Config.Facade.get_instance().set_directory_pattern(pf.pattern);
- }
- }
-
- private bool on_delete() {
- if (!get_allow_closing())
- return true;
-
- commit_on_close();
- return dialog.hide_on_delete(); //prevent widgets from getting destroyed
- }
-
- private void on_close() {
- if (!get_allow_closing())
- return;
-
- dialog.hide();
- commit_on_close();
- }
-
- private void on_value_changed() {
- set_background_color((double)(bg_color_adjustment.get_upper() -
- bg_color_adjustment.get_value()) / 65535.0);
- }
-
- private bool on_bg_color_reset(Gdk.EventButton event) {
- if (event.button == 1 && event.type == Gdk.EventType.BUTTON_PRESS
- && has_only_key_modifier(event.state, Gdk.ModifierType.CONTROL_MASK)) {
- // Left Mouse Button and CTRL pressed
- bg_color_slider.set_value(bg_color_adjustment.get_upper() -
- (parse_color(Config.Facade.DEFAULT_BG_COLOR).red * 65536.0f));
- on_value_changed();
-
- return true;
- }
-
- return false;
- }
-
- private void on_dir_pattern_combo_changed() {
- PathFormat pf = path_formats.get(dir_pattern_combo.get_active());
- if (null == pf.pattern) {
- // Custom format.
- string? dir_pattern = Config.Facade.get_instance().get_directory_pattern_custom();
- if (is_string_empty(dir_pattern))
- dir_pattern = "";
- dir_pattern_entry.set_text(dir_pattern);
- dir_pattern_entry.editable = true;
- dir_pattern_entry.sensitive = true;
- } else {
- dir_pattern_entry.set_text(pf.pattern);
- dir_pattern_entry.editable = false;
- dir_pattern_entry.sensitive = false;
- }
- }
-
- private void on_dir_pattern_entry_changed() {
- string example = example_date.format(dir_pattern_entry.text);
- if (is_string_empty(example) && !is_string_empty(dir_pattern_entry.text)) {
- // Invalid pattern.
- dir_pattern_example.set_text(_("Invalid pattern"));
- dir_pattern_entry.set_icon_from_icon_name(Gtk.EntryIconPosition.SECONDARY, "dialog-error");
- dir_pattern_entry.set_icon_activatable(Gtk.EntryIconPosition.SECONDARY, false);
- set_allow_closing(false);
- } else {
- // Valid pattern.
- dir_pattern_example.set_text(example);
- dir_pattern_entry.set_icon_from_icon_name(Gtk.EntryIconPosition.SECONDARY, null);
- set_allow_closing(true);
- }
- }
-
- private void set_allow_closing(bool allow) {
- dialog.set_deletable(allow);
- allow_closing = allow;
- }
-
- private bool get_allow_closing() {
- return allow_closing;
- }
-
- private void set_background_color(double bg_color_value) {
- Config.Facade.get_instance().set_bg_color(to_grayscale(bg_color_value));
- }
-
- private Gdk.RGBA to_grayscale(double color_value) {
- Gdk.RGBA color = Gdk.RGBA();
-
- color.red = color_value;
- color.green = color_value;
- color.blue = color_value;
- color.alpha = 1.0;
-
- return color;
- }
-
- private void on_photo_editor_changed() {
- int photo_app_choice_index = (photo_editor_combo.get_active() < external_photo_apps.size) ?
- photo_editor_combo.get_active() : external_photo_apps.size;
-
- AppInfo app = external_photo_apps.get_at(photo_app_choice_index);
-
- Config.Facade.get_instance().set_external_photo_app(DesktopIntegration.get_app_open_command(app));
-
- debug("setting external photo editor to: %s", DesktopIntegration.get_app_open_command(app));
- }
-
- private void on_raw_editor_changed() {
- int raw_app_choice_index = (raw_editor_combo.get_active() < external_raw_apps.size) ?
- raw_editor_combo.get_active() : external_raw_apps.size;
-
- AppInfo app = external_raw_apps.get_at(raw_app_choice_index);
-
- Config.Facade.get_instance().set_external_raw_app(app.get_commandline());
-
- debug("setting external raw editor to: %s", app.get_commandline());
- }
-
- private RawDeveloper raw_developer_from_combo() {
- if (default_raw_developer_combo.get_active() == 0)
- return RawDeveloper.CAMERA;
- return RawDeveloper.SHOTWELL;
- }
-
- private void set_raw_developer_combo(RawDeveloper d) {
- if (d == RawDeveloper.CAMERA)
- default_raw_developer_combo.set_active(0);
- else
- default_raw_developer_combo.set_active(1);
- }
-
- private void on_default_raw_developer_changed() {
- Config.Facade.get_instance().set_default_raw_developer(raw_developer_from_combo());
- }
-
- private void on_current_folder_changed() {
- lib_dir = library_dir_button.get_filename();
- }
-
- private bool map_event() {
- // Set the signal for the lib dir button after the dialog is displayed,
- // because the FileChooserButton has a nasty habit of selecting a
- // different folder when displayed if the provided path doesn't exist.
- // See ticket #3000 for more info.
- library_dir_button.current_folder_changed.connect(on_current_folder_changed);
- return true;
- }
-
- private void add_to_dir_formats(string name, string? pattern) {
- PathFormat pf = new PathFormat(name, pattern);
- path_formats.add(pf);
- dir_pattern_combo.append_text(name);
- }
-
- private void on_lowercase_toggled() {
- Config.Facade.get_instance().set_use_lowercase_filenames(lowercase.get_active());
- }
-}
-
// This function is used to determine whether or not files should be copied or linked when imported.
// Returns ACCEPT for copy, REJECT for link, and CANCEL for (drum-roll) cancel.
public Gtk.ResponseType copy_files_dialog() {