aboutsummaryrefslogtreecommitdiff
path: root/src/gui_import.c
diff options
context:
space:
mode:
authorThomas White <taw@physics.org>2021-02-24 16:27:42 +0100
committerThomas White <taw@physics.org>2021-02-24 16:27:42 +0100
commit4a6a4bfcffad676c4179a3c642e9665901c03eb7 (patch)
tree0eaa4bc60fe10dee5bd4b34ec715d563d3b1e38e /src/gui_import.c
parente00cb35a04144a18822c959210a83a33ac6374d8 (diff)
GUI: Move import stuff to separate file
Diffstat (limited to 'src/gui_import.c')
-rw-r--r--src/gui_import.c505
1 files changed, 505 insertions, 0 deletions
diff --git a/src/gui_import.c b/src/gui_import.c
new file mode 100644
index 00000000..ba5e44f8
--- /dev/null
+++ b/src/gui_import.c
@@ -0,0 +1,505 @@
+/*
+ * gui_import.c
+ *
+ * Data import to GUI
+ *
+ * Copyright © 2021 Deutsches Elektronen-Synchrotron DESY,
+ * a research centre of the Helmholtz Association.
+ *
+ * Authors:
+ * 2021 Thomas White <taw@physics.org>
+ *
+ * This file is part of CrystFEL.
+ *
+ * CrystFEL is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * CrystFEL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with CrystFEL. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <getopt.h>
+#include <string.h>
+#include <gtk/gtk.h>
+#include <assert.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <datatemplate.h>
+
+#include "crystfelimageview.h"
+#include "gui_project.h"
+#include "crystfel_gui.h"
+
+#include "version.h"
+
+static void add_all_events(struct crystfelproject *proj,
+ const char *filename,
+ const DataTemplate *dtempl)
+{
+ char **events;
+ int i;
+ int n_events;
+
+ events = image_expand_frames(dtempl, filename, &n_events);
+ if ( events == NULL ) {
+ ERROR("Couldn't expand event list\n");
+ return;
+ }
+
+ for ( i=0; i<n_events; i++ ) {
+ add_file_to_project(proj, filename, events[i]);
+ free(events[i]);
+ }
+ free(events);
+}
+
+
+static void add_files(struct crystfelproject *proj, GFile *folder,
+ enum match_type_id type,
+ const DataTemplate *dtempl)
+{
+ GFileEnumerator *fenum;
+ GFileInfo *finfo;
+ GError *error = NULL;
+
+ fenum = g_file_enumerate_children(folder, "standard::name,standard::type",
+ G_FILE_QUERY_INFO_NONE,
+ NULL, &error);
+
+ do {
+
+ GFile *file;
+
+ finfo = g_file_enumerator_next_file(fenum, NULL, &error);
+
+ if ( error != NULL ) {
+ STATUS("Error!\n");
+ g_object_unref(fenum);
+ return;
+ }
+
+ if ( finfo == NULL ) continue;
+
+ file = g_file_get_child(folder, g_file_info_get_name(finfo));
+
+ if ( g_file_info_get_file_type(finfo) == G_FILE_TYPE_DIRECTORY ) {
+
+ add_files(proj, file, type, dtempl);
+
+ } else {
+
+ char *bn = g_file_get_basename(file);
+ if ( match_filename(bn, type) ) {
+ add_all_events(proj, g_file_get_path(file),
+ dtempl);
+ }
+
+ }
+
+ g_object_unref(finfo);
+
+ } while ( finfo != NULL );
+
+ g_object_unref(fenum);
+}
+
+
+static void add_frames_from_stream(Stream *st,
+ DataTemplate *dtempl,
+ struct crystfelproject *proj)
+{
+ do {
+ struct image *image;
+ image = stream_read_chunk(st, 0);
+ if ( image == NULL ) break;
+ add_file_to_project(proj, image->filename, image->ev);
+ image_free(image);
+
+ } while ( 1 );
+}
+
+
+struct finddata_ctx
+{
+ struct crystfelproject *proj;
+ GtkWidget *geom_file;
+
+ /* "Select individual file" */
+ GtkWidget *indiv;
+ GtkWidget *indiv_chooser;
+
+ /* Read list of files */
+ GtkWidget *list; /* "Import list" radio */
+ GtkWidget *list_chooser;
+
+ /* Search for files */
+ GtkWidget *search;
+ GtkWidget *search_chooser;
+ GtkWidget *search_pattern;
+
+ /* Load stream */
+ GtkWidget *stream;
+ GtkWidget *stream_chooser;
+
+ GtkWidget *dump;
+};
+
+enum import_mode
+{
+ IMPORT_FILES,
+ IMPORT_LIST,
+ IMPORT_SEARCH,
+ IMPORT_STREAM
+};
+
+
+static enum import_mode import_mode(struct finddata_ctx *ctx)
+{
+ if ( gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(ctx->indiv))) {
+ return IMPORT_FILES;
+ } else if ( gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(ctx->list))) {
+ return IMPORT_LIST;
+ } else if ( gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(ctx->search))) {
+ return IMPORT_SEARCH;
+ } else {
+ return IMPORT_STREAM;
+ }
+}
+
+
+static void finddata_typetoggle_sig(GtkWidget *radio,
+ struct finddata_ctx *ctx)
+{
+ gtk_widget_set_sensitive(ctx->indiv_chooser, FALSE);
+ gtk_widget_set_sensitive(ctx->list_chooser, FALSE);
+ gtk_widget_set_sensitive(ctx->search_chooser, FALSE);
+ gtk_widget_set_sensitive(ctx->search_pattern, FALSE);
+ gtk_widget_set_sensitive(ctx->stream_chooser, FALSE);
+
+ gtk_widget_set_sensitive(ctx->geom_file, TRUE);
+
+ switch ( import_mode(ctx) ) {
+
+ case IMPORT_FILES :
+ gtk_widget_set_sensitive(ctx->indiv_chooser, TRUE);
+ break;
+
+ case IMPORT_LIST :
+ gtk_widget_set_sensitive(ctx->list_chooser, TRUE);
+ break;
+
+ case IMPORT_SEARCH :
+ gtk_widget_set_sensitive(ctx->search_chooser, TRUE);
+ gtk_widget_set_sensitive(ctx->search_pattern, TRUE);
+ break;
+
+ case IMPORT_STREAM :
+ gtk_widget_set_sensitive(ctx->geom_file, FALSE);
+ gtk_widget_set_sensitive(ctx->stream_chooser, TRUE);
+ break;
+ }
+}
+
+
+static void import_via_search(struct finddata_ctx *ctx)
+{
+ GFile *top;
+ DataTemplate *dtempl;
+ char *geom_filename;
+ const char *type_id;
+ struct crystfelproject *proj = ctx->proj;
+
+ geom_filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(ctx->geom_file));
+ if ( geom_filename == NULL ) return;
+
+ top = gtk_file_chooser_get_file(GTK_FILE_CHOOSER(ctx->search_chooser));
+ if ( top == NULL ) return;
+
+ dtempl = data_template_new_from_file(geom_filename);
+ if ( dtempl == NULL ) return;
+
+ type_id = gtk_combo_box_get_active_id(GTK_COMBO_BOX(ctx->search_pattern));
+ proj->data_search_pattern = decode_matchtype(type_id);
+
+ /* Totally clean up the old list */
+ clear_project_files(proj);
+ crystfel_image_view_set_image(CRYSTFEL_IMAGE_VIEW(proj->imageview),
+ NULL);
+
+ g_free(proj->geom_filename);
+ proj->geom_filename = geom_filename;
+
+ data_template_free(proj->dtempl);
+ proj->dtempl = dtempl;
+
+ g_free(proj->data_top_folder);
+ proj->data_top_folder = g_file_get_path(top);
+
+ add_files(proj, top, proj->data_search_pattern,
+ proj->dtempl);
+
+ g_object_unref(top);
+}
+
+
+static void import_stream(struct finddata_ctx *ctx)
+{
+ struct crystfelproject *proj = ctx->proj;
+ Stream *st;
+ char *stream_filename;
+ DataTemplate *dtempl;
+ const char *geom_str;
+ char **streams;
+
+ stream_filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(ctx->stream_chooser));
+ if ( stream_filename == NULL ) return;
+
+ st = stream_open_for_read(stream_filename);
+ if ( st == NULL ) return;
+
+ geom_str = stream_geometry_file(st);
+ if ( geom_str == NULL ) {
+ ERROR("No geometry file\n");
+ stream_close(st);
+ return;
+ }
+
+ dtempl = data_template_new_from_string(geom_str);
+ if ( dtempl == NULL ) {
+ stream_close(st);
+ return;
+ }
+
+ clear_project_files(proj);
+ crystfel_image_view_set_image(CRYSTFEL_IMAGE_VIEW(proj->imageview),
+ NULL);
+
+ data_template_free(proj->dtempl);
+ proj->dtempl = dtempl;
+
+ /* Set some defaults for things we won't be using */
+ g_free(proj->geom_filename);
+ proj->geom_filename = NULL;
+ g_free(proj->data_top_folder);
+ proj->data_top_folder = NULL;
+ proj->data_search_pattern = MATCH_EVERYTHING;
+
+ add_frames_from_stream(st, proj->dtempl, proj);
+ proj->stream_filename = stream_filename;
+ stream_close(st);
+
+ streams = malloc(sizeof(char *));
+ if ( streams != NULL ) {
+ char *result_name = safe_basename(stream_filename);
+ streams[0] = strdup(stream_filename);
+ add_indexing_result(proj, result_name, streams, 1);
+ select_result(proj, result_name);
+ }
+
+ crystfel_image_view_set_show_peaks(CRYSTFEL_IMAGE_VIEW(proj->imageview),
+ 1);
+}
+
+
+static void finddata_response_sig(GtkWidget *dialog, gint resp,
+ struct finddata_ctx *ctx)
+{
+ struct crystfelproject *proj = ctx->proj;
+
+ if ( (resp == GTK_RESPONSE_DELETE_EVENT)
+ || (resp == GTK_RESPONSE_CANCEL) )
+ {
+ gtk_widget_destroy(dialog);
+ free(ctx);
+ return;
+ }
+
+ switch ( import_mode(ctx) ) {
+
+ case IMPORT_FILES :
+ /* FIXME */
+ break;
+
+ case IMPORT_LIST :
+ /* FIXME */
+ break;
+
+ case IMPORT_SEARCH :
+ import_via_search(ctx);
+ break;
+
+ case IMPORT_STREAM :
+ import_stream(ctx);
+ break;
+ }
+
+ proj->unsaved = 1;
+ proj->cur_frame = 0;
+ crystfel_image_view_reset_zoom(CRYSTFEL_IMAGE_VIEW(proj->imageview));
+ update_imageview(proj);
+
+ free(ctx);
+ gtk_widget_destroy(dialog);
+}
+
+
+gint import_sig(GtkWidget *widget, struct crystfelproject *proj)
+{
+ GtkWidget *dialog;
+ GtkWidget *content_area;
+ GtkWidget *vbox;
+ GtkWidget *hbox;
+ GtkWidget *label;
+ struct finddata_ctx *ctx;
+
+ ctx = malloc(sizeof(struct finddata_ctx));
+ if ( ctx == NULL ) return FALSE;
+
+ ctx->proj = proj;
+
+ dialog = gtk_dialog_new_with_buttons("Import data",
+ GTK_WINDOW(proj->window),
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ "Cancel", GTK_RESPONSE_CANCEL,
+ "Import", GTK_RESPONSE_ACCEPT,
+ NULL);
+
+ vbox = gtk_vbox_new(FALSE, 0.0);
+ content_area = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
+ gtk_container_add(GTK_CONTAINER(content_area), vbox);
+ gtk_container_set_border_width(GTK_CONTAINER(content_area), 8);
+
+ hbox = gtk_hbox_new(FALSE, 0.0);
+ gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(hbox), FALSE, FALSE, 8.0);
+ label = gtk_label_new("Geometry file:");
+ gtk_misc_set_alignment(GTK_MISC(label), 1.0, 0.5);
+ gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(label), FALSE, FALSE, 2.0);
+ ctx->geom_file = gtk_file_chooser_button_new("Select geometry file",
+ GTK_FILE_CHOOSER_ACTION_OPEN);
+ if ( proj->geom_filename != NULL ) {
+ gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(ctx->geom_file),
+ proj->geom_filename);
+ }
+ gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(ctx->geom_file), TRUE, TRUE, 2.0);
+
+ /* Select individual files */
+ hbox = gtk_hbox_new(FALSE, 0.0);
+ gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(hbox), FALSE, FALSE, 8.0);
+ ctx->indiv = gtk_radio_button_new_with_label(NULL,
+ "Select an individual file");
+ gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(ctx->indiv),
+ FALSE, FALSE, 4.0);
+ g_signal_connect(ctx->indiv, "toggled",
+ G_CALLBACK(finddata_typetoggle_sig), ctx);
+ ctx->indiv_chooser = gtk_file_chooser_button_new("Select file",
+ GTK_FILE_CHOOSER_ACTION_OPEN);
+ gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(ctx->indiv_chooser),
+ FALSE, FALSE, 4.0);
+
+ /* Pre-prepared list of files */
+ hbox = gtk_hbox_new(FALSE, 0.0);
+ gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(hbox), FALSE, FALSE, 8.0);
+ ctx->list = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(ctx->indiv),
+ "Read a list of files");
+ gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(ctx->list),
+ FALSE, FALSE, 4.0);
+ g_signal_connect(ctx->list, "toggled",
+ G_CALLBACK(finddata_typetoggle_sig), ctx);
+ ctx->list_chooser = gtk_file_chooser_button_new("Select the list of filenames",
+ GTK_FILE_CHOOSER_ACTION_OPEN);
+ gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(ctx->list_chooser),
+ FALSE, FALSE, 4.0);
+
+ /* Search in folder */
+ hbox = gtk_hbox_new(FALSE, 0.0);
+ gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(hbox), FALSE, FALSE, 2.0);
+ gtk_widget_set_margin_top(hbox, 6.0);
+ ctx->search = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(ctx->indiv),
+ "Search for files in folder");
+ gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(ctx->search),
+ FALSE, FALSE, 4.0);
+ g_signal_connect(ctx->search, "toggled",
+ G_CALLBACK(finddata_typetoggle_sig), ctx);
+ ctx->search_chooser = gtk_file_chooser_button_new("Select a folder",
+ GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER);
+ if ( proj->data_top_folder != NULL ) {
+ gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(ctx->search_chooser),
+ proj->data_top_folder);
+ }
+ gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(ctx->search_chooser),
+ TRUE, TRUE, 2.0);
+
+ hbox = gtk_hbox_new(FALSE, 0.0);
+ gtk_widget_set_margin_bottom(hbox, 6.0);
+ gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(hbox), FALSE, FALSE, 2.0);
+ label = gtk_label_new("Search pattern:");
+ gtk_misc_set_alignment(GTK_MISC(label), 1.0, 0.5);
+ gtk_widget_set_margin_start(label, 32);
+ gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(label), FALSE, FALSE, 2.0);
+ ctx->search_pattern = gtk_combo_box_text_new();
+ gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(ctx->search_pattern), TRUE, TRUE, 2.0);
+ gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(ctx->search_pattern), "everything",
+ "All files in folder and subfolders");
+ gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(ctx->search_pattern), "hdf5",
+ "All HDF5 files ('*.h5')");
+ gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(ctx->search_pattern), "lcls-cheetah-hdf5",
+ "Individual LCLS files from Cheetah ('LCLS*.h5')");
+ gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(ctx->search_pattern), "cheetah-cxi",
+ "Multi-event CXI files from Cheetah ('*.cxi')");
+ gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(ctx->search_pattern), "cbf",
+ "Individual CBF files ('*.cbf')");
+ gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(ctx->search_pattern), "cbfgz",
+ "Individual gzipped CBF files ('*.cbf.gz')");
+ gtk_combo_box_set_active(GTK_COMBO_BOX(ctx->search_pattern),
+ proj->data_search_pattern);
+
+ /* Load a stream */
+ hbox = gtk_hbox_new(FALSE, 0.0);
+ gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(hbox), FALSE, FALSE, 8.0);
+ ctx->stream = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(ctx->indiv),
+ "Load stream");
+ gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(ctx->stream),
+ FALSE, FALSE, 4.0);
+ ctx->stream_chooser = gtk_file_chooser_button_new("Select stream file",
+ GTK_FILE_CHOOSER_ACTION_OPEN);
+ if ( proj->stream_filename != NULL ) {
+ gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(ctx->stream_chooser),
+ proj->stream_filename);
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(ctx->stream), TRUE);
+ }
+ gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(ctx->stream_chooser),
+ TRUE, TRUE, 2.0);
+
+ /* Replace data toggle */
+ hbox = gtk_hbox_new(FALSE, 0.0);
+ gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(hbox), FALSE, FALSE, 8.0);
+ ctx->dump = gtk_check_button_new_with_label("Replace all the current data");
+ gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(ctx->dump), FALSE, FALSE, 4.0);
+
+ g_signal_connect(dialog, "response",
+ G_CALLBACK(finddata_response_sig), ctx);
+
+ gtk_window_set_default_size(GTK_WINDOW(dialog), 512, 0);
+ finddata_typetoggle_sig(ctx->search, ctx);
+ gtk_widget_show_all(dialog);
+ return FALSE;
+}
+
+