From: Mark Cave-Ayland Date: Sat, 4 Feb 2012 00:39:24 +0000 (+0000) Subject: Add shapefile dumper (table export) to the shp2pgsql GUI. This closes ticket #1480. X-Git-Tag: 2.0.0alpha4~79 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=80f9c1e00c8bfa38dc4081273b6450406f2bcaf4;p=postgis Add shapefile dumper (table export) to the shp2pgsql GUI. This closes ticket #1480. git-svn-id: http://svn.osgeo.org/postgis/trunk@9025 b70326c6-7e19-0410-871a-916f4a2858ee --- diff --git a/loader/shp2pgsql-gui.c b/loader/shp2pgsql-gui.c index 07e94a1eb..426e73d12 100644 --- a/loader/shp2pgsql-gui.c +++ b/loader/shp2pgsql-gui.c @@ -45,30 +45,49 @@ static void update_conn_ui_from_conn_config(void); static GtkWidget *window_main = NULL; static GtkWidget *textview_log = NULL; -static GtkWidget *add_file_button = NULL; static GtkTextBuffer *textbuffer_log = NULL; -/* Main window (listview) */ -GtkListStore *list_store; -GtkWidget *tree; -GtkCellRenderer *filename_renderer; -GtkCellRenderer *schema_renderer; -GtkCellRenderer *table_renderer; -GtkCellRenderer *geom_column_renderer; -GtkCellRenderer *srid_renderer; -GtkCellRenderer *mode_renderer; -GtkCellRenderer *remove_renderer; - -GtkTreeViewColumn *filename_column; -GtkTreeViewColumn *schema_column; -GtkTreeViewColumn *table_column; -GtkTreeViewColumn *geom_column; -GtkTreeViewColumn *srid_column; -GtkTreeViewColumn *mode_column; -GtkTreeViewColumn *remove_column; - -GtkWidget *mode_combo = NULL; -GtkListStore *combo_list; +/* Main import window (listview) */ +GtkListStore *import_file_list_store; +GtkWidget *import_tree; +GtkCellRenderer *import_filename_renderer; +GtkCellRenderer *import_schema_renderer; +GtkCellRenderer *import_table_renderer; +GtkCellRenderer *import_geom_column_renderer; +GtkCellRenderer *import_srid_renderer; +GtkCellRenderer *import_mode_renderer; +GtkCellRenderer *import_remove_renderer; + +GtkTreeViewColumn *import_filename_column; +GtkTreeViewColumn *import_schema_column; +GtkTreeViewColumn *import_table_column; +GtkTreeViewColumn *import_geom_column; +GtkTreeViewColumn *import_srid_column; +GtkTreeViewColumn *import_mode_column; +GtkTreeViewColumn *import_remove_column; + +static GtkWidget *add_file_button = NULL; + +GtkWidget *loader_mode_combo = NULL; +GtkListStore *loader_mode_combo_list; + +/* Main export window (listview) */ +GtkListStore *export_table_list_store; +GtkWidget *export_tree; +GtkWidget *export_geom_column_combo; +GtkCellRenderer *export_schema_renderer; +GtkCellRenderer *export_table_renderer; +GtkCellRenderer *export_geom_column_renderer; +GtkCellRenderer *export_filename_renderer; +GtkCellRenderer *export_remove_renderer; + +GtkTreeViewColumn *export_schema_column; +GtkTreeViewColumn *export_table_column; +GtkTreeViewColumn *export_geom_column; +GtkTreeViewColumn *export_filename_column; +GtkTreeViewColumn *export_remove_column; + +static GtkWidget *add_table_button = NULL; /* PostgreSQL database connection window */ static GtkWidget *window_conn = NULL; @@ -79,49 +98,67 @@ static GtkWidget *entry_pg_host = NULL; static GtkWidget *entry_pg_port = NULL; static GtkWidget *entry_pg_db = NULL; -/* Options window */ -static GtkWidget *dialog_options = NULL; +/* Loader options window */ +static GtkWidget *dialog_loader_options = NULL; static GtkWidget *entry_options_encoding = NULL; -static GtkWidget *checkbutton_options_preservecase = NULL; -static GtkWidget *checkbutton_options_forceint = NULL; -static GtkWidget *checkbutton_options_autoindex = NULL; -static GtkWidget *checkbutton_options_dbfonly = NULL; -static GtkWidget *checkbutton_options_dumpformat = NULL; -static GtkWidget *checkbutton_options_geography = NULL; +static GtkWidget *checkbutton_loader_options_preservecase = NULL; +static GtkWidget *checkbutton_loader_options_forceint = NULL; +static GtkWidget *checkbutton_loader_options_autoindex = NULL; +static GtkWidget *checkbutton_loader_options_dbfonly = NULL; +static GtkWidget *checkbutton_loader_options_dumpformat = NULL; +static GtkWidget *checkbutton_loader_options_geography = NULL; + +/* Dumper options window */ +static GtkWidget *dialog_dumper_options = NULL; +static GtkWidget *checkbutton_dumper_options_includegid = NULL; +static GtkWidget *checkbutton_dumper_options_keep_fieldname_case = NULL; +static GtkWidget *checkbutton_dumper_options_unescapedattrs = NULL; /* About dialog */ static GtkWidget *dialog_about = NULL; /* File chooser */ static GtkWidget *dialog_filechooser = NULL; +static GtkWidget *dialog_folderchooser = NULL; /* Progress dialog */ static GtkWidget *dialog_progress = NULL; static GtkWidget *progress = NULL; static GtkWidget *label_progress = NULL; +/* Table chooser dialog */ +static GtkWidget *dialog_tablechooser = NULL; +GtkListStore *chooser_filtered_table_list_store; +GtkListStore *chooser_table_list_store; +GtkWidget *chooser_tree; +GtkCellRenderer *chooser_schema_renderer; +GtkCellRenderer *chooser_table_renderer; +GtkTreeViewColumn *chooser_schema_column; +GtkTreeViewColumn *chooser_table_column; +static GtkWidget *checkbutton_chooser_geoonly = NULL; + /* Other items */ static int valid_connection = 0; /* Constants for the list view etc. */ enum { - POINTER_COLUMN, - FILENAME_COLUMN, - SCHEMA_COLUMN, - TABLE_COLUMN, - GEOMETRY_COLUMN, - SRID_COLUMN, - MODE_COLUMN, - REMOVE_COLUMN, - N_COLUMNS + IMPORT_POINTER_COLUMN, + IMPORT_FILENAME_COLUMN, + IMPORT_SCHEMA_COLUMN, + IMPORT_TABLE_COLUMN, + IMPORT_GEOMETRY_COLUMN, + IMPORT_SRID_COLUMN, + IMPORT_MODE_COLUMN, + IMPORT_REMOVE_COLUMN, + IMPORT_N_COLUMNS }; enum { - COMBO_TEXT, - COMBO_OPTION_CHAR, - COMBO_COLUMNS + LOADER_MODE_COMBO_TEXT, + LOADER_MODE_COMBO_OPTION_CHAR, + LOADER_MODE_COMBO_COLUMNS }; enum @@ -132,14 +169,42 @@ enum PREPARE_MODE }; +enum +{ + EXPORT_POINTER_COLUMN, + EXPORT_SCHEMA_COLUMN, + EXPORT_TABLE_COLUMN, + EXPORT_GEOMETRY_COLUMN, + EXPORT_GEOMETRY_LISTSTORE_COLUMN, + EXPORT_FILENAME_COLUMN, + EXPORT_REMOVE_COLUMN, + EXPORT_N_COLUMNS +}; + +enum +{ + TABLECHOOSER_SCHEMA_COLUMN, + TABLECHOOSER_TABLE_COLUMN, + TABLECHOOSER_GEO_LISTSTORE_COLUMN, + TABLECHOOSER_GEO_COLUMN, + TABLECHOOSER_HASGEO_COLUMN, + TABLECHOOSER_N_COLUMNS +}; + +enum +{ + TABLECHOOSER_GEOCOL_COMBO_TEXT, + TABLECHOOSER_GEOCOL_COMBO_COLUMNS +}; + /* Other */ static char *pgui_errmsg = NULL; static PGconn *pg_connection = NULL; -static SHPLOADERSTATE *state = NULL; static SHPCONNECTIONCONFIG *conn = NULL; static SHPLOADERCONFIG *global_loader_config = NULL; +static SHPDUMPERCONFIG *global_dumper_config = NULL; -static volatile int import_running = FALSE; +static volatile int is_running = FALSE; /* Local prototypes */ static void pgui_sanitize_connection_string(char *connection_string); @@ -364,24 +429,24 @@ update_filename_field_width(void) /* Loop through the list store to find the maximum length of an entry */ max_width = 0; - is_valid = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(list_store), &iter); + is_valid = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(import_file_list_store), &iter); while (is_valid) { /* Grab the length of the filename entry in characters */ - gtk_tree_model_get(GTK_TREE_MODEL(list_store), &iter, FILENAME_COLUMN, &filename, -1); + gtk_tree_model_get(GTK_TREE_MODEL(import_file_list_store), &iter, IMPORT_FILENAME_COLUMN, &filename, -1); if (strlen(filename) > max_width) max_width = strlen(filename); /* Get next entry */ - is_valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(list_store), &iter); + is_valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(import_file_list_store), &iter); } /* Note the layout manager will handle the minimum size for us; we just need to be concerned with making sure we don't exceed a maximum limit */ if (max_width > SHAPEFIELDMAXWIDTH) - g_object_set(filename_renderer, "width-chars", SHAPEFIELDMAXWIDTH, NULL); + g_object_set(import_filename_renderer, "width-chars", SHAPEFIELDMAXWIDTH, NULL); else - g_object_set(filename_renderer, "width-chars", -1, NULL); + g_object_set(import_filename_renderer, "width-chars", -1, NULL); return; } @@ -445,7 +510,7 @@ static void pgui_action_progress_cancel(GtkDialog *dialog, gint response_id, gpointer user_data) { /* Stop the current import */ - import_running = FALSE; + is_running = FALSE; return; } @@ -454,25 +519,25 @@ static gint pgui_action_progress_delete(GtkWidget *widget, GdkEvent *event, gpointer data) { /* Stop the current import */ - import_running = FALSE; + is_running = FALSE; return TRUE; } -/* === Option Window functions === */ +/* === Loader option Window functions === */ /* Update the specified SHPLOADERCONFIG with the global settings from the Options dialog */ static void update_loader_config_globals_from_options_ui(SHPLOADERCONFIG *config) { const char *entry_encoding = gtk_entry_get_text(GTK_ENTRY(entry_options_encoding)); - gboolean preservecase = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(checkbutton_options_preservecase)); - gboolean forceint = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(checkbutton_options_forceint)); - gboolean createindex = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(checkbutton_options_autoindex)); - gboolean dbfonly = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(checkbutton_options_dbfonly)); - gboolean dumpformat = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(checkbutton_options_dumpformat)); - gboolean geography = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(checkbutton_options_geography)); + gboolean preservecase = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(checkbutton_loader_options_preservecase)); + gboolean forceint = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(checkbutton_loader_options_forceint)); + gboolean createindex = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(checkbutton_loader_options_autoindex)); + gboolean dbfonly = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(checkbutton_loader_options_dbfonly)); + gboolean dumpformat = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(checkbutton_loader_options_dumpformat)); + gboolean geography = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(checkbutton_loader_options_geography)); if (geography) { @@ -540,17 +605,17 @@ update_loader_config_globals_from_options_ui(SHPLOADERCONFIG *config) return; } -/* Update the options dialog with the current values from the global config */ +/* Update the loader options dialog with the current values from the global config */ static void update_options_ui_from_loader_config_globals(void) { gtk_entry_set_text(GTK_ENTRY(entry_options_encoding), global_loader_config->encoding); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(checkbutton_options_preservecase), global_loader_config->quoteidentifiers ? TRUE : FALSE); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(checkbutton_options_forceint), global_loader_config->forceint4 ? TRUE : FALSE); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(checkbutton_options_autoindex), global_loader_config->createindex ? TRUE : FALSE); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(checkbutton_options_dbfonly), global_loader_config->readshape ? FALSE : TRUE); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(checkbutton_options_dumpformat), global_loader_config->dump_format ? TRUE : FALSE); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(checkbutton_options_geography), global_loader_config->geography ? TRUE : FALSE); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(checkbutton_loader_options_preservecase), global_loader_config->quoteidentifiers ? TRUE : FALSE); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(checkbutton_loader_options_forceint), global_loader_config->forceint4 ? TRUE : FALSE); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(checkbutton_loader_options_autoindex), global_loader_config->createindex ? TRUE : FALSE); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(checkbutton_loader_options_dbfonly), global_loader_config->readshape ? FALSE : TRUE); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(checkbutton_loader_options_dumpformat), global_loader_config->dump_format ? TRUE : FALSE); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(checkbutton_loader_options_geography), global_loader_config->geography ? TRUE : FALSE); return; } @@ -569,27 +634,256 @@ pgui_set_loader_configs_from_options_ui() /* Now also update the same settings for any existing files already added. We do this by looping through all entries and updating their config too. */ - is_valid = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(list_store), &iter); + is_valid = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(import_file_list_store), &iter); while (is_valid) { /* Get the SHPLOADERCONFIG for this file entry */ - gtk_tree_model_get(GTK_TREE_MODEL(list_store), &iter, POINTER_COLUMN, &gptr, -1); + gtk_tree_model_get(GTK_TREE_MODEL(import_file_list_store), &iter, IMPORT_POINTER_COLUMN, &gptr, -1); loader_file_config = (SHPLOADERCONFIG *)gptr; /* Update it */ update_loader_config_globals_from_options_ui(loader_file_config); /* Get next entry */ - is_valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(list_store), &iter); + is_valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(import_file_list_store), &iter); + } + + return; +} + + +/* === Table selection dialog functions === */ + +/* Load the model with information from the database */ +static void +update_table_chooser_from_database() +{ + PGresult *result, *geocol_result; + GtkTreeIter iter, geocol_iter; + GtkListStore *dumper_geocol_combo_list; + char *connection_string, *sql_form, *query, *schema, *table, *geocol_query, *geocol_name; + int hasgeo, i, j; + + /* Open a connection to the database */ + connection_string = ShpDumperGetConnectionStringFromConn(conn); + pg_connection = PQconnectdb(connection_string); + + /* Here we find a list of all tables/views that not in a pg_* schema (or information_schema) and + we return the schema name, table name and whether or not the table/view contains any geo + columns */ + query = "SELECT tableoids.oid, n.nspname, tableoids.relname, COALESCE((SELECT 1 from pg_attribute WHERE attrelid = tableoids.oid AND atttypid IN (SELECT oid FROM pg_type WHERE typname in ('geometry', 'geography')) LIMIT 1), 0) hasgeo FROM (SELECT c.oid, c.relname, c.relnamespace FROM pg_class c WHERE c.relkind IN ('r', 'v') AND c.relnamespace IN (SELECT oid FROM pg_namespace WHERE nspname NOT ILIKE 'pg_%' AND nspname <> 'information_schema')) tableoids, pg_namespace n WHERE tableoids.relnamespace = n.oid ORDER BY n.nspname, tableoids.relname"; + + result = PQexec(pg_connection, query); + + /* Free any existing entries in the model */ + gtk_list_store_clear(chooser_table_list_store); + + /* Now insert one row for each query result */ + for (i = 0; i < PQntuples(result); i++) + { + gtk_list_store_insert_before(chooser_table_list_store, &iter, NULL); + + /* Look up the geo columns; if there are none then we set the field to (None). If we have just one + column then we set the column name directly. If we have more than one then we create a combo + dropdown containing the column names */ + schema = PQgetvalue(result, i, PQfnumber(result, "nspname")); + table = PQgetvalue(result, i, PQfnumber(result, "relname")); + + sql_form = "SELECT n.nspname, c.relname, a.attname FROM pg_class c, pg_namespace n, pg_attribute a WHERE c.relnamespace = n.oid AND n.nspname = '%s' AND c.relname = '%s' AND a.attrelid = c.oid AND a.atttypid IN (SELECT oid FROM pg_type WHERE typname in ('geometry', 'geography'))"; + + geocol_query = malloc(strlen(sql_form) + strlen(schema) + strlen(table) + 1); + sprintf(geocol_query, sql_form, schema, table); + + geocol_result = PQexec(pg_connection, geocol_query); + + /* Create a combo list loaded with the column names. Note that while we create the model and load + the data here, we don't actually display the geo column in this dialog. Instead we build the + list here so that we can pass to the export table list store when creating a new entry. This + is to ensure that the export table list model can directly represent a SHPDUMPERCONFIG. */ + dumper_geocol_combo_list = gtk_list_store_new(TABLECHOOSER_GEOCOL_COMBO_COLUMNS, G_TYPE_STRING); + + if (PQntuples(geocol_result) > 0) + { + /* Load the columns into the list store */ + for (j = 0; j < PQntuples(geocol_result); j++) + { + geocol_name = PQgetvalue(geocol_result, j, PQfnumber(geocol_result, "attname")); + + gtk_list_store_insert_before(dumper_geocol_combo_list, &geocol_iter, TABLECHOOSER_GEOCOL_COMBO_TEXT); + gtk_list_store_set(dumper_geocol_combo_list, &geocol_iter, + TABLECHOOSER_GEOCOL_COMBO_TEXT, geocol_name, + -1); + } + } + else + { + /* Add a "default" entry */ + geocol_name = NULL; + + gtk_list_store_insert_before(dumper_geocol_combo_list, &geocol_iter, TABLECHOOSER_GEOCOL_COMBO_TEXT); + gtk_list_store_set(dumper_geocol_combo_list, &geocol_iter, + TABLECHOOSER_GEOCOL_COMBO_TEXT, _("(None)"), + -1); + } + + /* Free the query result */ + PQclear(geocol_result); + + /* Free the query string */ + free(geocol_query); + + /* Set the list store data */ + hasgeo = atoi(PQgetvalue(result, i, PQfnumber(result, "hasgeo"))); + gtk_list_store_set(chooser_table_list_store, &iter, + TABLECHOOSER_SCHEMA_COLUMN, schema, + TABLECHOOSER_TABLE_COLUMN, table, + TABLECHOOSER_GEO_LISTSTORE_COLUMN, dumper_geocol_combo_list, + TABLECHOOSER_GEO_COLUMN, geocol_name, + TABLECHOOSER_HASGEO_COLUMN, hasgeo, + -1); + } + + /* Clear up the result set */ + PQclear(result); + + /* Close the existing connection */ + PQfinish(pg_connection); + pg_connection = NULL; + + return; +} + +/* GtkTreeModelFilter visibility function */ +static gboolean +table_chooser_visibility_func(GtkTreeModel *model, GtkTreeIter *iter, gpointer data) +{ + /* First determine whether the hasgeo tickbox is selected or not */ + gboolean geoonly = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(checkbutton_chooser_geoonly)); + int hasgeo; + + /* If unticked then we show all tables */ + if (!geoonly) + return TRUE; + else + { + /* Otherwise we only show the tables with geo columns */ + gtk_tree_model_get(GTK_TREE_MODEL(model), iter, TABLECHOOSER_HASGEO_COLUMN, &hasgeo, -1); + if (hasgeo) + return TRUE; + else + return FALSE; + } + + return FALSE; +} + +/* === Dumper option Window functions === */ + +/* Update the specified SHPDUMPERCONFIG with the global settings from the Options dialog */ +static void +update_dumper_config_globals_from_options_ui(SHPDUMPERCONFIG *config) +{ + gboolean includegid = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(checkbutton_dumper_options_includegid)); + gboolean keep_fieldname_case = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(checkbutton_dumper_options_keep_fieldname_case)); + gboolean unescapedattrs = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(checkbutton_dumper_options_unescapedattrs)); + + /* Include gid or not */ + if (includegid) + config->includegid = 1; + else + config->includegid = 0; + + /* Keep fieldname case */ + if (keep_fieldname_case) + config->keep_fieldname_case = 1; + else + config->keep_fieldname_case = 0; + + /* Escape column names or not */ + if (unescapedattrs) + config->unescapedattrs = 1; + else + config->unescapedattrs = 0; + + return; +} + +/* Update the options dialog with the current values from the global config */ +static void +update_options_ui_from_dumper_config_globals(void) +{ + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(checkbutton_dumper_options_includegid), global_dumper_config->includegid ? TRUE : FALSE); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(checkbutton_dumper_options_keep_fieldname_case), global_dumper_config->keep_fieldname_case ? TRUE : FALSE); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(checkbutton_dumper_options_unescapedattrs), global_dumper_config->unescapedattrs ? TRUE : FALSE); + + return; +} + +/* Set the global config variables controlled by the options dialogue */ +static void +pgui_set_dumper_configs_from_options_ui() +{ + GtkTreeIter iter; + gboolean is_valid; + gpointer gptr; + SHPDUMPERCONFIG *dumper_table_config; + + /* First update the global (template) configuration */ + update_dumper_config_globals_from_options_ui(global_dumper_config); + + /* Now also update the same settings for any existing tables already added. We + do this by looping through all entries and updating their config too. */ + is_valid = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(export_table_list_store), &iter); + while (is_valid) + { + /* Get the SHPDUMPERCONFIG for this file entry */ + gtk_tree_model_get(GTK_TREE_MODEL(export_table_list_store), &iter, EXPORT_POINTER_COLUMN, &gptr, -1); + dumper_table_config = (SHPDUMPERCONFIG *)gptr; + + /* Update it */ + update_dumper_config_globals_from_options_ui(dumper_table_config); + + /* Get next entry */ + is_valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(export_table_list_store), &iter); } + + return; +} + +/* Signal handler for ticking/unticking the "only show geo columns" box */ +static void +pgui_action_chooser_toggle_show_geocolumn(GtkToggleButton *togglebutton, gpointer user_data) +{ + /* Simply update the listview filter */ + gtk_tree_model_filter_refilter(GTK_TREE_MODEL_FILTER(chooser_filtered_table_list_store)); return; } +static void +pgui_action_dumper_options_open(GtkWidget *widget, gpointer data) +{ + update_options_ui_from_dumper_config_globals(); + gtk_widget_show_all(dialog_dumper_options); + return; +} + +static void +pgui_action_dumper_options_close(GtkWidget *widget, gint response, gpointer data) +{ + /* Only update the configuration if the user hit OK */ + if (response == GTK_RESPONSE_OK) + pgui_set_dumper_configs_from_options_ui(); + + /* Hide the dialog */ + gtk_widget_hide(dialog_dumper_options); + + return; +} /* === Main window functions === */ -/* Given a filename, generate a new configuration and add it to the listview */ +/* Given a filename, generate a new loader configuration */ static SHPLOADERCONFIG * create_new_file_config(const char *filename) { @@ -660,15 +954,15 @@ add_loader_file_config_to_list(SHPLOADERCONFIG *loader_file_config) /* Convert SRID into string */ lw_asprintf(&srid, "%d", loader_file_config->sr_id); - gtk_list_store_insert_before(list_store, &iter, NULL); - gtk_list_store_set(list_store, &iter, - POINTER_COLUMN, loader_file_config, - FILENAME_COLUMN, loader_file_config->shp_file, - SCHEMA_COLUMN, loader_file_config->schema, - TABLE_COLUMN, loader_file_config->table, - GEOMETRY_COLUMN, loader_file_config->geo_col, - SRID_COLUMN, srid, - MODE_COLUMN, _("Create"), + gtk_list_store_insert_before(import_file_list_store, &iter, NULL); + gtk_list_store_set(import_file_list_store, &iter, + IMPORT_POINTER_COLUMN, loader_file_config, + IMPORT_FILENAME_COLUMN, loader_file_config->shp_file, + IMPORT_SCHEMA_COLUMN, loader_file_config->schema, + IMPORT_TABLE_COLUMN, loader_file_config->table, + IMPORT_GEOMETRY_COLUMN, loader_file_config->geo_col, + IMPORT_SRID_COLUMN, srid, + IMPORT_MODE_COLUMN, _("Create"), -1); /* Update the filename field width */ @@ -707,6 +1001,96 @@ free_loader_config(SHPLOADERCONFIG *config) free(config); } +/* Given a table selection, generate a new configuration */ +static SHPDUMPERCONFIG * +create_new_table_config(GtkTreeIter *iter) +{ + SHPDUMPERCONFIG *dumper_table_config; + gchar *schema, *table, *geocol; + gint hasgeo; + + /* Generate a new configuration by copying the global options first and then + adding in the specific values for this table */ + dumper_table_config = malloc(sizeof(SHPDUMPERCONFIG)); + memcpy(dumper_table_config, global_dumper_config, sizeof(SHPDUMPERCONFIG)); + + /* Grab the values from the current iter */ + gtk_tree_model_get(GTK_TREE_MODEL(chooser_filtered_table_list_store), iter, + TABLECHOOSER_SCHEMA_COLUMN, &schema, + TABLECHOOSER_TABLE_COLUMN, &table, + TABLECHOOSER_GEO_COLUMN, &geocol, + TABLECHOOSER_HASGEO_COLUMN, &hasgeo, + -1); + + /* Set up the values in the SHPDUMPERCONFIG */ + dumper_table_config->schema = strdup(schema); + dumper_table_config->table = strdup(table); + + /* We also set the filename the same as the table name */ + dumper_table_config->shp_file = strdup(table); + + if (hasgeo && geocol) + dumper_table_config->geo_col_name = strdup(geocol); + else + dumper_table_config->geo_col_name = NULL; + + return dumper_table_config; +} + +/* Given the dumper configuration, add a new row representing this file to the listview. The liststore and iter arguments +are optional, and enable the user to specify additional information to the view, e.g. geo column multi-choice. */ +static void +add_dumper_table_config_to_list(SHPDUMPERCONFIG *dumper_table_config, GtkListStore *chooser_liststore, GtkTreeIter *chooser_iter) +{ + GtkTreeIter iter; + GtkListStore *geocol_liststore; + + gtk_list_store_insert_before(export_table_list_store, &iter, NULL); + gtk_list_store_set(export_table_list_store, &iter, + EXPORT_POINTER_COLUMN, dumper_table_config, + EXPORT_SCHEMA_COLUMN, dumper_table_config->schema, + EXPORT_TABLE_COLUMN, dumper_table_config->table, + EXPORT_GEOMETRY_COLUMN, dumper_table_config->geo_col_name, + EXPORT_FILENAME_COLUMN, dumper_table_config->shp_file, + -1); + + /* If we have supplied the table_chooser store for additional information, use it */ + if (chooser_liststore) + { + /* Let's add a multi-choice geometry column to the table */ + gtk_tree_model_get(GTK_TREE_MODEL(chooser_liststore), chooser_iter, + TABLECHOOSER_GEO_LISTSTORE_COLUMN, &geocol_liststore, + -1); + + gtk_list_store_set(export_table_list_store, &iter, + EXPORT_GEOMETRY_LISTSTORE_COLUMN, geocol_liststore, + -1); + } + + return; +} + +/* Free up the specified SHPDUMPERCONFIG */ +static void +free_dumper_config(SHPDUMPERCONFIG *config) +{ + + if (config->table) + free(config->table); + + if (config->schema) + free(config->schema); + + if (config->geo_col_name) + free(config->geo_col_name); + + if (config->shp_file) + free(config->shp_file); + + /* Free the config itself */ + free(config); +} + /* Validate a single DBF column type against a PostgreSQL type: return either TRUE or FALSE depending upon whether or not the type is (broadly) compatible */ static int @@ -755,6 +1139,7 @@ static int validate_remote_loader_columns(SHPLOADERCONFIG *config, PGresult *result) { ExecStatusType status; + SHPLOADERSTATE *state; int ntuples; char *pg_fieldname, *pg_fieldtype; int ret, i, j, found, response = SHPLOADEROK; @@ -868,29 +1253,29 @@ pgui_action_about_open() static void pgui_action_cancel(GtkWidget *widget, gpointer data) { - if (!import_running) + if (!is_running) pgui_quit(widget, data); /* quit if we're not running */ else - import_running = FALSE; + is_running = FALSE; } static void -pgui_action_options_open(GtkWidget *widget, gpointer data) +pgui_action_loader_options_open(GtkWidget *widget, gpointer data) { update_options_ui_from_loader_config_globals(); - gtk_widget_show_all(dialog_options); + gtk_widget_show_all(dialog_loader_options); return; } static void -pgui_action_options_close(GtkWidget *widget, gint response, gpointer data) +pgui_action_loader_options_close(GtkWidget *widget, gint response, gpointer data) { /* Only update the configuration if the user hit OK */ if (response == GTK_RESPONSE_OK) pgui_set_loader_configs_from_options_ui(); /* Hide the dialog */ - gtk_widget_hide(dialog_options); + gtk_widget_hide(dialog_loader_options); return; } @@ -911,21 +1296,105 @@ pgui_action_open_file_dialog(GtkWidget *widget, gpointer data) gtk_widget_hide(dialog_filechooser); } +static void +pgui_action_open_table_dialog(GtkWidget *widget, gpointer data) +{ + SHPDUMPERCONFIG *dumper_table_config; + GtkTreeSelection *chooser_selection; + GtkTreeModel *model; + GList *selected_rows_list, *selected_row; + GtkTreeIter iter; + GtkTreePath *tree_path; + + /* Make sure we can connect to the database first */ + if (!connection_test()) + { + pgui_seterr(_("Unable to connect to the database - please check your connection settings")); + pgui_raise_error_dialogue(); + + /* Open the connections UI for the user */ + update_conn_ui_from_conn_config(); + + gtk_widget_show_all(GTK_WIDGET(window_conn)); + return; + } + + /* Setup the form */ + update_table_chooser_from_database(); + gtk_tree_model_filter_refilter(GTK_TREE_MODEL_FILTER(chooser_filtered_table_list_store)); + + /* Run the dialog */ + gtk_widget_show_all(dialog_tablechooser); + if (gtk_dialog_run(GTK_DIALOG(dialog_tablechooser)) == GTK_RESPONSE_OK) + { + /* Create the new dumper configuration based upon the selected iters and add them to the listview */ + chooser_selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(chooser_tree)); + + selected_rows_list = gtk_tree_selection_get_selected_rows(chooser_selection, &model); + selected_row = g_list_first(selected_rows_list); + while (selected_row) + { + /* Get the tree iter */ + tree_path = (GtkTreePath *)g_list_nth_data(selected_row, 0); + gtk_tree_model_get_iter(model, &iter, tree_path); + + /* Get the config and add it to the list */ + dumper_table_config = create_new_table_config(&iter); + add_dumper_table_config_to_list(dumper_table_config, chooser_filtered_table_list_store, &iter); + + /* Get the next row */ + selected_row = g_list_next(selected_row); + } + + /* Free the GList */ + g_list_foreach(selected_row, (GFunc)gtk_tree_path_free, NULL); + g_list_free(selected_row); + } + + gtk_widget_hide(dialog_tablechooser); +} + +/* + * Signal handler for the remove box. Performs no user interaction, simply + * removes the row from the table. + */ +static void +pgui_action_handle_table_remove(GtkCellRendererToggle *renderer, + gchar *path, + gpointer user_data) +{ + GtkTreeIter iter; + SHPDUMPERCONFIG *dumper_table_config; + gpointer gptr; + + /* Grab the SHPDUMPERCONFIG from the EXPORT_POINTER_COLUMN for the list store */ + gtk_tree_model_get_iter_from_string(GTK_TREE_MODEL(export_table_list_store), &iter, path); + gtk_tree_model_get(GTK_TREE_MODEL(export_table_list_store), &iter, EXPORT_POINTER_COLUMN, &gptr, -1); + dumper_table_config = (SHPDUMPERCONFIG *)gptr; + + /* Free the configuration from memory */ + free_dumper_config(dumper_table_config); + + /* Remove the row from the list */ + gtk_list_store_remove(export_table_list_store, &iter); +} + static void pgui_action_import(GtkWidget *widget, gpointer data) { SHPLOADERCONFIG *loader_file_config; + SHPLOADERSTATE *state; gint is_valid; gpointer gptr; GtkTreeIter iter; - char *sql_form, *query, *progress_text = NULL, *progress_shapefile = NULL; + char *sql_form, *query, *connection_string, *progress_text = NULL, *progress_shapefile = NULL; PGresult *result; - char *connection_string = NULL; + int ret, success, i = 0; char *header, *footer, *record; /* Get the first row of the import list */ - is_valid = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(list_store), &iter); + is_valid = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(import_file_list_store), &iter); if (!is_valid) { pgui_seterr(_("ERROR: You haven't specified any files to import")); @@ -961,7 +1430,7 @@ pgui_action_import(GtkWidget *widget, gpointer data) while (is_valid) { /* Grab the SHPLOADERCONFIG for this row */ - gtk_tree_model_get(GTK_TREE_MODEL(list_store), &iter, POINTER_COLUMN, &gptr, -1); + gtk_tree_model_get(GTK_TREE_MODEL(import_file_list_store), &iter, IMPORT_POINTER_COLUMN, &gptr, -1); loader_file_config = (SHPLOADERCONFIG *)gptr; /* For each entry, we execute a remote query in order to determine the column names @@ -987,7 +1456,7 @@ pgui_action_import(GtkWidget *widget, gpointer data) free(query); /* Get next entry */ - is_valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(list_store), &iter); + is_valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(import_file_list_store), &iter); } /* Close our database connection */ @@ -995,11 +1464,11 @@ pgui_action_import(GtkWidget *widget, gpointer data) /* Once we've done the validation pass, now let's load the shapefile */ - is_valid = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(list_store), &iter); + is_valid = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(import_file_list_store), &iter); while (is_valid) { /* Grab the SHPLOADERCONFIG for this row */ - gtk_tree_model_get(GTK_TREE_MODEL(list_store), &iter, POINTER_COLUMN, &gptr, -1); + gtk_tree_model_get(GTK_TREE_MODEL(import_file_list_store), &iter, IMPORT_POINTER_COLUMN, &gptr, -1); loader_file_config = (SHPLOADERCONFIG *)gptr; pgui_logf("\n=============================="); @@ -1008,7 +1477,7 @@ pgui_action_import(GtkWidget *widget, gpointer data) /* * Loop through the items in the shapefile */ - import_running = TRUE; + is_running = TRUE; success = FALSE; /* One connection per file, otherwise error handling becomes tricky... */ @@ -1097,7 +1566,7 @@ pgui_action_import(GtkWidget *widget, gpointer data) } /* Main loop: iterate through all of the records and send them to stdout */ - for (i = 0; i < ShpLoaderGetRecordCount(state) && import_running; i++) + for (i = 0; i < ShpLoaderGetRecordCount(state) && is_running; i++) { ret = ShpLoaderGenerateSQLRowStatement(state, i, &record); @@ -1173,7 +1642,7 @@ pgui_action_import(GtkWidget *widget, gpointer data) } /* if (state->config->opt != 'p') */ /* Only continue if we didn't abort part way through */ - if (import_running) + if (is_running) { /* Get the footer */ ret = ShpLoaderGetSQLFooter(state, &footer); @@ -1208,7 +1677,7 @@ pgui_action_import(GtkWidget *widget, gpointer data) import_cleanup: /* Import has definitely stopped running */ - import_running = FALSE; + is_running = FALSE; /* Close the existing connection */ PQfinish(pg_connection); @@ -1231,11 +1700,11 @@ import_cleanup: free(progress_shapefile); /* Get next entry */ - is_valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(list_store), &iter); + is_valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(import_file_list_store), &iter); } /* Import has definitely finished */ - import_running = FALSE; + is_running = FALSE; /* Enable the button once again */ gtk_widget_set_sensitive(widget, TRUE); @@ -1257,37 +1726,254 @@ import_cleanup: return; } - -/* === ListView functions and signal handlers === */ - -/* Creates a single file row in the list table given the URI of a file */ static void -process_single_uri(char *uri) -{ - SHPLOADERCONFIG *loader_file_config; - char *filename = NULL; - char *hostname; - GError *error = NULL; - - if (uri == NULL) +pgui_action_export(GtkWidget *widget, gpointer data) +{ + SHPDUMPERCONFIG *dumper_table_config; + SHPDUMPERSTATE *state; + gint is_valid; + gpointer gptr; + GtkTreeIter iter; + char *output_shapefile, *orig_shapefile, *progress_text = NULL; + gchar *folder_path; + + int ret, success, i = 0; + + /* Get the first row of the import list */ + is_valid = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(export_table_list_store), &iter); + if (!is_valid) { - pgui_logf(_("Unable to process drag URI.")); + pgui_seterr(_("ERROR: You haven't specified any tables to export")); + pgui_raise_error_dialogue(); + return; } - filename = g_filename_from_uri(uri, &hostname, &error); - g_free(uri); - - if (filename == NULL) + /* Firstly make sure that we can connect to the database - if we can't then there isn't much + point doing anything else... */ + if (!connection_test()) { - pgui_logf(_("Unable to process filename: %s\n"), error->message); - g_error_free(error); + pgui_seterr(_("Unable to connect to the database - please check your connection settings")); + pgui_raise_error_dialogue(); + + /* Open the connections UI for the user */ + update_conn_ui_from_conn_config(); + + gtk_widget_show_all(GTK_WIDGET(window_conn)); return; } - /* Create a new row in the listview */ - loader_file_config = create_new_file_config(filename); - add_loader_file_config_to_list(loader_file_config); + /* Now open the file selector dialog so the user can specify where they would like the output + files to reside */ + if (gtk_dialog_run(GTK_DIALOG(dialog_folderchooser)) != GTK_RESPONSE_ACCEPT) + { + gtk_widget_hide(dialog_folderchooser); + + return; + } + + gtk_widget_hide(dialog_folderchooser); + folder_path = gtk_file_chooser_get_current_folder(GTK_FILE_CHOOSER(dialog_folderchooser)); + + /* Loop through each of the files and set the output filename to the path with the table name + appended. We do this as a separate pass here in case we wish to do any validation in future. */ + while (is_valid) + { + /* Grab the SHPDUMPERCONFIG for this row */ + gtk_tree_model_get(GTK_TREE_MODEL(export_table_list_store), &iter, EXPORT_POINTER_COLUMN, &gptr, -1); + dumper_table_config = (SHPDUMPERCONFIG *)gptr; + + orig_shapefile = dumper_table_config->shp_file; + output_shapefile = malloc(strlen(folder_path) + strlen(dumper_table_config->shp_file) + 2); + strcpy(output_shapefile, folder_path); + strcat(output_shapefile, G_DIR_SEPARATOR_S); + strcat(output_shapefile, dumper_table_config->shp_file); + + dumper_table_config->shp_file = output_shapefile; + + /* Get next entry */ + is_valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(export_table_list_store), &iter); + } + + /* Now everything is set up, let's extract the tables */ + is_valid = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(export_table_list_store), &iter); + while (is_valid) + { + /* Grab the SHPDUMPERCONFIG for this row */ + gtk_tree_model_get(GTK_TREE_MODEL(export_table_list_store), &iter, EXPORT_POINTER_COLUMN, &gptr, -1); + dumper_table_config = (SHPDUMPERCONFIG *)gptr; + + pgui_logf("\n=============================="); + pgui_logf("Exporting with configuration: %s, %s, %s", dumper_table_config->table, dumper_table_config->schema, dumper_table_config->shp_file); + + /* Export is running */ + is_running = TRUE; + success = FALSE; + + /* Disable the button to prevent multiple imports running at the same time */ + gtk_widget_set_sensitive(widget, FALSE); + + /* Allow GTK events to get a look in */ + while (gtk_events_pending()) + gtk_main_iteration(); + + /* Create the state for each configuration */ + state = ShpDumperCreate(dumper_table_config); + state->config->conn = conn; + + ret = ShpDumperConnectDatabase(state); + if (ret != SHPDUMPEROK) + { + pgui_seterr("%s", state->message); + pgui_raise_error_dialogue(); + + goto export_cleanup; + } + + /* Display the progress dialog */ + gtk_label_set_text(GTK_LABEL(label_progress), _("Initialising...")); + gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(progress), 0.0); + gtk_widget_show_all(dialog_progress); + + ret = ShpDumperOpenTable(state); + if (ret != SHPDUMPEROK) + { + pgui_logf("%s", state->message); + + if (ret == SHPDUMPERERR) + { + gtk_widget_hide(dialog_progress); + + pgui_seterr("%s", state->message); + pgui_raise_error_dialogue(); + + goto export_cleanup; + } + } + + /* Update the text */ + lw_asprintf(&progress_text, _("Exporting table %s (%d records)..."), dumper_table_config->table, ShpDumperGetRecordCount(state)); + gtk_label_set_text(GTK_LABEL(label_progress), progress_text); + + /* Allow GTK events to get a look in */ + while (gtk_events_pending()) + gtk_main_iteration(); + + pgui_logf(_("Done (postgis major version: %d)"), state->pgis_major_version); + pgui_logf(_("Output shape: %s"), shapetypename(state->outshptype)); + + for (i = 0; i < ShpDumperGetRecordCount(state) && is_running == TRUE; i++) + { + ret = ShpLoaderGenerateShapeRow(state); + if (ret != SHPDUMPEROK) + { + pgui_logf("%s", state->message); + + if (ret == SHPDUMPERERR) + { + gtk_widget_hide(dialog_progress); + + pgui_seterr("%s", state->message); + pgui_raise_error_dialogue(); + + goto export_cleanup; + } + } + + /* Update the progress bar */ + gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(progress), (float)i / ShpDumperGetRecordCount(state)); + + /* Allow GTK events to get a look in */ + while (gtk_events_pending()) + gtk_main_iteration(); + } + + /* Finish the dump */ + ret = ShpDumperCloseTable(state); + if (ret != SHPDUMPEROK) + { + pgui_logf("%s", state->message); + + if (ret == SHPDUMPERERR) + { + gtk_widget_hide(dialog_progress); + + pgui_seterr("%s", state->message); + pgui_raise_error_dialogue(); + } + } + + /* Indicate success */ + if (is_running) + success = TRUE; + +export_cleanup: + + /* Tidy up everything */ + ShpDumperDestroy(state); + + /* Reset shapefile back to original form (without full path) */ + dumper_table_config->shp_file = orig_shapefile; + + /* Get next entry */ + is_valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(export_table_list_store), &iter); + } + + /* Export has definitely finished */ + is_running = FALSE; + if (!success) + pgui_logf(_("Table export failed.")); + else + pgui_logf(_("Table export completed.")); + + /* Enable the button once again */ + gtk_widget_set_sensitive(widget, TRUE); + + /* Silly GTK bug means we have to hide and show the button for it to work again! */ + gtk_widget_hide(widget); + gtk_widget_show(widget); + + /* Hide the progress dialog */ + gtk_widget_hide(dialog_progress); + + /* Allow GTK events to get a look in */ + while (gtk_events_pending()) + gtk_main_iteration(); + + return; +} + + +/* === Import ListView functions and signal handlers === */ + +/* Creates a single file row in the list table given the URI of a file */ +static void +process_single_uri(char *uri) +{ + SHPLOADERCONFIG *loader_file_config; + char *filename = NULL; + char *hostname; + GError *error = NULL; + + if (uri == NULL) + { + pgui_logf(_("Unable to process drag URI.")); + return; + } + + filename = g_filename_from_uri(uri, &hostname, &error); + g_free(uri); + + if (filename == NULL) + { + pgui_logf(_("Unable to process filename: %s\n"), error->message); + g_error_free(error); + return; + } + + /* Create a new row in the listview */ + loader_file_config = create_new_file_config(filename); + add_loader_file_config_to_list(loader_file_config); g_free(filename); g_free(hostname); @@ -1301,11 +1987,11 @@ update_loader_file_config_from_listview_iter(GtkTreeIter *iter, SHPLOADERCONFIG gchar *schema, *table, *geo_col, *srid; /* Grab the main values for this file */ - gtk_tree_model_get(GTK_TREE_MODEL(list_store), iter, - SCHEMA_COLUMN, &schema, - TABLE_COLUMN, &table, - GEOMETRY_COLUMN, &geo_col, - SRID_COLUMN, &srid, + gtk_tree_model_get(GTK_TREE_MODEL(import_file_list_store), iter, + IMPORT_SCHEMA_COLUMN, &schema, + IMPORT_TABLE_COLUMN, &table, + IMPORT_GEOMETRY_COLUMN, &geo_col, + IMPORT_SRID_COLUMN, &srid, -1); /* Update the schema */ @@ -1403,13 +2089,13 @@ pgui_action_handle_tree_combo(GtkCellRendererCombo *combo, gchar *combo_text; gpointer gptr; - /* Grab the SHPLOADERCONFIG from the POINTER_COLUMN for the list store */ - gtk_tree_model_get_iter_from_string(GTK_TREE_MODEL(list_store), &iter, path_string); - gtk_tree_model_get(GTK_TREE_MODEL(list_store), &iter, POINTER_COLUMN, &gptr, -1); + /* Grab the SHPLOADERCONFIG from the IMPORT_POINTER_COLUMN for the list store */ + gtk_tree_model_get_iter_from_string(GTK_TREE_MODEL(import_file_list_store), &iter, path_string); + gtk_tree_model_get(GTK_TREE_MODEL(import_file_list_store), &iter, IMPORT_POINTER_COLUMN, &gptr, -1); loader_file_config = (SHPLOADERCONFIG *)gptr; /* Now grab the row selected within the combo box */ - gtk_tree_model_get(GTK_TREE_MODEL(combo_list), new_iter, COMBO_OPTION_CHAR, &opt, -1); + gtk_tree_model_get(GTK_TREE_MODEL(loader_mode_combo_list), new_iter, LOADER_MODE_COMBO_OPTION_CHAR, &opt, -1); /* Update the configuration */ @@ -1441,8 +2127,8 @@ pgui_action_handle_tree_combo(GtkCellRendererCombo *combo, } /* Update the selection in the listview with the text from the combo */ - gtk_tree_model_get(GTK_TREE_MODEL(combo_list), new_iter, COMBO_TEXT, &combo_text, -1); - gtk_list_store_set(list_store, &iter, MODE_COLUMN, combo_text, -1); + gtk_tree_model_get(GTK_TREE_MODEL(loader_mode_combo_list), new_iter, LOADER_MODE_COMBO_TEXT, &combo_text, -1); + gtk_list_store_set(import_file_list_store, &iter, IMPORT_MODE_COLUMN, combo_text, -1); return; } @@ -1455,7 +2141,7 @@ pgui_action_handle_tree_combo(GtkCellRendererCombo *combo, * are applied and the various validations called. */ static void -pgui_action_handle_tree_edit(GtkCellRendererText *renderer, +pgui_action_handle_loader_edit(GtkCellRendererText *renderer, gchar *path, gchar *new_text, gpointer column) @@ -1472,11 +2158,11 @@ pgui_action_handle_tree_edit(GtkCellRendererText *renderer, /* Update the model with the current edit change */ columnindex = *(gint *)column; - gtk_tree_model_get_iter_from_string(GTK_TREE_MODEL(list_store), &iter, path); - gtk_list_store_set(list_store, &iter, columnindex, new_text, -1); + gtk_tree_model_get_iter_from_string(GTK_TREE_MODEL(import_file_list_store), &iter, path); + gtk_list_store_set(import_file_list_store, &iter, columnindex, new_text, -1); - /* Grab the SHPLOADERCONFIG from the POINTER_COLUMN for the list store */ - gtk_tree_model_get(GTK_TREE_MODEL(list_store), &iter, POINTER_COLUMN, &gptr, -1); + /* Grab the SHPLOADERCONFIG from the IMPORT_POINTER_COLUMN for the list store */ + gtk_tree_model_get(GTK_TREE_MODEL(import_file_list_store), &iter, IMPORT_POINTER_COLUMN, &gptr, -1); loader_file_config = (SHPLOADERCONFIG *)gptr; /* Update the configuration from the current UI data */ @@ -1485,11 +2171,11 @@ pgui_action_handle_tree_edit(GtkCellRendererText *renderer, /* Now refresh the listview UI row with the new configuration */ lw_asprintf(&srid, "%d", loader_file_config->sr_id); - gtk_list_store_set(list_store, &iter, - SCHEMA_COLUMN, loader_file_config->schema, - TABLE_COLUMN, loader_file_config->table, - GEOMETRY_COLUMN, loader_file_config->geo_col, - SRID_COLUMN, srid, + gtk_list_store_set(import_file_list_store, &iter, + IMPORT_SCHEMA_COLUMN, loader_file_config->schema, + IMPORT_TABLE_COLUMN, loader_file_config->table, + IMPORT_GEOMETRY_COLUMN, loader_file_config->geo_col, + IMPORT_SRID_COLUMN, srid, -1); return; @@ -1500,7 +2186,7 @@ pgui_action_handle_tree_edit(GtkCellRendererText *renderer, * removes the row from the table. */ static void -pgui_action_handle_tree_remove(GtkCellRendererToggle *renderer, +pgui_action_handle_file_remove(GtkCellRendererToggle *renderer, gchar *path, gpointer user_data) { @@ -1508,22 +2194,144 @@ pgui_action_handle_tree_remove(GtkCellRendererToggle *renderer, SHPLOADERCONFIG *loader_file_config; gpointer gptr; - /* Grab the SHPLOADERCONFIG from the POINTER_COLUMN for the list store */ - gtk_tree_model_get_iter_from_string(GTK_TREE_MODEL(list_store), &iter, path); - gtk_tree_model_get(GTK_TREE_MODEL(list_store), &iter, POINTER_COLUMN, &gptr, -1); + /* Grab the SHPLOADERCONFIG from the IMPORT_POINTER_COLUMN for the list store */ + gtk_tree_model_get_iter_from_string(GTK_TREE_MODEL(import_file_list_store), &iter, path); + gtk_tree_model_get(GTK_TREE_MODEL(import_file_list_store), &iter, IMPORT_POINTER_COLUMN, &gptr, -1); loader_file_config = (SHPLOADERCONFIG *)gptr; /* Free the configuration from memory */ free_loader_config(loader_file_config); /* Remove the row from the list */ - gtk_list_store_remove(list_store, &iter); + gtk_list_store_remove(import_file_list_store, &iter); /* Update the filename field width */ update_filename_field_width(); } +/* === Export ListView functions and signal handlers === */ + +/* Update the SHPDUMPERCONFIG to the values currently contained within the iter */ +static void +update_dumper_table_config_from_listview_iter(GtkTreeIter *iter, SHPDUMPERCONFIG *dumper_table_config) +{ + gchar *schema, *table, *geo_col, *filename; + + /* Grab the main values for this file */ + gtk_tree_model_get(GTK_TREE_MODEL(export_table_list_store), iter, + EXPORT_SCHEMA_COLUMN, &schema, + EXPORT_TABLE_COLUMN, &table, + EXPORT_GEOMETRY_COLUMN, &geo_col, + EXPORT_FILENAME_COLUMN, &filename, + -1); + + /* Update the schema */ + if (dumper_table_config->schema) + free(dumper_table_config->schema); + + dumper_table_config->schema = strdup(schema); + + /* Update the table */ + if (dumper_table_config->table) + free(dumper_table_config->table); + + dumper_table_config->table = strdup(table); + + /* Update the geometry column */ + if (dumper_table_config->geo_col_name) + free(dumper_table_config->geo_col_name); + + dumper_table_config->geo_col_name = strdup(geo_col); + + /* Update the filename column (default to table name) */ + if (dumper_table_config->shp_file) + free(dumper_table_config->shp_file); + + dumper_table_config->shp_file = strdup(filename); + + return; +} + +static void +pgui_action_handle_table_geocol_combo(GtkCellRendererCombo *combo, + gchar *path_string, + GtkTreeIter *new_iter, + gpointer user_data) +{ + SHPDUMPERCONFIG *dumper_table_config; + gchar *geocol_name; + GtkTreeIter iter; + GtkListStore *model; + gpointer gptr; + + /* Get the existing geo column name */ + gtk_tree_model_get_iter_from_string(GTK_TREE_MODEL(export_table_list_store), &iter, path_string); + gtk_tree_model_get(GTK_TREE_MODEL(export_table_list_store), &iter, + EXPORT_POINTER_COLUMN, &gptr, + EXPORT_GEOMETRY_COLUMN, &geocol_name, + EXPORT_GEOMETRY_LISTSTORE_COLUMN, &model, + -1); + + /* If the geocol_name is NULL then there was no geo column so exit */ + if (!geocol_name) + return; + + /* Otherwise update the geo column name in the config and the model */ + gtk_tree_model_get(GTK_TREE_MODEL(model), new_iter, TABLECHOOSER_GEOCOL_COMBO_TEXT, &geocol_name, -1); + dumper_table_config = (SHPDUMPERCONFIG *)gptr; + + if (dumper_table_config->geo_col_name) + { + free(dumper_table_config->geo_col_name); + + dumper_table_config->geo_col_name = strdup(geocol_name); + } + + gtk_list_store_set(export_table_list_store, &iter, + EXPORT_GEOMETRY_COLUMN, geocol_name, + -1); + + return; +} + +static void +pgui_action_handle_dumper_edit(GtkCellRendererText *renderer, + gchar *path, + gchar *new_text, + gpointer column) +{ + GtkTreeIter iter; + gpointer gptr; + gint columnindex; + SHPDUMPERCONFIG *dumper_table_config; + + /* Empty doesn't fly */ + if (strlen(new_text) == 0) + return; + + /* Update the model with the current edit change */ + columnindex = *(gint *)column; + gtk_tree_model_get_iter_from_string(GTK_TREE_MODEL(export_table_list_store), &iter, path); + gtk_list_store_set(export_table_list_store, &iter, columnindex, new_text, -1); + + /* Grab the SHPDUMPERCONFIG from the EXPORT_POINTER_COLUMN for the list store */ + gtk_tree_model_get(GTK_TREE_MODEL(export_table_list_store), &iter, EXPORT_POINTER_COLUMN, &gptr, -1); + dumper_table_config = (SHPDUMPERCONFIG *)gptr; + + /* Update the configuration from the current UI data */ + update_dumper_table_config_from_listview_iter(&iter, dumper_table_config); + + /* Now refresh the listview UI row with the new configuration */ + gtk_list_store_set(export_table_list_store, &iter, + EXPORT_SCHEMA_COLUMN, dumper_table_config->schema, + EXPORT_TABLE_COLUMN, dumper_table_config->table, + EXPORT_GEOMETRY_COLUMN, dumper_table_config->geo_col_name, + EXPORT_FILENAME_COLUMN, dumper_table_config->shp_file, + -1); + + return; +} /* === Connection Window functions === */ @@ -1728,7 +2536,7 @@ pgui_create_filechooser_dialog(void) GtkFileFilter *file_filter_shape; /* Create the dialog */ - dialog_filechooser= gtk_file_chooser_dialog_new( _("Select a Shape File"), GTK_WINDOW (window_main), + dialog_filechooser = gtk_file_chooser_dialog_new( _("Select a Shape File"), GTK_WINDOW (window_main), GTK_FILE_CHOOSER_ACTION_OPEN, GTK_STOCK_CANCEL, GTK_RESPONSE_CLOSE, GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, NULL); /* Filter for .shp files */ @@ -1746,6 +2554,30 @@ pgui_create_filechooser_dialog(void) return; } +static void +pgui_create_folderchooser_dialog(void) +{ + GtkFileFilter *file_filter_shape; + + /* Create the dialog */ + dialog_folderchooser = gtk_file_chooser_dialog_new( _("Select an output folder"), GTK_WINDOW (window_main), + GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER, GTK_STOCK_CANCEL, GTK_RESPONSE_CLOSE, GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, NULL); + + /* Filter for .shp files */ + file_filter_shape = gtk_file_filter_new(); + gtk_file_filter_add_pattern(GTK_FILE_FILTER(file_filter_shape), "*.shp"); + gtk_file_filter_set_name(GTK_FILE_FILTER(file_filter_shape), _("Shape Files (*.shp)")); + gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog_folderchooser), file_filter_shape); + + /* Filter for .dbf files */ + file_filter_shape = gtk_file_filter_new(); + gtk_file_filter_add_pattern(GTK_FILE_FILTER(file_filter_shape), "*.dbf"); + gtk_file_filter_set_name(GTK_FILE_FILTER(file_filter_shape), _("DBF Files (*.dbf)")); + gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog_folderchooser), file_filter_shape); + + return; +} + static void pgui_create_progress_dialog() { @@ -1799,17 +2631,17 @@ pgui_create_options_dialog_add_label(GtkWidget *table, const char *str, gfloat a } static void -pgui_create_options_dialog() +pgui_create_loader_options_dialog() { GtkWidget *table_options; GtkWidget *align_options_center; static int text_width = 12; - dialog_options = gtk_dialog_new_with_buttons(_("Import Options"), GTK_WINDOW(window_main), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_STOCK_OK, GTK_RESPONSE_OK, NULL); + dialog_loader_options = gtk_dialog_new_with_buttons(_("Import Options"), GTK_WINDOW(window_main), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_STOCK_OK, GTK_RESPONSE_OK, NULL); - gtk_window_set_modal (GTK_WINDOW(dialog_options), TRUE); - gtk_window_set_keep_above (GTK_WINDOW(dialog_options), TRUE); - gtk_window_set_default_size (GTK_WINDOW(dialog_options), 180, 200); + gtk_window_set_modal (GTK_WINDOW(dialog_loader_options), TRUE); + gtk_window_set_keep_above (GTK_WINDOW(dialog_loader_options), TRUE); + gtk_window_set_default_size (GTK_WINDOW(dialog_loader_options), 180, -1); table_options = gtk_table_new(7, 3, TRUE); gtk_container_set_border_width (GTK_CONTAINER (table_options), 12); @@ -1822,47 +2654,90 @@ pgui_create_options_dialog() gtk_table_attach_defaults(GTK_TABLE(table_options), entry_options_encoding, 0, 1, 0, 1 ); pgui_create_options_dialog_add_label(table_options, _("Preserve case of column names"), 0.0, 1); - checkbutton_options_preservecase = gtk_check_button_new(); + checkbutton_loader_options_preservecase = gtk_check_button_new(); align_options_center = gtk_alignment_new( 0.5, 0.5, 0.0, 1.0 ); gtk_table_attach_defaults(GTK_TABLE(table_options), align_options_center, 0, 1, 1, 2 ); - gtk_container_add (GTK_CONTAINER (align_options_center), checkbutton_options_preservecase); + gtk_container_add (GTK_CONTAINER (align_options_center), checkbutton_loader_options_preservecase); pgui_create_options_dialog_add_label(table_options, _("Do not create 'bigint' columns"), 0.0, 2); - checkbutton_options_forceint = gtk_check_button_new(); + checkbutton_loader_options_forceint = gtk_check_button_new(); align_options_center = gtk_alignment_new( 0.5, 0.5, 0.0, 1.0 ); gtk_table_attach_defaults(GTK_TABLE(table_options), align_options_center, 0, 1, 2, 3 ); - gtk_container_add (GTK_CONTAINER (align_options_center), checkbutton_options_forceint); + gtk_container_add (GTK_CONTAINER (align_options_center), checkbutton_loader_options_forceint); pgui_create_options_dialog_add_label(table_options, _("Create spatial index automatically after load"), 0.0, 3); - checkbutton_options_autoindex = gtk_check_button_new(); + checkbutton_loader_options_autoindex = gtk_check_button_new(); align_options_center = gtk_alignment_new( 0.5, 0.5, 0.0, 1.0 ); gtk_table_attach_defaults(GTK_TABLE(table_options), align_options_center, 0, 1, 3, 4 ); - gtk_container_add (GTK_CONTAINER (align_options_center), checkbutton_options_autoindex); + gtk_container_add (GTK_CONTAINER (align_options_center), checkbutton_loader_options_autoindex); pgui_create_options_dialog_add_label(table_options, _("Load only attribute (dbf) data"), 0.0, 4); - checkbutton_options_dbfonly = gtk_check_button_new(); + checkbutton_loader_options_dbfonly = gtk_check_button_new(); align_options_center = gtk_alignment_new( 0.5, 0.5, 0.0, 1.0 ); gtk_table_attach_defaults(GTK_TABLE(table_options), align_options_center, 0, 1, 4, 5 ); - gtk_container_add (GTK_CONTAINER (align_options_center), checkbutton_options_dbfonly); + gtk_container_add (GTK_CONTAINER (align_options_center), checkbutton_loader_options_dbfonly); pgui_create_options_dialog_add_label(table_options, _("Load data using COPY rather than INSERT"), 0.0, 5); - checkbutton_options_dumpformat = gtk_check_button_new(); + checkbutton_loader_options_dumpformat = gtk_check_button_new(); align_options_center = gtk_alignment_new( 0.5, 0.5, 0.0, 0.0 ); gtk_table_attach_defaults(GTK_TABLE(table_options), align_options_center, 0, 1, 5, 6 ); - gtk_container_add (GTK_CONTAINER (align_options_center), checkbutton_options_dumpformat); + gtk_container_add (GTK_CONTAINER (align_options_center), checkbutton_loader_options_dumpformat); pgui_create_options_dialog_add_label(table_options, _("Load into GEOGRAPHY column"), 0.0, 6); - checkbutton_options_geography = gtk_check_button_new(); + checkbutton_loader_options_geography = gtk_check_button_new(); align_options_center = gtk_alignment_new( 0.5, 0.5, 0.0, 1.0 ); gtk_table_attach_defaults(GTK_TABLE(table_options), align_options_center, 0, 1, 6, 7 ); - gtk_container_add (GTK_CONTAINER (align_options_center), checkbutton_options_geography); + gtk_container_add (GTK_CONTAINER (align_options_center), checkbutton_loader_options_geography); /* Catch the response from the dialog */ - g_signal_connect(dialog_options, "response", G_CALLBACK(pgui_action_options_close), dialog_options); - gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog_options)->vbox), table_options, FALSE, FALSE, 0); + g_signal_connect(dialog_loader_options, "response", G_CALLBACK(pgui_action_loader_options_close), dialog_loader_options); + gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog_loader_options)->vbox), table_options, FALSE, FALSE, 0); /* Hook the delete event so we don't destroy the dialog (just hide) if cancelled */ - gtk_signal_connect(GTK_OBJECT(dialog_options), "delete_event", GTK_SIGNAL_FUNC(pgui_event_popup_delete), NULL); + gtk_signal_connect(GTK_OBJECT(dialog_loader_options), "delete_event", GTK_SIGNAL_FUNC(pgui_event_popup_delete), NULL); +} + +static void +pgui_create_dumper_options_dialog() +{ + GtkWidget *table_options; + GtkWidget *align_options_center; + + dialog_dumper_options = gtk_dialog_new_with_buttons(_("Export Options"), GTK_WINDOW(window_main), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_STOCK_OK, GTK_RESPONSE_OK, NULL); + + gtk_window_set_modal (GTK_WINDOW(dialog_dumper_options), TRUE); + gtk_window_set_keep_above (GTK_WINDOW(dialog_dumper_options), TRUE); + gtk_window_set_default_size (GTK_WINDOW(dialog_dumper_options), 180, -1); + + table_options = gtk_table_new(3, 3, TRUE); + gtk_container_set_border_width (GTK_CONTAINER (table_options), 12); + gtk_table_set_row_spacings(GTK_TABLE(table_options), 5); + gtk_table_set_col_spacings(GTK_TABLE(table_options), 10); + + pgui_create_options_dialog_add_label(table_options, _("Include gid column in the exported table"), 0.0, 0); + checkbutton_dumper_options_includegid = gtk_check_button_new(); + align_options_center = gtk_alignment_new( 0.5, 0.5, 0.0, 1.0 ); + gtk_table_attach_defaults(GTK_TABLE(table_options), align_options_center, 0, 1, 0, 1 ); + gtk_container_add (GTK_CONTAINER (align_options_center), checkbutton_dumper_options_includegid); + + pgui_create_options_dialog_add_label(table_options, _("Preserve case of column names"), 0.0, 1); + checkbutton_dumper_options_keep_fieldname_case = gtk_check_button_new(); + align_options_center = gtk_alignment_new( 0.5, 0.5, 0.0, 1.0 ); + gtk_table_attach_defaults(GTK_TABLE(table_options), align_options_center, 0, 1, 1, 2 ); + gtk_container_add (GTK_CONTAINER (align_options_center), checkbutton_dumper_options_keep_fieldname_case); + + pgui_create_options_dialog_add_label(table_options, _("Escape column names"), 0.0, 2); + checkbutton_dumper_options_unescapedattrs = gtk_check_button_new(); + align_options_center = gtk_alignment_new( 0.5, 0.5, 0.0, 1.0 ); + gtk_table_attach_defaults(GTK_TABLE(table_options), align_options_center, 0, 1, 2, 3 ); + gtk_container_add (GTK_CONTAINER (align_options_center), checkbutton_dumper_options_unescapedattrs); + + /* Catch the response from the dialog */ + g_signal_connect(dialog_dumper_options, "response", G_CALLBACK(pgui_action_dumper_options_close), dialog_dumper_options); + gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog_dumper_options)->vbox), table_options, FALSE, FALSE, 0); + + /* Hook the delete event so we don't destroy the dialog (just hide) if cancelled */ + gtk_signal_connect(GTK_OBJECT(dialog_dumper_options), "delete_event", GTK_SIGNAL_FUNC(pgui_event_popup_delete), NULL); } /* @@ -1870,21 +2745,121 @@ pgui_create_options_dialog() * up all the pretty signals. */ static void -pgui_create_file_table(GtkWidget *frame_shape) +pgui_create_tablechooser_dialog() +{ + GtkWidget *vbox_tree, *table_progress; + GtkWidget *sw, *label; + GtkTreeSelection *chooser_selection; + gint *column_indexes; + + /* Create the main top level window with a 10px border */ + dialog_tablechooser = gtk_dialog_new_with_buttons(_("Table selection"), GTK_WINDOW(window_main), + GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, GTK_STOCK_OK, GTK_RESPONSE_OK, NULL); + + gtk_container_set_border_width(GTK_CONTAINER(dialog_tablechooser), 10); + gtk_window_set_position(GTK_WINDOW(dialog_tablechooser), GTK_WIN_POS_CENTER); + + vbox_tree = gtk_dialog_get_content_area(GTK_DIALOG(dialog_tablechooser)); + + /* Setup a model */ + chooser_table_list_store = gtk_list_store_new(TABLECHOOSER_N_COLUMNS, + G_TYPE_STRING, + G_TYPE_STRING, + GTK_TYPE_TREE_MODEL, + G_TYPE_STRING, + G_TYPE_INT); + + /* Because we want to do selective filtering on the treeview content, we now implement a GtkTreeModel + filter on top of the original tree model */ + chooser_filtered_table_list_store = (GtkListStore *)gtk_tree_model_filter_new(GTK_TREE_MODEL(chooser_table_list_store), NULL); + gtk_tree_model_filter_set_visible_func(GTK_TREE_MODEL_FILTER(chooser_filtered_table_list_store), + (GtkTreeModelFilterVisibleFunc)table_chooser_visibility_func, NULL, NULL); + + /* Create the view and such */ + chooser_tree = gtk_tree_view_new_with_model(GTK_TREE_MODEL(chooser_filtered_table_list_store)); + chooser_selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(chooser_tree)); + gtk_tree_selection_set_mode(chooser_selection, GTK_SELECTION_MULTIPLE); + + /* GTK has a slightly brain-dead API in that you can't directly find + the column being used by a GtkCellRenderer when using the same + callback to handle multiple fields; hence we manually store this + information here and pass a pointer to the column index into + the signal handler */ + column_indexes = g_malloc(sizeof(gint) * TABLECHOOSER_N_COLUMNS); + + /* Make the tree view in a scrollable window */ + sw = gtk_scrolled_window_new(NULL, NULL); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW(sw), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); + gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW(sw), GTK_SHADOW_ETCHED_IN); + gtk_widget_set_size_request(sw, 320, 240); + + gtk_box_pack_start(GTK_BOX(vbox_tree), sw, FALSE, FALSE, 10); + gtk_container_add(GTK_CONTAINER(sw), chooser_tree); + + /* Schema Field */ + chooser_schema_renderer = gtk_cell_renderer_text_new(); + g_object_set(chooser_schema_renderer, "editable", TRUE, NULL); + g_signal_connect(G_OBJECT(chooser_schema_renderer), "edited", G_CALLBACK(pgui_action_handle_loader_edit), NULL); + chooser_schema_column = gtk_tree_view_column_new_with_attributes(_("Schema"), + chooser_schema_renderer, + "text", + TABLECHOOSER_SCHEMA_COLUMN, + NULL); + g_object_set(chooser_schema_column, "resizable", TRUE, "sizing", GTK_TREE_VIEW_COLUMN_AUTOSIZE, NULL); + gtk_tree_view_append_column(GTK_TREE_VIEW(chooser_tree), chooser_schema_column); + + /* Table Field */ + chooser_table_renderer = gtk_cell_renderer_text_new(); + g_object_set(chooser_table_renderer, "editable", FALSE, NULL); + g_signal_connect(G_OBJECT(chooser_table_renderer), "edited", G_CALLBACK(pgui_action_handle_loader_edit), NULL); + chooser_table_column = gtk_tree_view_column_new_with_attributes("Table", + chooser_table_renderer, + "text", + TABLECHOOSER_TABLE_COLUMN, + NULL); + g_object_set(chooser_table_column, "resizable", TRUE, "sizing", GTK_TREE_VIEW_COLUMN_AUTOSIZE, NULL); + gtk_tree_view_append_column(GTK_TREE_VIEW(chooser_tree), chooser_table_column); + + /* Create table to hold the tick-box and text */ + table_progress = gtk_table_new(1, 2, FALSE); + gtk_container_set_border_width (GTK_CONTAINER (table_progress), 0); + gtk_table_set_row_spacings(GTK_TABLE(table_progress), 0); + gtk_table_set_col_spacings(GTK_TABLE(table_progress), 0); + + checkbutton_chooser_geoonly = gtk_check_button_new(); + gtk_table_attach(GTK_TABLE(table_progress), checkbutton_chooser_geoonly, 0, 1, 0, 1, GTK_SHRINK, GTK_FILL, 0, 0); + label = gtk_label_new(_("Only show tables with geo columns")); + gtk_table_attach(GTK_TABLE(table_progress), label, 1, 2, 0, 1, GTK_FILL, GTK_FILL, 5, 0); + g_signal_connect(G_OBJECT(checkbutton_chooser_geoonly), "toggled", G_CALLBACK(pgui_action_chooser_toggle_show_geocolumn), NULL); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(checkbutton_chooser_geoonly), TRUE); + + /* Attach table to the vbox */ + gtk_box_pack_start(GTK_BOX(vbox_tree), table_progress, FALSE, FALSE, 10); + + return; +} + + +/* + * This function creates the UI artefacts for the file list table and hooks + * up all the pretty signals. + */ +static void +pgui_create_import_file_table(GtkWidget *import_list_frame) { GtkWidget *vbox_tree; GtkWidget *sw; GtkTreeIter iter; gint *column_indexes; - gtk_container_set_border_width (GTK_CONTAINER (frame_shape), 0); + gtk_container_set_border_width (GTK_CONTAINER (import_list_frame), 0); vbox_tree = gtk_vbox_new(FALSE, 15); gtk_container_set_border_width(GTK_CONTAINER(vbox_tree), 5); - gtk_container_add(GTK_CONTAINER(frame_shape), vbox_tree); + gtk_container_add(GTK_CONTAINER(import_list_frame), vbox_tree); /* Setup a model */ - list_store = gtk_list_store_new(N_COLUMNS, + import_file_list_store = gtk_list_store_new(IMPORT_N_COLUMNS, G_TYPE_POINTER, G_TYPE_STRING, G_TYPE_STRING, @@ -1895,14 +2870,14 @@ pgui_create_file_table(GtkWidget *frame_shape) G_TYPE_BOOLEAN); /* Create the view and such */ - tree = gtk_tree_view_new_with_model(GTK_TREE_MODEL(list_store)); + import_tree = gtk_tree_view_new_with_model(GTK_TREE_MODEL(import_file_list_store)); /* GTK has a slightly brain-dead API in that you can't directly find the column being used by a GtkCellRenderer when using the same callback to handle multiple fields; hence we manually store this information here and pass a pointer to the column index into the signal handler */ - column_indexes = g_malloc(sizeof(gint) * N_COLUMNS); + column_indexes = g_malloc(sizeof(gint) * IMPORT_N_COLUMNS); /* Make the tree view in a scrollable window */ sw = gtk_scrolled_window_new(NULL, NULL); @@ -1911,132 +2886,133 @@ pgui_create_file_table(GtkWidget *frame_shape) gtk_widget_set_size_request(sw, -1, 150); gtk_box_pack_start(GTK_BOX(vbox_tree), sw, TRUE, TRUE, 0); - gtk_container_add(GTK_CONTAINER (sw), tree); + gtk_container_add(GTK_CONTAINER (sw), import_tree); /* Place the "Add File" button below the list view */ add_file_button = gtk_button_new_with_label(_("Add File")); gtk_container_add (GTK_CONTAINER (vbox_tree), add_file_button); /* Filename Field */ - filename_renderer = gtk_cell_renderer_text_new(); - g_object_set(filename_renderer, "editable", FALSE, NULL); - column_indexes[FILENAME_COLUMN] = FILENAME_COLUMN; - g_signal_connect(G_OBJECT(filename_renderer), "edited", G_CALLBACK(pgui_action_handle_tree_edit), &column_indexes[FILENAME_COLUMN]); - filename_column = gtk_tree_view_column_new_with_attributes(_("Shapefile"), - filename_renderer, + import_filename_renderer = gtk_cell_renderer_text_new(); + g_object_set(import_filename_renderer, "editable", FALSE, NULL); + column_indexes[IMPORT_FILENAME_COLUMN] = IMPORT_FILENAME_COLUMN; + g_signal_connect(G_OBJECT(import_filename_renderer), "edited", G_CALLBACK(pgui_action_handle_loader_edit), &column_indexes[IMPORT_FILENAME_COLUMN]); + import_filename_column = gtk_tree_view_column_new_with_attributes(_("Shapefile"), + import_filename_renderer, "text", - FILENAME_COLUMN, + IMPORT_FILENAME_COLUMN, NULL); - g_object_set(filename_column, "resizable", TRUE, NULL); - gtk_tree_view_append_column(GTK_TREE_VIEW(tree), filename_column); + g_object_set(import_filename_column, "resizable", TRUE, NULL); + gtk_tree_view_append_column(GTK_TREE_VIEW(import_tree), import_filename_column); /* Schema Field */ - schema_renderer = gtk_cell_renderer_text_new(); - g_object_set(schema_renderer, "editable", TRUE, NULL); - column_indexes[SCHEMA_COLUMN] = SCHEMA_COLUMN; - g_signal_connect(G_OBJECT(schema_renderer), "edited", G_CALLBACK(pgui_action_handle_tree_edit), &column_indexes[SCHEMA_COLUMN]); - schema_column = gtk_tree_view_column_new_with_attributes(_("Schema"), - schema_renderer, + import_schema_renderer = gtk_cell_renderer_text_new(); + g_object_set(import_schema_renderer, "editable", TRUE, NULL); + column_indexes[IMPORT_SCHEMA_COLUMN] = IMPORT_SCHEMA_COLUMN; + g_signal_connect(G_OBJECT(import_schema_renderer), "edited", G_CALLBACK(pgui_action_handle_loader_edit), &column_indexes[IMPORT_SCHEMA_COLUMN]); + import_schema_column = gtk_tree_view_column_new_with_attributes(_("Schema"), + import_schema_renderer, "text", - SCHEMA_COLUMN, + IMPORT_SCHEMA_COLUMN, NULL); - g_object_set(schema_column, "resizable", TRUE, "sizing", GTK_TREE_VIEW_COLUMN_AUTOSIZE, NULL); - gtk_tree_view_append_column(GTK_TREE_VIEW(tree), schema_column); + g_object_set(import_schema_column, "resizable", TRUE, "expand", TRUE, "sizing", GTK_TREE_VIEW_COLUMN_AUTOSIZE, NULL); + gtk_tree_view_append_column(GTK_TREE_VIEW(import_tree), import_schema_column); /* Table Field */ - table_renderer = gtk_cell_renderer_text_new(); - g_object_set(table_renderer, "editable", TRUE, NULL); - column_indexes[TABLE_COLUMN] = TABLE_COLUMN; - g_signal_connect(G_OBJECT(table_renderer), "edited", G_CALLBACK(pgui_action_handle_tree_edit), &column_indexes[TABLE_COLUMN]); - table_column = gtk_tree_view_column_new_with_attributes("Table", - table_renderer, + import_table_renderer = gtk_cell_renderer_text_new(); + g_object_set(import_table_renderer, "editable", TRUE, NULL); + column_indexes[IMPORT_TABLE_COLUMN] = IMPORT_TABLE_COLUMN; + g_signal_connect(G_OBJECT(import_table_renderer), "edited", G_CALLBACK(pgui_action_handle_loader_edit), &column_indexes[IMPORT_TABLE_COLUMN]); + import_table_column = gtk_tree_view_column_new_with_attributes("Table", + import_table_renderer, "text", - TABLE_COLUMN, + IMPORT_TABLE_COLUMN, NULL); - g_object_set(schema_column, "resizable", TRUE, "sizing", GTK_TREE_VIEW_COLUMN_AUTOSIZE, NULL); - gtk_tree_view_append_column(GTK_TREE_VIEW(tree), table_column); + g_object_set(import_schema_column, "resizable", TRUE, "expand", TRUE, "sizing", GTK_TREE_VIEW_COLUMN_AUTOSIZE, NULL); + gtk_tree_view_append_column(GTK_TREE_VIEW(import_tree), import_table_column); /* Geo column field */ - geom_column_renderer = gtk_cell_renderer_text_new(); - g_object_set(geom_column_renderer, "editable", TRUE, NULL); - column_indexes[GEOMETRY_COLUMN] = GEOMETRY_COLUMN; - g_signal_connect(G_OBJECT(geom_column_renderer), "edited", G_CALLBACK(pgui_action_handle_tree_edit), &column_indexes[GEOMETRY_COLUMN]); - geom_column = gtk_tree_view_column_new_with_attributes(_("Geo Column"), - geom_column_renderer, + import_geom_column_renderer = gtk_cell_renderer_text_new(); + g_object_set(import_geom_column_renderer, "editable", TRUE, NULL); + column_indexes[IMPORT_GEOMETRY_COLUMN] = IMPORT_GEOMETRY_COLUMN; + g_signal_connect(G_OBJECT(import_geom_column_renderer), "edited", G_CALLBACK(pgui_action_handle_loader_edit), &column_indexes[IMPORT_GEOMETRY_COLUMN]); + import_geom_column = gtk_tree_view_column_new_with_attributes(_("Geo Column"), + import_geom_column_renderer, "text", - GEOMETRY_COLUMN, + IMPORT_GEOMETRY_COLUMN, NULL); - g_object_set(geom_column, "resizable", TRUE, "sizing", GTK_TREE_VIEW_COLUMN_AUTOSIZE, NULL); - gtk_tree_view_append_column(GTK_TREE_VIEW(tree), geom_column); + g_object_set(import_geom_column, "resizable", TRUE, "expand", TRUE, "sizing", GTK_TREE_VIEW_COLUMN_AUTOSIZE, NULL); + gtk_tree_view_append_column(GTK_TREE_VIEW(import_tree), import_geom_column); /* SRID Field */ - srid_renderer = gtk_cell_renderer_text_new(); - g_object_set(srid_renderer, "editable", TRUE, NULL); - column_indexes[SRID_COLUMN] = SRID_COLUMN; - g_signal_connect(G_OBJECT(srid_renderer), "edited", G_CALLBACK(pgui_action_handle_tree_edit), &column_indexes[SRID_COLUMN]); - srid_column = gtk_tree_view_column_new_with_attributes("SRID", - srid_renderer, + import_srid_renderer = gtk_cell_renderer_text_new(); + g_object_set(import_srid_renderer, "editable", TRUE, NULL); + column_indexes[IMPORT_SRID_COLUMN] = IMPORT_SRID_COLUMN; + g_signal_connect(G_OBJECT(import_srid_renderer), "edited", G_CALLBACK(pgui_action_handle_loader_edit), &column_indexes[IMPORT_SRID_COLUMN]); + import_srid_column = gtk_tree_view_column_new_with_attributes("SRID", + import_srid_renderer, "text", - SRID_COLUMN, + IMPORT_SRID_COLUMN, NULL); - g_object_set(srid_column, "resizable", TRUE, "sizing", GTK_TREE_VIEW_COLUMN_AUTOSIZE, NULL); - gtk_tree_view_append_column(GTK_TREE_VIEW(tree), srid_column); + g_object_set(import_srid_column, "resizable", TRUE, "expand", TRUE, "sizing", GTK_TREE_VIEW_COLUMN_AUTOSIZE, NULL); + gtk_tree_view_append_column(GTK_TREE_VIEW(import_tree), import_srid_column); /* Mode Combo Field */ - combo_list = gtk_list_store_new(COMBO_COLUMNS, + loader_mode_combo_list = gtk_list_store_new(LOADER_MODE_COMBO_COLUMNS, G_TYPE_STRING, G_TYPE_CHAR); - gtk_list_store_insert(combo_list, &iter, CREATE_MODE); - gtk_list_store_set(combo_list, &iter, - COMBO_TEXT, _("Create"), - COMBO_OPTION_CHAR, 'c', + gtk_list_store_insert(loader_mode_combo_list, &iter, CREATE_MODE); + gtk_list_store_set(loader_mode_combo_list, &iter, + LOADER_MODE_COMBO_TEXT, _("Create"), + LOADER_MODE_COMBO_OPTION_CHAR, 'c', -1); - gtk_list_store_insert(combo_list, &iter, APPEND_MODE); - gtk_list_store_set(combo_list, &iter, - COMBO_TEXT, _("Append"), - COMBO_OPTION_CHAR, 'a', + gtk_list_store_insert(loader_mode_combo_list, &iter, APPEND_MODE); + gtk_list_store_set(loader_mode_combo_list, &iter, + LOADER_MODE_COMBO_TEXT, _("Append"), + LOADER_MODE_COMBO_OPTION_CHAR, 'a', -1); - gtk_list_store_insert(combo_list, &iter, DELETE_MODE); - gtk_list_store_set(combo_list, &iter, - COMBO_TEXT, _("Delete"), - COMBO_OPTION_CHAR, 'd', + gtk_list_store_insert(loader_mode_combo_list, &iter, DELETE_MODE); + gtk_list_store_set(loader_mode_combo_list, &iter, + LOADER_MODE_COMBO_TEXT, _("Delete"), + LOADER_MODE_COMBO_OPTION_CHAR, 'd', -1); - gtk_list_store_insert(combo_list, &iter, PREPARE_MODE); - gtk_list_store_set(combo_list, &iter, - COMBO_TEXT, _("Prepare"), - COMBO_OPTION_CHAR, 'p', + gtk_list_store_insert(loader_mode_combo_list, &iter, PREPARE_MODE); + gtk_list_store_set(loader_mode_combo_list, &iter, + LOADER_MODE_COMBO_TEXT, _("Prepare"), + LOADER_MODE_COMBO_OPTION_CHAR, 'p', -1); - mode_combo = gtk_combo_box_new_with_model(GTK_TREE_MODEL(combo_list)); - mode_renderer = gtk_cell_renderer_combo_new(); - gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(mode_combo), - mode_renderer, TRUE); - gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(mode_combo), - mode_renderer, "text", 0); - g_object_set(mode_renderer, - "model", combo_list, + loader_mode_combo = gtk_combo_box_new_with_model(GTK_TREE_MODEL(loader_mode_combo_list)); + import_mode_renderer = gtk_cell_renderer_combo_new(); + gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(loader_mode_combo), + import_mode_renderer, TRUE); + gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(loader_mode_combo), + import_mode_renderer, "text", 0); + g_object_set(import_mode_renderer, + "model", loader_mode_combo_list, "editable", TRUE, "has-entry", FALSE, - "text-column", COMBO_TEXT, + "text-column", LOADER_MODE_COMBO_TEXT, NULL); - mode_column = gtk_tree_view_column_new_with_attributes(_("Mode"), - mode_renderer, + import_mode_column = gtk_tree_view_column_new_with_attributes(_("Mode"), + import_mode_renderer, "text", - MODE_COLUMN, + IMPORT_MODE_COLUMN, NULL); - gtk_tree_view_append_column(GTK_TREE_VIEW(tree), mode_column); - gtk_combo_box_set_active(GTK_COMBO_BOX(mode_combo), 1); - - g_signal_connect (G_OBJECT(mode_renderer), "changed", G_CALLBACK(pgui_action_handle_tree_combo), NULL); + gtk_tree_view_append_column(GTK_TREE_VIEW(import_tree), import_mode_column); + gtk_combo_box_set_active(GTK_COMBO_BOX(loader_mode_combo), 1); + g_object_set(import_mode_column, "resizable", TRUE, "expand", TRUE, "sizing", GTK_TREE_VIEW_COLUMN_AUTOSIZE, NULL); + + g_signal_connect (G_OBJECT(import_mode_renderer), "changed", G_CALLBACK(pgui_action_handle_tree_combo), NULL); /* Remove Field */ - remove_renderer = gtk_cell_renderer_toggle_new(); - g_object_set(remove_renderer, "activatable", TRUE, NULL); - g_signal_connect(G_OBJECT(remove_renderer), "toggled", G_CALLBACK (pgui_action_handle_tree_remove), NULL); - remove_column = gtk_tree_view_column_new_with_attributes("Rm", - remove_renderer, NULL); - g_object_set(remove_column, "resizable", TRUE, "sizing", GTK_TREE_VIEW_COLUMN_AUTOSIZE, NULL); - gtk_tree_view_append_column(GTK_TREE_VIEW(tree), remove_column); + import_remove_renderer = gtk_cell_renderer_toggle_new(); + g_object_set(import_remove_renderer, "activatable", TRUE, NULL); + g_signal_connect(G_OBJECT(import_remove_renderer), "toggled", G_CALLBACK (pgui_action_handle_file_remove), NULL); + import_remove_column = gtk_tree_view_column_new_with_attributes("Rm", + import_remove_renderer, NULL); + g_object_set(import_remove_column, "resizable", TRUE, "expand", FALSE, "fixed-width", 64, "sizing", GTK_TREE_VIEW_COLUMN_FIXED, NULL); + gtk_tree_view_append_column(GTK_TREE_VIEW(import_tree), import_remove_column); g_signal_connect (G_OBJECT (add_file_button), "clicked", G_CALLBACK (pgui_action_open_file_dialog), NULL); @@ -2047,14 +3023,136 @@ pgui_create_file_table(GtkWidget *frame_shape) }; gint n_drop_types = sizeof(drop_types)/sizeof(drop_types[0]); - gtk_drag_dest_set(GTK_WIDGET(tree), + gtk_drag_dest_set(GTK_WIDGET(import_tree), GTK_DEST_DEFAULT_ALL, drop_types, n_drop_types, GDK_ACTION_COPY); - g_signal_connect(G_OBJECT(tree), "drag_data_received", + g_signal_connect(G_OBJECT(import_tree), "drag_data_received", G_CALLBACK(pgui_action_handle_file_drop), NULL); } +/* + * This function creates the UI artefacts for the file list table and hooks + * up all the pretty signals. + */ +static void +pgui_create_export_table_table(GtkWidget *export_list_frame) +{ + GtkWidget *vbox_tree; + GtkWidget *sw; + gint *column_indexes; + + gtk_container_set_border_width (GTK_CONTAINER (export_list_frame), 0); + + vbox_tree = gtk_vbox_new(FALSE, 15); + gtk_container_set_border_width(GTK_CONTAINER(vbox_tree), 5); + gtk_container_add(GTK_CONTAINER(export_list_frame), vbox_tree); + + /* Setup a model */ + export_table_list_store = gtk_list_store_new(EXPORT_N_COLUMNS, + G_TYPE_POINTER, + G_TYPE_STRING, + G_TYPE_STRING, + G_TYPE_STRING, + GTK_TYPE_TREE_MODEL, + G_TYPE_STRING, + G_TYPE_BOOLEAN); + + /* Create the view and such */ + export_tree = gtk_tree_view_new_with_model(GTK_TREE_MODEL(export_table_list_store)); + + /* GTK has a slightly brain-dead API in that you can't directly find + the column being used by a GtkCellRenderer when using the same + callback to handle multiple fields; hence we manually store this + information here and pass a pointer to the column index into + the signal handler */ + column_indexes = g_malloc(sizeof(gint) * EXPORT_N_COLUMNS); + + /* Make the tree view in a scrollable window */ + sw = gtk_scrolled_window_new(NULL, NULL); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW(sw), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); + gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW(sw), GTK_SHADOW_ETCHED_IN); + gtk_widget_set_size_request(sw, -1, 150); + + gtk_box_pack_start(GTK_BOX(vbox_tree), sw, TRUE, TRUE, 0); + gtk_container_add(GTK_CONTAINER (sw), export_tree); + + /* Place the "Add Table" button below the list view */ + add_table_button = gtk_button_new_with_label(_("Add Table")); + gtk_container_add (GTK_CONTAINER (vbox_tree), add_table_button); + + /* Schema Field */ + export_schema_renderer = gtk_cell_renderer_text_new(); + g_object_set(export_schema_renderer, "editable", TRUE, NULL); + column_indexes[EXPORT_SCHEMA_COLUMN] = EXPORT_SCHEMA_COLUMN; + g_signal_connect(G_OBJECT(import_schema_renderer), "edited", G_CALLBACK(pgui_action_handle_loader_edit), &column_indexes[EXPORT_SCHEMA_COLUMN]); + export_schema_column = gtk_tree_view_column_new_with_attributes(_("Schema"), + export_schema_renderer, + "text", + EXPORT_SCHEMA_COLUMN, + NULL); + g_object_set(export_schema_column, "resizable", TRUE, "expand", TRUE, "sizing", GTK_TREE_VIEW_COLUMN_AUTOSIZE, NULL); + gtk_tree_view_append_column(GTK_TREE_VIEW(export_tree), export_schema_column); + + /* Table Field */ + export_table_renderer = gtk_cell_renderer_text_new(); + g_object_set(export_table_renderer, "editable", FALSE, NULL); + column_indexes[EXPORT_TABLE_COLUMN] = EXPORT_TABLE_COLUMN; + g_signal_connect(G_OBJECT(export_table_renderer), "edited", G_CALLBACK(pgui_action_handle_loader_edit), &column_indexes[EXPORT_TABLE_COLUMN]); + export_table_column = gtk_tree_view_column_new_with_attributes("Table", + export_table_renderer, + "text", + EXPORT_TABLE_COLUMN, + NULL); + g_object_set(export_table_column, "resizable", TRUE, "expand", TRUE, "sizing", GTK_TREE_VIEW_COLUMN_AUTOSIZE, NULL); + gtk_tree_view_append_column(GTK_TREE_VIEW(export_tree), export_table_column); + + /* Geo column field */ + export_geom_column_combo = gtk_combo_box_new(); + export_geom_column_renderer = gtk_cell_renderer_combo_new(); + gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(export_geom_column_combo), + export_geom_column_renderer, TRUE); + g_object_set(export_geom_column_renderer, + "editable", TRUE, + "has-entry", FALSE, + "text-column", TABLECHOOSER_GEOCOL_COMBO_TEXT, + NULL); + export_geom_column = gtk_tree_view_column_new_with_attributes("Geo Column", + export_geom_column_renderer, + "model", + EXPORT_GEOMETRY_LISTSTORE_COLUMN, + "text", + EXPORT_GEOMETRY_COLUMN, + NULL); + g_object_set(export_geom_column, "resizable", TRUE, "sizing", GTK_TREE_VIEW_COLUMN_AUTOSIZE, NULL); + gtk_tree_view_append_column(GTK_TREE_VIEW(export_tree), export_geom_column); + g_signal_connect (G_OBJECT(export_geom_column_renderer), "changed", G_CALLBACK(pgui_action_handle_table_geocol_combo), NULL); + + /* Filename Field */ + export_filename_renderer = gtk_cell_renderer_text_new(); + g_object_set(export_filename_renderer, "editable", TRUE, NULL); + column_indexes[EXPORT_FILENAME_COLUMN] = EXPORT_FILENAME_COLUMN; + g_signal_connect(G_OBJECT(export_filename_renderer), "edited", G_CALLBACK(pgui_action_handle_dumper_edit), &column_indexes[EXPORT_FILENAME_COLUMN]); + export_filename_column = gtk_tree_view_column_new_with_attributes("Filename", + export_filename_renderer, + "text", + EXPORT_FILENAME_COLUMN, + NULL); + g_object_set(export_filename_column, "resizable", TRUE, "expand", TRUE, "sizing", GTK_TREE_VIEW_COLUMN_AUTOSIZE, NULL); + gtk_tree_view_append_column(GTK_TREE_VIEW(export_tree), export_filename_column); + + /* Remove Field */ + export_remove_renderer = gtk_cell_renderer_toggle_new(); + g_object_set(export_remove_renderer, "activatable", TRUE, NULL); + g_signal_connect(G_OBJECT(export_remove_renderer), "toggled", G_CALLBACK (pgui_action_handle_table_remove), NULL); + export_remove_column = gtk_tree_view_column_new_with_attributes("Rm", + export_remove_renderer, NULL); + g_object_set(export_remove_column, "resizable", TRUE, "expand", FALSE, "fixed-width", 64, "sizing", GTK_TREE_VIEW_COLUMN_FIXED, NULL); + gtk_tree_view_append_column(GTK_TREE_VIEW(export_tree), export_remove_column); + + g_signal_connect (G_OBJECT (add_table_button), "clicked", G_CALLBACK (pgui_action_open_table_dialog), NULL); +} + static void pgui_create_connection_window() { @@ -2146,17 +3244,18 @@ static void pgui_create_main_window(const SHPCONNECTIONCONFIG *conn) { /* Main widgets */ - GtkWidget *vbox_main, *vbox_loader; + GtkWidget *vbox_main, *vbox_loader, *vbox_dumper; /* PgSQL section */ - GtkWidget *frame_pg, *frame_shape, *frame_log; + GtkWidget *frame_pg, *import_list_frame, *export_list_frame, *frame_log; GtkWidget *button_pg_conn; /* Notebook */ GtkWidget *notebook; /* Button section */ - GtkWidget *hbox_buttons, *button_options, *button_import, *button_cancel, *button_about; + GtkWidget *loader_hbox_buttons, *loader_button_options, *loader_button_import, *loader_button_cancel, *loader_button_about; + GtkWidget *dumper_hbox_buttons, *dumper_button_options, *dumper_button_export, *dumper_button_cancel, *dumper_button_about; /* Log section */ GtkWidget *scrolledwindow_log; @@ -2194,30 +3293,63 @@ pgui_create_main_window(const SHPCONNECTIONCONFIG *conn) /* ** Shape file selector */ - frame_shape = gtk_frame_new(_("Import List")); - pgui_create_file_table(frame_shape); + import_list_frame = gtk_frame_new(_("Import List")); + pgui_create_import_file_table(import_list_frame); /* ** Row of action buttons */ - hbox_buttons = gtk_hbox_new(TRUE, 15); - gtk_container_set_border_width (GTK_CONTAINER (hbox_buttons), 0); + loader_hbox_buttons = gtk_hbox_new(TRUE, 15); + gtk_container_set_border_width (GTK_CONTAINER (loader_hbox_buttons), 0); + /* Create the buttons themselves */ - button_options = gtk_button_new_with_label(_("Options...")); - button_import = gtk_button_new_with_label(_("Import")); - button_cancel = gtk_button_new_with_label(_("Cancel")); - button_about = gtk_button_new_with_label(_("About")); + loader_button_options = gtk_button_new_with_label(_("Options...")); + loader_button_import = gtk_button_new_with_label(_("Import")); + loader_button_cancel = gtk_button_new_with_label(_("Cancel")); + loader_button_about = gtk_button_new_with_label(_("About")); + /* Add actions to the buttons */ - g_signal_connect (G_OBJECT (button_import), "clicked", G_CALLBACK (pgui_action_import), NULL); - g_signal_connect (G_OBJECT (button_options), "clicked", G_CALLBACK (pgui_action_options_open), NULL); - g_signal_connect (G_OBJECT (button_cancel), "clicked", G_CALLBACK (pgui_action_cancel), NULL); - g_signal_connect (G_OBJECT (button_about), "clicked", G_CALLBACK (pgui_action_about_open), NULL); + g_signal_connect (G_OBJECT (loader_button_import), "clicked", G_CALLBACK (pgui_action_import), NULL); + g_signal_connect (G_OBJECT (loader_button_options), "clicked", G_CALLBACK (pgui_action_loader_options_open), NULL); + g_signal_connect (G_OBJECT (loader_button_cancel), "clicked", G_CALLBACK (pgui_action_cancel), NULL); + g_signal_connect (G_OBJECT (loader_button_about), "clicked", G_CALLBACK (pgui_action_about_open), NULL); + /* And insert the buttons into the hbox */ - gtk_box_pack_start(GTK_BOX(hbox_buttons), button_options, TRUE, TRUE, 0); - gtk_box_pack_end(GTK_BOX(hbox_buttons), button_cancel, TRUE, TRUE, 0); - gtk_box_pack_end(GTK_BOX(hbox_buttons), button_about, TRUE, TRUE, 0); - gtk_box_pack_end(GTK_BOX(hbox_buttons), button_import, TRUE, TRUE, 0); + gtk_box_pack_start(GTK_BOX(loader_hbox_buttons), loader_button_options, TRUE, TRUE, 0); + gtk_box_pack_end(GTK_BOX(loader_hbox_buttons), loader_button_cancel, TRUE, TRUE, 0); + gtk_box_pack_end(GTK_BOX(loader_hbox_buttons), loader_button_about, TRUE, TRUE, 0); + gtk_box_pack_end(GTK_BOX(loader_hbox_buttons), loader_button_import, TRUE, TRUE, 0); + + /* + ** Table selector + */ + export_list_frame = gtk_frame_new(_("Export List")); + pgui_create_export_table_table(export_list_frame); + + /* + ** Row of action buttons + */ + dumper_hbox_buttons = gtk_hbox_new(TRUE, 15); + gtk_container_set_border_width (GTK_CONTAINER (dumper_hbox_buttons), 0); + + /* Create the buttons themselves */ + dumper_button_options = gtk_button_new_with_label(_("Options...")); + dumper_button_export = gtk_button_new_with_label(_("Export")); + dumper_button_cancel = gtk_button_new_with_label(_("Cancel")); + dumper_button_about = gtk_button_new_with_label(_("About")); + + /* Add actions to the buttons */ + g_signal_connect (G_OBJECT (dumper_button_export), "clicked", G_CALLBACK (pgui_action_export), NULL); + g_signal_connect (G_OBJECT (dumper_button_options), "clicked", G_CALLBACK (pgui_action_dumper_options_open), NULL); + g_signal_connect (G_OBJECT (dumper_button_cancel), "clicked", G_CALLBACK (pgui_action_cancel), NULL); + g_signal_connect (G_OBJECT (dumper_button_about), "clicked", G_CALLBACK (pgui_action_about_open), NULL); + /* And insert the buttons into the hbox */ + gtk_box_pack_start(GTK_BOX(dumper_hbox_buttons), dumper_button_options, TRUE, TRUE, 0); + gtk_box_pack_end(GTK_BOX(dumper_hbox_buttons), dumper_button_cancel, TRUE, TRUE, 0); + gtk_box_pack_end(GTK_BOX(dumper_hbox_buttons), dumper_button_about, TRUE, TRUE, 0); + gtk_box_pack_end(GTK_BOX(dumper_hbox_buttons), dumper_button_export, TRUE, TRUE, 0); + /* ** Log window */ @@ -2246,10 +3378,18 @@ pgui_create_main_window(const SHPCONNECTIONCONFIG *conn) vbox_loader = gtk_vbox_new(FALSE, 10); gtk_container_set_border_width(GTK_CONTAINER(vbox_loader), 10); - gtk_box_pack_start(GTK_BOX(vbox_loader), frame_shape, FALSE, TRUE, 0); - gtk_box_pack_start(GTK_BOX(vbox_loader), hbox_buttons, FALSE, FALSE, 0); + gtk_box_pack_start(GTK_BOX(vbox_loader), import_list_frame, FALSE, TRUE, 0); + gtk_box_pack_start(GTK_BOX(vbox_loader), loader_hbox_buttons, FALSE, FALSE, 0); gtk_notebook_append_page(GTK_NOTEBOOK(notebook), vbox_loader, gtk_label_new(_("Import"))); + /* Add the dumper frames into the notebook page */ + vbox_dumper = gtk_vbox_new(FALSE, 10); + gtk_container_set_border_width(GTK_CONTAINER(vbox_dumper), 10); + + gtk_box_pack_start(GTK_BOX(vbox_dumper), export_list_frame, FALSE, TRUE, 0); + gtk_box_pack_start(GTK_BOX(vbox_dumper), dumper_hbox_buttons, FALSE, FALSE, 0); + gtk_notebook_append_page(GTK_NOTEBOOK(notebook), vbox_dumper, gtk_label_new(_("Export"))); + /* Add the frames into the main vbox */ gtk_box_pack_start(GTK_BOX(vbox_main), frame_pg, FALSE, TRUE, 0); gtk_box_pack_start(GTK_BOX(vbox_main), notebook, FALSE, TRUE, 0); @@ -2292,7 +3432,9 @@ main(int argc, char *argv[]) /* Parse command line options and set configuration */ global_loader_config = malloc(sizeof(SHPLOADERCONFIG)); set_loader_config_defaults(global_loader_config); - + global_dumper_config = malloc(sizeof(SHPDUMPERCONFIG)); + set_dumper_config_defaults(global_dumper_config); + /* Here we override any defaults for the GUI */ global_loader_config->createindex = 1; global_loader_config->geo_col = strdup(GEOMETRY_DEFAULT); @@ -2338,11 +3480,14 @@ main(int argc, char *argv[]) /* set up the user interface */ pgui_create_main_window(conn); pgui_create_connection_window(); - pgui_create_options_dialog(); + pgui_create_loader_options_dialog(); + pgui_create_dumper_options_dialog(); pgui_create_about_dialog(); pgui_create_filechooser_dialog(); pgui_create_progress_dialog(); - + pgui_create_tablechooser_dialog(); + pgui_create_folderchooser_dialog(); + /* start the main loop */ gtk_main();