123 sqlite3_stmt *stmt, *inner_stmt;
124 GList *result = NULL;
128 "SELECT i.id, write_timestamp, version,"
129 " folder || '" G_DIR_SEPARATOR_S
"' || filename, flags"
130 " FROM main.images i, main.film_rolls f"
131 " ON i.film_id = f.id"
132 " ORDER BY f.id, filename",
136 "UPDATE main.images SET flags = ?1 WHERE id = ?2", -1,
142 while(sqlite3_step(stmt) == SQLITE_ROW)
144 const int id = sqlite3_column_int(stmt, 0);
145 const time_t timestamp = sqlite3_column_int(stmt, 1);
146 const int version = sqlite3_column_int(stmt, 2);
147 const gchar *image_path = (
char *)sqlite3_column_text(stmt, 3);
148 int flags = sqlite3_column_int(stmt, 4);
151 if(!g_file_test(image_path, G_FILE_TEST_EXISTS))
159 g_strlcpy(xmp_path, image_path,
sizeof(xmp_path));
161 size_t len = strlen(xmp_path);
163 xmp_path[len++] =
'.';
164 xmp_path[len++] =
'x';
165 xmp_path[len++] =
'm';
166 xmp_path[len++] =
'p';
167 xmp_path[len] =
'\0';
174 struct _stati64 statbuf;
178 wchar_t *wfilename = g_utf8_to_utf16(xmp_path_locale, -1, NULL, NULL, NULL);
179 stat_res = _wstati64(wfilename, &statbuf);
184 stat_res = stat(xmp_path_locale, &statbuf);
187 if(stat_res)
continue;
191 if(timestamp < statbuf.st_mtime)
199 item->
xmp_path = g_strdup(xmp_path);
201 result = g_list_prepend(result, item);
203 "[crawler] `%s' (id: %d) is a newer XMP file.\n", xmp_path,
id);
209 len = strlen(image_path);
210 const char *c = image_path + len;
211 while((c > image_path) && (*c !=
'.')) c--;
212 len = c - image_path + 1;
218 char *extra_path = (
char *)calloc(len + 3 + 1,
sizeof(
char));
219 g_strlcpy(extra_path, image_path, len + 1);
221 extra_path[len] =
'w';
222 extra_path[len + 1] =
'a';
223 extra_path[len + 2] =
'v';
224 gboolean has_wav = g_file_test(extra_path, G_FILE_TEST_EXISTS);
228 extra_path[len] =
'W';
229 extra_path[len + 1] =
'A';
230 extra_path[len + 2] =
'V';
231 has_wav = g_file_test(extra_path, G_FILE_TEST_EXISTS);
236 int new_flags =
flags;
240 new_flags &= ~DT_IMAGE_HAS_TXT;
244 new_flags &= ~DT_IMAGE_HAS_WAV;
245 if(
flags != new_flags)
247 sqlite3_bind_int(inner_stmt, 1, new_flags);
248 sqlite3_bind_int(inner_stmt, 2,
id);
249 sqlite3_step(inner_stmt);
250 sqlite3_reset(inner_stmt);
251 sqlite3_clear_bindings(inner_stmt);
259 sqlite3_finalize(stmt);
260 sqlite3_finalize(inner_stmt);
262 return g_list_reverse(result);
688 GtkTreeViewColumn *column;
689 GtkWidget *scroll = gtk_scrolled_window_new(NULL, NULL);
690 gtk_widget_set_vexpand(scroll,
TRUE);
704 for(GList *list_iter = images; list_iter; list_iter = g_list_next(list_iter))
708 char timestamp_db[64], timestamp_xmp[64];
710 strftime(timestamp_db,
sizeof(timestamp_db),
712 strftime(timestamp_xmp,
sizeof(timestamp_xmp),
718 gtk_list_store_append(
store, &iter);
739 GtkWidget *tree = gtk_tree_view_new_with_model(GTK_TREE_MODEL(
store));
740 GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree));
741 gtk_tree_selection_set_mode(selection, GTK_SELECTION_MULTIPLE);
743 gui->
tree = GTK_TREE_VIEW(tree);
745 GtkCellRenderer *renderer_text = gtk_cell_renderer_text_new();
746 column = gtk_tree_view_column_new_with_attributes
747 (_(
"path"), renderer_text,
"text",
749 gtk_tree_view_append_column(GTK_TREE_VIEW(tree), column);
750 gtk_tree_view_column_set_expand(column,
TRUE);
751 gtk_tree_view_column_set_resizable(column,
TRUE);
753 g_object_set(renderer_text,
"ellipsize", PANGO_ELLIPSIZE_MIDDLE, NULL);
755 column = gtk_tree_view_column_new_with_attributes
756 (_(
"XMP timestamp"), gtk_cell_renderer_text_new(),
"text",
758 gtk_tree_view_append_column(GTK_TREE_VIEW(tree), column);
760 column = gtk_tree_view_column_new_with_attributes
761 (_(
"database timestamp"), gtk_cell_renderer_text_new(),
"text",
763 gtk_tree_view_append_column(GTK_TREE_VIEW(tree), column);
765 column = gtk_tree_view_column_new_with_attributes
766 (_(
"newest"), gtk_cell_renderer_text_new(),
"text",
768 gtk_tree_view_append_column(GTK_TREE_VIEW(tree), column);
770 GtkCellRenderer *renderer_date = gtk_cell_renderer_text_new();
771 column = gtk_tree_view_column_new_with_attributes
772 (_(
"time difference"), renderer_date,
"text",
774 g_object_set(renderer_date,
"xalign", 1., NULL);
775 gtk_tree_view_append_column(GTK_TREE_VIEW(tree), column);
778 gtk_container_add(GTK_CONTAINER(scroll), tree);
779 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll),
780 GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
784 GtkWidget *dialog = gtk_dialog_new_with_buttons
785 (_(
"updated XMP sidecar files found"), GTK_WINDOW(win),
786 GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_MODAL, _(
"_close"),
787 GTK_RESPONSE_CLOSE, NULL);
789#ifdef GDK_WINDOWING_QUARTZ
793 gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(win));
794 GtkWidget *content_area = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
797 gtk_container_add(GTK_CONTAINER(content_area), content_box);
800 gtk_box_pack_start(GTK_BOX(content_box), box,
FALSE,
FALSE, 0);
801 GtkWidget *select_all = gtk_button_new_with_label(_(
"select all"));
802 GtkWidget *select_none = gtk_button_new_with_label(_(
"select none"));
803 GtkWidget *select_invert = gtk_button_new_with_label(_(
"invert selection"));
804 gtk_box_pack_start(GTK_BOX(box), select_all,
FALSE,
FALSE, 0);
805 gtk_box_pack_start(GTK_BOX(box), select_none,
FALSE,
FALSE, 0);
806 gtk_box_pack_start(GTK_BOX(box), select_invert,
FALSE,
FALSE, 0);
811 gtk_box_pack_start(GTK_BOX(content_box), scroll,
TRUE,
TRUE, 0);
814 gtk_box_pack_start(GTK_BOX(content_box), box,
FALSE,
FALSE, 1);
815 GtkWidget *label = gtk_label_new_with_mnemonic(_(
"on the selection:"));
816 GtkWidget *reload_button = gtk_button_new_with_label(_(
"keep the XMP edit"));
817 GtkWidget *overwrite_button = gtk_button_new_with_label(_(
"keep the database edit"));
818 GtkWidget *newest_button = gtk_button_new_with_label(_(
"keep the newest edit"));
819 GtkWidget *oldest_button = gtk_button_new_with_label(_(
"keep the oldest edit"));
820 gtk_box_pack_start(GTK_BOX(box), label,
FALSE,
FALSE, 0);
821 gtk_box_pack_start(GTK_BOX(box), reload_button,
FALSE,
FALSE, 0);
822 gtk_box_pack_start(GTK_BOX(box), overwrite_button,
FALSE,
FALSE, 0);
823 gtk_box_pack_start(GTK_BOX(box), newest_button,
FALSE,
FALSE, 0);
824 gtk_box_pack_start(GTK_BOX(box), oldest_button,
FALSE,
FALSE, 0);
831 gui->
spinner = gtk_spinner_new();
835 scroll = gtk_scrolled_window_new(NULL, NULL);
836 gui->
log = gtk_tree_view_new();
837 gtk_box_pack_start(GTK_BOX(content_box), scroll,
TRUE,
TRUE, 0);
839 gtk_container_add(GTK_CONTAINER(scroll), gui->
log);
840 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll),
841 GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
843 gtk_tree_view_insert_column_with_attributes
844 (GTK_TREE_VIEW(gui->
log), -1,
845 _(
"synchronization log"), renderer_text,
848 GtkListStore *store_log = gtk_list_store_new (1, G_TYPE_STRING);
849 GtkTreeModel *model_log = GTK_TREE_MODEL(store_log);
850 gtk_tree_view_set_model(GTK_TREE_VIEW(gui->
log), model_log);
851 g_object_unref(model_log);
853 gtk_widget_show_all(dialog);
855 g_signal_connect(dialog,
"response",