static void button_clicked(GtkWidget *widget, dt_imageio_module_storage_t *self) { disk_t *d = (disk_t *)self->gui_data; GtkWidget *win = dt_ui_main_window(darktable.gui->ui); GtkWidget *filechooser = gtk_file_chooser_dialog_new( _("select directory"), GTK_WINDOW(win), GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER, _("_cancel"), GTK_RESPONSE_CANCEL, _("_select as output destination"), GTK_RESPONSE_ACCEPT, (char *)NULL); #ifdef GDK_WINDOWING_QUARTZ dt_osx_disallow_fullscreen(filechooser); #endif gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(filechooser), FALSE); gchar *old = g_strdup(gtk_entry_get_text(d->entry)); char *c = g_strstr_len(old, -1, "$"); if(c) *c = '\0'; gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(filechooser), old); g_free(old); if(gtk_dialog_run(GTK_DIALOG(filechooser)) == GTK_RESPONSE_ACCEPT) { gchar *dir = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(filechooser)); char *composed = g_build_filename(dir, "$(FILE_NAME)", NULL); // composed can now contain '\': on Windows it's the path separator, // on other platforms it can be part of a regular folder name. // This would later clash with variable substitution, so we have to escape them gchar *escaped = dt_util_str_replace(composed, "\\", "\\\\"); gtk_entry_set_text(GTK_ENTRY(d->entry), escaped); // the signal handler will write this to conf g_free(dir); g_free(composed); g_free(escaped); } gtk_widget_destroy(filechooser); }
static gboolean ask_and_delete(gpointer user_data) { GList *empty_dirs = (GList *)user_data; const int n_empty_dirs = g_list_length(empty_dirs); GtkWidget *dialog; GtkWidget *win = dt_ui_main_window(darktable.gui->ui); dialog = gtk_message_dialog_new(GTK_WINDOW(win), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_QUESTION, GTK_BUTTONS_YES_NO, ngettext("do you want to remove this empty directory?", "do you want to remove these empty directories?", n_empty_dirs)); #ifdef GDK_WINDOWING_QUARTZ dt_osx_disallow_fullscreen(dialog); #endif gtk_window_set_title(GTK_WINDOW(dialog), ngettext("remove empty directory?", "remove empty directories?", n_empty_dirs)); GtkWidget *content_area = gtk_dialog_get_content_area(GTK_DIALOG(dialog)); GtkWidget *scroll = gtk_scrolled_window_new(NULL, NULL); gtk_widget_set_vexpand(scroll, TRUE); GtkListStore *store = gtk_list_store_new(1, G_TYPE_STRING); for(GList *list_iter = empty_dirs; list_iter; list_iter = g_list_next(list_iter)) { GtkTreeIter iter; gtk_list_store_append(store, &iter); gtk_list_store_set(store, &iter, 0, list_iter->data, -1); } GtkWidget *tree = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store)); gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(tree), FALSE); GtkTreeViewColumn *column = gtk_tree_view_column_new_with_attributes(_("name"), gtk_cell_renderer_text_new(), "text", 0, NULL); gtk_tree_view_append_column(GTK_TREE_VIEW(tree), column); gtk_container_add(GTK_CONTAINER(scroll), tree); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); gtk_container_add(GTK_CONTAINER(content_area), scroll); gtk_widget_show_all(dialog); // needed for the content area! gint res = gtk_dialog_run(GTK_DIALOG(dialog)); gtk_widget_destroy(dialog); if(res == GTK_RESPONSE_YES) for(GList *iter = empty_dirs; iter; iter = g_list_next(iter)) rmdir((char *)iter->data); g_list_free_full(empty_dirs, g_free); g_object_unref(store); return FALSE; }
/** * @see https://developers.google.com/accounts/docs/OAuth2InstalledApp * @returns NULL if the user cancels the operation or a valid token */ static int gphoto_get_user_auth_token(dt_storage_gphoto_gui_data_t *ui) { ///////////// open the authentication url in a browser GError *error = NULL; gchar *params = NULL; params = dt_util_dstrcat(params, GOOGLE_WS_BASE_URL "o/oauth2/v2/auth?" "client_id=%s&redirect_uri=urn:ietf:wg:oauth:2.0:oob" "&scope=" GOOGLE_API_BASE_URL "auth/photoslibrary " GOOGLE_API_BASE_URL "auth/userinfo.profile " GOOGLE_API_BASE_URL "auth/userinfo.email" "&response_type=code&access_type=offline", ui->gphoto_api->google_client_id); if(!gtk_show_uri(gdk_screen_get_default(), params, gtk_get_current_event_time(), &error)) { fprintf(stderr, "[gphoto] error opening browser: %s\n", error->message); g_error_free(error); } ////////////// build & show the validation dialog const gchar *text1 = _("step 1: a new window or tab of your browser should have been " "loaded. you have to login into your google account there " "and authorize darktable to upload photos before continuing."); const gchar *text2 = _("step 2: paste the verification code shown to you in the browser " "and click the OK button once you are done."); GtkWidget *window = dt_ui_main_window(darktable.gui->ui); GtkDialog *gphoto_auth_dialog = GTK_DIALOG( gtk_message_dialog_new(GTK_WINDOW(window), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_QUESTION, GTK_BUTTONS_OK_CANCEL, _("google authentication"))); #ifdef GDK_WINDOWING_QUARTZ dt_osx_disallow_fullscreen(GTK_WIDGET(gphoto_auth_dialog)); #endif gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(gphoto_auth_dialog), "%s\n\n%s", text1, text2); GtkWidget *entry = gtk_entry_new(); GtkWidget *hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 5); gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(gtk_label_new(_("verification code:"))), FALSE, FALSE, 0); gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(entry), TRUE, TRUE, 0); GtkWidget *gphotoauthdialog_vbox = gtk_message_dialog_get_message_area(GTK_MESSAGE_DIALOG(gphoto_auth_dialog)); gtk_box_pack_end(GTK_BOX(gphotoauthdialog_vbox), hbox, TRUE, TRUE, 0); gtk_widget_show_all(GTK_WIDGET(gphoto_auth_dialog)); ////////////// wait for the user to enter the verification code gint result; gchar *token = NULL; const char *replycode; while(TRUE) { result = gtk_dialog_run(GTK_DIALOG(gphoto_auth_dialog)); if(result == GTK_RESPONSE_CANCEL) break; replycode = gtk_entry_get_text(GTK_ENTRY(entry)); if(replycode == NULL || g_strcmp0(replycode, "") == 0) { gtk_message_dialog_format_secondary_markup(GTK_MESSAGE_DIALOG(gphoto_auth_dialog), "%s\n\n%s\n\n<span foreground=\"" MSGCOLOR_RED "\" ><small>%s</small></span>", text1, text2, _("please enter the verification code")); continue; } else { token = g_strdup(replycode); break; } } gtk_widget_destroy(GTK_WIDGET(gphoto_auth_dialog)); g_free(params); if(result == GTK_RESPONSE_CANCEL) return 1; // Interchange now the authorization_code for an access_token and refresh_token JsonObject *reply; params = NULL; params = dt_util_dstrcat(params, "code=%s&client_id=%s&client_secret=%s" "&redirect_uri=" GOOGLE_URI "&grant_type=authorization_code", token, ui->gphoto_api->google_client_id, ui->gphoto_api->google_client_secret); g_free(token); reply = gphoto_query_post_auth(ui->gphoto_api, GOOGLE_WS_BASE_URL "o/oauth2/token", params); gchar *access_token = g_strdup(json_object_get_string_member(reply, "access_token")); gchar *refresh_token = g_strdup(json_object_get_string_member(reply, "refresh_token")); ui->gphoto_api->token = access_token; ui->gphoto_api->refresh_token = refresh_token; g_free(params); return 0; // FIXME }
int dt_gui_hist_dialog_new(dt_gui_hist_dialog_t *d, int imgid, gboolean iscopy) { int res; GtkWidget *window = dt_ui_main_window(darktable.gui->ui); GtkDialog *dialog = GTK_DIALOG(gtk_dialog_new_with_buttons( _("select parts"), GTK_WINDOW(window), GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, _("_cancel"), GTK_RESPONSE_CANCEL, _("select _all"), GTK_RESPONSE_YES, _("select _none"), GTK_RESPONSE_NONE, _("_ok"), GTK_RESPONSE_OK, NULL)); #ifdef GDK_WINDOWING_QUARTZ dt_osx_disallow_fullscreen(GTK_WIDGET(dialog)); #endif GtkContainer *content_area = GTK_CONTAINER(gtk_dialog_get_content_area(GTK_DIALOG(dialog))); GtkBox *box = GTK_BOX(gtk_box_new(GTK_ORIENTATION_VERTICAL, 3)); gtk_widget_set_margin_start(GTK_WIDGET(box), DT_PIXEL_APPLY_DPI(5)); gtk_widget_set_margin_end(GTK_WIDGET(box), DT_PIXEL_APPLY_DPI(5)); gtk_widget_set_margin_top(GTK_WIDGET(box), DT_PIXEL_APPLY_DPI(5)); gtk_widget_set_margin_bottom(GTK_WIDGET(box), DT_PIXEL_APPLY_DPI(5)); gtk_container_add(content_area, GTK_WIDGET(box)); /* create the list of items */ d->items = GTK_TREE_VIEW(gtk_tree_view_new()); GtkListStore *liststore = gtk_list_store_new(DT_HIST_ITEMS_NUM_COLS, G_TYPE_BOOLEAN, G_TYPE_STRING, G_TYPE_UINT); /* enabled */ GtkCellRenderer *renderer = gtk_cell_renderer_toggle_new(); gtk_cell_renderer_toggle_set_activatable(GTK_CELL_RENDERER_TOGGLE(renderer), TRUE); g_object_set_data(G_OBJECT(renderer), "column", (gint *)DT_HIST_ITEMS_COL_ENABLED); g_signal_connect(renderer, "toggled", G_CALLBACK(_gui_hist_item_toggled), d); gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(d->items), -1, _("include"), renderer, "active", DT_HIST_ITEMS_COL_ENABLED, NULL); /* name */ renderer = gtk_cell_renderer_text_new(); g_object_set_data(G_OBJECT(renderer), "column", (gint *)DT_HIST_ITEMS_COL_NAME); g_object_set(renderer, "xalign", 0.0, (gchar *)0); gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(d->items), -1, _("item"), renderer, "text", DT_HIST_ITEMS_COL_NAME, NULL); gtk_tree_selection_set_mode(gtk_tree_view_get_selection(GTK_TREE_VIEW(d->items)), GTK_SELECTION_SINGLE); gtk_tree_view_set_model(GTK_TREE_VIEW(d->items), GTK_TREE_MODEL(liststore)); gtk_box_pack_start(box, GTK_WIDGET(d->items), TRUE, TRUE, 0); /* fill list with history items */ GtkTreeIter iter; GList *items = dt_history_get_items(imgid, FALSE); if(items) { do { dt_history_item_t *item = (dt_history_item_t *)items->data; gtk_list_store_append(GTK_LIST_STORE(liststore), &iter); gtk_list_store_set(GTK_LIST_STORE(liststore), &iter, DT_HIST_ITEMS_COL_ENABLED, iscopy ? TRUE : _gui_is_set(d->selops, item->num), DT_HIST_ITEMS_COL_NAME, item->name, DT_HIST_ITEMS_COL_NUM, (guint)item->num, -1); } while((items = g_list_next(items))); g_list_free_full(items, dt_history_item_free); } else { dt_control_log(_("can't copy history out of unaltered image")); return GTK_RESPONSE_CANCEL; } g_object_unref(liststore); g_signal_connect(dialog, "response", G_CALLBACK(_gui_hist_copy_response), d); gtk_widget_show_all(GTK_WIDGET(dialog)); while(1) { res = gtk_dialog_run(GTK_DIALOG(dialog)); if(res == GTK_RESPONSE_CANCEL || res == GTK_RESPONSE_DELETE_EVENT || res == GTK_RESPONSE_OK) break; } gtk_widget_destroy(GTK_WIDGET(dialog)); return res; }