Commit d783672b authored by Jens Georg's avatar Jens Georg

Extract Preferences Dialog

parent 70215a71
......@@ -2008,470 +2008,6 @@ public class WelcomeDialog : Gtk.Dialog {
}
}
[GtkTemplate (ui = "/org/gnome/Shotwell/ui/preferences_dialog.ui")]
public class PreferencesDialog : Gtk.Dialog {
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;
[GtkChild]
private Gtk.Adjustment bg_color_adjustment;
[GtkChild]
private Gtk.Scale bg_color_slider;
[GtkChild]
private Gtk.ComboBox photo_editor_combo;
[GtkChild]
private Gtk.ComboBox raw_editor_combo;
private SortedList<AppInfo> external_raw_apps;
private SortedList<AppInfo> external_photo_apps;
[GtkChild]
private Gtk.FileChooserButton library_dir_button;
[GtkChild]
private Gtk.ComboBoxText dir_pattern_combo;
[GtkChild]
private Gtk.Entry dir_pattern_entry;
[GtkChild]
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);
[GtkChild]
private Gtk.CheckButton lowercase;
private Plugins.ManifestWidgetMediator plugins_mediator = new Plugins.ManifestWidgetMediator();
[GtkChild]
private Gtk.ComboBoxText default_raw_developer_combo;
[GtkChild]
private Gtk.CheckButton autoimport;
[GtkChild]
private Gtk.CheckButton write_metadata;
[GtkChild]
private Gtk.Label pattern_help;
[GtkChild]
private Gtk.Notebook preferences_notebook;
[GtkChild]
private Gtk.RadioButton transparent_checker_radio;
[GtkChild]
private Gtk.RadioButton transparent_solid_radio;
[GtkChild]
private Gtk.ColorButton transparent_solid_color;
[GtkChild]
private Gtk.RadioButton transparent_none_radio;
private PreferencesDialog() {
bool use_header;
Gtk.Settings.get_default ().get ("gtk-dialogs-use-header", out use_header);
Object (use_header_bar: use_header ? 1 : 0);
set_parent_window(AppWindow.get_instance().get_parent_window());
set_transient_for(AppWindow.get_instance());
delete_event.connect(on_delete);
response.connect(on_close);
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.button_press_event.connect(on_bg_color_reset);
transparent_checker_radio.toggled.connect(on_radio_changed);
transparent_solid_radio.toggled.connect(on_radio_changed);
transparent_none_radio.toggled.connect(on_radio_changed);
transparent_solid_radio.bind_property("active",
transparent_solid_color,
"sensitive");
Gdk.RGBA color = Gdk.RGBA();
color.parse(Config.Facade.get_instance().get_transparent_background_color());
(transparent_solid_color as Gtk.ColorChooser).rgba = color;
transparent_solid_color.color_set.connect(on_color_changed);
switch (Config.Facade.get_instance().get_transparent_background_type()) {
case "checkered":
transparent_checker_radio.active = true;
break;
case "solid":
transparent_solid_radio.active = true;
break;
default:
transparent_none_radio.active = true;
break;
}
// 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);
}
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);
lowercase.toggled.connect(on_lowercase_toggled);
(preferences_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);
autoimport.set_active(Config.Facade.get_instance().get_auto_import_from_library());
write_metadata.set_active(Config.Facade.get_instance().get_commit_metadata_to_masters());
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);
}
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());
}
private void on_radio_changed() {
var config = Config.Facade.get_instance();
if (transparent_checker_radio.active) {
config.set_transparent_background_type("checkered");
} else if (transparent_solid_radio.active) {
config.set_transparent_background_type("solid");
} else {
config.set_transparent_background_type("none");
}
}
private void on_color_changed() {
var color = (transparent_solid_color as Gtk.ColorChooser).rgba.to_string();
Config.Facade.get_instance().set_transparent_background_color(color);
}
// 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_preferences() {
if (preferences_dialog == null)
preferences_dialog = new PreferencesDialog();
preferences_dialog.populate_preference_options();
preferences_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.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();
Config.Facade.get_instance().set_auto_import_from_library(autoimport.active);
Config.Facade.get_instance().set_commit_metadata_to_masters(write_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 hide_on_delete(); //prevent widgets from getting destroyed
}
private void on_close() {
if (!get_allow_closing())
return;
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) {
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();
}
public override bool map_event(Gdk.EventAny event) {
var result = base.map_event(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 result;
}
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() {
......
/* 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.
*/
[GtkTemplate (ui = "/org/gnome/Shotwell/ui/preferences_dialog.ui")]
public class PreferencesDialog : Gtk.Dialog {
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;
[GtkChild]
private Gtk.Adjustment bg_color_adjustment;
[GtkChild]
private Gtk.Scale bg_color_slider;
[GtkChild]
private Gtk.ComboBox photo_editor_combo;
[GtkChild]
private Gtk.ComboBox raw_editor_combo;
private SortedList<AppInfo> external_raw_apps;
private SortedList<AppInfo> external_photo_apps;
[GtkChild]
private Gtk.FileChooserButton library_dir_button;
[GtkChild]
private Gtk.ComboBoxText dir_pattern_combo;
[GtkChild]
private Gtk.Entry dir_pattern_entry;
[GtkChild]
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);
[GtkChild]
private Gtk.CheckButton lowercase;
private Plugins.ManifestWidgetMediator plugins_mediator = new Plugins.ManifestWidgetMediator();
[GtkChild]
private Gtk.ComboBoxText default_raw_developer_combo;
[GtkChild]
private Gtk.CheckButton autoimport;
[GtkChild]
private Gtk.CheckButton write_metadata;
[GtkChild]
private Gtk.Label pattern_help;
[GtkChild]
private Gtk.Notebook preferences_notebook;
[GtkChild]
private Gtk.RadioButton transparent_checker_radio;
[GtkChild]
private Gtk.RadioButton transparent_solid_radio;
[GtkChild]
private Gtk.ColorButton transparent_solid_color;
[GtkChild]
private Gtk.RadioButton transparent_none_radio;
private PreferencesDialog() {
bool use_header;
Gtk.Settings.get_default ().get ("gtk-dialogs-use-header", out use_header);
Object (use_header_bar: use_header ? 1 : 0);
set_parent_window(AppWindow.get_instance().get_parent_window());
set_transient_for(AppWindow.get_instance());
delete_event.connect(on_delete);
response.connect(on_close);
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.button_press_event.connect(on_bg_color_reset);
transparent_checker_radio.toggled.connect(on_radio_changed);
transparent_solid_radio.toggled.connect(on_radio_changed);
transparent_none_radio.toggled.connect(on_radio_changed);
transparent_solid_radio.bind_property("active",
transparent_solid_color,
"sensitive");
Gdk.RGBA color = Gdk.RGBA();
color.parse(Config.Facade.get_instance().get_transparent_background_color());
(transparent_solid_color as Gtk.ColorChooser).rgba = color;
transparent_solid_color.color_set.connect(on_color_changed);
switch (Config.Facade.get_instance().get_transparent_background_type()) {
case "checkered":
transparent_checker_radio.active = true;
break;
case "solid":
transparent_solid_radio.active = true;
break;
default:
transparent_none_radio.active = true;
break;
}
// 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);
}
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);
lowercase.toggled.connect(on_lowercase_toggled);
(preferences_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);
autoimport.set_active(Config.Facade.get_instance().get_auto_import_from_library());
write_metadata.set_active(Config.Facade.get_instance().get_commit_metadata_to_masters());
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);
}
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());
}
private void on_radio_changed() {
var config = Config.Facade.get_instance();
if (transparent_checker_radio.active) {
config.set_transparent_background_type("checkered");
} else if (transparent_solid_radio.active) {
config.set_transparent_background_type("solid");
} else {
config.set_transparent_background_type("none");
}
}
private void on_color_changed() {
var color = (transparent_solid_color as Gtk.ColorChooser).rgba.to_string();
Config.Facade.get_instance().set_transparent_background_color(color);
}
// 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..."