]> granicus.if.org Git - postgis/commitdiff
Commit reworked version of shp2pgsql-gui to the repository.
authorMark Cave-Ayland <mark.cave-ayland@siriusit.co.uk>
Sun, 8 Jan 2012 23:32:05 +0000 (23:32 +0000)
committerMark Cave-Ayland <mark.cave-ayland@siriusit.co.uk>
Sun, 8 Jan 2012 23:32:05 +0000 (23:32 +0000)
As per my email to postgis-devel, this commit contains a major reworking
of the inner core, with many bugfixes. The primary changes are:

- Elimination of FILENODE, since we can just use pointers to
  SHPLOADERCONFIG

- Abstract the configuration structures from the GUI interface

- Restrict entry to either drag/drop or file chooser

- Instead of constantly destroying/creating new dialogs, create
  them once and then just show/hide them (in particular this
  enables the file chooser to open at its previous directory)

- Add separate connection details and progress bar dialogs

- Rework both internals and GUI in preparation for adding dumper
  support

Note that the dumper integration changes are being worked on separately
and will be included in a later commit.

git-svn-id: http://svn.osgeo.org/postgis/trunk@8706 b70326c6-7e19-0410-871a-916f4a2858ee

13 files changed:
loader/Makefile.in
loader/cunit/Makefile.in
loader/cunit/cu_list.c [deleted file]
loader/cunit/cu_list.h [deleted file]
loader/cunit/cu_tester.c
loader/pgsql2shp-core.c
loader/pgsql2shp-core.h
loader/shp2pgsql-core.c
loader/shp2pgsql-core.h
loader/shp2pgsql-gui.c
loader/shpcommon.h
loader/structure.c [deleted file]
loader/structure.h [deleted file]

index 83e5009e67565d44f7113d5ce7b7b1c4d1b023a4..acd4a2bf33adbc6d47131c967c2a4cad9515dfe8 100644 (file)
@@ -104,13 +104,10 @@ $(PGSQL2SHP-CLI): shpopen.o dbfopen.o getopt.o pgsql2shp-core.o shpcommon.o pgsq
 $(SHP2PGSQL-CLI): shpopen.o dbfopen.o getopt.o shp2pgsql-core.o shpcommon.o shp2pgsql-cli.o safileio.o $(LIBLWGEOM) 
        $(LIBTOOL) --mode=link $(CC) $(CFLAGS) $^ -o $@ $(GETTEXT_LDFLAGS) $(ICONV_LDFLAGS)
 
-structure.o: structure.c structure.h
-       $(CC) $(CFLAGS) $(GTK_CFLAGS) -o $@ -c structure.c
-
-shp2pgsql-gui.o: shp2pgsql-gui.c structure.h shp2pgsql-core.h shpcommon.h
+shp2pgsql-gui.o: shp2pgsql-gui.c shp2pgsql-core.h shpcommon.h
        $(CC) $(CFLAGS) $(GTK_CFLAGS) $(PGSQL_FE_CPPFLAGS) -o $@ -c shp2pgsql-gui.c
 
-$(SHP2PGSQL-GUI): shpopen.o dbfopen.o shp2pgsql-core.o shpcommon.o shp2pgsql-gui.o getopt.o structure.o safileio.o $(LIBLWGEOM) $(GTK_WIN32_RES)
+$(SHP2PGSQL-GUI): shpopen.o dbfopen.o shp2pgsql-core.o shpcommon.o shp2pgsql-gui.o getopt.o safileio.o pgsql2shp-core.o $(LIBLWGEOM) $(GTK_WIN32_RES)
        $(LIBTOOL) --mode=link $(CC) $(CFLAGS) $(GTK_WIN32_FLAGS) $^ -o $@ $(GTK_LIBS) $(ICONV_LDFLAGS) $(PGSQL_FE_LDFLAGS) $(GETTEXT_LDFLAGS)
 
 installdir:
index f116fdaff8764e4f6046081a9e435a10aa7a9b74..cd07017f4d02f8fa5c9d957b6dceb579cb2ea2b5 100644 (file)
@@ -54,18 +54,6 @@ LOADER_OBJS= \
        ../pgsql2shp-core.o \
        ../shp2pgsql-core.o
 
-# We test this variable later to see if we're building the GUI
-gtk_build = @GTK_BUILD@
-
-# If we are, define a variable so we can conditionally perform regression
-# and also build an extra test file
-ifneq ($(gtk_build),)
-CFLAGS += -DGTK
-OBJS += cu_list.o
-LOADER_OBJS += ../structure.o
-endif
-
-
 # If we couldn't find the cunit library then display a helpful message
 ifeq ($(CUNIT_LDFLAGS),)
 all: requirements_not_met_cunit
diff --git a/loader/cunit/cu_list.c b/loader/cunit/cu_list.c
deleted file mode 100644 (file)
index 40ad8d4..0000000
+++ /dev/null
@@ -1,337 +0,0 @@
-/**********************************************************************
- * $Id: cu_list.c 5674 2010-06-03 02:04:15Z mleslie $
- *
- * PostGIS - Spatial Types for PostgreSQL
- * http://postgis.refractions.net
- * Copyright 2010 LISAsoft Pty Ltd
- *
- * This is free software; you can redistribute and/or modify it under
- * the terms of the GNU General Public Licence. See the COPYING file.
- *
- **********************************************************************/
-
-#include "cu_list.h"
-#include "cu_tester.h"
-#include "../structure.h"
-
-/*
-typedef struct _GtkTreeIter GtkTreeIter;
-
-struct _GtkTreeIter
-{
-       gint stamp;
-       gpointer user_data;
-       gpointer user_data2;
-       gpointer user_data3;
-}
-*/
-
-/* Test functions */
-void test_append_file(void);
-void test_find_file(void);
-void test_traversal(void);
-void test_remove_first(void);
-void test_remove_middle(void);
-void test_remove_last(void);
-void test_find_index(void);
-
-/*
-** Called from test harness to register the tests in this file.
-*/
-CU_pSuite register_list_suite(void)
-{
-       CU_pSuite pSuite;
-       pSuite = CU_add_suite("GUI Shapefile Loader File List Test", init_list_suite, clean_list_suite);
-       if (NULL == pSuite)
-       {
-               CU_cleanup_registry();
-               return NULL;
-       }
-
-       if (
-           (NULL == CU_add_test(pSuite, "test_append_file()", test_append_file))
-           ||
-           (NULL == CU_add_test(pSuite, "test_find_file()", test_find_file))
-           ||
-           (NULL == CU_add_test(pSuite, "test_traversal()", test_traversal))
-           ||
-           (NULL == CU_add_test(pSuite, "test_remove_first()", test_remove_first))
-           ||
-           (NULL == CU_add_test(pSuite, "test_remove_last()", test_remove_first))
-           ||
-           (NULL == CU_add_test(pSuite, "test_remove_middle()", test_remove_middle))
-           ||
-           (NULL == CU_add_test(pSuite, "test_find_index()", test_find_index))
-       )
-       {
-               CU_cleanup_registry();
-               return NULL;
-       }
-       return pSuite;
-}
-
-/*
-** The suite initialization function.
-** Create any re-used objects.
-*/
-int init_list_suite(void)
-{
-       return 0;
-
-}
-
-/*
-** The suite cleanup function.
-** Frees any global objects.
-*/
-int clean_list_suite(void)
-{
-       return 0;
-}
-
-void test_append_file(void)
-{
-       FILENODE *node;
-       GtkTreeIter iter;
-       init_file_list();
-
-       node = append_file("file1", "schema", "table", "geom_column", "-1", 'c', &iter);
-       CU_ASSERT_PTR_NOT_NULL(node);
-
-       node = append_file("file2", "schema", "table", "geom_column", "-1", 'c', &iter);
-       CU_ASSERT_PTR_NOT_NULL(node);
-
-       destroy_file_list();
-}
-
-void test_find_file(void)
-{
-       FILENODE *node;
-       FILENODE *keeper_node;
-       GtkTreeIter iter;
-       GtkTreeIter keeper_iter;
-       init_file_list();
-
-       node = append_file("file1", "schema", "table", "geom_column", "-1", 'c', &iter);
-       CU_ASSERT_PTR_NOT_NULL(node);
-
-       node = append_file("file2", "schema", "table", "geom_column", "-1", 'c', &iter);
-       CU_ASSERT_PTR_NOT_NULL(node);
-       node = append_file("file3", "schema", "table", "geom_column", "-1", 'c', &iter);
-       CU_ASSERT_PTR_NOT_NULL(node);
-
-       node = append_file("file4", "schema", "table", "geom_column", "-1", 'c', &iter);
-       CU_ASSERT_PTR_NOT_NULL(node);
-       keeper_node = append_file("file5", "schema", "table", "geom_column", "-1", 'c', &keeper_iter);
-       CU_ASSERT_PTR_NOT_NULL(node);
-
-       node = append_file("file6", "schema", "table", "geom_column", "-1", 'c', &iter);
-       CU_ASSERT_PTR_NOT_NULL(node);
-       node = append_file("file7", "schema", "table", "geom_column", "-1", 'c', &iter);
-       CU_ASSERT_PTR_NOT_NULL(node);
-
-       node = append_file("file8", "schema", "table", "geom_column", "-1", 'c', &iter);
-       CU_ASSERT_PTR_NOT_NULL(node);
-
-       node = find_file_by_iter(&keeper_iter);
-       CU_ASSERT_PTR_NOT_NULL(node);
-       CU_ASSERT_PTR_EQUAL(node, keeper_node);
-
-       destroy_file_list();
-}
-
-void test_traversal(void)
-{
-       FILENODE *node[5];
-       FILENODE *current_node;
-       GtkTreeIter iter;
-       int i = 0;
-       init_file_list();
-
-       node[0] = append_file("file1", "schema", "table", "geom_column", "-1", 'c', &iter);
-       CU_ASSERT_PTR_NOT_NULL(node[0]);
-       node[1] = append_file("file2", "schema", "table", "geom_column", "-1", 'c', &iter);
-       CU_ASSERT_PTR_NOT_NULL(node[1]);
-       node[2] = append_file("file3", "schema", "table", "geom_column", "-1", 'c', &iter);
-       CU_ASSERT_PTR_NOT_NULL(node[2]);
-       node[3] = append_file("file4", "schema", "table", "geom_column", "-1", 'c', &iter);
-       CU_ASSERT_PTR_NOT_NULL(node[3]);
-       node[4] = append_file("file5", "schema", "table", "geom_column", "-1", 'c', &iter);
-       CU_ASSERT_PTR_NOT_NULL(node[4]);
-
-       current_node = get_next_node(NULL);
-       CU_ASSERT_PTR_NOT_NULL(current_node);
-       while (current_node != NULL)
-       {
-               CU_ASSERT_NOT_EQUAL(i, 5);
-               CU_ASSERT_PTR_EQUAL(current_node, node[i]);
-               current_node = get_next_node(current_node);
-               i++;
-       }
-}
-
-void test_remove_first(void)
-{
-       FILENODE *node[5];
-       FILENODE *current_node;
-       GtkTreeIter iter;
-       int i = 0;
-       init_file_list();
-
-       node[0] = append_file("file1", "schema", "table", "geom_column", "-1", 'c', &iter);
-       CU_ASSERT_PTR_NOT_NULL(node[0]);
-       node[1] = append_file("file2", "schema", "table", "geom_column", "-1", 'c', &iter);
-       CU_ASSERT_PTR_NOT_NULL(node[1]);
-       node[2] = append_file("file3", "schema", "table", "geom_column", "-1", 'c', &iter);
-       CU_ASSERT_PTR_NOT_NULL(node[2]);
-       node[3] = append_file("file4", "schema", "table", "geom_column", "-1", 'c', &iter);
-       CU_ASSERT_PTR_NOT_NULL(node[3]);
-       node[4] = append_file("file5", "schema", "table", "geom_column", "-1", 'c', &iter);
-       CU_ASSERT_PTR_NOT_NULL(node[4]);
-
-       current_node = get_next_node(NULL);
-       CU_ASSERT_PTR_NOT_NULL(current_node);
-       while (current_node != NULL)
-       {
-               CU_ASSERT_NOT_EQUAL(i, 5);
-               CU_ASSERT_PTR_EQUAL(current_node, node[i]);
-               current_node = get_next_node(current_node);
-               i++;
-       }
-
-       remove_file(node[0]);
-       i = 1;
-       current_node = get_next_node(NULL);
-       CU_ASSERT_PTR_NOT_NULL(current_node);
-       while (current_node != NULL)
-       {
-               CU_ASSERT_NOT_EQUAL(i, 5);
-               CU_ASSERT_PTR_EQUAL(current_node, node[i]);
-               current_node = get_next_node(current_node);
-               i++;
-       }
-       CU_ASSERT_EQUAL(i, 5);
-
-}
-
-void test_remove_last(void)
-{
-       FILENODE *node[5];
-       FILENODE *current_node;
-       GtkTreeIter iter;
-       int i = 0;
-       init_file_list();
-
-       node[0] = append_file("file1", "schema", "table", "geom_column", "-1", 'c', &iter);
-       CU_ASSERT_PTR_NOT_NULL(node[0]);
-       node[1] = append_file("file2", "schema", "table", "geom_column", "-1", 'c', &iter);
-       CU_ASSERT_PTR_NOT_NULL(node[1]);
-       node[2] = append_file("file3", "schema", "table", "geom_column", "-1", 'c', &iter);
-       CU_ASSERT_PTR_NOT_NULL(node[2]);
-       node[3] = append_file("file4", "schema", "table", "geom_column", "-1", 'c', &iter);
-       CU_ASSERT_PTR_NOT_NULL(node[3]);
-       node[4] = append_file("file5", "schema", "table", "geom_column", "-1", 'c', &iter);
-       CU_ASSERT_PTR_NOT_NULL(node[4]);
-
-       current_node = get_next_node(NULL);
-       CU_ASSERT_PTR_NOT_NULL(current_node);
-       while (current_node != NULL)
-       {
-               CU_ASSERT_NOT_EQUAL(i, 5);
-               CU_ASSERT_PTR_EQUAL(current_node, node[i]);
-               current_node = get_next_node(current_node);
-               i++;
-       }
-
-       remove_file(node[4]);
-       i = 0;
-       current_node = get_next_node(NULL);
-       CU_ASSERT_PTR_NOT_NULL(current_node);
-       while (current_node != NULL)
-       {
-               CU_ASSERT_NOT_EQUAL(i, 4);
-               CU_ASSERT_PTR_EQUAL(current_node, node[i]);
-               current_node = get_next_node(current_node);
-               i++;
-       }
-       CU_ASSERT_EQUAL(i, 4);
-
-}
-
-void test_remove_middle(void)
-{
-       FILENODE *node[5];
-       FILENODE *current_node;
-       GtkTreeIter iter;
-       int i = 0;
-       init_file_list();
-
-       node[0] = append_file("file1", "schema", "table", "geom_column", "-1", 'c', &iter);
-       CU_ASSERT_PTR_NOT_NULL(node[0]);
-       node[1] = append_file("file2", "schema", "table", "geom_column", "-1", 'c', &iter);
-       CU_ASSERT_PTR_NOT_NULL(node[1]);
-       node[2] = append_file("file3", "schema", "table", "geom_column", "-1", 'c', &iter);
-       CU_ASSERT_PTR_NOT_NULL(node[2]);
-       node[3] = append_file("file4", "schema", "table", "geom_column", "-1", 'c', &iter);
-       CU_ASSERT_PTR_NOT_NULL(node[3]);
-       node[4] = append_file("file5", "schema", "table", "geom_column", "-1", 'c', &iter);
-       CU_ASSERT_PTR_NOT_NULL(node[4]);
-
-       current_node = get_next_node(NULL);
-       CU_ASSERT_PTR_NOT_NULL(current_node);
-       while (current_node != NULL)
-       {
-               CU_ASSERT_NOT_EQUAL(i, 5);
-               CU_ASSERT_PTR_EQUAL(current_node, node[i]);
-               current_node = get_next_node(current_node);
-               i++;
-       }
-
-       remove_file(node[3]);
-       i = 0;
-       current_node = get_next_node(NULL);
-       CU_ASSERT_PTR_NOT_NULL(current_node);
-       while (current_node != NULL)
-       {
-               CU_ASSERT_NOT_EQUAL(i, 5);
-               CU_ASSERT_PTR_EQUAL(current_node, node[i]);
-               current_node = get_next_node(current_node);
-               i++;
-               if (i == 3)
-                       i++;
-       }
-       CU_ASSERT_EQUAL(i, 5);
-
-       destroy_file_list();
-
-}
-
-void test_find_index(void)
-{
-       FILENODE *node[5];
-       FILENODE *current_node;
-       GtkTreeIter iter;
-       int index[11] = {4, 3, 2, 1, 0, 3, 2, 4, 0, 1, 1};
-       int i = 0;
-       init_file_list();
-
-       node[0] = append_file("file1", "schema", "table", "geom_column", "-1", 'c', &iter);
-       CU_ASSERT_PTR_NOT_NULL(node[0]);
-       node[1] = append_file("file2", "schema", "table", "geom_column", "-1", 'c', &iter);
-       CU_ASSERT_PTR_NOT_NULL(node[1]);
-       node[2] = append_file("file3", "schema", "table", "geom_column", "-1", 'c', &iter);
-       CU_ASSERT_PTR_NOT_NULL(node[2]);
-       node[3] = append_file("file4", "schema", "table", "geom_column", "-1", 'c', &iter);
-       CU_ASSERT_PTR_NOT_NULL(node[3]);
-       node[4] = append_file("file5", "schema", "table", "geom_column", "-1", 'c', &iter);
-       CU_ASSERT_PTR_NOT_NULL(node[4]);
-
-       for (i = 0; i < 11; i++)
-       {
-               current_node = find_file_by_index(index[i]);
-               CU_ASSERT_PTR_EQUAL(node[index[i]], current_node);
-       }
-
-       destroy_file_list();
-
-}
diff --git a/loader/cunit/cu_list.h b/loader/cunit/cu_list.h
deleted file mode 100644 (file)
index 60cfe72..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-/**********************************************************************
- * $Id: cu_list.h 5674 2010-06-03 02:04:15Z mleslie $
- *
- * PostGIS - Spatial Types for PostgreSQL
- * http://postgis.refractions.net
- * Copyright 2010 LISAsoft Pty Ltd
- *
- * This is free software; you can redistribute and/or modify it under
- * the terms of the GNU General Public Licence. See the COPYING file.
- *
- **********************************************************************/
-
-#ifndef __cu_list_h__
-#define __cu_list_h__
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include "CUnit/Basic.h"
-
-/***********************************************************************
-** for Computational Geometry Suite
-*/
-
-/* Admin functions */
-int init_list_suite(void);
-int clean_list_suite(void);
-
-#endif /* __cu_list_h__ */
index 333a1e13d573cf9cb40926fdccd24914c140c608..9d22833808a808c950fa19fb29ad21bca9d2782f 100644 (file)
@@ -27,15 +27,6 @@ int main()
        if (CUE_SUCCESS != CU_initialize_registry())
                return CU_get_error();
 
-#ifdef GTK
-       /* Add the GUI algorithms suite to the registry */
-       if (NULL == register_list_suite())
-       {
-               CU_cleanup_registry();
-               return CU_get_error();
-       }
-#endif
-
        /* Add the shp2pgsql test suite */
        if (NULL == register_shp2pgsql_suite())
        {
index c0edc6298bdaf0802528b5679d6df31a3f8ea7d8..f391472ef7325a0029424e8156348ad32fd3f0e6 100644 (file)
@@ -1264,56 +1264,67 @@ ShpDumperCreate(SHPDUMPERCONFIG *config)
        return state;
 }
 
-
-/* Connect to the database and identify the version of PostGIS (and any other
-capabilities required) */
-int
-ShpDumperConnectDatabase(SHPDUMPERSTATE *state)
+/* Generate the database connection string used by a state */
+char *
+ShpDumperGetConnectionStringFromConn(SHPCONNECTIONCONFIG *conn)
 {
-       PGresult *res;
-
-       char *connstring, *tmpvalue;
+       char *connstring;
        int connlen;
-
-       /* Generate database connection string */
+       
        connlen = 64 + 
-               (state->config->conn->host ? strlen(state->config->conn->host) : 0) + (state->config->conn->port ? strlen(state->config->conn->port) : 0) +
-               (state->config->conn->username ? strlen(state->config->conn->username) : 0) + (state->config->conn->password ? strlen(state->config->conn->password) : 0) +
-               (state->config->conn->database ? strlen(state->config->conn->database) : 0);
+               (conn->host ? strlen(conn->host) : 0) + (conn->port ? strlen(conn->port) : 0) +
+               (conn->username ? strlen(conn->username) : 0) + (conn->password ? strlen(conn->password) : 0) +
+               (conn->database ? strlen(conn->database) : 0);
 
        connstring = malloc(connlen);
        memset(connstring, 0, connlen);
 
-       if (state->config->conn->host)
+       if (conn->host)
        {
                strcat(connstring, " host=");
-               strcat(connstring, state->config->conn->host);
+               strcat(connstring, conn->host);
        }
 
-       if (state->config->conn->port)
+       if (conn->port)
        {
                strcat(connstring, " port=");
-               strcat(connstring, state->config->conn->port);
+               strcat(connstring, conn->port);
        }
 
-       if (state->config->conn->username)
+       if (conn->username)
        {
                strcat(connstring, " user=");
-               strcat(connstring, state->config->conn->username);
+               strcat(connstring, conn->username);
        }
 
-       if (state->config->conn->password)
+       if (conn->password)
        {       
-               strcat(connstring, " password=");
-               strcat(connstring, state->config->conn->password);
+               strcat(connstring, " password='");
+               strcat(connstring, conn->password);
+               strcat(connstring, "'");
        }
 
-       if (state->config->conn->database)
+       if (conn->database)
        {
                strcat(connstring, " dbname=");
-               strcat(connstring, state->config->conn->database);
+               strcat(connstring, conn->database);
        }
 
+       return connstring;
+}
+
+/* Connect to the database and identify the version of PostGIS (and any other
+capabilities required) */
+int
+ShpDumperConnectDatabase(SHPDUMPERSTATE *state)
+{
+       PGresult *res;
+
+       char *connstring, *tmpvalue;
+
+       /* Generate the PostgreSQL connection string */
+       connstring = ShpDumperGetConnectionStringFromConn(state->config->conn);
+
        /* Connect to the database */
        state->conn = PQconnectdb(connstring);
        if (PQstatus(state->conn) == CONNECTION_BAD)
@@ -1457,7 +1468,7 @@ ShpDumperOpenTable(SHPDUMPERSTATE *state)
                query = malloc(250 + strlen(state->schema) + strlen(state->table));
 
                sprintf(query, "SELECT a.attname, a.atttypid, "
-                       "a.atttypmod FROM "
+                       "a.atttypmod, a.attlen FROM "
                        "pg_attribute a, pg_class c, pg_namespace n WHERE "
                        "n.nspname = '%s' AND a.attrelid = c.oid AND "
                        "n.oid = c.relnamespace AND "
@@ -1469,7 +1480,7 @@ ShpDumperOpenTable(SHPDUMPERSTATE *state)
                query = malloc(250 + strlen(state->table));
 
                sprintf(query, "SELECT a.attname, a.atttypid, "
-                       "a.atttypmod FROM "
+                       "a.atttypmod, a.attlen FROM "
                        "pg_attribute a, pg_class c WHERE "
                        "a.attrelid = c.oid and a.attnum > 0 AND "
                        "a.atttypid != 0 AND "
@@ -1516,6 +1527,8 @@ ShpDumperOpenTable(SHPDUMPERSTATE *state)
        state->dbffieldnames = malloc(sizeof(char *) * PQntuples(res));
        state->dbffieldtypes = malloc(sizeof(int) * PQntuples(res));
        state->pgfieldnames = malloc(sizeof(char *) * PQntuples(res));
+       state->pgfieldlens = malloc(sizeof(int) * PQntuples(res));
+       state->pgfieldtypmods = malloc(sizeof(int) * PQntuples(res));
        state->fieldcount = 0;
        int tmpint = 1;
 
@@ -1523,7 +1536,7 @@ ShpDumperOpenTable(SHPDUMPERSTATE *state)
        {
                char *ptr;
 
-               int pgfieldtype, pgtypmod;
+               int pgfieldtype, pgtypmod, pgfieldlen;
                char *pgfieldname;
 
                int dbffieldtype, dbffieldsize, dbffielddecs;
@@ -1532,6 +1545,7 @@ ShpDumperOpenTable(SHPDUMPERSTATE *state)
                pgfieldname = PQgetvalue(res, i, 0);
                pgfieldtype = atoi(PQgetvalue(res, i, 1));
                pgtypmod = atoi(PQgetvalue(res, i, 2));
+               pgfieldlen = atoi(PQgetvalue(res, i, 3));
                dbffieldtype = -1;
                dbffieldsize = 0;
                dbffielddecs = 0;
@@ -1837,7 +1851,9 @@ ShpDumperOpenTable(SHPDUMPERSTATE *state)
                        state->dbffieldnames[state->fieldcount] = dbffieldname;
                        state->dbffieldtypes[state->fieldcount] = dbffieldtype;
                        state->pgfieldnames[state->fieldcount] = pgfieldname;
-       
+                       state->pgfieldlens[state->fieldcount] = pgfieldlen;
+                       state->pgfieldtypmods[state->fieldcount] = pgtypmod;
+                       
                        state->fieldcount++;
                }
        }
index 111351a1dbf1469444cb22c40c72698a54b76b18..2119364fca2198e21db90892c763182a4829567d 100644 (file)
@@ -141,6 +141,12 @@ typedef struct shp_dumper_state
        /* PostgreSQL column names for all non-spatial fields */
        char **pgfieldnames;
 
+       /* PostgreSQL column lengths for all non-spatial fields */
+       int *pgfieldlens;
+       
+       /* PostgreSQL column typmods for all non-spatial fields */
+       int *pgfieldtypmods;
+       
        /* Number of non-spatial fields in DBF output file */
        int fieldcount;
 
@@ -203,6 +209,7 @@ void set_dumper_config_defaults(SHPDUMPERCONFIG *config);
 char *shapetypename(int num);
 
 SHPDUMPERSTATE *ShpDumperCreate(SHPDUMPERCONFIG *config);
+char *ShpDumperGetConnectionStringFromConn(SHPCONNECTIONCONFIG *config);
 int ShpDumperConnectDatabase(SHPDUMPERSTATE *state);
 int ShpDumperOpenTable(SHPDUMPERSTATE *state);
 int ShpDumperGetRecordCount(SHPDUMPERSTATE *state);
index 4b0efe88c82aa54d7086be67cc820d07e3f810c8..96987178c07361e998adc9d94b7df1e5ee62a8d4 100644 (file)
@@ -1030,6 +1030,7 @@ ShpLoaderOpenShape(SHPLOADERSTATE *state)
        state->types = (DBFFieldType *)malloc(state->num_fields * sizeof(int));
        state->widths = malloc(state->num_fields * sizeof(int));
        state->precisions = malloc(state->num_fields * sizeof(int));
+       state->pgfieldtypes = malloc(state->num_fields * sizeof(char *));
        state->col_names = malloc((state->num_fields + 2) * sizeof(char) * MAXFIELDNAMELEN);
 
        /* Generate a string of comma separated column names of the form "(col1, col2 ... colN)" for the SQL
@@ -1110,6 +1111,62 @@ ShpLoaderOpenShape(SHPLOADERSTATE *state)
                state->field_names[j] = malloc(strlen(name) + 1);
                strcpy(state->field_names[j], name);
 
+               /* Now generate the PostgreSQL type name string and width based upon the shapefile type */
+               switch (state->types[j])
+               {
+               case FTString:
+                       state->pgfieldtypes[j] = malloc(strlen("varchar") + 1);
+                       strcpy(state->pgfieldtypes[j], "varchar");
+                       break;
+
+               case FTDate:
+                       state->pgfieldtypes[j] = malloc(strlen("date") + 1);
+                       strcpy(state->pgfieldtypes[j], "date");
+                       break;
+
+               case FTInteger:
+                       /* Determine exact type based upon field width */
+                       if (state->config->forceint4 || (state->widths[j] >=5 && state->widths[j] < 10))
+                       {
+                               state->pgfieldtypes[j] = malloc(strlen("int4") + 1);
+                               strcpy(state->pgfieldtypes[j], "int4"); 
+                       }
+                       else if (state->widths[j] < 5)
+                       {
+                               state->pgfieldtypes[j] = malloc(strlen("int2") + 1);
+                               strcpy(state->pgfieldtypes[j], "int2");
+                       }
+                       else
+                       {
+                               state->pgfieldtypes[j] = malloc(strlen("numeric") + 1);
+                               strcpy(state->pgfieldtypes[j], "numeric");
+                       }
+                       break;
+
+               case FTDouble:
+                       /* Determine exact type based upon field width */
+                       if (state->widths[j] > 18)
+                       {
+                               state->pgfieldtypes[j] = malloc(strlen("numeric") + 1);
+                               strcpy(state->pgfieldtypes[j], "numeric");
+                       }
+                       else
+                       {
+                               state->pgfieldtypes[j] = malloc(strlen("float8") + 1);
+                               strcpy(state->pgfieldtypes[j], "float8");
+                       }
+                       break;
+
+               case FTLogical:
+                       state->pgfieldtypes[j] = malloc(strlen("boolean") + 1);
+                       strcpy(state->pgfieldtypes[j], "boolean");
+                       break;
+
+               default:
+                       snprintf(state->message, SHPLOADERMSGLEN, _("Invalid type %x in DBF file"), state->types[j]);
+                       return SHPLOADERERR;
+               }
+               
                strcat(state->col_names, "\"");
                strcat(state->col_names, name);
 
@@ -1147,13 +1204,13 @@ ShpLoaderGetSQLHeader(SHPLOADERSTATE *state, char **strheader)
           for handling string resizing during append */
        sb = stringbuffer_create();
        stringbuffer_clear(sb);
-
+       
        /* Set the client encoding if required */
        if (state->config->encoding)
        {
                stringbuffer_aprintf(sb, "SET CLIENT_ENCODING TO UTF8;\n");
        }
-
+       
        /* Use SQL-standard string escaping rather than PostgreSQL standard */
        stringbuffer_aprintf(sb, "SET STANDARD_CONFORMING_STRINGS TO ON;\n");
 
@@ -1222,57 +1279,18 @@ ShpLoaderGetSQLHeader(SHPLOADERSTATE *state, char **strheader)
                {
                        stringbuffer_aprintf(sb, ",\n\"%s\" ", state->field_names[j]);
 
-                       switch (state->types[j])
-                       {
-                       case FTString:
-                               /* use DBF attribute size as maximum width */
-                               stringbuffer_aprintf(sb, "varchar(%d)", state->widths[j]);
-                               break;
-
-                       case FTDate:
-                               stringbuffer_aprintf(sb, "date");
-                               break;
+                       /* First output the raw field type string */
+                       stringbuffer_aprintf(sb, "%s", state->pgfieldtypes[j]);
+                       
+                       /* Some types do have typmods though... */
+                       if (!strcmp("varchar", state->pgfieldtypes[j]))
+                               stringbuffer_aprintf(sb, "(%d)", state->widths[j]);
 
-                       case FTInteger:
-                               /* Determine exact type based upon field width */
-                               if (state->config->forceint4)
-                               {
-                                       stringbuffer_aprintf(sb, "int4");
-                               }
-                               else if (state->widths[j] < 5)
-                               {
-                                       stringbuffer_aprintf(sb, "int2");
-                               }
-                               else if (state->widths[j] < 10)
-                               {
-                                       stringbuffer_aprintf(sb, "int4");
-                               }
-                               else
-                               {
-                                       stringbuffer_aprintf(sb, "numeric(%d,0)", state->widths[j]);
-                               }
-                               break;
-
-                       case FTDouble:
-                               /* Determine exact type based upon field width */
-                               if (state->widths[j] > 18)
-                               {
-                                       stringbuffer_aprintf(sb, "numeric");
-                               }
-                               else
-                               {
-                                       stringbuffer_aprintf(sb, "float8");
-                               }
-                               break;
-
-                       case FTLogical:
-                               stringbuffer_aprintf(sb, "boolean");
-                               break;
-
-                       default:
-                               snprintf(state->message, SHPLOADERMSGLEN, _("Invalid type %x in DBF file"), state->types[j]);
-                               stringbuffer_destroy(sb);
-                               return SHPLOADERERR;
+                       if (!strcmp("numeric", state->pgfieldtypes[j]))
+                       {
+                               /* Doubles we just allow PostgreSQL to auto-detect the size */
+                               if (state->types[j] != FTDouble)
+                                       stringbuffer_aprintf(sb, "(%d,0)", state->widths[j]);
                        }
                }
 
@@ -1758,7 +1776,8 @@ void
 ShpLoaderDestroy(SHPLOADERSTATE *state)
 {
        /* Destroy a state object created with ShpLoaderOpenShape */
-
+       int i;
+       
        if (state != NULL)
        {
                if (state->hSHPHandle)
@@ -1767,12 +1786,18 @@ ShpLoaderDestroy(SHPLOADERSTATE *state)
                        DBFClose(state->hDBFHandle);
                if (state->field_names)
                {
-                       int i;
                        for (i = 0; i < state->num_fields; i++)
                                free(state->field_names[i]);
 
                        free(state->field_names);
                }
+               if (state->pgfieldtypes)
+               {
+                       for (i = 0; i < state->num_fields; i++)
+                               free(state->pgfieldtypes[i]);
+                       
+                       free(state->pgfieldtypes);
+               }
                if (state->types)
                        free(state->types);
                if (state->widths)
@@ -1786,6 +1811,3 @@ ShpLoaderDestroy(SHPLOADERSTATE *state)
                free(state);
        }
 }
-
-
-
index 1fa5f22b42105d70d8ea19034037da16f344d6b2..b516299122c30c9df0cf183726881d4e1b813aff 100644 (file)
@@ -187,6 +187,9 @@ typedef struct shp_loader_state
        int *widths;
        int *precisions;
 
+       /* Pointer to an array of PostgreSQL field types */
+       char **pgfieldtypes;
+       
        /* String containing colume name list in the form "(col1, col2, col3 ... , colN)" */
        char *col_names;
 
index 0d6e1e207de25427f3c364cc81ed1a4e6b0c9579..5b99a36be50be4acce83765fed8311f094c97e68 100644 (file)
 #include <sys/stat.h>
 #include "libpq-fe.h"
 #include "shp2pgsql-core.h"
-#include "structure.h"
+#include "pgsql2shp-core.h"
 
 #include "../liblwgeom/liblwgeom.h" /* for lw_vasprintf */
 
 #define GUI_RCSID "shp2pgsql-gui $Revision$"
 #define SHAPEFIELDMAXWIDTH 60
-#define SHAPEFIELDMINWIDTH 30
+
+static void pgui_log_va(const char *fmt, va_list ap);
+static void pgui_seterr_va(const char *fmt, va_list ap);
 
 /*
 ** Global variables for GUI only
 
 /* Main window */
 static GtkWidget *window_main = NULL;
-static GtkWidget *entry_pg_user = NULL;
-static GtkWidget *entry_pg_pass = NULL;
-static GtkWidget *entry_pg_host = NULL;
-static GtkWidget *entry_pg_port = NULL;
-static GtkWidget *entry_pg_db = NULL;
-static GtkWidget *label_pg_connection_test = NULL;
+
 static GtkWidget *textview_log = NULL;
 static GtkWidget *add_file_button = NULL;
-static GtkWidget *progress = NULL;
 static GtkTextBuffer *textbuffer_log = NULL;
-static int current_list_index = 0;
-static int valid_connection = 0;
-
-/* Tree View Stuffs */
-
-enum
-{
-       FILENAME_COLUMN,
-       SCHEMA_COLUMN,
-       TABLE_COLUMN,
-       GEOMETRY_COLUMN,
-       SRID_COLUMN,
-       MODE_COLUMN,
-       REMOVE_COLUMN,
-       N_COLUMNS
-};
-
-enum
-{
-       COMBO_TEXT,
-       COMBO_COLUMNS
-};
-
-enum
-{
-       CREATE_MODE,
-       APPEND_MODE,
-       DELETE_MODE,
-       PREPARE_MODE
-};
-
-
-static void pgui_logf(const char *fmt, ...);
-static void pgui_log_va(const char *fmt, va_list ap);
-
 
+/* Main window (listview) */
 GtkListStore *list_store;
 GtkWidget *tree;
 GtkCellRenderer *filename_renderer;
@@ -102,10 +64,19 @@ GtkTreeViewColumn *mode_column;
 GtkTreeViewColumn *remove_column;
 
 GtkWidget *mode_combo = NULL;
-
 GtkListStore *combo_list;
 
+/* PostgreSQL database connection window */
+static GtkWidget *window_conn = NULL;
+
+static GtkWidget *entry_pg_user = NULL;
+static GtkWidget *entry_pg_pass = NULL;
+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;
 static GtkWidget *entry_options_encoding = NULL;
 static GtkWidget *checkbutton_options_preservecase = NULL;
 static GtkWidget *checkbutton_options_forceint = NULL;
@@ -114,31 +85,61 @@ static GtkWidget *checkbutton_options_dbfonly = NULL;
 static GtkWidget *checkbutton_options_dumpformat = NULL;
 static GtkWidget *checkbutton_options_geography = NULL;
 
+/* About dialog */
+static GtkWidget *dialog_about = NULL;
+
+/* File chooser */
+static GtkWidget *dialog_filechooser = NULL;
+
+/* Progress dialog */
+static GtkWidget *dialog_progress = NULL;
+static GtkWidget *progress = NULL;
+static GtkWidget *label_progress = 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
+};
+
+enum
+{
+       COMBO_TEXT,
+       COMBO_OPTION_CHAR,
+       COMBO_COLUMNS
+};
+
+enum
+{
+       CREATE_MODE,
+       APPEND_MODE,
+       DELETE_MODE,
+       PREPARE_MODE
+};
+
 /* Other */
 static char *pgui_errmsg = NULL;
 static PGconn *pg_connection = NULL;
-static SHPLOADERCONFIG *config = NULL;
 static SHPLOADERSTATE *state = NULL;
 static SHPCONNECTIONCONFIG *conn = NULL;
+static SHPLOADERCONFIG *global_loader_config = NULL;
 
-static volatile int import_running = 0;
+static volatile int import_running = FALSE;
 
 /* Local prototypes */
-static void pgui_create_options_dialogue(void);
-static void pgui_create_file_table(GtkWidget *frame_shape);
-static void pgui_action_shape_file_set(const char *gtk_filename);
-static void pgui_action_handle_file_drop(GtkWidget *widget,
-        GdkDragContext *dc,
-        gint x, gint y,
-        GtkSelectionData *selection_data,
-        guint info, guint t, gpointer data);
-static int validate_string(char *string);
-static int validate_shape_file(FILENODE *filenode);
-static int validate_shape_filename(const char *filename);
-static void pgui_set_config_from_options_ui(void);
-static void pgui_set_config_from_ui(FILENODE *file);
 static void pgui_sanitize_connection_string(char *connection_string);
-static char *pgui_read_connection(void);
+
 
 /*
 ** Write a message to the Import Log text area.
@@ -181,522 +182,286 @@ pgui_logf(const char *fmt, ...)
        return;
 }
 
-static void
-pgui_seterr(const char *errmsg)
+/* Write an error message */
+void
+pgui_seterr_va(const char *fmt, va_list ap)
 {
-       if ( pgui_errmsg )
-       {
+       /* Free any existing message */
+       if (pgui_errmsg)
                free(pgui_errmsg);
-       }
-       pgui_errmsg = strdup(errmsg);
+       
+       if (!lw_vasprintf (&pgui_errmsg, fmt, ap)) return;
+}
+
+static void
+pgui_seterr(const char *fmt, ...)
+{
+       va_list ap;
+       va_start(ap, fmt);
+       
+       pgui_seterr_va(fmt, ap);
+       
+       va_end(ap);
        return;
 }
 
-/*
- * Ensures that the field width is within the stated bounds, and
- * 'appropriately' sized, for some definition of 'appropriately'.
- */
 static void
-set_filename_field_width(void)
+pgui_raise_error_dialogue(void)
 {
-       FILENODE *node;
-       int needed_width = -1;
-       int i;
+       GtkWidget *dialog, *label;
+       gint result;
+
+       label = gtk_label_new(pgui_errmsg);
+       dialog = gtk_dialog_new_with_buttons(_("Error"), GTK_WINDOW(window_main),
+                                            GTK_DIALOG_MODAL & GTK_DIALOG_NO_SEPARATOR & GTK_DIALOG_DESTROY_WITH_PARENT,
+                                            GTK_STOCK_OK, GTK_RESPONSE_OK, NULL);
+       gtk_dialog_set_has_separator(GTK_DIALOG(dialog), FALSE );
+       gtk_container_set_border_width(GTK_CONTAINER(dialog), 5);
+       gtk_container_set_border_width(GTK_CONTAINER (GTK_DIALOG(dialog)->vbox), 15);
+       gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), label);
+       gtk_widget_show_all(dialog);
+       result = gtk_dialog_run(GTK_DIALOG(dialog));
+       gtk_widget_destroy(dialog);
+       return;
+}
+
+/*
+** Run a SQL command against the current connection.
+*/
+static int
+pgui_exec(const char *sql)
+{
+       PGresult *res = NULL;
+       ExecStatusType status;
+       char sql_trunc[256];
+
+       /* We need a connection to do anything. */
+       if ( ! pg_connection ) return 0;
+       if ( ! sql ) return 0;
+
+       res = PQexec(pg_connection, sql);
+       status = PQresultStatus(res);
+       PQclear(res);
 
-       node = get_next_node(NULL);
-       while (node)
+       /* Did something unexpected happen? */
+       if ( ! ( status == PGRES_COMMAND_OK || status == PGRES_TUPLES_OK ) )
        {
-               i = strlen(node->filename);
-               if (i > needed_width)
+               /* Log notices and return success. */
+               if ( status == PGRES_NONFATAL_ERROR )
                {
-                       needed_width = i;
+                       pgui_logf("%s", PQerrorMessage(pg_connection));
+                       return 1;
                }
-               node = get_next_node(node);
-       }
 
-       if (needed_width < SHAPEFIELDMINWIDTH)
-       {
-               g_object_set(filename_renderer, "width-chars", SHAPEFIELDMINWIDTH, NULL);
-       }
-       else if (needed_width > SHAPEFIELDMAXWIDTH)
-       {
-               g_object_set(filename_renderer, "width-chars", SHAPEFIELDMAXWIDTH, NULL);
-       }
-       else
-       {
-               g_object_set(filename_renderer, "width-chars", -1, NULL);
+               /* Log errors and return failure. */
+               snprintf(sql_trunc, 255, "%s", sql);
+               pgui_logf("Failed SQL begins: \"%s\"", sql_trunc);
+               pgui_logf("Failed in pgui_exec(): %s", PQerrorMessage(pg_connection));
+               return 0;
        }
 
+       return 1;
 }
 
 /*
- * Signal handler for the remove box.  Performs no user interaction, simply
- * removes the FILENODE from the list and the row from the table.
- */
-static void
-pgui_action_handle_tree_remove(GtkCellRendererToggle *renderer,
-                               gchar *path,
-                               gpointer user_data)
+** Start the COPY process.
+*/
+static int
+pgui_copy_start(const char *sql)
 {
-       GtkTreeIter iter;
-       FILENODE *file_node;
-       int index;
-
-       /*
-        * First item of business, find me a GtkTreeIter.
-        * Second item, find the correct FILENODE
-        */
-       if (!gtk_tree_model_get_iter_from_string(GTK_TREE_MODEL(list_store), &iter,
-               path))
-       {
-               pgui_logf(_("Problem retrieving the edited row."));
-               return;
-       }
+       PGresult *res = NULL;
+       ExecStatusType status;
+       char sql_trunc[256];
 
-       index = atoi(path);
-       if (index >= current_list_index)
-               return;
+       /* We need a connection to do anything. */
+       if ( ! pg_connection ) return 0;
+       if ( ! sql ) return 0;
 
-       file_node = find_file_by_index(index);
-       if (file_node == NULL)
-       {
-               /*
-                * If we can't find the struct, we shouldn't update the ui.
-                * That would just be misleading.
-                */
-               pgui_logf(_("Problem finding the correct file."));
-               return;
-       }
+       res = PQexec(pg_connection, sql);
+       status = PQresultStatus(res);
+       PQclear(res);
 
-       /* Remove the row from the list */
-       if (!gtk_list_store_remove(list_store, &iter))
+       /* Did something unexpected happen? */
+       if ( status != PGRES_COPY_IN )
        {
-               pgui_logf(_("Unable to remove row."));
-               return;
+               /* Log errors and return failure. */
+               snprintf(sql_trunc, 255, "%s", sql);
+               pgui_logf("Failed SQL begins: \"%s\"", sql_trunc);
+               pgui_logf("Failed in pgui_copy_start(): %s", PQerrorMessage(pg_connection));
+               return 0;
        }
 
-       current_list_index--;
-       remove_file(file_node);
-
-       set_filename_field_width();
+       return 1;
 }
 
 /*
- * Ensures that the given file has a .shp extension.
- * This function will return a new string, come hell or high water, so free it.
- */
-static char*
-ensure_shapefile(char *filein)
+** Send a line (row) of data into the COPY procedure.
+*/
+static int
+pgui_copy_write(const char *line)
 {
-       char *fileout;
-       char *p;
-
-       p = filein;
-       while (*p)
-               p++;
-       p--;
-       while (g_ascii_isspace(*p))
-               p--;
-       while (*p && p > filein && *p != '.')
-               p--;
-
-       if (strcmp(p, ".shp") == 0
-               || strcmp(p, ".SHP") == 0
-               || strcmp(p, ".Shp") == 0)
-               return strdup(filein);
-
-       /* if there is no extension, let's add one. */
-       if (p == filein)
+       char line_trunc[256];
+
+       /* We need a connection to do anything. */
+       if ( ! pg_connection ) return 0;
+       if ( ! line ) return 0;
+
+       /* Did something unexpected happen? */
+       if ( PQputCopyData(pg_connection, line, strlen(line)) < 0 )
        {
-               fileout = malloc(strlen(filein) + 5);
-               strcpy(fileout, filein);
-               strcat(fileout, ".shp");
-               return fileout;
+               /* Log errors and return failure. */
+               snprintf(line_trunc, 255, "%s", line);
+               pgui_logf("Failed row begins: \"%s\"", line_trunc);
+               pgui_logf("Failed in pgui_copy_write(): %s", PQerrorMessage(pg_connection));
+               return 0;
        }
 
-       /* p is on the '.', so we need to remember not to copy it. */
-       pgui_logf("mallocing %d, from %p %p", p - filein + 5, p, filein);
-       fileout = malloc(p - filein + 5);
-       strncpy(fileout, filein, p - filein);
-       fileout[p - filein] = '\0';
-       pgui_logf("b: %s", fileout);
-       strcat(fileout, ".shp");
+       /* Send linefeed to signify end of line */
+       PQputCopyData(pg_connection, "\n", 1);
 
-       pgui_logf("Rewritten as %s", fileout);
-       return fileout;
+       return 1;
 }
 
 /*
- * Creates a single file row in the list table given the URI of a file.
- */
-static void
-process_single_uri(char *uri)
+** Finish the COPY process.
+*/
+static int
+pgui_copy_end(const int rollback)
 {
-       char *filename = NULL;
-       char *hostname;
-       GError *error = NULL;
+       char *errmsg = NULL;
 
-       if (uri == NULL)
-       {
-               pgui_logf(_("Unable to process drag URI."));
-               return;
-       }
+       /* We need a connection to do anything. */
+       if ( ! pg_connection ) return 0;
 
-       filename = g_filename_from_uri(uri, &hostname, &error);
-       g_free(uri);
+       if ( rollback ) errmsg = "Roll back the copy.";
 
-       if (filename == NULL)
+       /* Did something unexpected happen? */
+       if ( PQputCopyEnd(pg_connection, errmsg) < 0 )
        {
-               pgui_logf(_("Unable to process filename: %s\n"), error->message);
-               g_error_free(error);
-               return;
+               /* Log errors and return failure. */
+               pgui_logf("Failed in pgui_copy_end(): %s", PQerrorMessage(pg_connection));
+               return 0;
        }
 
-       pgui_action_shape_file_set(filename);
-
-       g_free(filename);
-       g_free(hostname);
-
+       return 1;
 }
 
 /*
- * Here lives the magic of the drag-n-drop of the app.  We really don't care
- * about much of the provided tidbits.  We only actually user selection_data
- * and extract a list of filenames from it.
+ * Ensures that the filename field width is within the stated bounds, and
+ * 'appropriately' sized, for some definition of 'appropriately'.
  */
 static void
-pgui_action_handle_file_drop(GtkWidget *widget,
-                             GdkDragContext *dc,
-                             gint x, gint y,
-                             GtkSelectionData *selection_data,
-                             guint info, guint t, gpointer data)
-{
-       const gchar *p, *q;
-
-       if (selection_data->data == NULL)
-       {
-               pgui_logf(_("Unable to process drag data."));
-               return;
-       }
-
-       p = (char*)selection_data->data;
-       while (p)
-       {
-               /* Only process non-comments */
-               if (*p != '#')
-               {
-                       /* Trim leading whitespace */
-                       while (g_ascii_isspace(*p))
-                               p++;
-                       q = p;
-                       /* Scan to the end of the string (null or newline) */
-                       while (*q && (*q != '\n') && (*q != '\r'))
-                               q++;
-                       if (q > p)
-                       {
-                               /* Ignore terminating character */
-                               q--;
-                               /* Trim trailing whitespace */
-                               while (q > p && g_ascii_isspace(*q))
-                                       q--;
-                               if (q > p)
-                               {
-                                       process_single_uri(g_strndup(p, q - p + 1));
-                               }
-                       }
-               }
-               /* Skip to the next entry */
-               p = strchr(p, '\n');
-               if (p)
-                       p++;
-       }
-}
-
-/*
- * This function is a signal handler for the load mode combo boxes.
- * It's fairly small-minded, but is where the char's representing the various
- * modes in the FILENODE are hardcoded.
- */
-static void
-pgui_action_handle_tree_combo(GtkCellRendererCombo *combo,
-                              gchar *path_string,
-                              GtkTreeIter *new_iter,
-                              gpointer user_data)
+update_filename_field_width(void)
 {
        GtkTreeIter iter;
-       FILENODE *file_node;
-       int index;
-
-       /*
-        * First item of business, find me a GtkTreeIter.
-        * Second item, find the correct FILENODE
-        */
-       if (!gtk_tree_model_get_iter_from_string(GTK_TREE_MODEL(list_store), &iter,
-               path_string))
-       {
-               pgui_logf(_("Problem retrieving the edited row."));
-               return;
-       }
-
-       index = atoi(path_string);
-       file_node = find_file_by_index(index);
-       if (file_node == NULL)
-       {
-               /*
-                * If we can't find the struct, we shouldn't update the ui.
-                * That would just be misleading.
-                */
-               pgui_logf(_("Problem finding the correct file."));
-               return;
-       }
-
-       GtkTreePath *path = gtk_tree_model_get_path(GTK_TREE_MODEL(combo_list), new_iter);
-       const char *str_path = gtk_tree_path_to_string(path);
-       index = atoi(str_path);
-       gtk_tree_path_free(path);
-
-       if (index == APPEND_MODE)
-       {
-               file_node->mode = 'a';
-               gtk_list_store_set(list_store, &iter,
-                                  MODE_COLUMN, _("Append"),
-                                  -1);
-       }
-       else if (index == DELETE_MODE)
-       {
-               file_node->mode = 'd';
-               gtk_list_store_set(list_store, &iter,
-                                  MODE_COLUMN, _("Delete"),
-                                  -1);
-       }
-       else if (index == PREPARE_MODE)
-       {
-               file_node->mode = 'p';
-               gtk_list_store_set(list_store, &iter,
-                                  MODE_COLUMN, _("Prepare"),
-                                  -1);
+       gboolean is_valid;
+       gchar *filename;
+       int max_width;
+       
+       /* 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);
+       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);
+               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);
        }
+       
+       /* 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);
        else
-       {
-
-               file_node->mode = 'c';
-               gtk_list_store_set(list_store, &iter,
-                                  MODE_COLUMN, _("Create"),
-                                  -1);
-       }
-       validate_shape_file(file_node);
-
+               g_object_set(filename_renderer, "width-chars", -1, NULL);
+       
+       return;
 }
 
 /*
- * This method will generate a file row in the list table given an edit
- * of a single column.  Most fields will contain defaults, but a filename
- * generally can't be created from the ether, so faking that up is still
- * a bit weak.
+ * This will create a connection to the database, just to see if it can.
+ * It cleans up after itself like a good little function and maintains
+ * the status of the valid_connection parameter.
  */
-static void
-generate_file_bits(GtkCellRendererText *renderer, char *new_text)
+static int
+connection_test(void)
 {
-       GtkTreeIter iter;
-       FILENODE *file_node;
-       char *filename;
-       char *schema;
-       char *table;
-       char *geom_column;
-       char *srid;
-
-       if (renderer == GTK_CELL_RENDERER_TEXT(filename_renderer))
-       {
-               /* If we've been given a filename, we can use the existing method. */
-               pgui_logf(_("Setting filename to %s"), new_text);
-               pgui_action_shape_file_set(ensure_shapefile(new_text));
-               return;
-       }
-       else if (renderer == GTK_CELL_RENDERER_TEXT(table_renderer))
-       {
-               pgui_logf(_("Setting table to %s"), new_text);
-               table = strdup(new_text);
-               filename = malloc(strlen(new_text) + 5);
-               sprintf(filename, "%s.shp", new_text);
-       }
-       else
-       {
-               pgui_logf(_("Default filename / table."));
-               filename = "";
-               table = "new_table";
-       }
-       if (renderer == GTK_CELL_RENDERER_TEXT(schema_renderer))
-       {
-               pgui_logf(_("Setting schema to %s"), new_text);
-               schema = strdup(new_text);
-       }
-       else
-       {
-               pgui_logf(_("Default schema."));
-               schema = "public";
-       }
-       if (renderer == GTK_CELL_RENDERER_TEXT(geom_column_renderer))
-       {
-               pgui_logf(_("Setting geometry column to %s"), new_text);
-               geom_column = strdup(new_text);
-       }
-       else
-       {
-               pgui_logf(_("Default geom_column"));
-               if (config->geography)
-                       geom_column = GEOGRAPHY_DEFAULT;
-               else
-                       geom_column = GEOMETRY_DEFAULT;
+       char *connection_string = NULL;
+       char *connection_sanitized = NULL;
 
-       }
-       if (renderer == GTK_CELL_RENDERER_TEXT(srid_renderer))
-       {
-               pgui_logf(_("Setting srid to %s"), new_text);
-               srid = strdup(new_text);
-       }
-       else
+       if (!(connection_string = ShpDumperGetConnectionStringFromConn(conn)))
        {
-               pgui_logf(_("Default SRID."));
-               srid = "-1";
+               pgui_raise_error_dialogue();
+               valid_connection = 0;
+               return 0;
        }
 
-       file_node = append_file(filename, schema, table, geom_column, srid, 'c', &iter);
-
-       validate_shape_file(file_node);
-       
-       gtk_list_store_insert_with_values(
-           list_store, &iter, current_list_index++,
-           FILENAME_COLUMN, filename,
-           SCHEMA_COLUMN, schema,
-           TABLE_COLUMN, table,
-           GEOMETRY_COLUMN, geom_column,
-           SRID_COLUMN, srid,
-           MODE_COLUMN, "Create",
-           -1);
-}
-
-/*
- * This method is a signal listener for all text renderers in the file
- * list table, including the empty ones.  Edits of the empty table are
- * passed to an appropriate function, while edits of existing file rows
- * are applied and the various validations called.
- */
-static void
-pgui_action_handle_tree_edit(GtkCellRendererText *renderer,
-                             gchar *path,
-                             gchar *new_text,
-                             gpointer user_data)
-{
-       GtkTreeIter iter;
-       FILENODE *file_node;
-       int index;
-
-       /* Empty doesn't fly */
-       if (strlen(new_text) == 0)
-               return;
+       connection_sanitized = strdup(connection_string);
+       pgui_sanitize_connection_string(connection_sanitized);
+       pgui_logf("Connecting: %s", connection_sanitized);
+       free(connection_sanitized);
 
-       /*
-        * First item of business, find me a GtkTreeIter.
-        * Second item, find the correct FILENODE
-        */
-       if (!gtk_tree_model_get_iter_from_string(GTK_TREE_MODEL(list_store), &iter,
-               path))
+       pg_connection = PQconnectdb(connection_string);
+       if (PQstatus(pg_connection) == CONNECTION_BAD)
        {
-               pgui_logf(_("Problem retrieving the edited row."));
-               return;
+               pgui_logf( _("Database connection failed: %s"), PQerrorMessage(pg_connection));
+               free(connection_string);
+               PQfinish(pg_connection);
+               pg_connection = NULL;
+               valid_connection = 0;
+               return 0;
        }
-       index = atoi(path);
-       file_node = find_file_by_index(index);
-       if (file_node == NULL)
-       {
-               /*
-                * If there is no file, it may be a new addition.
-                * Check the path against our current index to see if they're
-                * editing the empty row.
-                */
-               int index = atoi(path);
-               if (index == current_list_index)
-               {
-                       generate_file_bits(renderer, new_text);
-                       return;
-               }
+       PQfinish(pg_connection);
+       pg_connection = NULL;
+       free(connection_string);
 
-               /*
-                * If we can't find (or create) the struct, we shouldn't update the ui.
-                * That would just be misleading.
-                */
-               pgui_logf(_("Problem finding the correct file."));
-               return;
-       }
+       valid_connection = 1;
+       return 1;
+}
 
-       if (renderer == GTK_CELL_RENDERER_TEXT(filename_renderer))
-       {
-               file_node->filename = ensure_shapefile(new_text);
-               set_filename_field_width();
-       }
-       else if (renderer == GTK_CELL_RENDERER_TEXT(schema_renderer))
-       {
-               file_node->schema = strdup(new_text);
-       }
-       else if (renderer == GTK_CELL_RENDERER_TEXT(table_renderer))
-       {
-               file_node->table = strdup(new_text);
-       }
-       else if (renderer == GTK_CELL_RENDERER_TEXT(geom_column_renderer))
-       {
-               file_node->geom_column = strdup(new_text);
-       }
-       else if (renderer == GTK_CELL_RENDERER_TEXT(srid_renderer))
-       {
-               file_node->srid = strdup(new_text);
-       }
 
-       validate_shape_file(file_node);
+/* === Generic window functions === */
 
-       gtk_list_store_set(list_store, &iter,
-                          FILENAME_COLUMN, file_node->filename,
-                          SCHEMA_COLUMN, file_node->schema,
-                          TABLE_COLUMN, file_node->table,
-                          GEOMETRY_COLUMN, file_node->geom_column,
-                          SRID_COLUMN, file_node->srid,
-                          -1);
+/* Delete event handler for popups that simply returns TRUE to prevent GTK from
+   destroying the window and then hides it manually */
+static gint
+pgui_event_popup_delete(GtkWidget *widget, GdkEvent *event, gpointer data)
+{
+       gtk_widget_hide(GTK_WIDGET(widget));
+       return TRUE;
 }
 
+/* === Progress window functions === */
+
 static void
-pgui_raise_error_dialogue(void)
+pgui_action_progress_cancel(GtkDialog *dialog, gint response_id, gpointer user_data) 
 {
-       GtkWidget *dialog, *label;
-       gint result;
+       /* Stop the current import */
+       import_running = FALSE;
 
-       label = gtk_label_new(pgui_errmsg);
-       dialog = gtk_dialog_new_with_buttons(_("Error"), GTK_WINDOW(window_main),
-                                            GTK_DIALOG_MODAL & GTK_DIALOG_NO_SEPARATOR & GTK_DIALOG_DESTROY_WITH_PARENT,
-                                            GTK_STOCK_OK, GTK_RESPONSE_OK, NULL);
-       gtk_dialog_set_has_separator ( GTK_DIALOG(dialog), FALSE );
-       gtk_container_set_border_width (GTK_CONTAINER(dialog), 5);
-       gtk_container_set_border_width (GTK_CONTAINER (GTK_DIALOG(dialog)->vbox), 15);
-       gtk_container_add (GTK_CONTAINER (GTK_DIALOG(dialog)->vbox), label);
-       gtk_widget_show_all (dialog);
-       result = gtk_dialog_run(GTK_DIALOG(dialog));
-       gtk_widget_destroy(dialog);
        return;
 }
 
-/* Terminate the main loop and exit the application. */
-static void
-pgui_quit (GtkWidget *widget, gpointer data)
+static gint
+pgui_action_progress_delete(GtkWidget *widget, GdkEvent *event, gpointer data)
 {
-       if ( pg_connection) PQfinish(pg_connection);
-       pg_connection = NULL;
-       destroy_file_list();
-       gtk_main_quit ();
+       /* Stop the current import */
+       import_running = FALSE;
+
+       return TRUE;
 }
 
-/* Set the global config variables controlled by the options dialogue */
+
+/* === Option Window functions === */
+
+/* Update the specified SHPLOADERCONFIG with the global settings from the Options dialog */
 static void
-pgui_set_config_from_options_ui()
+update_loader_config_globals_from_options_ui(SHPLOADERCONFIG *config)
 {
-       FILENODE *current_node;
        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));
@@ -705,51 +470,27 @@ pgui_set_config_from_options_ui()
        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));
 
-       if ( geography )
+       if (geography)
        {
                config->geography = 1;
-               /* Flip the geometry column name to match the load type */
-               current_node = get_next_node(NULL);
-               while (current_node != NULL)
-               {
-                       if (!strcmp(current_node->geom_column, GEOMETRY_DEFAULT))
-                       {
-                               free(current_node->geom_column);
-                               current_node->geom_column = strdup(GEOGRAPHY_DEFAULT);
-                               gtk_list_store_set(GTK_LIST_STORE(list_store),
-                                                  current_node->tree_iterator,
-                                                  GEOMETRY_COLUMN,
-                                                  GEOGRAPHY_DEFAULT, -1);
-                               free(config->geo_col);
-                               config->geo_col = strdup(GEOGRAPHY_DEFAULT);
-                       }
-                       current_node = get_next_node(current_node);
-               }
+               
+               if (config->geo_col)
+                       free(config->geo_col);
+               
+               config->geo_col = strdup(GEOGRAPHY_DEFAULT);
        }
        else
        {
                config->geography = 0;
-               /* Flip the geometry column name to match the load type */
-               current_node = get_next_node(NULL);
-               while (current_node != NULL)
-               {
-                       if (!strcmp(current_node->geom_column, GEOGRAPHY_DEFAULT))
-                       {
-                               free(current_node->geom_column);
-                               current_node->geom_column = strdup(GEOMETRY_DEFAULT);
-                               gtk_list_store_set(GTK_LIST_STORE(list_store),
-                                                  current_node->tree_iterator,
-                                                  GEOMETRY_COLUMN,
-                                                  GEOMETRY_DEFAULT, -1);
-                               free(config->geo_col);
-                               config->geo_col = strdup(GEOMETRY_DEFAULT);
-                       }
-                       current_node = get_next_node(current_node);
-               }
+
+               if (config->geo_col)
+                       free(config->geo_col);
+               
+               config->geo_col = strdup(GEOMETRY_DEFAULT);
        }
 
        /* Encoding */
-       if ( entry_encoding && strlen(entry_encoding) > 0 )
+       if (entry_encoding && strlen(entry_encoding) > 0)
        {
                if (config->encoding)
                        free(config->encoding);
@@ -758,27 +499,28 @@ pgui_set_config_from_options_ui()
        }
 
        /* Preserve case */
-       if ( preservecase )
+       if (preservecase)
                config->quoteidentifiers = 1;
        else
                config->quoteidentifiers = 0;
 
        /* No long integers in table */
-       if ( forceint )
+       if (forceint)
                config->forceint4 = 1;
        else
                config->forceint4 = 0;
 
        /* Create spatial index after load */
-       if ( createindex )
+       if (createindex)
                config->createindex = 1;
        else
                config->createindex = 0;
 
        /* Read the .shp file, don't ignore it */
-       if ( dbfonly )
+       if (dbfonly)
        {
                config->readshape = 0;
+               
                /* There will be no spatial column so don't create a spatial index */
                config->createindex = 0; 
        }
@@ -786,1078 +528,558 @@ pgui_set_config_from_options_ui()
                config->readshape = 1;
 
        /* Use COPY rather than INSERT format */
-       if ( dumpformat )
+       if (dumpformat)
                config->dump_format = 1;
        else
                config->dump_format = 0;
-
+       
        return;
 }
 
-/* Set the global configuration based upon the current UI */
+/* Update the options dialog with the current values from the global config */
 static void
-pgui_set_config_from_ui(FILENODE *file_node)
+update_options_ui_from_loader_config_globals(void)
 {
-       const char *srid = strdup(file_node->srid);
-       char *c;
-
-       /* Set the destination schema, table and column parameters */
-       if (config->table)
-               free(config->table);
+       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);
+       
+       return;
+}
+       
+/* Set the global config variables controlled by the options dialogue */
+static void
+pgui_set_loader_configs_from_options_ui()
+{
+       GtkTreeIter iter;
+       gboolean is_valid;
+       gpointer gptr;
+       SHPLOADERCONFIG *loader_file_config;
+       
+       /* First update the global (template) configuration */
+       update_loader_config_globals_from_options_ui(global_loader_config);
 
-       config->table = strdup(file_node->table);
+       /* 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);
+       while (is_valid)
+       {
+               /* Get the SHPLOADERCONFIG for this file entry */
+               gtk_tree_model_get(GTK_TREE_MODEL(list_store), &iter, 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);
+       }
+       
+       return;
+}
 
-       if (config->schema)
-               free(config->schema);
 
-       if (strlen(file_node->schema) == 0)
-               config->schema = strdup("public");
-       else
-               config->schema = strdup(file_node->schema);
+/* === Main window functions === */
 
-       if (strlen(file_node->geom_column) == 0)
-               config->geo_col = strdup(GEOMETRY_DEFAULT);
-       else
-               config->geo_col = strdup(file_node->geom_column);
+/* Given a filename, generate a new configuration and add it to the listview */
+static SHPLOADERCONFIG *
+create_new_file_config(const char *filename)
+{
+       SHPLOADERCONFIG *loader_file_config;
+       char *table_start, *table_end;
+       int i;
+       
+       /* Generate a new configuration by copying the global options first and then
+          adding in the specific values for this file */
+       loader_file_config = malloc(sizeof(SHPLOADERCONFIG));
+       memcpy(loader_file_config, global_loader_config, sizeof(SHPLOADERCONFIG));
+       
+       /* Note: we must copy the encoding here since it is the only pass-by-reference
+          type set in set_loader_config_defaults() and each config needs its own copy
+          of any referenced items */
+       loader_file_config->encoding = strdup(global_loader_config->encoding);
+       
+       /* Copy the filename (we'll remove the .shp extension in a sec) */
+       loader_file_config->shp_file = strdup(filename);
+       
+       /* Generate the default table name from the filename */
+       table_start = loader_file_config->shp_file + strlen(loader_file_config->shp_file);
+       while (*table_start != '/' && *table_start != '\\' && table_start > loader_file_config->shp_file)
+               table_start--;
+       
+       /* Forward one to start of actual characters */
+       table_start++;
 
-       /* Set the destination filename: note the shp2pgsql core engine simply wants the file
-          without the .shp extension */
-       if (config->shp_file)
-               free(config->shp_file);
+       /* Roll back from end to first . character. */
+       table_end = loader_file_config->shp_file + strlen(loader_file_config->shp_file);
+       while (*table_end != '.' && table_end > loader_file_config->shp_file && table_end > table_start )
+               table_end--;
+       
+       /* Sneakily remove .shp from shp_file */
+       *table_end = '\0';
 
-       /* Handle empty selection */
-       if (file_node->filename == NULL)
-               config->shp_file = strdup("");
-       else
-               config->shp_file = strdup(file_node->filename);
+       /* Copy the table name */
+       loader_file_config->table = malloc(table_end - table_start + 1);
+       memcpy(loader_file_config->table, table_start, table_end - table_start);
+       loader_file_config->table[table_end - table_start] = '\0';
 
-       /*  NULL-terminate the file name before the .shp extension */
-       for (c = config->shp_file + strlen(config->shp_file); c >= config->shp_file; c--)
+       /* Force the table name to lower case */
+       for (i = 0; i < table_end - table_start; i++)
        {
-               if (*c == '.')
-               {
-                       *c = '\0';
-                       break;
-               }
-       }
-
-       /* SRID */
-       if ( srid == NULL || ! ( config->sr_id = atoi(srid) ) )
-       {
-               config->sr_id = -1;
+               if (isupper(loader_file_config->table[i]) != 0)
+                       loader_file_config->table[i] = tolower(loader_file_config->table[i]);
        }
 
-       /* Mode */
-       if (file_node->mode == '\0')
-               config->opt = 'c';
+       /* Set the default schema to public */
+       loader_file_config->schema = strdup("public");
+       
+       /* Set the default geo column name */
+       if (global_loader_config->geography)
+               loader_file_config->geo_col = strdup(GEOGRAPHY_DEFAULT);
        else
-               config->opt = file_node->mode;
+               loader_file_config->geo_col = strdup(GEOMETRY_DEFAULT);
+       
+       return loader_file_config;
+}
 
+/* Given the loader configuration, add a new row representing this file to the listview */
+static void
+add_loader_file_config_to_list(SHPLOADERCONFIG *loader_file_config)
+{
+       GtkTreeIter iter;
+       char *srid;
+       
+       /* 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"),
+                          -1); 
+                  
+       /* Update the filename field width */
+       update_filename_field_width();
+       
        return;
 }
 
-/*
- * Performs rudimentary validation on the given string.  This takes the form
- * of checking for nullage and zero length, the trimming whitespace and
- * checking again for zero length.
- *
- * Returns 1 for valid, 0 for not.
- */
-static int
-validate_string(char *string)
+/* Free up the specified SHPLOADERCONFIG */
+static void
+free_loader_config(SHPLOADERCONFIG *config)
 {
-       char *p, *q;
-       if (string == NULL || strlen(string) == 0)
-               return 0;
 
-       p = string;
-       while (g_ascii_isspace(*p))
-               p++;
-       q = p;
-       while (*q)
-               q++;
-       q--;
-       while (g_ascii_isspace(*q) && q > p)
-               q--;
-       if (p >= q)
-               return 0;
+       if (config->table)
+               free(config->table);
 
-       return 1;
+       if (config->schema)
+               free(config->schema);
+       
+       if (config->geo_col)
+               free(config->geo_col);
+       
+       if (config->shp_file)
+               free(config->shp_file);
+
+       if (config->encoding)
+               free(config->encoding);
+
+       if (config->tablespace)
+               free(config->tablespace);
+       
+       if (config->idxtablespace)
+               free(config->idxtablespace);
+       
+       /* Free the config itself */
+       free(config);
 }
 
-/*
- * This compares two columns indicated state/result structs.  They are
- * assumed to already have had their names compared, so this will only
- * compare the types.  Precision remains TBD.
- *
- * 0 if the comparison fails, 1 if it's happy.
- */
+/* 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
-compare_columns(SHPLOADERSTATE *state, int dbf_index,
-                PGresult *result, int db_index)
+validate_shape_column_against_pg_column(int dbf_fieldtype, char *pg_fieldtype)
 {
-       char *string;
-       int value = 1;
-       int i = dbf_index;
-       int j  = db_index;
-
-       int dbTypeColumn = PQfnumber(result, "type");
-       /* It would be nice to go into this level of detail, but not today. */
-       /*
-       int dbSizeColumn = PQfnumber(result, "length");
-       int dbPrecisionColumn = PQfnumber(result, "precision");
-       */
+       switch (dbf_fieldtype)
+       {
+               case FTString:
+                       /* Only varchar */
+                       if (!strcmp(pg_fieldtype, "varchar"))
+                               return -1;
+                       break;
+                       
+               case FTDate:
+                       /* Only date */
+                       if (!strcmp(pg_fieldtype, "date"))
+                               return -1;
+                       break;
+                       
+               case FTInteger:
+                       /* Tentatively allow int2, int4 and numeric */
+                       if (!strcmp(pg_fieldtype, "int2") || !strcmp(pg_fieldtype, "int4") || !strcmp(pg_fieldtype, "numeric"))
+                               return -1;
+                       break;
+                       
+               case FTDouble:
+                       /* Only float8/numeric */
+                       if (!strcmp(pg_fieldtype, "float8") || !strcmp(pg_fieldtype, "numeric"))
+                               return -1;
+                       break;
+                       
+               case FTLogical:
+                       /* Only boolean */
+                       if (!strcmp(pg_fieldtype, "boolean"))
+                               return -1;
+                       break;
+       }
+       
+       /* Otherwise we can't guarantee this (but this is just a warning anyway) */
+       return 0;
+}
 
-       string = PQgetvalue(result, j, dbTypeColumn);
-       switch (state->types[i])
+/* Validate column compatibility for the given loader configuration against the table/column
+   list returned in result */
+static int
+validate_remote_loader_columns(SHPLOADERCONFIG *config, PGresult *result)
+{
+       ExecStatusType status;
+       int ntuples;
+       char *pg_fieldname, *pg_fieldtype;
+       int ret, i, j, found, response = SHPLOADEROK;
+       
+       /* Check the status of the result set */
+       status = PQresultStatus(result);
+       if (status == PGRES_TUPLES_OK)
        {
-       case FTString:
-               if (strcmp(string, "varchar") != 0)
-               {
-                       pgui_logf(_("  DBF field %s is a varchar, while the table attribute is of type %s"), state->field_names[i], string);
-                       value = 0;
-               }
-               break;
-       case FTDate:
-               if (strcmp(string, "date") != 0)
-               {
-                       pgui_logf(_("  DBF field %s is a date, while the table attribute is of type %s"), state->field_names[i], string);
-                       value = 0;
-               }
-               break;
-       case FTInteger:
-               if (state->widths[i] < 5 && !state->config->forceint4 && strcmp(string, "int2") != 0)
-               {
-                       pgui_logf(_("  DBF field %s is an int2, while the table attribute is of type %s"), state->field_names[i], string);
-                       value = 0;
-               }
-               else if ((state->widths[i] < 10 || state->config->forceint4) && strcmp(string, "int4") != 0)
-               {
-                       pgui_logf(_("  DBF field %s is an int4, while the table attribute is of type %s"), state->field_names[i], string);
-                       value = 0;
-               }
-               else if (strcmp(string, "numeric") != 0)
+               ntuples = PQntuples(result);
+       
+               switch (config->opt)
                {
-                       pgui_logf(_("  DBF field %s is a numeric, while the table attribute is of type %s"), state->field_names[i], string);
-                       value = 0;
-               }
+                       case 'c':
+                               /* If we have a row matching the table given in the config, then it already exists */
+                               if (ntuples > 0)
+                               {
+                                       pgui_seterr(_("ERROR: Create mode selected for existing table: %s.%s"), config->schema, config->table);
+                                       response = SHPLOADERERR;
+                               }       
+                               break;
+                       
+                       case 'p':
+                               /* If we have a row matching the table given in the config, then it already exists */
+                               if (ntuples > 0)
+                               {
+                                       pgui_seterr(_("ERROR: Prepare mode selected for existing table: %s.%s"), config->schema, config->table);
+                                       response = SHPLOADERERR;
+                               }
+                               break;  
 
-               break;
-       case FTDouble:
-               if (state->widths[i] > 18 && strcmp(string, "numeric") != 0)
-               {
-                       pgui_logf(_("  DBF field %s is a numeric, while the table attribute is of type %s"), state->field_names[i], string);
-                       value = 0;
-               }
-               else if (state->widths[i] <= 18 && strcmp(string, "float8") != 0)
-               {
-                       pgui_logf(_("  DBF field %s is a float8, while the table attribute is of type %s"), state->field_names[i], string);
-                       value = 0;
-               }
-               break;
-       case FTLogical:
-               if (strcmp(string, "boolean") != 0)
-               {
-                       pgui_logf(_("  DBF field %s is a boolean, while the table attribue is of type %s"), state->field_names[i], string);
-                       value = 0;
+                       case 'a':
+                               /* If we are trying to append to a table but it doesn't exist, emit a warning */
+                               if (ntuples == 0)
+                               {
+                                       pgui_seterr(_("ERROR: Destination table %s.%s could not be found for appending"), config->schema, config->table);
+                                       response = SHPLOADERERR;
+                               }
+                               else
+                               {
+                                       /* If we have a row then lets do some simple column validation... */
+                                       state = ShpLoaderCreate(config);
+                                       ret = ShpLoaderOpenShape(state);
+                                       if (ret != SHPLOADEROK)
+                                       {
+                                               pgui_logf(_("Warning: Could not load shapefile %s"), config->shp_file);
+                                               ShpLoaderDestroy(state);
+                                       }
+                                       
+                                       /* Find each column based upon its name and then validate type separately... */
+                                       for (i = 0; i < state->num_fields; i++)
+                                       {
+                                               /* Make sure we find a column */
+                                               found = 0;
+                                               for (j = 0; j < ntuples; j++)
+                                               {
+                                                       pg_fieldname = PQgetvalue(result, j, PQfnumber(result, "field"));
+                                                       pg_fieldtype = PQgetvalue(result, j, PQfnumber(result, "type"));
+                                               
+                                                       if (!strcmp(state->field_names[i], pg_fieldname))
+                                                       {
+                                                               found = -1;
+                                                               
+                                                               ret = validate_shape_column_against_pg_column(state->types[i], pg_fieldtype);
+                                                               if (!ret)
+                                                               {
+                                                                       pgui_logf(_("Warning: DBF Field '%s' is not compatible with PostgreSQL column '%s' in %s.%s"), state->field_names[i], pg_fieldname, config->schema, config->table);
+                                                                       response = SHPLOADERWARN;
+                                                               }
+                                                       }
+                                               }
+                                               
+                                               /* Flag a warning if we can't find a match */
+                                               if (!found)
+                                               {
+                                                       pgui_logf(_("Warning: DBF Field '%s' within file %s could not be matched to a column within table %s.%s"), 
+                                                                 state->field_names[i], config->shp_file, config->schema, config->table);
+                                                       response = SHPLOADERWARN;
+                                               }
+                                       }
+                                       
+                                       ShpLoaderDestroy(state);
+                               }
+                               
+                               break;
                }
-               break;
-       /* 
-        * It should be safe to assume that we aren't going to 
-        * match an invalid column 
-        */
-       case FTInvalid:
-               value = 0;
-               break;
        }
-       return value;
+       else
+       {
+               pgui_seterr(_("ERROR: unable to process validation response from remote server"));
+               response = SHPLOADERERR;
+       }
+       
+       return response;        
 }
 
-/*
- * This will loop through each field defined in the DBF and find an attribute
- * in the table (provided by the PGresult) with the same name.  It then
- * delegates a comparison to the compare_columns function.
- *
- * 0 if all fields in the DBF cannot be matched to one in the table results,
- * 1 if they all can.
- */
-static int
-compare_column_lists(SHPLOADERSTATE *state, PGresult *result)
+/* Terminate the main loop and exit the application. */
+static void
+pgui_quit (GtkWidget *widget, gpointer data)
 {
-       int dbCount= PQntuples(result);
-       int dbNameColumn = PQfnumber(result, "field");
-       char **db_columns;
-       int i, j, colgood;
-       int value = 1;
+       gtk_main_quit();
+}
 
-       int shpCount = state->num_fields;
+static void
+pgui_action_about_open()
+{
+       /* Display the dialog and hide it again upon exit */
+       gtk_dialog_run(GTK_DIALOG(dialog_about));
+       gtk_widget_hide(dialog_about);
+}
 
-       db_columns = malloc(dbCount * sizeof(char*));
-       for (j = 0; j < dbCount; j++)
-       {
-               db_columns[j] = strdup(PQgetvalue(result, j, dbNameColumn));
-       }
+static void
+pgui_action_cancel(GtkWidget *widget, gpointer data)
+{
+       if (!import_running)
+               pgui_quit(widget, data); /* quit if we're not running */
+       else
+               import_running = FALSE;
+}
 
-       for (i = 0; i < shpCount; i++)
-       {
-               colgood = 0;
-               for (j = 0; j < dbCount; j++)
-               {
-                       if (strcmp(state->field_names[i], db_columns[j]) == 0)
-                       {
-                               value = value & compare_columns(state, i, result, j);
-                               colgood = 1;
-                               break;
-                       }
-               }
-               if (colgood == 0)
-               {
-                       pgui_logf(_("   DBF field %s (%d) could not be matched to a table attribute."), state->field_names[i], i);
-                       value = 0;
-               }
-       }
+static void
+pgui_action_options_open(GtkWidget *widget, gpointer data)
+{
+       update_options_ui_from_loader_config_globals();
+       gtk_widget_show_all(dialog_options);
+       return;
+}
 
-       return value;
+static void
+pgui_action_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);
+       
+       return;
 }
 
-/*
- * Checks the file node for general completeness.
- * First all fields are checked to ensure they contain values.
- * Next the filename is checked to ensure it is stat'able (ie can be parsed
- * and is visible to the application).
- * Finally the database is checked.  What is done here depends on the load
- * mode as follows:
- *   Delete: nothing is checked.
- *   Create: check if the table already exists.
- *   Prepare: check if the table already exists.
- *   Append: check if the table is absent or if columns are missing or of the
- *           wrong type as defined in the DBF.
- *
- * returns 0 for error, 1 for warning, 2 for good
- */
-static int
-validate_shape_file(FILENODE *filenode)
+static void
+pgui_action_open_file_dialog(GtkWidget *widget, gpointer data)
 {
-       PGresult *result = NULL;
-       int nresult;
-       ExecStatusType status;
-       char *connection_string;
-       char *query;
+       SHPLOADERCONFIG *loader_file_config;
+       
+       /* Run the dialog */
+       if (gtk_dialog_run(GTK_DIALOG(dialog_filechooser)) == GTK_RESPONSE_ACCEPT)
+       {
+               /* Create the new file configuration based upon the filename and add it to the listview */
+               loader_file_config = create_new_file_config(gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog_filechooser)));
+               add_loader_file_config_to_list(loader_file_config);
+       }
+       
+       gtk_widget_hide(dialog_filechooser);
+}
 
-       if (validate_string(filenode->filename) == 0
-               || validate_string(filenode->schema) == 0
-               || validate_string(filenode->table) == 0
-               || validate_string(filenode->srid) == 0)
+static void
+pgui_action_import(GtkWidget *widget, gpointer data)
+{      
+       SHPLOADERCONFIG *loader_file_config;
+       gint is_valid;
+       gpointer gptr;
+       GtkTreeIter iter;
+       char *sql_form, *query, *progress_text = NULL, *progress_shapefile = NULL;
+       PGresult *result;
+       char *connection_string = NULL;
+       int ret, success, i = 0;
+       char *header, *footer, *record;
+       
+       /* 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(_("Incomplete, please fill in all fields."));
-               return 0;
+               pgui_seterr(_("Unable to connect to the database - please check your connection settings"));
+               pgui_raise_error_dialogue();
+       
+               return;
        }
 
-       if (!validate_shape_filename(filenode->filename))
+       /* Validation: we loop through each of the files in order to validate them as a separate pass */
+       is_valid = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(list_store), &iter);
+       
+       /* Let's open a single connection to the remote DB for the duration of the validation pass;
+          note that we already know the connection string works, otherwise we would have bailed
+          out earlier in the function */
+       connection_string = ShpDumperGetConnectionStringFromConn(conn);
+       pg_connection = PQconnectdb(connection_string);
+       
+       /* Setup the table/column type discovery query */
+       sql_form = "SELECT a.attnum, a.attname AS field, t.typname AS type, a.attlen AS length, a.atttypmod AS precision FROM pg_class c, pg_attribute a, pg_type t, pg_namespace n WHERE c.relname = '%s' AND n.nspname = '%s' AND a.attnum > 0 AND a.attrelid = c.oid AND a.atttypid = t.oid AND c.relnamespace = n.oid ORDER BY a.attnum";
+       
+       while (is_valid)
        {
-               pgui_logf(_("Warning: Cannot find file %s"), filenode->filename);
-               return 1;
+               /* Grab the SHPLOADERCONFIG for this row */
+               gtk_tree_model_get(GTK_TREE_MODEL(list_store), &iter, POINTER_COLUMN, &gptr, -1);
+               loader_file_config = (SHPLOADERCONFIG *)gptr;
+               
+               /* For each entry, we execute a remote query in order to determine the column names
+                  and types for the remote table if they actually exist */
+               query = malloc(strlen(sql_form) + strlen(loader_file_config->schema) + strlen(loader_file_config->table) + 1);
+               sprintf(query, sql_form, loader_file_config->table, loader_file_config->schema);
+               result = PQexec(pg_connection, query);
+               
+               /* Call the validation function with the SHPLOADERCONFIG and the result set */
+               ret = validate_remote_loader_columns(loader_file_config, result);
+               if (ret == SHPLOADERERR)
+               {
+                       pgui_raise_error_dialogue();
+                       
+                       PQclear(result);
+                       free(query);
+                       
+                       return;
+               }       
+               
+               /* Free the SQL query */
+               PQclear(result);
+               free(query);
+
+               /* Get next entry */
+               is_valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(list_store), &iter);
        }
+       
+       /* Close our database connection */
+       PQfinish(pg_connection);        
 
-       if (filenode->mode != 'd')
+       
+       /* Once we've done the validation pass, now let's load the shapefile */
+       pg_connection = PQconnectdb(connection_string);
+       
+       is_valid = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(list_store), &iter);
+       while (is_valid)
        {
-               int ret;
-               SHPLOADERSTATE *state;
+               /* Grab the SHPLOADERCONFIG for this row */
+               gtk_tree_model_get(GTK_TREE_MODEL(list_store), &iter, POINTER_COLUMN, &gptr, -1);
+               loader_file_config = (SHPLOADERCONFIG *)gptr;
+       
+               pgui_logf("\n==============================");
+               pgui_logf("Importing with configuration: %s, %s, %s, %s, mode=%c, dump=%d, simple=%d, geography=%d, index=%d, shape=%d, srid=%d", loader_file_config->table, loader_file_config->schema, loader_file_config->geo_col, loader_file_config->shp_file, loader_file_config->opt, loader_file_config->dump_format, loader_file_config->simple_geometries, loader_file_config->geography, loader_file_config->createindex, loader_file_config->readshape, loader_file_config->sr_id);
+               
+               /*
+                * Loop through the items in the shapefile
+                */
+               import_running = TRUE;
+               success = FALSE;
+               
+               /* Disable the button to prevent multiple imports running at the same time */
+               gtk_widget_set_sensitive(widget, FALSE);
 
-               pgui_set_config_from_options_ui();
-               pgui_set_config_from_ui(filenode);
+               /* Allow GTK events to get a look in */
+               while (gtk_events_pending())
+                       gtk_main_iteration();
+                               
+               /* Create the shapefile state object */
+               state = ShpLoaderCreate(loader_file_config);
 
-               state = ShpLoaderCreate(config);
+               /* Open the shapefile */
                ret = ShpLoaderOpenShape(state);
                if (ret != SHPLOADEROK)
                {
-                       pgui_logf(_("Warning: Could not load shapefile %s"), filenode->filename);
-                       ShpLoaderDestroy(state);
-                       return 1;
+                       pgui_logf("%s", state->message);
+
+                       if (ret == SHPLOADERERR)
+                               goto import_cleanup;
                }
 
-               if (valid_connection == 1)
-               {
-                       const char *sql_form = "SELECT a.attnum, a.attname AS field, t.typname AS type, a.attlen AS length, a.atttypmod AS precision FROM pg_class c, pg_attribute a, pg_type t, pg_namespace n WHERE c.relname = '%s' AND n.nspname = '%s' AND a.attnum > 0 AND a.attrelid = c.oid AND a.atttypid = t.oid AND c.relnamespace = n.oid ORDER BY a.attnum";
+               /* For progress display, only show the "core" filename */
+               for (i = strlen(loader_file_config->shp_file); i >= 0 
+                       && loader_file_config->shp_file[i - 1] != '\\' && loader_file_config->shp_file[i - 1] != '/'; i--);
 
-                       query = malloc(strlen(sql_form) + strlen(filenode->schema) + strlen(filenode->table) + 1);
-                       sprintf(query, sql_form, filenode->table, filenode->schema);
+               progress_shapefile = malloc(strlen(loader_file_config->shp_file));
+               strcpy(progress_shapefile, &loader_file_config->shp_file[i]);
+               
+               /* Display the progress dialog */
+               lw_asprintf(&progress_text, _("Importing shapefile %s (%d records)..."), progress_shapefile, ShpLoaderGetRecordCount(state));
+               gtk_label_set_text(GTK_LABEL(label_progress), progress_text);
+               gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(progress), 0.0);
+               gtk_widget_show_all(dialog_progress);
 
-                       if ( ! (connection_string = pgui_read_connection()) )
-                       {
-                               pgui_raise_error_dialogue();
-                               ShpLoaderDestroy(state);
-                               valid_connection = 0;
-                               return 0;
-                       }
+               /* If reading the whole shapefile, display its type */
+               if (state->config->readshape)
+               {
+                       pgui_logf("Shapefile type: %s", SHPTypeName(state->shpfiletype));
+                       pgui_logf("PostGIS type: %s[%d]", state->pgtype, state->pgdims);
+               }
 
-                       /* This has been moved into the earlier validation functions. */
-                       /*
-                       connection_sanitized = strdup(connection_string);
-                       pgui_sanitize_connection_string(connection_sanitized);
-                       pgui_logf("Connection: %s", connection_sanitized);
-                       free(connection_sanitized);
-                       */
+               /* Get the header */
+               ret = ShpLoaderGetSQLHeader(state, &header);
+               if (ret != SHPLOADEROK)
+               {
+                       pgui_logf("%s", state->message);
 
-                       if ( pg_connection ) PQfinish(pg_connection);
-                       pg_connection = PQconnectdb(connection_string);
+                       if (ret == SHPLOADERERR)
+                               goto import_cleanup;
+               }
 
-                       if (PQstatus(pg_connection) == CONNECTION_BAD)
-                       {
-                               pgui_logf(_("Warning: Database connection failed: %s"), PQerrorMessage(pg_connection));
-                               free(connection_string);
-                               free(query);
-                               PQfinish(pg_connection);
-                               pg_connection = NULL;
-                               ShpLoaderDestroy(state);
-                               return 1;
-                       }
+               /* Send the header to the remote server: if we are in COPY mode then the last
+                  statement will be a COPY and so will change connection mode */
+               ret = pgui_exec(header);
+               free(header);
 
-                       /*
-                        * TBD: There is a horrible amount of switching/cleanup code
-                        * here.  I would love to decompose this a bit better.
-                        */
+               if (!ret)
+                       goto import_cleanup;
 
-                       result = PQexec(pg_connection, query);
-                       status = PQresultStatus(result);
-                       if (filenode->mode == 'a' && status != PGRES_TUPLES_OK)
+               /* If we are in prepare mode, we need to skip the actual load. */
+               if (state->config->opt != 'p')
+               {
+                       /* If we are in COPY (dump format) mode, output the COPY statement and enter COPY mode */
+                       if (state->config->dump_format)
                        {
-                               pgui_logf(_("Warning: Append mode selected but no existing table found: %s"), filenode->table);
-                               PQclear(result);
-                               free(connection_string);
-                               free(query);
-                               PQfinish(pg_connection);
-                               pg_connection = NULL;
-                               ShpLoaderDestroy(state);
-                               return 1;
-                       }
+                               ret = ShpLoaderGetSQLCopyStatement(state, &header);
 
-                       if (status == PGRES_TUPLES_OK)
-                       {
-                               nresult = PQntuples(result);
-                               if ((filenode->mode == 'c' || filenode->mode == 'p')
-                                       && nresult > 0)
+                               if (ret != SHPLOADEROK)
                                {
-                                       if (filenode->mode == 'c')
-                                               pgui_logf(_("Warning: Create mode selected for existing table name: %s"), filenode->table);
-                                       else
-                                               pgui_logf(_("Warning: Prepare mode selected for existing table name: %s"), filenode->table);
+                                       pgui_logf("%s", state->message);
 
-                                       PQclear(result);
-                                       free(connection_string);
-                                       free(query);
-                                       PQfinish(pg_connection);
-                                       pg_connection = NULL;
-                                       ShpLoaderDestroy(state);
-                                       return 1;
+                                       if (ret == SHPLOADERERR)
+                                               goto import_cleanup;
                                }
-                               if (filenode->mode == 'a')
-                               {
-                                       if (nresult == 0)
-                                       {
-                                               pgui_logf(_("Warning: Destination table (%s.%s) could not be found for appending."), filenode->schema, filenode->table);
-                                               PQclear(result);
-                                               free(connection_string);
-                                               free(query);
-                                               PQfinish(pg_connection);
-                                               pg_connection = NULL;
-                                               ShpLoaderDestroy(state);
-                                               return 1;
 
-                                       }
-                                       int generated_columns = 2;
-                                       if (config->readshape == 0)
-                                               generated_columns = 1;
-                                       pgui_logf(_("Validating schema of %s.%s against the shapefile %s."),
-                                                 filenode->schema, filenode->table,
-                                                 filenode->filename);
-                                       if (compare_column_lists(state, result) == 0)
-                                               ret = 1;
-                                       else
-                                               ret = 2;
+                               /* Send the result to the remote server: this should put us in COPY mode */
+                               ret = pgui_copy_start(header);
+                               free(header);
 
-                                       PQclear(result);
-                                       free(connection_string);
-                                       free(query);
-                                       PQfinish(pg_connection);
-                                       pg_connection = NULL;
-                                       ShpLoaderDestroy(state);
-                                       return ret;
-                               }
-                       }
-                       PQclear(result);
-                       free(connection_string);
-                       free(query);
-                       PQfinish(pg_connection);
-                       pg_connection = NULL;
-                       ShpLoaderDestroy(state);
-               }
-       }
-       return 2;
-}
-
-/*
- * This checks the shapefile to ensure it exists.
- *
- * returns 0 for invalid, 1 for happy goodness
- */
-static int
-validate_shape_filename(const char *filename)
-{
-       struct stat buf;
-
-       if (stat(filename, &buf) != 0)
-       {
-               return 0;
-       }
-       return 1;
-}
-
-/* Validate the configuration, returning true or false */
-static int
-pgui_validate_config()
-{
-       char *p;
-       /* Validate table parameters */
-       if ( ! config->table || strlen(config->table) == 0 )
-       {
-               pgui_seterr(_("Fill in the destination table."));
-               return 0;
-       }
-
-       if ( ! config->schema || strlen(config->schema) == 0 )
-       {
-               pgui_seterr(_("Fill in the destination schema."));
-               return 0;
-       }
-
-       if ( ! config->geo_col || strlen(config->geo_col) == 0 )
-       {
-               pgui_seterr(_("Fill in the destination column."));
-               return 0;
-       }
-
-       if ( ! config->shp_file || strlen(config->shp_file) == 0 )
-       {
-               pgui_seterr(_("Select a shape file to import."));
-               return 0;
-       }
-
-       p = malloc(strlen(config->shp_file) + 5);
-       sprintf(p, "%s.shp", config->shp_file);
-       if (validate_shape_filename(p) == 0)
-       {
-               const char *format = _("Unable to stat file: %s");
-               char *s = malloc(strlen(p) + strlen(format) + 1);
-               sprintf(s, format, p);
-               pgui_seterr(s);
-               free(s);
-               free(p);
-               return 0;
-       }
-       free(p);
-
-       return 1;
-}
-
-/*
-** Run a SQL command against the current connection.
-*/
-static int
-pgui_exec(const char *sql)
-{
-       PGresult *res = NULL;
-       ExecStatusType status;
-       char sql_trunc[256];
-
-       /* We need a connection to do anything. */
-       if ( ! pg_connection ) return 0;
-       if ( ! sql ) return 0;
-
-       res = PQexec(pg_connection, sql);
-       status = PQresultStatus(res);
-       PQclear(res);
-
-       /* Did something unexpected happen? */
-       if ( ! ( status == PGRES_COMMAND_OK || status == PGRES_TUPLES_OK ) )
-       {
-               /* Log notices and return success. */
-               if ( status == PGRES_NONFATAL_ERROR )
-               {
-                       pgui_logf("%s", PQerrorMessage(pg_connection));
-                       return 1;
-               }
-
-               /* Log errors and return failure. */
-               snprintf(sql_trunc, 255, "%s", sql);
-               pgui_logf("Failed SQL begins: \"%s\"", sql_trunc);
-               pgui_logf("Failed in pgui_exec(): %s", PQerrorMessage(pg_connection));
-               return 0;
-       }
-
-       return 1;
-}
-
-/*
-** Start the COPY process.
-*/
-static int
-pgui_copy_start(const char *sql)
-{
-       PGresult *res = NULL;
-       ExecStatusType status;
-       char sql_trunc[256];
-
-       /* We need a connection to do anything. */
-       if ( ! pg_connection ) return 0;
-       if ( ! sql ) return 0;
-
-       res = PQexec(pg_connection, sql);
-       status = PQresultStatus(res);
-       PQclear(res);
-
-       /* Did something unexpected happen? */
-       if ( status != PGRES_COPY_IN )
-       {
-               /* Log errors and return failure. */
-               snprintf(sql_trunc, 255, "%s", sql);
-               pgui_logf("Failed SQL begins: \"%s\"", sql_trunc);
-               pgui_logf("Failed in pgui_copy_start(): %s", PQerrorMessage(pg_connection));
-               return 0;
-       }
-
-       return 1;
-}
-
-/*
-** Send a line (row) of data into the COPY procedure.
-*/
-static int
-pgui_copy_write(const char *line)
-{
-       char line_trunc[256];
-
-       /* We need a connection to do anything. */
-       if ( ! pg_connection ) return 0;
-       if ( ! line ) return 0;
-
-       /* Did something unexpected happen? */
-       if ( PQputCopyData(pg_connection, line, strlen(line)) < 0 )
-       {
-               /* Log errors and return failure. */
-               snprintf(line_trunc, 255, "%s", line);
-               pgui_logf("Failed row begins: \"%s\"", line_trunc);
-               pgui_logf("Failed in pgui_copy_write(): %s", PQerrorMessage(pg_connection));
-               return 0;
-       }
-
-       /* Send linefeed to signify end of line */
-       PQputCopyData(pg_connection, "\n", 1);
-
-       return 1;
-}
-
-/*
-** Finish the COPY process.
-*/
-static int
-pgui_copy_end(const int rollback)
-{
-       char *errmsg = NULL;
-
-       /* We need a connection to do anything. */
-       if ( ! pg_connection ) return 0;
-
-       if ( rollback ) errmsg = "Roll back the copy.";
-
-       /* Did something unexpected happen? */
-       if ( PQputCopyEnd(pg_connection, errmsg) < 0 )
-       {
-               /* Log errors and return failure. */
-               pgui_logf("Failed in pgui_copy_end(): %s", PQerrorMessage(pg_connection));
-               return 0;
-       }
-
-       return 1;
-}
-
-static char *
-pgui_read_connection(void)
-{
-       const char *pg_host = gtk_entry_get_text(GTK_ENTRY(entry_pg_host));
-       const char *pg_port = gtk_entry_get_text(GTK_ENTRY(entry_pg_port));
-       const char *pg_user = gtk_entry_get_text(GTK_ENTRY(entry_pg_user));
-       const char *pg_pass = gtk_entry_get_text(GTK_ENTRY(entry_pg_pass));
-       const char *pg_db = gtk_entry_get_text(GTK_ENTRY(entry_pg_db));
-       char *connection_string = NULL;
-       char *escape_pg_pass = NULL;
-
-       if ( ! pg_host || strlen(pg_host) == 0 )
-       {
-               pgui_seterr(_("Fill in the server host."));
-               return NULL;
-       }
-       if ( ! pg_port || strlen(pg_port) == 0 )
-       {
-               pgui_seterr(_("Fill in the server port."));
-               return NULL;
-       }
-       if ( ! pg_user || strlen(pg_user) == 0 )
-       {
-               pgui_seterr(_("Fill in the user name."));
-               return NULL;
-       }
-       if ( ! pg_db || strlen(pg_db) == 0 )
-       {
-               pgui_seterr(_("Fill in the database name."));
-               return NULL;
-       }
-       if ( ! atoi(pg_port) )
-       {
-               pgui_seterr(_("Server port must be a number."));
-               return NULL;
-       }
-
-       /* Escape the password in case it contains any special characters */
-       escape_pg_pass = escape_connection_string((char *)pg_pass);
-
-       if ( ! lw_asprintf(&connection_string, "user=%s password='%s' port=%s host=%s dbname=%s", pg_user, escape_pg_pass, pg_port, pg_host, pg_db) )
-       {
-               return NULL;
-       }
-
-       /* Free the escaped version */
-       if (escape_pg_pass != pg_pass)
-               free(escape_pg_pass);
-
-       if ( connection_string )
-       {
-               return connection_string;
-       }
-       return NULL;
-}
-
-static void
-pgui_action_cancel(GtkWidget *widget, gpointer data)
-{
-       if (!import_running)
-               pgui_quit(widget, data); /* quit if we're not running */
-       else
-               import_running = FALSE;
-}
-
-static void
-pgui_sanitize_connection_string(char *connection_string)
-{
-       char *ptr = strstr(connection_string, "password");
-       if ( ptr )
-       {
-               ptr += 10;
-               while ( *ptr != '\'' && *ptr != '\0' )
-               {
-                       /* If we find a \, hide both it and the next character */
-                       if ( *ptr == '\\' )
-                               *ptr++ = '*';
-               
-                       *ptr++ = '*';
-               }
-       }
-       return;
-}
-
-/*
- * This will create a connection to the database, just to see if it can.
- * It cleans up after itself like a good little function and maintains
- * the status of the valid_connection parameter.
- */
-static int
-connection_test(void)
-{
-       char *connection_string = NULL;
-       char *connection_sanitized = NULL;
-
-       if ( ! (connection_string = pgui_read_connection()) )
-       {
-               pgui_raise_error_dialogue();
-               valid_connection = 0;
-               return 0;
-       }
-
-       connection_sanitized = strdup(connection_string);
-       pgui_sanitize_connection_string(connection_sanitized);
-       pgui_logf("Connecting: %s", connection_sanitized);
-       free(connection_sanitized);
-
-       if ( pg_connection )
-               PQfinish(pg_connection);
-
-       pg_connection = PQconnectdb(connection_string);
-       if (PQstatus(pg_connection) == CONNECTION_BAD)
-       {
-               pgui_logf( _("Database connection failed: %s"), PQerrorMessage(pg_connection));
-               free(connection_string);
-               PQfinish(pg_connection);
-               pg_connection = NULL;
-               valid_connection = 0;
-               return 0;
-       }
-       PQfinish(pg_connection);
-       pg_connection = NULL;
-       free(connection_string);
-
-       valid_connection = 1;
-       return 1;
-}
-
-/*
- * This is a signal handler delegate used for validating connection
- * parameters as the user is changing them, prior to testing for a database
- * connection.
- */
-static void
-pgui_action_auto_connection_test()
-{
-       /*
-        * Since this isn't explicitly triggered, I don't want to error
-        * if we don't have enough information.
-        */
-       if (validate_string((char*)gtk_entry_get_text(GTK_ENTRY(entry_pg_host))) == 0
-               || validate_string((char*)gtk_entry_get_text(GTK_ENTRY(entry_pg_port))) == 0
-               || validate_string((char*)gtk_entry_get_text(GTK_ENTRY(entry_pg_user))) == 0
-               || validate_string((char*)gtk_entry_get_text(GTK_ENTRY(entry_pg_pass))) == 0
-               || validate_string((char*)gtk_entry_get_text(GTK_ENTRY(entry_pg_db))) == 0)
-               return;
-       if (connection_test() == 1)
-               pgui_logf(_("Database connection succeeded."));
-       else
-               pgui_logf(_("Database connection failed."));
-}
-
-/*
- * Signal handler for the connection parameter entry fields on activation.
- */
-static void
-pgui_action_auto_connection_test_activate(GtkWidget *entry, gpointer user_data)
-{
-       pgui_action_auto_connection_test();
-}
-
-/*
- * Signal handler for the connection parameter entry fields on loss of focus.
- *
- * Note that this must always return FALSE to allow subsequent event handlers
- * to be called.
- */
-static gboolean
-pgui_action_auto_connection_test_focus(GtkWidget *widget, GdkEventFocus *event, gpointer user_data)
-{
-       pgui_action_auto_connection_test();
-       return FALSE;
-}
-
-/*
- * We retain the ability to explicitly request a test of the connection
- * parameters.  This is the button signal handler to do so.
- */
-static void
-pgui_action_connection_test(GtkWidget *widget, gpointer data)
-{
-       if (!connection_test())
-       {
-               gtk_label_set_text(GTK_LABEL(label_pg_connection_test), _("Connection failed."));
-               pgui_logf( _("Connection failed.") );
-               gtk_widget_show(label_pg_connection_test);
-
-       }
-       else
-       {
-               gtk_label_set_text(
-               GTK_LABEL(label_pg_connection_test),
-               _("Connection succeeded."));
-               pgui_logf( _("Connection succeeded.") );
-               gtk_widget_show(label_pg_connection_test);
-       }
-}
-
-static void
-pgui_action_options_open(GtkWidget *widget, gpointer data)
-{
-       pgui_create_options_dialogue();
-       return;
-}
-
-static void
-pgui_action_options_close(GtkWidget *widget, gpointer data)
-{
-       pgui_set_config_from_options_ui();
-       gtk_widget_destroy(widget);
-       return;
-}
-
-static void
-pgui_action_null(GtkWidget *widget, gpointer data)
-{
-       ;
-}
-
-static void
-pgui_action_open_file_dialog(GtkWidget *widget, gpointer data)
-{
-       GtkFileFilter *file_filter_shape;
-
-       GtkWidget *file_chooser_dialog_shape = 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);
-
-       pgui_logf("pgui_action_open_file_dialog called.");
-
-
-       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(file_chooser_dialog_shape), 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(file_chooser_dialog_shape), file_filter_shape);
-
-       if (gtk_dialog_run(GTK_DIALOG(file_chooser_dialog_shape))
-               == GTK_RESPONSE_ACCEPT)
-       {
-               pgui_action_shape_file_set(gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(file_chooser_dialog_shape)));
-               gtk_widget_destroy(file_chooser_dialog_shape);
-       }
-
-}
-
-/*
- * Given a filename, this function generates the default load parameters,
- * creates a new FILENODE in the file list and adds a row to the list table.
- */
-static void
-pgui_action_shape_file_set(const char *gtk_filename)
-{
-       GtkTreeIter iter;
-       FILENODE *file;
-       char *shp_file;
-       int shp_file_len;
-       int i;
-       char *table_start;
-       char *table_end;
-       char *table;
-
-       if ( gtk_filename )
-       {
-               shp_file = strdup(gtk_filename);
-               shp_file_len = strlen(shp_file);
-       }
-       else
-       {
-               return;
-       }
-
-       /* Roll back from end to first slash character. */
-       table_start = shp_file + shp_file_len;
-       while ( *table_start != '/' && *table_start != '\\' && table_start > shp_file)
-       {
-               table_start--;
-       }
-       table_start++; /* Forward one to start of actual characters. */
-
-       /* Roll back from end to first . character. */
-       table_end = shp_file + shp_file_len;
-       while ( *table_end != '.' && table_end > shp_file && table_end > table_start )
-       {
-               table_end--;
-       }
-
-       /* Copy the table name into a fresh memory slot. */
-       table = malloc(table_end - table_start + 1);
-       memcpy(table, table_start, table_end - table_start);
-       table[table_end - table_start] = '\0';
-
-       /* Force the table name to lower case */
-       for(i = 0; i < table_end - table_start; i++)
-       {
-               if(isupper(table[i]) != 0)
-               {
-                       table[i] = tolower(table[i]);
-               }
-       }
-
-       /* Set the table name into the configuration */
-       config->table = table;
-
-
-       /*
-       gtk_entry_set_text(GTK_ENTRY(entry_config_table), table);
-       */
-
-       file = append_file(shp_file, "public", table, GEOMETRY_DEFAULT, "-1", 'c', &iter);
-
-       set_filename_field_width();
-
-       validate_shape_file(file);
-
-       gtk_list_store_insert(list_store, &iter, current_list_index++);
-       gtk_list_store_set(list_store, &iter,
-                          FILENAME_COLUMN, shp_file,
-                          SCHEMA_COLUMN, "public",
-                          TABLE_COLUMN, table,
-                          GEOMETRY_COLUMN, GEOMETRY_DEFAULT,
-                          SRID_COLUMN, "-1",
-                          MODE_COLUMN, _("Create"),
-                          -1);
-
-       free(shp_file);
-}
-
-static void
-pgui_action_import(GtkWidget *widget, gpointer data)
-{
-       char *connection_string = NULL;
-       char *connection_sanitized = NULL;
-       char *dest_string = NULL;
-       int ret, i = 0;
-       char *header, *footer, *record;
-       PGresult *result;
-       FILENODE *current_file;
-
-
-       if ( ! (connection_string = pgui_read_connection() ) )
-       {
-               pgui_raise_error_dialogue();
-               return;
-       }
-
-       current_file = get_next_node(NULL);
-       if (current_file == NULL)
-       {
-               pgui_logf(_("File list is empty or uninitialised."));
-               return;
-       }
-
-       while (current_file != NULL)
-       {
-
-               /*
-               ** Set the configuration from the UI and validate
-               */
-               pgui_set_config_from_ui(current_file);
-               if (! pgui_validate_config() )
-               {
-                       pgui_raise_error_dialogue();
-
-                       current_file = get_next_node(current_file);
-                       continue;
-               }
-
-               pgui_logf("\n==============================");
-               pgui_logf("Importing with configuration: %s, %s, %s, %s, mode=%c, dump=%d, simple=%d, geography=%d, index=%d, shape=%d, srid=%d", config->table, config->schema, config->geo_col, config->shp_file, config->opt, config->dump_format, config->simple_geometries, config->geography, config->createindex, config->readshape, config->sr_id);
-
-               /* Log what we know so far */
-               connection_sanitized = strdup(connection_string);
-               pgui_sanitize_connection_string(connection_sanitized);
-               pgui_logf("Connection: %s", connection_sanitized);
-               pgui_logf("Destination: %s.%s", config->schema, config->table);
-               pgui_logf("Source File: %s", config->shp_file);
-               free(connection_sanitized);
-
-               /* Connect to the database. */
-               if ( pg_connection ) PQfinish(pg_connection);
-               pg_connection = PQconnectdb(connection_string);
-
-               if (PQstatus(pg_connection) == CONNECTION_BAD)
-               {
-                       pgui_logf( _("Database connection failed: %s"), PQerrorMessage(pg_connection));
-                       gtk_label_set_text(GTK_LABEL(label_pg_connection_test), _("Connection failed."));
-                       free(connection_string);
-                       free(dest_string);
-                       PQfinish(pg_connection);
-                       pg_connection = NULL;
-                       return;
-               }
-
-               /*
-                * Loop through the items in the shapefile
-                */
-
-               /* 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 shapefile state object */
-               state = ShpLoaderCreate(config);
-
-               /* Open the shapefile */
-               ret = ShpLoaderOpenShape(state);
-               if (ret != SHPLOADEROK)
-               {
-                       pgui_logf("%s", state->message);
-
-                       if (ret == SHPLOADERERR)
-                               goto import_cleanup;
-               }
-
-               /* If reading the whole shapefile, display its type */
-               if (state->config->readshape)
-               {
-                       pgui_logf("Shapefile type: %s", SHPTypeName(state->shpfiletype));
-                       pgui_logf("PostGIS type: %s[%d]", state->pgtype, state->pgdims);
-               }
-
-               /* Get the header */
-               ret = ShpLoaderGetSQLHeader(state, &header);
-               if (ret != SHPLOADEROK)
-               {
-                       pgui_logf("%s", state->message);
-
-                       if (ret == SHPLOADERERR)
-                               goto import_cleanup;
-               }
-
-               /* Send the header to the remote server: if we are in COPY mode then the last
-                  statement will be a COPY and so will change connection mode */
-               ret = pgui_exec(header);
-               free(header);
-
-               if (!ret)
-                       goto import_cleanup;
-
-               import_running = TRUE;
-
-               /* If we are in prepare mode, we need to skip the actual load. */
-               if (state->config->opt != 'p')
-               {
-
-                       /* If we are in COPY (dump format) mode, output the COPY statement and enter COPY mode */
-                       if (state->config->dump_format)
-                       {
-                               ret = ShpLoaderGetSQLCopyStatement(state, &header);
-
-                               if (ret != SHPLOADEROK)
-                               {
-                                       pgui_logf("%s", state->message);
-
-                                       if (ret == SHPLOADERERR)
-                                               goto import_cleanup;
-                               }
-
-                               /* Send the result to the remote server: this should put us in COPY mode */
-                               ret = pgui_copy_start(header);
-                               free(header);
-
-                               if (!ret)
-                                       goto import_cleanup;
+                               if (!ret)
+                                       goto import_cleanup;
                        }
 
                        /* Main loop: iterate through all of the records and send them to stdout */
-                       pgui_logf(_("Importing shapefile (%d records)..."), ShpLoaderGetRecordCount(state));
-
                        for (i = 0; i < ShpLoaderGetRecordCount(state) && import_running; i++)
                        {
                                ret = ShpLoaderGenerateSQLRowStatement(state, i, &record);
@@ -1946,75 +1168,517 @@ pgui_action_import(GtkWidget *widget, gpointer data)
                                        goto import_cleanup;
                        }
 
-                       if ( state->config->createindex )
+                       if (state->config->createindex)
                        {
                                pgui_logf(_("Creating spatial index...\n"));
                        }
 
-                       /* Send the footer to the server */
-                       ret = pgui_exec(footer);
-                       free(footer);
+                       /* Send the footer to the server */
+                       ret = pgui_exec(footer);
+                       free(footer);
+
+                       if (!ret)
+                               goto import_cleanup;
+               }
+               
+               /* Indicate success */
+               success = TRUE;
+
+import_cleanup:
+               /* Import has definitely stopped running */
+               import_running = FALSE;
+
+               /* Make sure we abort any existing transaction */
+               if (!success)
+                       pgui_exec("ABORT");
+               
+               /* If we didn't finish inserting all of the items (and we expected to), an error occurred */
+               if ((state->config->opt != 'p' && i != ShpLoaderGetRecordCount(state)) || !ret)
+                       pgui_logf(_("Shapefile import failed."));
+               else
+                       pgui_logf(_("Shapefile import completed."));
+
+               /* Free the state object */
+               ShpLoaderDestroy(state);
+
+               /* Tidy up */
+               if (progress_text)
+                       free(progress_text);
+               
+               if (progress_shapefile)
+                       free(progress_shapefile);
+               
+               /* Get next entry */
+               is_valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(list_store), &iter);
+       }
+       
+       /* Import has definitely finished */
+       import_running = FALSE;
+
+       /* 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();
+
+       /* Disconnect from the database */
+       PQfinish(pg_connection);
+       pg_connection = NULL;
+
+       /* Tidy up */
+       free(connection_string);
+
+       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_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);
+
+}
+
+/* Update the SHPLOADERCONFIG to the values currently contained within the iter  */
+static void
+update_loader_file_config_from_listview_iter(GtkTreeIter *iter, SHPLOADERCONFIG *loader_file_config)
+{
+       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,
+               -1);
+       
+       /* Update the schema */
+       if (loader_file_config->schema)
+               free(loader_file_config->schema);
+       
+       loader_file_config->schema = strdup(schema);
+
+       /* Update the table */
+       if (loader_file_config->table)
+               free(loader_file_config->table);
+               
+       loader_file_config->table = strdup(table);
+
+       /* Update the geo column */
+       if (loader_file_config->geo_col)
+               free(loader_file_config->geo_col);
+               
+       loader_file_config->geo_col = strdup(geo_col);
+       
+       /* Update the SRID */
+       loader_file_config->sr_id = atoi(srid);
+
+       /* Free the values */
+       return;
+}
+
+
+/*
+ * Here lives the magic of the drag-n-drop of the app.  We really don't care
+ * about much of the provided tidbits.  We only actually user selection_data
+ * and extract a list of filenames from it.
+ */
+static void
+pgui_action_handle_file_drop(GtkWidget *widget,
+                             GdkDragContext *dc,
+                             gint x, gint y,
+                             GtkSelectionData *selection_data,
+                             guint info, guint t, gpointer data)
+{
+       const gchar *p, *q;
+
+       if (selection_data->data == NULL)
+       {
+               pgui_logf(_("Unable to process drag data."));
+               return;
+       }
+
+       p = (char*)selection_data->data;
+       while (p)
+       {
+               /* Only process non-comments */
+               if (*p != '#')
+               {
+                       /* Trim leading whitespace */
+                       while (g_ascii_isspace(*p))
+                               p++;
+                       q = p;
+                       /* Scan to the end of the string (null or newline) */
+                       while (*q && (*q != '\n') && (*q != '\r'))
+                               q++;
+                       if (q > p)
+                       {
+                               /* Ignore terminating character */
+                               q--;
+                               /* Trim trailing whitespace */
+                               while (q > p && g_ascii_isspace(*q))
+                                       q--;
+                               if (q > p)
+                               {
+                                       process_single_uri(g_strndup(p, q - p + 1));
+                               }
+                       }
+               }
+               /* Skip to the next entry */
+               p = strchr(p, '\n');
+               if (p)
+                       p++;
+       }
+}
+
+
+/*
+ * This function is a signal handler for the load mode combo boxes.
+ */
+static void
+pgui_action_handle_tree_combo(GtkCellRendererCombo *combo,
+                              gchar *path_string,
+                              GtkTreeIter *new_iter,
+                              gpointer user_data)
+{
+       GtkTreeIter iter;
+       SHPLOADERCONFIG *loader_file_config;
+       char opt;
+       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);
+       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);
+       
+       /* Update the configuration */
+       
+       /* Hack for index creation: we must disable it if we are appending, otherwise we
+          end up trying to generate the index again */
+       loader_file_config->createindex = global_loader_config->createindex;
+       
+       switch (opt)
+       {
+               case 'a':
+                       loader_file_config->opt = 'a';
+                       
+                       /* Other half of index creation hack */
+                       loader_file_config->createindex = 0;
+                               
+                       break;
+                       
+               case 'd':
+                       loader_file_config->opt = 'd';
+                       break;
+                       
+               case 'p':
+                       loader_file_config->opt = 'p';
+                       break;
+                       
+               case 'c':
+                       loader_file_config->opt = 'c';
+                       break;
+       }
+       
+       /* 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);
+       
+       return; 
+}
+       
+
+/*
+ * This method is a signal listener for all text renderers in the file
+ * list table, including the empty ones.  Edits of the empty table are
+ * passed to an appropriate function, while edits of existing file rows
+ * are applied and the various validations called.
+ */
+static void
+pgui_action_handle_tree_edit(GtkCellRendererText *renderer,
+                             gchar *path,
+                             gchar *new_text,
+                             gpointer column)
+{
+       GtkTreeIter iter;
+       gpointer gptr;
+       gint columnindex;
+       SHPLOADERCONFIG *loader_file_config;
+       char *srid;
+       
+       /* 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(list_store), &iter, path);
+       gtk_list_store_set(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);
+       loader_file_config = (SHPLOADERCONFIG *)gptr;
+       
+       /* Update the configuration from the current UI data */
+       update_loader_file_config_from_listview_iter(&iter, loader_file_config);
+       
+       /* 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,
+                          -1);
+
+       return;
+}
+
+/*
+ * Signal handler for the remove box.  Performs no user interaction, simply
+ * removes the row from the table.
+ */
+static void
+pgui_action_handle_tree_remove(GtkCellRendererToggle *renderer,
+                               gchar *path,
+                               gpointer user_data)
+{
+       GtkTreeIter iter;
+       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);
+       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);
+
+       /* Update the filename field width */
+       update_filename_field_width();
+}
 
-                       if (!ret)
-                               goto import_cleanup;
-               }
 
 
-import_cleanup:
-               /* If we didn't finish inserting all of the items (and we expected to), an error occurred */
-               if ((state->config->opt != 'p' && i != ShpLoaderGetRecordCount(state)) || !ret)
-                       pgui_logf(_("Shapefile import failed."));
-               else
-                       pgui_logf(_("Shapefile import completed."));
+/* === Connection Window functions === */
 
-               /* Free the state object */
-               ShpLoaderDestroy(state);
+/* Set the connection details UI from the current configuration */
+static void 
+update_conn_ui_from_conn_config(void)
+{
+       if (conn->username)
+               gtk_entry_set_text(GTK_ENTRY(entry_pg_user), conn->username);
+       
+       if (conn->password)
+               gtk_entry_set_text(GTK_ENTRY(entry_pg_pass), conn->password);
+       
+       if (conn->host)
+               gtk_entry_set_text(GTK_ENTRY(entry_pg_host), conn->host);
+       
+       if (conn->port)
+               gtk_entry_set_text(GTK_ENTRY(entry_pg_port), conn->port);
+       
+       if (conn->database)
+               gtk_entry_set_text(GTK_ENTRY(entry_pg_db), conn->database);
 
-               /* Import has definitely finished */
-               import_running = FALSE;
+       return;
+}
 
-               /* Enable the button once again */
-               gtk_widget_set_sensitive(widget, TRUE);
+/* Set the current connection configuration from the connection details UI */
+static void
+update_conn_config_from_conn_ui(void)
+{
+       const char *text;
+       
+       text = gtk_entry_get_text(GTK_ENTRY(entry_pg_user));
+       if (conn->username)
+               free(conn->username);
+       
+       if (strlen(text))
+               conn->username = strdup(text);
+       else
+               conn->username = NULL;
+       
+       text = gtk_entry_get_text(GTK_ENTRY(entry_pg_pass));
+       if (conn->password)
+               free(conn->password);
+       
+       if (strlen(text))
+               conn->password = strdup(text);
+       else
+               conn->password = NULL;
+       
+       text = gtk_entry_get_text(GTK_ENTRY(entry_pg_host));
+       if (conn->host)
+               free(conn->host);
+       
+       if (strlen(text))
+               conn->host = strdup(text);
+       else
+               conn->host = NULL;
 
-               /* 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);
+       text = gtk_entry_get_text(GTK_ENTRY(entry_pg_port));
+       if (conn->port)
+               free(conn->port);
+       
+       if (strlen(text))
+               conn->port = strdup(text);
+       else
+               conn->port = NULL;
 
-               /* Reset the progress bar */
-               gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(progress), 0.0);
+       text = gtk_entry_get_text(GTK_ENTRY(entry_pg_db));
+       if (conn->database)
+               free(conn->database);
+       
+       if (strlen(text))
+               conn->database = strdup(text);
+       else
+               conn->database = NULL;
 
-               /* Allow GTK events to get a look in */
-               while (gtk_events_pending())
-                       gtk_main_iteration();
+       return;
+}
 
-               /* Disconnect from the database */
-               PQfinish(pg_connection);
-               pg_connection = NULL;
+/*
+ * Open the connection details dialog
+ */
+static void
+pgui_action_connection_details(GtkWidget *widget, gpointer data)
+{
+       /* Update the UI with the current options */
+       update_conn_ui_from_conn_config();
+       
+       gtk_widget_show_all(GTK_WIDGET(window_conn));
+       return;
+}
 
-               current_file = get_next_node(current_file);
+/* Validate the connection, returning true or false */
+static int
+pgui_validate_connection()
+{
+       int i;
+       
+       if (strlen(conn->port))
+       {
+               for (i = 0; i < strlen(conn->port); i++)
+               {
+                       if (!isdigit(conn->port[i]))
+                       {
+                               pgui_seterr(_("The connection port must be numeric!"));
+                               return 0;
+                       }
+               }
        }
+       
+       return 1;
+}
 
-       /* Tidy up */
-       free(connection_string);
-       free(dest_string);
-       connection_string = dest_string = NULL;
-
+static void
+pgui_sanitize_connection_string(char *connection_string)
+{
+       char *ptr = strstr(connection_string, "password");
+       if ( ptr )
+       {
+               ptr += 10;
+               while ( *ptr != '\'' && *ptr != '\0' )
+               {
+                       /* If we find a \, hide both it and the next character */
+                       if ( *ptr == '\\' )
+                               *ptr++ = '*';
+               
+                       *ptr++ = '*';
+               }
+       }
        return;
 }
 
+/*
+ * We retain the ability to explicitly request a test of the connection
+ * parameters.  This is the button signal handler to do so.
+ */
 static void
-pgui_create_options_dialogue_add_label(GtkWidget *table, const char *str, gfloat alignment, int row)
+pgui_action_connection_okay(GtkWidget *widget, gpointer data)
 {
-       GtkWidget *align = gtk_alignment_new( alignment, 0.5, 0.0, 1.0 );
-       GtkWidget *label = gtk_label_new( str );
-       gtk_table_attach_defaults(GTK_TABLE(table), align, 1, 3, row, row+1 );
-       gtk_container_add (GTK_CONTAINER (align), label);
+       /* Update the configuration structure from the form */
+       update_conn_config_from_conn_ui();
+       
+       /* Make sure have a valid connection first */
+       if (!pgui_validate_connection())
+       {
+               pgui_raise_error_dialogue();
+               return;
+       }
+       
+       if (!connection_test())
+       {
+               pgui_logf(_("Connection failed."));
+       
+               /* If the connection failed, display a warning before closing */
+               pgui_seterr(_("Unable to connect to the database - please check your connection settings"));
+               pgui_raise_error_dialogue();
+       }
+       else
+       {
+               pgui_logf(_("Connection succeeded."));
+       }
+       
+                       
+       /* Hide the window after the test */
+       gtk_widget_hide(GTK_WIDGET(window_conn));
 }
 
+
+/* === Window creation functions === */
+
 static void
-pgui_action_about_open()
+pgui_create_about_dialog(void)
 {
-       GtkWidget *dlg;
        const char *authors[] =
        {
                "Paul Ramsey <pramsey@opengeo.org>",
@@ -2023,25 +1687,97 @@ pgui_action_about_open()
                NULL
        };
 
-       dlg = gtk_about_dialog_new ();
-       gtk_about_dialog_set_name (GTK_ABOUT_DIALOG(dlg), _("Shape to PostGIS"));
-       gtk_about_dialog_set_comments (GTK_ABOUT_DIALOG(dlg), GUI_RCSID);
-       /*      gtk_about_dialog_set_version (GTK_ABOUT_DIALOG(dlg), GUI_RCSID); */
-       gtk_about_dialog_set_website (GTK_ABOUT_DIALOG(dlg), "http://postgis.org/");
-       gtk_about_dialog_set_authors (GTK_ABOUT_DIALOG(dlg), authors);
-       g_signal_connect_swapped(dlg, "response", G_CALLBACK(gtk_widget_destroy), dlg);
-       gtk_widget_show (dlg);
+       dialog_about = gtk_about_dialog_new();
+       gtk_about_dialog_set_name(GTK_ABOUT_DIALOG(dialog_about), _("Shape to PostGIS"));
+       gtk_about_dialog_set_comments(GTK_ABOUT_DIALOG(dialog_about), GUI_RCSID);
+       gtk_about_dialog_set_website(GTK_ABOUT_DIALOG(dialog_about), "http://postgis.org/");
+       gtk_about_dialog_set_authors(GTK_ABOUT_DIALOG(dialog_about), authors);
+}
+
+static void
+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), 
+               GTK_FILE_CHOOSER_ACTION_OPEN, 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_filechooser), 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_filechooser), file_filter_shape);
+
+       return;
+}
+
+static void
+pgui_create_progress_dialog()
+{
+       GtkWidget *vbox_progress, *table_progress;
+       
+       dialog_progress = gtk_dialog_new_with_buttons(_("Working..."), GTK_WINDOW(window_main), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, NULL);
+
+       gtk_window_set_modal(GTK_WINDOW(dialog_progress), TRUE);
+       gtk_window_set_keep_above(GTK_WINDOW(dialog_progress), TRUE);
+       gtk_window_set_default_size(GTK_WINDOW(dialog_progress), 640, -1);
+
+       /* Use a vbox as the base container */
+       vbox_progress = gtk_dialog_get_content_area(GTK_DIALOG(dialog_progress));
+       gtk_box_set_spacing(GTK_BOX(vbox_progress), 15);
+       
+       /* Create a table within the vbox */
+       table_progress = gtk_table_new(2, 1, TRUE);
+       gtk_container_set_border_width (GTK_CONTAINER (table_progress), 12);
+       gtk_table_set_row_spacings(GTK_TABLE(table_progress), 5);
+       gtk_table_set_col_spacings(GTK_TABLE(table_progress), 10);
+       
+       /* Text for the progress bar */
+       label_progress = gtk_label_new("");
+       gtk_table_attach_defaults(GTK_TABLE(table_progress), label_progress, 0, 1, 0, 1);
+       
+       /* Progress bar for the import */
+       progress = gtk_progress_bar_new();
+       gtk_progress_bar_set_orientation(GTK_PROGRESS_BAR(progress), GTK_PROGRESS_LEFT_TO_RIGHT);
+       gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(progress), 0.0);
+       gtk_table_attach_defaults(GTK_TABLE(table_progress), progress, 0, 1, 1, 2);
+       
+       /* Add the table to the vbox */
+       gtk_box_pack_start(GTK_BOX(vbox_progress), table_progress, FALSE, FALSE, 0);
+       
+       /* Add signal for cancel button */
+       g_signal_connect(dialog_progress, "response", G_CALLBACK(pgui_action_progress_cancel), dialog_progress);
+       
+       /* Make sure we catch a delete event too */
+       gtk_signal_connect(GTK_OBJECT(dialog_progress), "delete_event", GTK_SIGNAL_FUNC(pgui_action_progress_delete), NULL);
+       
+       return;
+}
+
+static void
+pgui_create_options_dialog_add_label(GtkWidget *table, const char *str, gfloat alignment, int row)
+{
+       GtkWidget *align = gtk_alignment_new(alignment, 0.5, 0.0, 1.0);
+       GtkWidget *label = gtk_label_new(str);
+       gtk_table_attach_defaults(GTK_TABLE(table), align, 1, 3, row, row + 1);
+       gtk_container_add(GTK_CONTAINER (align), label);
 }
 
 static void
-pgui_create_options_dialogue()
+pgui_create_options_dialog()
 {
        GtkWidget *table_options;
        GtkWidget *align_options_center;
-       GtkWidget *dialog_options;
        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_NONE, NULL);
+       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);
 
        gtk_window_set_modal (GTK_WINDOW(dialog_options), TRUE);
        gtk_window_set_keep_above (GTK_WINDOW(dialog_options), TRUE);
@@ -2052,237 +1788,53 @@ pgui_create_options_dialogue()
        gtk_table_set_row_spacings(GTK_TABLE(table_options), 5);
        gtk_table_set_col_spacings(GTK_TABLE(table_options), 10);
 
-       pgui_create_options_dialogue_add_label(table_options, _("DBF file character encoding"), 0.0, 0);
+       pgui_create_options_dialog_add_label(table_options, _("DBF file character encoding"), 0.0, 0);
        entry_options_encoding = gtk_entry_new();
        gtk_entry_set_width_chars(GTK_ENTRY(entry_options_encoding), text_width);
-       gtk_entry_set_text(GTK_ENTRY(entry_options_encoding), config->encoding);
        gtk_table_attach_defaults(GTK_TABLE(table_options), entry_options_encoding, 0, 1, 0, 1 );
 
-       pgui_create_options_dialogue_add_label(table_options, _("Preserve case of column names"), 0.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();
-       gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(checkbutton_options_preservecase), config->quoteidentifiers ? TRUE : FALSE);
        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);
 
-       pgui_create_options_dialogue_add_label(table_options, _("Do not create 'bigint' columns"), 0.0, 2);
-       checkbutton_options_forceint = gtk_check_button_new();
-       gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(checkbutton_options_forceint), config->forceint4 ? TRUE : FALSE);
-       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);
-
-       pgui_create_options_dialogue_add_label(table_options, _("Create spatial index automatically after load"), 0.0, 3);
-       checkbutton_options_autoindex = gtk_check_button_new();
-       gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(checkbutton_options_autoindex), config->createindex ? TRUE : FALSE);
-       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);
-
-       pgui_create_options_dialogue_add_label(table_options, _("Load only attribute (dbf) data"), 0.0, 4);
-       checkbutton_options_dbfonly = gtk_check_button_new();
-       gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON  (checkbutton_options_dbfonly), config->readshape ? FALSE : TRUE);
-       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);
-
-       pgui_create_options_dialogue_add_label(table_options, _("Load data using COPY rather than INSERT"), 0.0, 5);
-       checkbutton_options_dumpformat = gtk_check_button_new();
-       gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON  (checkbutton_options_dumpformat), config->dump_format ? TRUE : FALSE);
-       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);
-
-       pgui_create_options_dialogue_add_label(table_options, _("Load into GEOGRAPHY column"), 0.0, 6);
-       checkbutton_options_geography = gtk_check_button_new();
-       gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(checkbutton_options_geography), config->geography ? TRUE : FALSE);
-       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);
-
-       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);
-
-       gtk_widget_show_all (dialog_options);
-}
-
-static void
-pgui_create_main_window(const SHPCONNECTIONCONFIG *conn)
-{
-       static int text_width = 12;
-       /* Reusable label handle */
-       GtkWidget *label;
-       /* Main widgets */
-       GtkWidget *vbox_main;
-       /* PgSQL section */
-       GtkWidget *frame_pg, *frame_shape, *frame_log;
-       GtkWidget *table_pg;
-       GtkWidget *button_pg_test;
-       /* Button section */
-       GtkWidget *hbox_buttons, *button_options, *button_import, *button_cancel, *button_about;
-       /* Log section */
-       GtkWidget *scrolledwindow_log;
-
-       /* create the main, top level, window */
-       window_main = gtk_window_new (GTK_WINDOW_TOPLEVEL);
-
-       /* give the window a 10px wide border */
-       gtk_container_set_border_width (GTK_CONTAINER (window_main), 10);
-
-       /* give it the title */
-       gtk_window_set_title (GTK_WINDOW (window_main), _("Shape File to PostGIS Importer"));
-
-       /* open it a bit wider so that both the label and title show up */
-       gtk_window_set_default_size (GTK_WINDOW (window_main), 180, 500);
-
-       /* Connect the destroy event of the window with our pgui_quit function
-       *  When the window is about to be destroyed we get a notificaiton and
-       *  stop the main GTK loop
-       */
-       g_signal_connect (G_OBJECT (window_main), "destroy", G_CALLBACK (pgui_quit), NULL);
-
-       /*
-       ** PostGIS info in a table
-       */
-       frame_pg = gtk_frame_new(_("PostGIS Connection"));
-       table_pg = gtk_table_new(5, 3, TRUE);
-       gtk_container_set_border_width (GTK_CONTAINER (table_pg), 8);
-       gtk_table_set_col_spacings(GTK_TABLE(table_pg), 7);
-       gtk_table_set_row_spacings(GTK_TABLE(table_pg), 3);
-       /* User name row */
-       label = gtk_label_new(_("Username:"));
-       entry_pg_user = gtk_entry_new();
-       if ( conn->username )
-               gtk_entry_set_text(GTK_ENTRY(entry_pg_user), conn->username);
-       gtk_table_attach_defaults(GTK_TABLE(table_pg), label, 0, 1, 0, 1 );
-       gtk_table_attach_defaults(GTK_TABLE(table_pg), entry_pg_user, 1, 3, 0, 1 );
-       g_signal_connect(G_OBJECT(entry_pg_user), "activate",
-                        G_CALLBACK(pgui_action_auto_connection_test), NULL);
-       g_signal_connect(G_OBJECT(entry_pg_user), "focus-out-event",
-                        G_CALLBACK(pgui_action_auto_connection_test_focus), NULL);
-       /* Password row */
-       label = gtk_label_new(_("Password:"));
-       entry_pg_pass = gtk_entry_new();
-       if ( conn->password )
-               gtk_entry_set_text(GTK_ENTRY(entry_pg_pass), conn->password);
-       gtk_entry_set_visibility( GTK_ENTRY(entry_pg_pass), FALSE);
-       gtk_table_attach_defaults(GTK_TABLE(table_pg), label, 0, 1, 1, 2 );
-       gtk_table_attach_defaults(GTK_TABLE(table_pg), entry_pg_pass, 1, 3, 1, 2 );
-       g_signal_connect(G_OBJECT(entry_pg_pass), "activate",
-                        G_CALLBACK(pgui_action_auto_connection_test_activate), NULL);
-       g_signal_connect(G_OBJECT(entry_pg_pass), "focus-out-event",
-                        G_CALLBACK(pgui_action_auto_connection_test_focus), NULL);
-       /* Host and port row */
-       label = gtk_label_new(_("Server Host:"));
-       entry_pg_host = gtk_entry_new();
-       if ( conn->host )
-               gtk_entry_set_text(GTK_ENTRY(entry_pg_host), conn->host);
-       else
-               gtk_entry_set_text(GTK_ENTRY(entry_pg_host), "localhost");
-       gtk_entry_set_width_chars(GTK_ENTRY(entry_pg_host), text_width);
-       gtk_table_attach_defaults(GTK_TABLE(table_pg), label, 0, 1, 2, 3 );
-       gtk_table_attach_defaults(GTK_TABLE(table_pg), entry_pg_host, 1, 2, 2, 3 );
-       g_signal_connect(G_OBJECT(entry_pg_host), "activate",
-                        G_CALLBACK(pgui_action_auto_connection_test_activate), NULL);
-       g_signal_connect(G_OBJECT(entry_pg_host), "focus-out-event",
-                        G_CALLBACK(pgui_action_auto_connection_test_focus), NULL);
-       entry_pg_port = gtk_entry_new();
-       if ( conn->port )
-               gtk_entry_set_text(GTK_ENTRY(entry_pg_port), conn->port);
-       else
-               gtk_entry_set_text(GTK_ENTRY(entry_pg_port), "5432");
-       gtk_entry_set_width_chars(GTK_ENTRY(entry_pg_port), 8);
-       gtk_table_attach_defaults(GTK_TABLE(table_pg), entry_pg_port, 2, 3, 2, 3 );
-       g_signal_connect(G_OBJECT(entry_pg_port), "activate",
-                        G_CALLBACK(pgui_action_auto_connection_test_activate), NULL);
-       g_signal_connect(G_OBJECT(entry_pg_port), "focus-out-event",
-                        G_CALLBACK(pgui_action_auto_connection_test_focus), NULL);
-       /* Database row */
-       label = gtk_label_new(_("Database:"));
-       entry_pg_db   = gtk_entry_new();
-       if ( conn->database )
-               gtk_entry_set_text(GTK_ENTRY(entry_pg_db), conn->database);
-       gtk_table_attach_defaults(GTK_TABLE(table_pg), label, 0, 1, 3, 4 );
-       gtk_table_attach_defaults(GTK_TABLE(table_pg), entry_pg_db, 1, 3, 3, 4 );
-       g_signal_connect(G_OBJECT(entry_pg_db), "activate",
-                        G_CALLBACK(pgui_action_auto_connection_test_activate), NULL);
-       g_signal_connect(G_OBJECT(entry_pg_db), "focus-out-event",
-                        G_CALLBACK(pgui_action_auto_connection_test_focus), NULL);
-       /* Test button row */
-       button_pg_test = gtk_button_new_with_label(_("Test Connection..."));
-       gtk_table_attach_defaults(GTK_TABLE(table_pg), button_pg_test, 1, 2, 4, 5 );
-       g_signal_connect (G_OBJECT (button_pg_test), "clicked", G_CALLBACK (pgui_action_connection_test), NULL);
-       label_pg_connection_test = gtk_label_new("");
-       gtk_table_attach_defaults(GTK_TABLE(table_pg), label_pg_connection_test, 2, 3, 4, 5 );
-       /* Add table into containing frame */
-       gtk_container_add (GTK_CONTAINER (frame_pg), table_pg);
-
-       /*
-       ** Shape file selector
-       */
-       frame_shape = gtk_frame_new(_("Shape File"));
-       pgui_create_file_table(frame_shape);
+       pgui_create_options_dialog_add_label(table_options, _("Do not create 'bigint' columns"), 0.0, 2);
+       checkbutton_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);
 
-       /* Progress bar for the import */
-       progress = gtk_progress_bar_new();
-       gtk_progress_bar_set_orientation(GTK_PROGRESS_BAR(progress), GTK_PROGRESS_LEFT_TO_RIGHT);
-       gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(progress), 0.0);
+       pgui_create_options_dialog_add_label(table_options, _("Create spatial index automatically after load"), 0.0, 3);
+       checkbutton_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);
 
-       /*
-       ** Row of action buttons
-       */
-       hbox_buttons = gtk_hbox_new(TRUE, 15);
-       gtk_container_set_border_width (GTK_CONTAINER (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"));
-       /* 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);
-       /* 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);
+       pgui_create_options_dialog_add_label(table_options, _("Load only attribute (dbf) data"), 0.0, 4);
+       checkbutton_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);
 
-       /*
-       ** Log window
-       */
-       frame_log = gtk_frame_new(_("Import Log"));
-       gtk_container_set_border_width (GTK_CONTAINER (frame_log), 0);
-       textview_log = gtk_text_view_new();
-       textbuffer_log = gtk_text_buffer_new(NULL);
-       scrolledwindow_log = gtk_scrolled_window_new(NULL, NULL);
-       gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW(scrolledwindow_log), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
-       gtk_text_view_set_buffer(GTK_TEXT_VIEW(textview_log), textbuffer_log);
-       gtk_container_set_border_width (GTK_CONTAINER (textview_log), 5);
-       gtk_text_view_set_editable(GTK_TEXT_VIEW(textview_log), FALSE);
-       gtk_text_view_set_cursor_visible(GTK_TEXT_VIEW(textview_log), FALSE);
-       gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(textview_log), GTK_WRAP_WORD);
-       gtk_container_add (GTK_CONTAINER (scrolledwindow_log), textview_log);
-       gtk_container_add (GTK_CONTAINER (frame_log), scrolledwindow_log);
+       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();
+       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);
 
-       /*
-       ** Main window
-       */
-       vbox_main = gtk_vbox_new(FALSE, 10);
-       gtk_container_set_border_width (GTK_CONTAINER (vbox_main), 0);
-       /* 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), frame_shape, FALSE, TRUE, 0);
-       gtk_box_pack_start(GTK_BOX(vbox_main), hbox_buttons, FALSE, FALSE, 0);
-       gtk_box_pack_start(GTK_BOX(vbox_main), progress, FALSE, FALSE, 0);
-       gtk_box_pack_start(GTK_BOX(vbox_main), frame_log, TRUE, TRUE, 0);
-       /* and insert the vbox into the main window  */
-       gtk_container_add (GTK_CONTAINER (window_main), vbox_main);
-       /* make sure that everything, window and label, are visible */
-       gtk_widget_show_all (window_main);
+       pgui_create_options_dialog_add_label(table_options, _("Load into GEOGRAPHY column"), 0.0, 6);
+       checkbutton_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);
 
-       return;
+       /* 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);
+       
+       /* 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);
 }
 
 /*
@@ -2293,19 +1845,19 @@ static void
 pgui_create_file_table(GtkWidget *frame_shape)
 {
        GtkWidget *vbox_tree;
-
+       GtkWidget *sw;
+       GtkTreeIter iter;
+       gint *column_indexes;
+       
        gtk_container_set_border_width (GTK_CONTAINER (frame_shape), 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);
 
-       add_file_button = gtk_button_new_with_label(_("Add File"));
-
-       gtk_container_add (GTK_CONTAINER (vbox_tree), add_file_button);
-
        /* Setup a model */
-       list_store = gtk_list_store_new (N_COLUMNS,
+       list_store = gtk_list_store_new(N_COLUMNS,
+                                        G_TYPE_POINTER,
                                         G_TYPE_STRING,
                                         G_TYPE_STRING,
                                         G_TYPE_STRING,
@@ -2313,103 +1865,126 @@ pgui_create_file_table(GtkWidget *frame_shape)
                                         G_TYPE_STRING,
                                         G_TYPE_STRING,
                                         G_TYPE_BOOLEAN);
-       /* Create file details list */
-       init_file_list();
+       
        /* Create the view and such */
        tree = gtk_tree_view_new_with_model(GTK_TREE_MODEL(list_store));
-       /* Make the tree view */
-       gtk_box_pack_start(GTK_BOX(vbox_tree), tree, TRUE, TRUE, 0);
+       
+       /* 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);
+       
+       /* 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), 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();
-       set_filename_field_width();
-       g_object_set(filename_renderer, "editable", TRUE, NULL);
-       g_signal_connect(G_OBJECT(filename_renderer), "edited", G_CALLBACK(pgui_action_handle_tree_edit), NULL);
+       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,
                          "text",
                          FILENAME_COLUMN,
                          NULL);
-       g_object_set(filename_column, "resizable", TRUE, NULL);
+       g_object_set(filename_column, "resizable", TRUE, "sizing", GTK_TREE_VIEW_COLUMN_AUTOSIZE, NULL);
        gtk_tree_view_append_column(GTK_TREE_VIEW(tree), filename_column);
 
        /* Schema Field */
        schema_renderer = gtk_cell_renderer_text_new();
        g_object_set(schema_renderer, "editable", TRUE, NULL);
-       g_signal_connect(G_OBJECT(schema_renderer), "edited", G_CALLBACK(pgui_action_handle_tree_edit), 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,
                        "text",
                        SCHEMA_COLUMN,
-                       "background",
-                       "white",
                        NULL);
-       g_object_set(schema_column, "resizable", TRUE, 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);
 
        /* Table Field */
        table_renderer = gtk_cell_renderer_text_new();
        g_object_set(table_renderer, "editable", TRUE, NULL);
-       g_signal_connect(G_OBJECT(table_renderer), "edited", G_CALLBACK(pgui_action_handle_tree_edit), 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,
                       "text",
                       TABLE_COLUMN,
-                      "background",
-                      "white",
                       NULL);
-       g_object_set(schema_column, "resizable", TRUE, 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);
 
+       /* Geo column field */
        geom_column_renderer = gtk_cell_renderer_text_new();
        g_object_set(geom_column_renderer, "editable", TRUE, NULL);
-       g_signal_connect(G_OBJECT(geom_column_renderer), "edited", G_CALLBACK(pgui_action_handle_tree_edit), 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(_("Geometry Column"),
                      geom_column_renderer,
                      "text",
                      GEOMETRY_COLUMN,
-                     "background",
-                     "white",
                      NULL);
-       g_object_set(geom_column, "resizable", TRUE, 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);
 
        /* SRID Field */
        srid_renderer = gtk_cell_renderer_text_new();
        g_object_set(srid_renderer, "editable", TRUE, NULL);
-       g_signal_connect(G_OBJECT(srid_renderer), "edited", G_CALLBACK(pgui_action_handle_tree_edit), 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,
                      "text",
                      SRID_COLUMN,
-                     "background",
-                     "white",
                      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);
 
-       /* Mode Combo */
-       combo_list = gtk_list_store_new(COMBO_COLUMNS,
-                                       G_TYPE_STRING);
-       GtkTreeIter iter;
+       /* Mode Combo Field */
+       combo_list = gtk_list_store_new(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"), -1);
+                          COMBO_TEXT, _("Create"), 
+                          COMBO_OPTION_CHAR, 'c',                         
+                          -1);
        gtk_list_store_insert(combo_list, &iter, APPEND_MODE);
        gtk_list_store_set(combo_list, &iter,
-                          COMBO_TEXT, _("Append"), -1);
+                          COMBO_TEXT, _("Append"), 
+                          COMBO_OPTION_CHAR, 'a', 
+                          -1);
        gtk_list_store_insert(combo_list, &iter, DELETE_MODE);
        gtk_list_store_set(combo_list, &iter,
-                          COMBO_TEXT, _("Delete"), -1);
+                          COMBO_TEXT, _("Delete"), 
+                          COMBO_OPTION_CHAR, 'd', 
+                          -1);
        gtk_list_store_insert(combo_list, &iter, PREPARE_MODE);
        gtk_list_store_set(combo_list, &iter,
-                          COMBO_TEXT, _("Prepare"), -1);
+                          COMBO_TEXT, _("Prepare"), 
+                          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, "width-chars", 8, NULL);
        g_object_set(mode_renderer,
                     "model", combo_list,
                     "editable", TRUE,
@@ -2426,34 +2001,23 @@ pgui_create_file_table(GtkWidget *frame_shape)
 
        g_signal_connect (G_OBJECT(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, "editable", TRUE, NULL);
+       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);
 
-
        g_signal_connect (G_OBJECT (add_file_button), "clicked", G_CALLBACK (pgui_action_open_file_dialog), NULL);
 
-
-       //GtkTreeIter iter;
-       gtk_list_store_append(list_store, &iter);
-       gtk_list_store_set(list_store, &iter,
-                          FILENAME_COLUMN, "",
-                          SCHEMA_COLUMN, "",
-                          TABLE_COLUMN, "",
-                          GEOMETRY_COLUMN, "",
-                          SRID_COLUMN, "",
-                          -1);
-
        /* Drag n Drop wiring */
        GtkTargetEntry drop_types[] =
        {
                { "text/uri-list", 0, 0}
        };
+       
        gint n_drop_types = sizeof(drop_types)/sizeof(drop_types[0]);
        gtk_drag_dest_set(GTK_WIDGET(tree),
                          GTK_DEST_DEFAULT_ALL,
@@ -2461,10 +2025,216 @@ pgui_create_file_table(GtkWidget *frame_shape)
                          GDK_ACTION_COPY);
        g_signal_connect(G_OBJECT(tree), "drag_data_received",
                         G_CALLBACK(pgui_action_handle_file_drop), NULL);
+}
 
+static void
+pgui_create_connection_window()
+{
+       /* Default text width */
+       static int text_width = 12;
+       
+       /* Vbox container */
+       GtkWidget *vbox;
+       
+       /* Reusable label handle */
+       GtkWidget *label;
 
-}
+       /* PgSQL section */
+       GtkWidget *frame_pg, *table_pg;
+       
+       /* OK button */
+       GtkWidget *button_okay;
+
+       /* Create the main top level window with a 10px border */
+       window_conn = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+       gtk_container_set_border_width(GTK_CONTAINER(window_conn), 10);
+       gtk_window_set_title(GTK_WINDOW(window_conn), _("PostGIS connection"));
+       gtk_window_set_position(GTK_WINDOW(window_conn), GTK_WIN_POS_CENTER);
+       gtk_window_set_modal(GTK_WINDOW(window_conn), TRUE);
+       
+       /* Use a vbox as the base container */
+       vbox = gtk_vbox_new(FALSE, 15);
+       
+       /*
+       ** PostGIS info in a table
+       */
+       frame_pg = gtk_frame_new(_("PostGIS Connection"));
+       table_pg = gtk_table_new(5, 3, TRUE);
+       gtk_container_set_border_width (GTK_CONTAINER (table_pg), 8);
+       gtk_table_set_col_spacings(GTK_TABLE(table_pg), 7);
+       gtk_table_set_row_spacings(GTK_TABLE(table_pg), 3);
+
+       /* User name row */
+       label = gtk_label_new(_("Username:"));
+       entry_pg_user = gtk_entry_new();
+       gtk_table_attach_defaults(GTK_TABLE(table_pg), label, 0, 1, 0, 1 );
+       gtk_table_attach_defaults(GTK_TABLE(table_pg), entry_pg_user, 1, 3, 0, 1 );
 
+       /* Password row */
+       label = gtk_label_new(_("Password:"));
+       entry_pg_pass = gtk_entry_new();
+       gtk_entry_set_visibility( GTK_ENTRY(entry_pg_pass), FALSE);
+       gtk_table_attach_defaults(GTK_TABLE(table_pg), label, 0, 1, 1, 2 );
+       gtk_table_attach_defaults(GTK_TABLE(table_pg), entry_pg_pass, 1, 3, 1, 2 );
+
+       /* Host and port row */
+       label = gtk_label_new(_("Server Host:"));
+       entry_pg_host = gtk_entry_new();
+       gtk_entry_set_width_chars(GTK_ENTRY(entry_pg_host), text_width);
+       gtk_table_attach_defaults(GTK_TABLE(table_pg), label, 0, 1, 2, 3 );
+       gtk_table_attach_defaults(GTK_TABLE(table_pg), entry_pg_host, 1, 2, 2, 3 );
+
+       entry_pg_port = gtk_entry_new();
+       gtk_entry_set_width_chars(GTK_ENTRY(entry_pg_port), 8);
+       gtk_table_attach_defaults(GTK_TABLE(table_pg), entry_pg_port, 2, 3, 2, 3 );
+
+       /* Database row */
+       label = gtk_label_new(_("Database:"));
+       entry_pg_db   = gtk_entry_new();
+       gtk_table_attach_defaults(GTK_TABLE(table_pg), label, 0, 1, 3, 4 );
+       gtk_table_attach_defaults(GTK_TABLE(table_pg), entry_pg_db, 1, 3, 3, 4 );
+                        
+       /* Add table into containing frame */
+       gtk_container_add(GTK_CONTAINER(frame_pg), table_pg);
+
+       /* Add frame into containing vbox */
+       gtk_container_add(GTK_CONTAINER(window_conn), vbox);
+       
+       /* Add the vbox into the window */
+       gtk_container_add(GTK_CONTAINER(vbox), frame_pg);
+       
+       /* Create a simple "OK" button for the dialog */
+       button_okay = gtk_button_new_with_label(_("OK"));
+       gtk_container_add(GTK_CONTAINER(vbox), button_okay);
+       g_signal_connect(G_OBJECT(button_okay), "clicked", G_CALLBACK(pgui_action_connection_okay), NULL);
+       
+       /* Hook the delete event so we don't destroy the dialog (only hide it) if cancelled */
+       gtk_signal_connect(GTK_OBJECT(window_conn), "delete_event", GTK_SIGNAL_FUNC(pgui_event_popup_delete), NULL);
+       
+       return;
+}      
+
+static void
+pgui_create_main_window(const SHPCONNECTIONCONFIG *conn)
+{
+       /* Main widgets */
+       GtkWidget *vbox_main, *vbox_loader;
+       
+       /* PgSQL section */
+       GtkWidget *frame_pg, *frame_shape, *frame_log;
+       GtkWidget *button_pg_conn;
+       
+       /* Notebook */
+       GtkWidget *notebook;
+       
+       /* Button section */
+       GtkWidget *hbox_buttons, *button_options, *button_import, *button_cancel, *button_about;
+       
+       /* Log section */
+       GtkWidget *scrolledwindow_log;
+
+       /* Create the main top level window with a 10px border */
+       window_main = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+       gtk_container_set_border_width(GTK_CONTAINER(window_main), 10);
+       gtk_window_set_title(GTK_WINDOW(window_main), _("Shape File to PostGIS Importer"));
+       gtk_window_set_position(GTK_WINDOW(window_main), GTK_WIN_POS_CENTER_ALWAYS);
+       gtk_window_set_resizable(GTK_WINDOW(window_main), FALSE);
+       
+       /* Open it a bit wider so that both the label and title show up */
+       gtk_window_set_default_size(GTK_WINDOW(window_main), 180, 500);
+       
+       /* Connect the destroy event of the window with our pgui_quit function
+       *  When the window is about to be destroyed we get a notificaiton and
+       *  stop the main GTK loop
+       */
+       g_signal_connect(G_OBJECT(window_main), "destroy", G_CALLBACK(pgui_quit), NULL);
+
+       /* Connection row */
+       frame_pg = gtk_frame_new(_("PostGIS Connection"));
+       
+       /* Test button row */
+       button_pg_conn = gtk_button_new_with_label(_("View connection details..."));
+       g_signal_connect(G_OBJECT(button_pg_conn), "clicked", G_CALLBACK(pgui_action_connection_details), NULL);
+       gtk_container_set_border_width(GTK_CONTAINER(button_pg_conn), 10);
+       gtk_container_add(GTK_CONTAINER(frame_pg), button_pg_conn);
+       
+       /*
+        * GTK Notebook for selecting import/export
+        */
+       notebook = gtk_notebook_new();
+       
+       /*
+       ** Shape file selector
+       */
+       frame_shape = gtk_frame_new(_("Import List"));
+       pgui_create_file_table(frame_shape);
+
+       /*
+       ** Row of action buttons
+       */
+       hbox_buttons = gtk_hbox_new(TRUE, 15);
+       gtk_container_set_border_width (GTK_CONTAINER (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"));
+       /* 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);
+       /* 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);
+
+       /*
+       ** Log window
+       */
+       frame_log = gtk_frame_new(_("Log Window"));
+       gtk_container_set_border_width (GTK_CONTAINER (frame_log), 0);
+       gtk_widget_set_size_request(frame_log, -1, 200);
+       textview_log = gtk_text_view_new();
+       textbuffer_log = gtk_text_buffer_new(NULL);
+       scrolledwindow_log = gtk_scrolled_window_new(NULL, NULL);
+       gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW(scrolledwindow_log), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
+       gtk_text_view_set_buffer(GTK_TEXT_VIEW(textview_log), textbuffer_log);
+       gtk_container_set_border_width (GTK_CONTAINER (textview_log), 5);
+       gtk_text_view_set_editable(GTK_TEXT_VIEW(textview_log), FALSE);
+       gtk_text_view_set_cursor_visible(GTK_TEXT_VIEW(textview_log), FALSE);
+       gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(textview_log), GTK_WRAP_WORD);
+       gtk_container_add (GTK_CONTAINER (scrolledwindow_log), textview_log);
+       gtk_container_add (GTK_CONTAINER (frame_log), scrolledwindow_log);
+
+       /*
+       ** Main window
+       */
+       vbox_main = gtk_vbox_new(FALSE, 10);
+       gtk_container_set_border_width (GTK_CONTAINER (vbox_main), 0);
+
+       /* Add the loader frames into the notebook page */
+       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_notebook_append_page(GTK_NOTEBOOK(notebook), vbox_loader, gtk_label_new(_("Import")));
+       
+       /* 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);
+       gtk_box_pack_start(GTK_BOX(vbox_main), frame_log, TRUE, TRUE, 0);
+       
+       /* and insert the vbox into the main window  */
+       gtk_container_add(GTK_CONTAINER(window_main), vbox_main);
+       
+       /* make sure that everything, window and label, are visible */
+       gtk_widget_show_all(window_main);
+
+       return;
+}
 
 static void
 usage()
@@ -2492,54 +2262,64 @@ main(int argc, char *argv[])
 #endif
 
        /* Parse command line options and set configuration */
-       config = malloc(sizeof(SHPLOADERCONFIG));
-       set_loader_config_defaults(config);
+       global_loader_config = malloc(sizeof(SHPLOADERCONFIG));
+       set_loader_config_defaults(global_loader_config);
 
        /* Here we override any defaults for the GUI */
-       config->createindex = 1;
-
+       global_loader_config->createindex = 1;
+       global_loader_config->geo_col = strdup(GEOMETRY_DEFAULT);
+       
        conn = malloc(sizeof(SHPCONNECTIONCONFIG));
        memset(conn, 0, sizeof(SHPCONNECTIONCONFIG));
+       
+       /* Here we override any defaults for the connection */
+       conn->host = strdup("localhost");
+       conn->port = strdup("5432");
 
        while ((c = pgis_getopt(argc, argv, "U:p:W:d:h:")) != -1)
        {
                switch (c)
                {
                case 'U':
-                       conn->username = pgis_optarg;
+                       conn->username = strdup(pgis_optarg);
                        break;
                case 'p':
-                       conn->port = pgis_optarg;
+                       conn->port = strdup(pgis_optarg);
                        break;
                case 'W':
-                       conn->password = pgis_optarg;
+                       conn->password = strdup(pgis_optarg);
                        break;
                case 'd':
-                       conn->database = pgis_optarg;
+                       conn->database = strdup(pgis_optarg);
                        break;
                case 'h':
-                       conn->host = pgis_optarg;
+                       conn->host = strdup(pgis_optarg);
                        break;
                default:
                        usage();
                        free(conn);
-                       free(config);
+                       free(global_loader_config);
                        exit(0);
                }
        }
 
        /* initialize the GTK stack */
        gtk_init(&argc, &argv);
-
+       
        /* set up the user interface */
        pgui_create_main_window(conn);
-
+       pgui_create_connection_window();
+       pgui_create_options_dialog();
+       pgui_create_about_dialog();
+       pgui_create_filechooser_dialog();
+       pgui_create_progress_dialog();
+               
        /* start the main loop */
        gtk_main();
 
        /* Free the configuration */
        free(conn);
-       free(config);
+       free(global_loader_config);
 
        return 0;
 }
index a937109693881a66bdaa28dcba65e34e9d56e48f..f5b34f9defe8c348f779c4a93fe942af504af791 100644 (file)
@@ -10,6 +10,9 @@
  *
  **********************************************************************/
 
+#ifndef SHPCOMMON_H
+#define SHPCOMMON_H
+
 typedef struct shp_connection_state
 {
        /* PgSQL username to log in with */
@@ -31,3 +34,5 @@ typedef struct shp_connection_state
 
 /* External shared functions */
 char *escape_connection_string(char *str);
+
+#endif
diff --git a/loader/structure.c b/loader/structure.c
deleted file mode 100644 (file)
index bfc5148..0000000
+++ /dev/null
@@ -1,252 +0,0 @@
-/**********************************************************************\r
- * $Id$\r
- *\r
- * PostGIS - Spatial Types for PostgreSQL\r
- * http://postgis.refractions.net\r
- * Copyright 2010 LISAsoft Pty Ltd <mark.leslie@lisasoft.com>\r
- *\r
- * This is free softwark; you can redistribute and/or modify it under \r
- * the terms of the GNU General Public Licence.  See the COPYING file.\r
- *\r
- * This file contains functions used to manage the basic elements \r
- * stored withing the shp2pgsql-gui.c list item.  These were separated\r
- * out for ease of testing.\r
- *\r
- *********************************************************************/\r
-\r
-#include <stdarg.h>\r
-#include <stdlib.h>\r
-#include <string.h>\r
-#include "structure.h"\r
-\r
-FILENODE *file_list_head = NULL;\r
-FILENODE *file_list_tail = NULL;\r
-\r
-void\r
-init_file_list(void)\r
-{\r
-       file_list_head = malloc(sizeof(FILENODE));\r
-       file_list_tail = malloc(sizeof(FILENODE));\r
-\r
-       file_list_head->filename = NULL;\r
-       file_list_head->schema = NULL;\r
-       file_list_head->table = NULL;\r
-       file_list_head->geom_column = NULL;\r
-       file_list_head->srid = NULL;\r
-       file_list_head->mode = '\0';\r
-       file_list_head->prev = NULL;\r
-       file_list_head->next = file_list_tail;\r
-\r
-       file_list_tail->filename = NULL;\r
-       file_list_tail->schema = NULL;\r
-       file_list_tail->table = NULL;\r
-       file_list_tail->geom_column = NULL;\r
-       file_list_tail->srid = NULL;\r
-       file_list_tail->mode = '\0';\r
-       file_list_tail->prev = file_list_head;\r
-       file_list_tail->next = NULL;\r
-}\r
-\r
-void\r
-destroy_file_list(void)\r
-{\r
-       FILENODE *node = get_next_node(NULL);\r
-       while (node != NULL)\r
-       {\r
-               remove_file(node);\r
-               node = get_next_node(NULL);\r
-       }\r
-\r
-       if (file_list_head != NULL)\r
-       {\r
-               file_list_head->next = NULL;\r
-               file_list_head->prev = NULL;\r
-               free(file_list_head);\r
-       }\r
-\r
-       if (file_list_tail != NULL)\r
-       {\r
-               file_list_tail->next = NULL;\r
-               file_list_tail->prev = NULL;\r
-               free(file_list_tail);\r
-       }\r
-}\r
-\r
-\r
-FILENODE*\r
-append_file_node(void)\r
-{\r
-       if (file_list_head == NULL || file_list_tail == NULL)\r
-       {\r
-               init_file_list();\r
-       }\r
-       FILENODE *new_node = malloc(sizeof(FILENODE));\r
-\r
-       new_node->filename = NULL;\r
-       new_node->schema = NULL;\r
-       new_node->table = NULL;\r
-       new_node->geom_column = NULL;\r
-       new_node->srid = NULL;\r
-       new_node->mode = '\0';\r
-       new_node->tree_iterator = NULL;\r
-       new_node->next = file_list_tail;\r
-       new_node->prev = file_list_tail->prev;\r
-       file_list_tail->prev->next = new_node;\r
-       file_list_tail->prev = new_node;\r
-\r
-       return new_node;\r
-}\r
-\r
-FILENODE*\r
-append_file(char *filename, char *schema, char *table,\r
-            char *geom_column, char *srid, char mode,\r
-            GtkTreeIter *tree_iterator)\r
-{\r
-       FILENODE *new_file = append_file_node();\r
-\r
-       /*\r
-        * I have no reason to believe that freeing char*'s in the struct will\r
-        * not harm the ui and vice versa, so I'm avoiding the problem by dup'ing.\r
-        */\r
-       new_file->filename = strdup(filename);\r
-       new_file->schema = strdup(schema);\r
-       new_file->table = strdup(table);\r
-       new_file->geom_column = strdup(geom_column);\r
-       new_file->srid = strdup(srid);\r
-       new_file->mode = mode;\r
-       new_file->tree_iterator = tree_iterator;\r
-\r
-       return new_file;\r
-}\r
-\r
-FILENODE*\r
-find_file_by_iter(GtkTreeIter *tree_iterator)\r
-{\r
-\r
-       FILENODE *current_node;\r
-\r
-       if (file_list_head == NULL)\r
-       {\r
-               return NULL;\r
-       }\r
-       current_node = file_list_head->next;\r
-       while (current_node != NULL && current_node != file_list_tail)\r
-       {\r
-               if (current_node->tree_iterator == tree_iterator)\r
-               {\r
-                       return current_node;\r
-               }\r
-               current_node = current_node->next;\r
-       }\r
-       return NULL;\r
-}\r
-\r
-FILENODE*\r
-find_file_by_index(int index)\r
-{\r
-       FILENODE *current_node;\r
-       int i = 0;\r
-\r
-       if (file_list_head == NULL)\r
-       {\r
-               return NULL;\r
-       }\r
-       current_node = file_list_head->next;\r
-       while (current_node != NULL && current_node != file_list_tail)\r
-       {\r
-               if (i == index)\r
-               {\r
-                       return current_node;\r
-               }\r
-\r
-               current_node = current_node->next;\r
-               i++;\r
-       }\r
-       return NULL;\r
-}\r
-\r
-void\r
-remove_file(FILENODE *remove_node)\r
-{\r
-       if (remove_node == NULL\r
-               || remove_node->next == NULL\r
-               || remove_node->prev == NULL)\r
-       {\r
-               return;\r
-       }\r
-       remove_node->next->prev = remove_node->prev;\r
-       remove_node->prev->next = remove_node->next;\r
-       remove_node->next = NULL;\r
-       remove_node->prev = NULL;\r
-       if (remove_node->filename == NULL)\r
-       {\r
-               free(remove_node->filename);\r
-               remove_node->filename = NULL;\r
-       }\r
-       if (remove_node->schema == NULL)\r
-       {\r
-               free(remove_node->schema);\r
-               remove_node->schema = NULL;\r
-       }\r
-       if (remove_node->table == NULL)\r
-       {\r
-               free(remove_node->table);\r
-               remove_node->table = NULL;\r
-       }\r
-       if (remove_node->geom_column == NULL)\r
-       {\r
-               free(remove_node->geom_column);\r
-               remove_node->geom_column = NULL;\r
-       }\r
-       if (remove_node->srid == NULL)\r
-       {\r
-               free(remove_node->srid);\r
-               remove_node->srid = NULL;\r
-       }\r
-       free(remove_node);\r
-}\r
-\r
-FILENODE*\r
-get_next_node(FILENODE *current)\r
-{\r
-       if (file_list_head == NULL)\r
-               return NULL;\r
-       if (current == NULL)\r
-               current = file_list_head;\r
-       return (current->next != file_list_tail) ? current->next : NULL;\r
-\r
-}\r
-\r
-void\r
-print_file_list_delegate(void (*printer)(const char *fmta, va_list apa), const char *fmt, ...)\r
-{\r
-       va_list ap;\r
-\r
-       va_start(ap, fmt);\r
-\r
-       (*printer)(fmt, ap);\r
-\r
-       va_end(ap);\r
-       return;\r
-\r
-}\r
-\r
-void\r
-print_file_list(void (*printer)(const char *fmt, va_list ap))\r
-{\r
-       FILENODE *current_node;\r
-       int i = 0;\r
-\r
-       print_file_list_delegate(printer, "File List:\n");\r
-       print_file_list_delegate(printer, "Head %p <-- %p --> %p\n", file_list_head->prev, file_list_head, file_list_head->next);\r
-\r
-       current_node = get_next_node(NULL);\r
-       while (current_node != NULL)\r
-       {\r
-               print_file_list_delegate(printer, "  Node %d: %s\n", i++, current_node->filename);\r
-               print_file_list_delegate(printer, "    %p <-- %p --> %p\n", current_node->prev, current_node, current_node->next);\r
-               current_node = get_next_node(current_node);\r
-       }\r
-\r
-       print_file_list_delegate(printer, "Tail %p <-- %p --> %p\n", file_list_tail->prev, file_list_tail, file_list_tail->next);\r
-}\r
diff --git a/loader/structure.h b/loader/structure.h
deleted file mode 100644 (file)
index 867a7eb..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-/**********************************************************************\r
- * $Id$\r
- *\r
- * PostGIS - Spatial Types for PostgreSQL\r
- * http://postgis.refractions.net\r
- * Copyright 2010 LISAsoft Pty Ltd <mark.leslie@lisasoft.com>\r
- *\r
- * This is free softwark; you can redistribute and/or modify it under \r
- * the terms of the GNU General Public Licence.  See the COPYING file.\r
- *\r
- * This file contains struct and method definitions used to manage the\r
- * basic elements stored withing the shp2pgsql-gui.c list item.  These\r
- * were separated out for ease of testing.\r
- *\r
- *********************************************************************/\r
-\r
-\r
-#ifndef __PGIS_STRUCTURE_H__\r
-#define __PGIS_STRUCTURE_H__\r
-\r
-#include <gtk/gtktreemodel.h>\r
-\r
-typedef struct file_node\r
-{\r
-       char *filename;\r
-       char *schema;\r
-       char *table;\r
-       char *geom_column;\r
-       char *srid;\r
-       char mode;\r
-       GtkTreeIter *tree_iterator;\r
-       struct file_node *next;\r
-       struct file_node *prev;\r
-} FILENODE;\r
-\r
-void init_file_list(void);\r
-void destroy_file_list(void);\r
-FILENODE *append_file_node(void);\r
-FILENODE *append_file(char *filename, char *schema, char *table, \r
-                   char *geom_column, char *srid, char mode, \r
-                       GtkTreeIter *tree_iterator);\r
-FILENODE *find_file_by_iter(GtkTreeIter *tree_iterator);\r
-FILENODE *find_file_by_index(int index);\r
-void remove_file(FILENODE *remove_node);\r
-void print_file_list_delegate(void (*printer)(const char *fmta, va_list apa), const char *fmt, ...);\r
-\r
-/*\r
- * This is a debugging function, it shouldn't really be used for \r
- * general status output.  It takes a function pointer of the same\r
- * signature as vprintf (hint).\r
- */\r
-void print_file_list(void (*printer)(const char *fmt, va_list ap));\r
-\r
-/*\r
- * This will return the next node after the current node.\r
- * If the current is null, it will return the first node.  Returns NULL\r
- * if the list is uninitialised, empty or if the current node is the last node.\r
- */\r
-FILENODE *get_next_node(FILENODE *current);\r
-\r
-#endif /* __PGIS_STRUCTURE_H__ */\r