source: branches/1.5/loader/shp2pgsql-gui.c @ 5977

Last change on this file since 5977 was 5977, checked in by pramsey, 6 years ago

Add DBF *.dbf filter to file chooser.. (#513)

  • Property svn:keywords set to Author Date Id Revision
File size: 38.8 KB
Line 
1/**********************************************************************
2 * $Id: shp2pgsql-gui.c 5977 2010-09-18 18:51:59Z pramsey $
3 *
4 * PostGIS - Spatial Types for PostgreSQL
5 * http://postgis.refractions.net
6 * Copyright 2008 OpenGeo.org
7 *
8 * This is free software; you can redistribute and/or modify it under
9 * the terms of the GNU General Public Licence. See the COPYING file.
10 *
11 * Maintainer: Paul Ramsey <pramsey@opengeo.org>
12 *
13 **********************************************************************/
14
15#include <stdarg.h>
16#include <stdio.h>
17#include <stdlib.h>
18#include <string.h>
19#include <gtk/gtk.h>
20#ifdef MAC_INTEGRATION
21#include <ige-mac-integration.h>
22#endif
23#include "libpq-fe.h"
24#include "shp2pgsql-core.h"
25
26#define GUI_RCSID "shp2pgsql-gui $Revision: 5977 $"
27
28/*
29** Global variables for GUI only
30*/
31
32/* Main window */
33static GtkWidget *window_main = NULL;
34static GtkWidget *entry_pg_user = NULL;
35static GtkWidget *entry_pg_pass = NULL;
36static GtkWidget *entry_pg_host = NULL;
37static GtkWidget *entry_pg_port = NULL;
38static GtkWidget *entry_pg_db = NULL;
39static GtkWidget *entry_config_table = NULL;
40static GtkWidget *entry_config_schema = NULL;
41static GtkWidget *entry_config_srid = NULL;
42static GtkWidget *entry_config_geocolumn = NULL;
43static GtkWidget *label_pg_connection_test = NULL;
44static GtkWidget *textview_log = NULL;
45static GtkWidget *file_chooser_button_shape = NULL;
46static GtkWidget *progress = NULL;
47static GtkTextBuffer *textbuffer_log = NULL;
48
49/* Options window */
50static GtkWidget *entry_options_encoding = NULL;
51static GtkWidget *checkbutton_options_preservecase = NULL;
52static GtkWidget *checkbutton_options_forceint = NULL;
53static GtkWidget *checkbutton_options_autoindex = NULL;
54static GtkWidget *checkbutton_options_dbfonly = NULL;
55static GtkWidget *checkbutton_options_dumpformat = NULL;
56static GtkWidget *checkbutton_options_geography = NULL;
57
58/* Other */
59static char *pgui_errmsg = NULL;
60static PGconn *pg_connection = NULL;
61static SHPLOADERCONFIG *config = NULL;
62static SHPLOADERSTATE *state = NULL;
63static SHPCONNECTIONCONFIG *conn = NULL;
64
65static volatile int import_running = 0;
66
67/* Local prototypes */
68static void pgui_create_options_dialogue(void);
69
70
71/*
72** Write a message to the Import Log text area.
73*/
74static void
75pgui_log_va(const char *fmt, va_list ap)
76{
77        GtkTextIter iter;
78        char *msg;
79
80        if (!lw_vasprintf (&msg, fmt, ap)) return;
81
82        /* Append text to the end of the text area, scrolling if required to make it visible */
83        gtk_text_buffer_get_end_iter(textbuffer_log, &iter);
84        gtk_text_buffer_insert(textbuffer_log, &iter, msg, -1);
85        gtk_text_buffer_insert(textbuffer_log, &iter, "\n", -1);
86
87        gtk_text_view_scroll_to_iter(GTK_TEXT_VIEW(textview_log), &iter, 0.0, TRUE, 0.0, 1.0);
88       
89        /* Allow GTK to process events */
90        while (gtk_events_pending())
91                gtk_main_iteration();
92
93        free(msg);
94        return;
95}
96
97/*
98** Write a message to the Import Log text area.
99*/
100static void
101pgui_logf(const char *fmt, ...)
102{
103        va_list ap;
104        va_start(ap, fmt);
105
106        pgui_log_va(fmt, ap);
107
108        va_end(ap);
109        return;
110}
111
112static void
113pgui_seterr(const char *errmsg)
114{
115        if ( pgui_errmsg )
116        {
117                free(pgui_errmsg);
118        }
119        pgui_errmsg = strdup(errmsg);
120        return;
121}
122
123static void
124pgui_raise_error_dialogue(void)
125{
126        GtkWidget *dialog, *label;
127        gint result;
128
129        label = gtk_label_new(pgui_errmsg);
130        dialog = gtk_dialog_new_with_buttons("Error", GTK_WINDOW(window_main),
131                                                                                 GTK_DIALOG_MODAL & GTK_DIALOG_NO_SEPARATOR & GTK_DIALOG_DESTROY_WITH_PARENT,
132                                                                                 GTK_STOCK_OK, GTK_RESPONSE_OK, NULL);
133        gtk_dialog_set_has_separator ( GTK_DIALOG(dialog), FALSE );
134        gtk_container_set_border_width (GTK_CONTAINER(dialog), 5);
135        gtk_container_set_border_width (GTK_CONTAINER (GTK_DIALOG(dialog)->vbox), 15);
136        gtk_container_add (GTK_CONTAINER (GTK_DIALOG(dialog)->vbox), label);
137        gtk_widget_show_all (dialog);
138        result = gtk_dialog_run(GTK_DIALOG(dialog));
139        gtk_widget_destroy(dialog);
140        return;
141}
142
143/* Terminate the main loop and exit the application. */
144static void
145pgui_quit (GtkWidget *widget, gpointer data)
146{
147        if ( pg_connection) PQfinish(pg_connection);
148        pg_connection = NULL;
149        gtk_main_quit ();
150}
151
152/* Set the global config variables controlled by the options dialogue */
153static void
154pgui_set_config_from_options_ui()
155{
156        const char *entry_encoding = gtk_entry_get_text(GTK_ENTRY(entry_options_encoding));
157        gboolean preservecase = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(checkbutton_options_preservecase));
158        gboolean forceint = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(checkbutton_options_forceint));
159        gboolean createindex = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(checkbutton_options_autoindex));
160        gboolean dbfonly = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(checkbutton_options_dbfonly));
161        gboolean dumpformat = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(checkbutton_options_dumpformat));
162        gboolean geography = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(checkbutton_options_geography));
163
164        if ( geography )
165        {
166                config->geography = 1;
167                /* Flip the geometry column name to match the load type */
168                if ( ! strcmp(gtk_entry_get_text(GTK_ENTRY(entry_config_geocolumn)), GEOMETRY_DEFAULT) )
169                {
170                        gtk_entry_set_text(GTK_ENTRY(entry_config_geocolumn), GEOGRAPHY_DEFAULT );
171                        free(config->geom);
172                        config->geom = strdup(GEOGRAPHY_DEFAULT);
173                }
174        }
175
176        /* Encoding */
177        if ( entry_encoding && strlen(entry_encoding) > 0 )
178        {
179                if (config->encoding)
180                        free(config->encoding);
181
182                config->encoding = strdup(entry_encoding);
183        }
184
185        /* Preserve case */
186        if ( preservecase )
187                config->quoteidentifiers = 1;
188        else
189                config->quoteidentifiers = 0;
190
191        /* No long integers in table */
192        if ( forceint )
193                config->forceint4 = 1;
194        else
195                config->forceint4 = 0;
196
197        /* Create spatial index after load */
198        if ( createindex )
199                config->createindex = 1;
200        else
201                config->createindex = 0;
202
203        /* Don't read the .shp file, just the .dbf */
204        if ( dbfonly )
205        {
206                config->readshape = 0;
207                /* There will be no spatial column so don't create a spatial index */
208                config->createindex = 0; 
209        }
210        else
211                config->readshape = 1;
212
213        /* Use COPY rather than INSERT format */
214        if ( dumpformat )
215                config->dump_format = 1;
216        else
217                config->dump_format = 0;
218
219        return;
220}
221
222/* Set the global configuration based upon the current UI */
223static void
224pgui_set_config_from_ui()
225{
226        const char *pg_table = gtk_entry_get_text(GTK_ENTRY(entry_config_table));
227        const char *pg_schema = gtk_entry_get_text(GTK_ENTRY(entry_config_schema));
228        const char *pg_geom = gtk_entry_get_text(GTK_ENTRY(entry_config_geocolumn));
229        const char *source_file = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(file_chooser_button_shape));
230        const char *entry_srid = gtk_entry_get_text(GTK_ENTRY(entry_config_srid));
231
232        char *c;
233
234        /* Set the destination schema, table and column parameters */
235        if (config->table)
236                free(config->table);
237
238        config->table = strdup(pg_table);
239
240        if (config->schema)
241                free(config->schema);
242
243        if (strlen(pg_schema) == 0)
244                config->schema = strdup("public");
245        else
246                config->schema = strdup(pg_schema);
247
248        if (strlen(pg_geom) == 0)
249                config->geom = strdup(GEOMETRY_DEFAULT);
250        else
251                config->geom = strdup(pg_geom);
252
253        /* Set the destination filename: note the shp2pgsql core engine simply wants the file
254           without the .shp extension */
255        if (config->shp_file)
256                free(config->shp_file);
257
258        /* Handle empty selection */
259        if (source_file == NULL)
260                config->shp_file = strdup("");
261        else
262                config->shp_file = strdup(source_file);
263
264        /*  NULL-terminate the file name before the .shp extension */
265        for (c = config->shp_file + strlen(config->shp_file); c >= config->shp_file; c--)
266        {
267                if (*c == '.')
268                {
269                        *c = '\0';
270                        break;
271                }
272        }
273
274        /* SRID */
275        if ( ! ( config->sr_id = atoi(entry_srid) ) )
276        {
277                config->sr_id = -1;
278        }
279
280
281        return;
282}
283
284/* Validate the configuration, returning true or false */
285static int
286pgui_validate_config()
287{
288        /* Validate table parameters */
289        if ( ! config->table || strlen(config->table) == 0 )
290        {
291                pgui_seterr("Fill in the destination table.");
292                return 0;
293        }
294
295        if ( ! config->schema || strlen(config->schema) == 0 )
296        {
297                pgui_seterr("Fill in the destination schema.");
298                return 0;
299        }
300
301        if ( ! config->geom || strlen(config->geom) == 0 )
302        {
303                pgui_seterr("Fill in the destination column.");
304                return 0;
305        }
306
307        if ( ! config->shp_file || strlen(config->shp_file) == 0 )
308        {
309                pgui_seterr("Select a shape file to import.");
310                return 0;
311        }
312
313        return 1;
314}
315
316/*
317** Run a SQL command against the current connection.
318*/
319static int
320pgui_exec(const char *sql)
321{
322        PGresult *res = NULL;
323        ExecStatusType status;
324        char sql_trunc[256];
325
326        /* We need a connection to do anything. */
327        if ( ! pg_connection ) return 0;
328        if ( ! sql ) return 0;
329
330        res = PQexec(pg_connection, sql);
331        status = PQresultStatus(res);
332        PQclear(res);
333
334        /* Did something unexpected happen? */
335        if ( ! ( status == PGRES_COMMAND_OK || status == PGRES_TUPLES_OK ) )
336        {
337                /* Log notices and return success. */
338                if ( status == PGRES_NONFATAL_ERROR )
339                {
340                        pgui_logf("%s", PQerrorMessage(pg_connection));
341                        return 1;
342                }
343
344                /* Log errors and return failure. */
345                snprintf(sql_trunc, 255, "%s", sql);
346                pgui_logf("Failed SQL begins: \"%s\"", sql_trunc);
347                pgui_logf("Failed in pgui_exec(): %s", PQerrorMessage(pg_connection));
348                return 0;
349        }
350
351        return 1;
352}
353
354/*
355** Start the COPY process.
356*/
357static int
358pgui_copy_start(const char *sql)
359{
360        PGresult *res = NULL;
361        ExecStatusType status;
362        char sql_trunc[256];
363
364        /* We need a connection to do anything. */
365        if ( ! pg_connection ) return 0;
366        if ( ! sql ) return 0;
367
368        res = PQexec(pg_connection, sql);
369        status = PQresultStatus(res);
370        PQclear(res);
371
372        /* Did something unexpected happen? */
373        if ( status != PGRES_COPY_IN )
374        {
375                /* Log errors and return failure. */
376                snprintf(sql_trunc, 255, "%s", sql);
377                pgui_logf("Failed SQL begins: \"%s\"", sql_trunc);
378                pgui_logf("Failed in pgui_copy_start(): %s", PQerrorMessage(pg_connection));
379                return 0;
380        }
381
382        return 1;
383}
384
385/*
386** Send a line (row) of data into the COPY procedure.
387*/
388static int
389pgui_copy_write(const char *line)
390{
391        char line_trunc[256];
392
393        /* We need a connection to do anything. */
394        if ( ! pg_connection ) return 0;
395        if ( ! line ) return 0;
396
397        /* Did something unexpected happen? */
398        if ( PQputCopyData(pg_connection, line, strlen(line)) < 0 )
399        {
400                /* Log errors and return failure. */
401                snprintf(line_trunc, 255, "%s", line);
402                pgui_logf("Failed row begins: \"%s\"", line_trunc);
403                pgui_logf("Failed in pgui_copy_write(): %s", PQerrorMessage(pg_connection));
404                return 0;
405        }
406
407        /* Send linefeed to signify end of line */
408        PQputCopyData(pg_connection, "\n", 1);
409
410        return 1;
411}
412
413/*
414** Finish the COPY process.
415*/
416static int
417pgui_copy_end(const int rollback)
418{
419        char *errmsg = NULL;
420
421        /* We need a connection to do anything. */
422        if ( ! pg_connection ) return 0;
423
424        if ( rollback ) errmsg = "Roll back the copy.";
425
426        /* Did something unexpected happen? */
427        if ( PQputCopyEnd(pg_connection, errmsg) < 0 )
428        {
429                /* Log errors and return failure. */
430                pgui_logf("Failed in pgui_copy_end(): %s", PQerrorMessage(pg_connection));
431                return 0;
432        }
433
434        return 1;
435}
436
437static char *
438pgui_read_connection(void)
439{
440        const char *pg_host = gtk_entry_get_text(GTK_ENTRY(entry_pg_host));
441        const char *pg_port = gtk_entry_get_text(GTK_ENTRY(entry_pg_port));
442        const char *pg_user = gtk_entry_get_text(GTK_ENTRY(entry_pg_user));
443        const char *pg_pass = gtk_entry_get_text(GTK_ENTRY(entry_pg_pass));
444        const char *pg_db = gtk_entry_get_text(GTK_ENTRY(entry_pg_db));
445        char *connection_string = NULL;
446
447        stringbuffer_t *sb = stringbuffer_create();
448
449        /* Read the host */
450        if ( pg_host && strlen(pg_host) > 0 )
451        {
452                vasbappend(sb, "host=%s ", pg_host);
453        }
454
455        /* Read the port */
456        if ( pg_port && strlen(pg_port) > 0 )
457        {       
458                if ( ! atoi(pg_port) )
459                {
460                        pgui_seterr("Server port must be a number.");
461                        stringbuffer_destroy(sb);
462                        return NULL;
463                }
464                vasbappend(sb, "port=%s ", pg_port);
465        }
466
467        /* Read the user name */
468        if ( pg_user && strlen(pg_user) > 0 )
469        {
470                vasbappend(sb, "user=%s ", pg_user);
471        }
472
473        /* Read the database name */
474        if ( pg_db && strlen(pg_db) > 0 )
475        {
476                vasbappend(sb, "dbname=%s ", pg_db);
477        }
478
479        /* Read the password */
480        if ( pg_pass && strlen(pg_pass) > 0 )
481        {
482                vasbappend(sb, "password=%s ", pg_pass);
483        }
484
485        /* Return the connection string */
486        connection_string = strdup(stringbuffer_getstring(sb));
487        stringbuffer_destroy(sb);       
488        return connection_string;
489}
490
491static void
492pgui_action_cancel(GtkWidget *widget, gpointer data)
493{
494        if (!import_running)
495                pgui_quit(widget, data); /* quit if we're not running */
496        else
497                import_running = FALSE;
498}
499
500static void
501pgui_sanitize_connection_string(char *connection_string)
502{
503        char *ptr = strstr(connection_string, "password");
504        if ( ptr )
505        {
506                ptr += 9;
507                while ( *ptr != ' ' && *ptr != '\0' )
508                {
509                        *ptr = '*';
510                        ptr++;
511                }
512        }
513        return;
514}
515
516static void
517pgui_action_connection_test(GtkWidget *widget, gpointer data)
518{
519        char *connection_string = NULL;
520        char *connection_sanitized = NULL;
521
522        if ( ! (connection_string = pgui_read_connection()) )
523        {
524                pgui_raise_error_dialogue();
525                return;
526        }
527
528        connection_sanitized = strdup(connection_string);
529        pgui_sanitize_connection_string(connection_sanitized);
530        pgui_logf("Connecting: %s", connection_sanitized);
531        free(connection_sanitized);
532
533        if ( pg_connection )
534                PQfinish(pg_connection);
535
536        pg_connection = PQconnectdb(connection_string);
537        if (PQstatus(pg_connection) == CONNECTION_BAD)
538        {
539                pgui_logf( "Connection failed: %s", PQerrorMessage(pg_connection));
540                gtk_label_set_text(GTK_LABEL(label_pg_connection_test), "Connection failed.");
541                free(connection_string);
542                PQfinish(pg_connection);
543                pg_connection = NULL;
544                return;
545        }
546        gtk_label_set_text(GTK_LABEL(label_pg_connection_test), "Connection succeeded.");
547        pgui_logf( "Connection succeeded." );
548        gtk_widget_show(label_pg_connection_test);
549        PQfinish(pg_connection);
550        pg_connection = NULL;
551        free(connection_string);
552
553        return;
554}
555
556static void
557pgui_action_options_open(GtkWidget *widget, gpointer data)
558{
559        pgui_create_options_dialogue();
560        return;
561}
562
563static void
564pgui_action_options_close(GtkWidget *widget, gpointer data)
565{
566        pgui_set_config_from_options_ui();
567        gtk_widget_destroy(widget);
568        return;
569}
570
571static void
572pgui_action_shape_file_set(GtkWidget *widget, gpointer data)
573{
574        char *shp_file;
575        int shp_file_len;
576        char *table_start;
577        char *table_end;
578        char *table;
579        const char *gtk_filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(widget));
580
581        if ( gtk_filename )
582        {
583                shp_file = strdup(gtk_filename);
584                shp_file_len = strlen(shp_file);
585        }
586        else
587        {
588                return;
589        }
590
591        /* Roll back from end to first slash character. */
592        table_start = shp_file + shp_file_len;
593        while ( *table_start != '/' && *table_start != '\\' && table_start > shp_file)
594        {
595                table_start--;
596        }
597        table_start++; /* Forward one to start of actual characters. */
598
599        /* Roll back from end to first . character. */
600        table_end = shp_file + shp_file_len;
601        while ( *table_end != '.' && table_end > shp_file && table_end > table_start )
602        {
603                table_end--;
604        }
605
606        /* Copy the table name into a fresh memory slot. */
607        table = malloc(table_end - table_start + 1);
608        memcpy(table, table_start, table_end - table_start);
609        table[table_end - table_start] = '\0';
610
611        /* Set the table name into the configuration */
612        config->table = table;
613
614        gtk_entry_set_text(GTK_ENTRY(entry_config_table), table);
615
616        free(shp_file);
617}
618
619static void
620pgui_action_import(GtkWidget *widget, gpointer data)
621{
622        char *connection_string = NULL;
623        char *connection_sanitized = NULL;
624        char *dest_string = NULL;
625        int ret, record_count = 0, i = 0, progress_bar_update_frequency = 1;
626        char *header, *footer, *record;
627        PGresult *result;
628
629
630        if ( ! (connection_string = pgui_read_connection() ) )
631        {
632                pgui_raise_error_dialogue();
633                return;
634        }
635
636        /*
637        ** Set the configuration from the UI and validate
638        */
639        pgui_set_config_from_ui();
640        if (! pgui_validate_config() )
641        {
642                pgui_raise_error_dialogue();
643                free(connection_string);
644
645                return;
646        }
647
648        /* Log what we know so far */
649        connection_sanitized = strdup(connection_string);
650        pgui_sanitize_connection_string(connection_sanitized);
651        pgui_logf("Connection: %s", connection_sanitized);
652        pgui_logf("Destination: %s.%s", config->schema, config->table);
653        pgui_logf("Source File: %s", config->shp_file);
654        free(connection_sanitized);
655
656        /* Connect to the database. */
657        if ( pg_connection ) PQfinish(pg_connection);
658        pg_connection = PQconnectdb(connection_string);
659
660        if (PQstatus(pg_connection) == CONNECTION_BAD)
661        {
662                pgui_logf( "Connection failed: %s", PQerrorMessage(pg_connection));
663                gtk_label_set_text(GTK_LABEL(label_pg_connection_test), "Connection failed.");
664                free(connection_string);
665                free(dest_string);
666                PQfinish(pg_connection);
667                pg_connection = NULL;
668                return;
669        }
670
671        /*
672         * Loop through the items in the shapefile
673         */
674
675        /* Disable the button to prevent multiple imports running at the same time */
676        gtk_widget_set_sensitive(widget, FALSE);
677
678        /* Allow GTK events to get a look in */
679        while (gtk_events_pending())
680                gtk_main_iteration();
681
682        /* Create the shapefile state object */
683        state = ShpLoaderCreate(config);
684
685        /* Open the shapefile */
686        ret = ShpLoaderOpenShape(state);
687        if (ret != SHPLOADEROK)
688        {
689                pgui_logf("%s", state->message);
690
691                if (ret == SHPLOADERERR)
692                        goto import_cleanup;
693        }
694
695        /* If reading the whole shapefile, display its type */
696        if (state->config->readshape)
697        {
698                pgui_logf("Shapefile type: %s", SHPTypeName(state->shpfiletype));
699                pgui_logf("Postgis type: %s[%d]", state->pgtype, state->pgdims);
700        }
701
702        /* Get the header */
703        ret = ShpLoaderGetSQLHeader(state, &header);
704        if (ret != SHPLOADEROK)
705        {
706                pgui_logf("%s", state->message);
707
708                if (ret == SHPLOADERERR)
709                        goto import_cleanup;
710        }
711
712        /* Send the header to the remote server: if we are in COPY mode then the last
713           statement will be a COPY and so will change connection mode */
714        ret = pgui_exec(header);
715        free(header);
716
717        if (!ret)
718                goto import_cleanup;
719
720        /* If we are in COPY (dump format) mode, output the COPY statement and enter COPY mode */
721        if (state->config->dump_format)
722        {
723                ret = ShpLoaderGetSQLCopyStatement(state, &header);
724
725                if (ret != SHPLOADEROK)
726                {
727                        pgui_logf("%s", state->message);
728
729                        if (ret == SHPLOADERERR)
730                                goto import_cleanup;
731                }
732
733                /* Send the result to the remote server: this should put us in COPY mode */
734                ret = pgui_copy_start(header);
735                free(header);
736
737                if (!ret)
738                        goto import_cleanup;
739        }
740
741        /* Main loop: iterate through all of the records and send them to stdout */
742        pgui_logf("Importing shapefile (%d records)...", ShpLoaderGetRecordCount(state));
743
744    /* Number of records in this file */
745    record_count = ShpLoaderGetRecordCount(state);
746    /* Assume a progress bar 1000 pixels across, how we only want to update it every N records */
747    progress_bar_update_frequency = 1 + record_count / 1000;
748   
749        import_running = TRUE;
750        for (i = 0; (i < record_count) && import_running; i++)
751        {
752                ret = ShpLoaderGenerateSQLRowStatement(state, i, &record);
753
754                switch (ret)
755                {
756                case SHPLOADEROK:
757                        /* Simply send the statement */
758                        if (state->config->dump_format)
759                                ret = pgui_copy_write(record);
760                        else
761                                ret = pgui_exec(record);
762
763                        /* Display a record number if we failed */
764                        if (!ret)
765                                pgui_logf("Failed record number #%d", i);
766
767                        free(record);
768                        break;
769
770                case SHPLOADERERR:
771                        /* Display the error message then stop */
772                        pgui_logf("%s\n", state->message);
773                        goto import_cleanup;
774                        break;
775
776                case SHPLOADERWARN:
777                        /* Display the warning, but continue */
778                        pgui_logf("%s\n", state->message);
779
780                        if (state->config->dump_format)
781                                ret = pgui_copy_write(record);
782                        else
783                                ret = pgui_exec(record);
784
785                        /* Display a record number if we failed */
786                        if (!ret)
787                                pgui_logf("Failed record number #%d", i);
788
789                        free(record);
790                        break;
791
792                case SHPLOADERRECDELETED:
793                        /* Record is marked as deleted - ignore */
794                        break;
795
796                case SHPLOADERRECISNULL:
797                        /* Record is NULL and should be ignored according to NULL policy */
798                        break;
799                }
800
801                /* Update the progress bar */
802        if( i % progress_bar_update_frequency == 0 )
803        {
804                    gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(progress), (float)i / record_count);
805            }
806
807                /* Allow GTK events to get a look in */
808                while (gtk_events_pending())
809                        gtk_main_iteration();
810        }
811
812        /* If we are in COPY (dump format) mode, leave COPY mode */
813        if (state->config->dump_format)
814        {
815                if (! pgui_copy_end(0) )
816                        goto import_cleanup;
817
818                result = PQgetResult(pg_connection);
819                if (PQresultStatus(result) != PGRES_COMMAND_OK)
820                {
821                        pgui_logf("COPY failed with the following error: %s", PQerrorMessage(pg_connection));
822                        ret = SHPLOADERERR;
823                        goto import_cleanup;
824                }
825        }
826
827        /* Only continue if we didn't abort part way through */
828        if (import_running)
829        {
830                /* Get the footer */
831                ret = ShpLoaderGetSQLFooter(state, &footer);
832                if (ret != SHPLOADEROK)
833                {
834                        pgui_logf("%s\n", state->message);
835
836                        if (ret == SHPLOADERERR)
837                                goto import_cleanup;
838                }
839
840                if ( state->config->createindex )
841                {
842                        pgui_logf("Creating spatial index...\n");
843                }
844
845                /* Send the footer to the server */
846                ret = pgui_exec(footer);
847                free(footer);
848
849                if (!ret)
850                        goto import_cleanup;
851        }
852
853
854import_cleanup:
855        /* If we didn't finish inserting all of the items, an error occurred */
856        if (i != ShpLoaderGetRecordCount(state) || !ret)
857                pgui_logf("Shapefile import failed.");
858        else
859                pgui_logf("Shapefile import completed.");
860
861        /* Free the state object */
862        ShpLoaderDestroy(state);
863
864        /* Import has definitely finished */
865        import_running = FALSE;
866
867        /* Enable the button once again */
868        gtk_widget_set_sensitive(widget, TRUE);
869
870        /* Silly GTK bug means we have to hide and show the button for it to work again! */
871        gtk_widget_hide(widget);
872        gtk_widget_show(widget);
873
874        /* Reset the progress bar */
875        gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(progress), 0.0);
876
877        /* Allow GTK events to get a look in */
878        while (gtk_events_pending())
879                gtk_main_iteration();
880
881        /* Tidy up */
882        free(connection_string);
883        free(dest_string);
884        connection_string = dest_string = NULL;
885
886        /* Disconnect from the database */
887        PQfinish(pg_connection);
888        pg_connection = NULL;
889
890        return;
891}
892
893static void
894pgui_create_options_dialogue_add_label(GtkWidget *table, const char *str, gfloat alignment, int row)
895{
896        GtkWidget *align = gtk_alignment_new( alignment, 0.5, 0.0, 1.0 );
897        GtkWidget *label = gtk_label_new( str );
898        gtk_table_attach_defaults(GTK_TABLE(table), align, 1, 3, row, row+1 );
899        gtk_container_add (GTK_CONTAINER (align), label);
900}
901
902static void
903pgui_action_about_open()
904{
905        GtkWidget *dlg;
906        const char *authors[] =
907        {
908                "Paul Ramsey <pramsey@opengeo.org>",
909                "Mark Cave-Ayland <mark.cave-ayland@siriusit.co.uk>",
910                NULL
911        };
912
913        dlg = gtk_about_dialog_new ();
914        gtk_about_dialog_set_name (GTK_ABOUT_DIALOG(dlg), "Shape to PostGIS");
915        gtk_about_dialog_set_comments (GTK_ABOUT_DIALOG(dlg), GUI_RCSID);
916        /*      gtk_about_dialog_set_version (GTK_ABOUT_DIALOG(dlg), GUI_RCSID); */
917        gtk_about_dialog_set_website (GTK_ABOUT_DIALOG(dlg), "http://postgis.org/");
918        gtk_about_dialog_set_authors (GTK_ABOUT_DIALOG(dlg), authors);
919        g_signal_connect_swapped(dlg, "response", G_CALLBACK(gtk_widget_destroy), dlg);
920        gtk_widget_show (dlg);
921}
922
923static void
924pgui_create_options_dialogue()
925{
926        GtkWidget *table_options;
927        GtkWidget *align_options_center;
928        GtkWidget *dialog_options;
929        static int text_width = 12;
930
931        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);
932
933        gtk_window_set_modal (GTK_WINDOW(dialog_options), TRUE);
934        gtk_window_set_keep_above (GTK_WINDOW(dialog_options), TRUE);
935        gtk_window_set_default_size (GTK_WINDOW(dialog_options), 180, 200);
936
937        table_options = gtk_table_new(7, 3, TRUE);
938        gtk_container_set_border_width (GTK_CONTAINER (table_options), 12);
939        gtk_table_set_row_spacings(GTK_TABLE(table_options), 5);
940        gtk_table_set_col_spacings(GTK_TABLE(table_options), 10);
941
942        pgui_create_options_dialogue_add_label(table_options, "DBF file character encoding", 0.0, 0);
943        entry_options_encoding = gtk_entry_new();
944        gtk_entry_set_width_chars(GTK_ENTRY(entry_options_encoding), text_width);
945        gtk_entry_set_text(GTK_ENTRY(entry_options_encoding), config->encoding);
946        gtk_table_attach_defaults(GTK_TABLE(table_options), entry_options_encoding, 0, 1, 0, 1 );
947
948        pgui_create_options_dialogue_add_label(table_options, "Preserve case of column names", 0.0, 1);
949        checkbutton_options_preservecase = gtk_check_button_new();
950        gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(checkbutton_options_preservecase), config->quoteidentifiers ? TRUE : FALSE);
951        align_options_center = gtk_alignment_new( 0.5, 0.5, 0.0, 1.0 );
952        gtk_table_attach_defaults(GTK_TABLE(table_options), align_options_center, 0, 1, 1, 2 );
953        gtk_container_add (GTK_CONTAINER (align_options_center), checkbutton_options_preservecase);
954
955        pgui_create_options_dialogue_add_label(table_options, "Do not create 'bigint' columns", 0.0, 2);
956        checkbutton_options_forceint = gtk_check_button_new();
957        gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(checkbutton_options_forceint), config->forceint4 ? TRUE : FALSE);
958        align_options_center = gtk_alignment_new( 0.5, 0.5, 0.0, 1.0 );
959        gtk_table_attach_defaults(GTK_TABLE(table_options), align_options_center, 0, 1, 2, 3 );
960        gtk_container_add (GTK_CONTAINER (align_options_center), checkbutton_options_forceint);
961
962        pgui_create_options_dialogue_add_label(table_options, "Create spatial index automatically after load", 0.0, 3);
963        checkbutton_options_autoindex = gtk_check_button_new();
964        gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(checkbutton_options_autoindex), config->createindex ? TRUE : FALSE);
965        align_options_center = gtk_alignment_new( 0.5, 0.5, 0.0, 1.0 );
966        gtk_table_attach_defaults(GTK_TABLE(table_options), align_options_center, 0, 1, 3, 4 );
967        gtk_container_add (GTK_CONTAINER (align_options_center), checkbutton_options_autoindex);
968
969        pgui_create_options_dialogue_add_label(table_options, "Load only attribute (dbf) data", 0.0, 4);
970        checkbutton_options_dbfonly = gtk_check_button_new();
971        gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON  (checkbutton_options_dbfonly), config->readshape ? FALSE : TRUE);
972        align_options_center = gtk_alignment_new( 0.5, 0.5, 0.0, 1.0 );
973        gtk_table_attach_defaults(GTK_TABLE(table_options), align_options_center, 0, 1, 4, 5 );
974        gtk_container_add (GTK_CONTAINER (align_options_center), checkbutton_options_dbfonly);
975
976        pgui_create_options_dialogue_add_label(table_options, "Load data using COPY rather than INSERT", 0.0, 5);
977        checkbutton_options_dumpformat = gtk_check_button_new();
978        gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON  (checkbutton_options_dumpformat), config->dump_format ? TRUE : FALSE);
979        align_options_center = gtk_alignment_new( 0.5, 0.5, 0.0, 0.0 );
980        gtk_table_attach_defaults(GTK_TABLE(table_options), align_options_center, 0, 1, 5, 6 );
981        gtk_container_add (GTK_CONTAINER (align_options_center), checkbutton_options_dumpformat);
982
983        pgui_create_options_dialogue_add_label(table_options, "Load into GEOGRAPHY column", 0.0, 6);
984        checkbutton_options_geography = gtk_check_button_new();
985        gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(checkbutton_options_geography), config->geography ? TRUE : FALSE);
986        align_options_center = gtk_alignment_new( 0.5, 0.5, 0.0, 1.0 );
987        gtk_table_attach_defaults(GTK_TABLE(table_options), align_options_center, 0, 1, 6, 7 );
988        gtk_container_add (GTK_CONTAINER (align_options_center), checkbutton_options_geography);
989
990        g_signal_connect(dialog_options, "response", G_CALLBACK(pgui_action_options_close), dialog_options);
991        gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog_options)->vbox), table_options, FALSE, FALSE, 0);
992
993        gtk_widget_show_all (dialog_options);
994}
995
996static void
997pgui_create_main_window(const SHPCONNECTIONCONFIG *conn)
998{
999        static int text_width = 12;
1000        /* Reusable label handle */
1001        GtkWidget *label;
1002        /* Main widgets */
1003        GtkWidget *vbox_main;
1004        /* Shape file section */
1005        GtkWidget *file_chooser_dialog_shape;
1006        GtkFileFilter *file_filter_shape;
1007        /* PgSQL section */
1008        GtkWidget *frame_pg, *frame_shape, *frame_log, *frame_config;
1009        GtkWidget *table_pg, *table_config;
1010        GtkWidget *button_pg_test;
1011        /* Button section */
1012        GtkWidget *hbox_buttons, *button_options, *button_import, *button_cancel, *button_about;
1013        /* Log section */
1014        GtkWidget *scrolledwindow_log;
1015#ifdef MAC_INTEGRATION
1016        /* MacOSX Command-Quit menu item */
1017        GtkWidget *menu_item_quit;
1018#endif
1019
1020        /* create the main, top level, window */
1021        window_main = gtk_window_new (GTK_WINDOW_TOPLEVEL);
1022
1023        /* give the window a 10px wide border */
1024        gtk_container_set_border_width (GTK_CONTAINER (window_main), 10);
1025
1026        /* give it the title */
1027        gtk_window_set_title (GTK_WINDOW (window_main), "Shape File to PostGIS Importer");
1028
1029        /* open it a bit wider so that both the label and title show up */
1030        gtk_window_set_default_size (GTK_WINDOW (window_main), 180, 500);
1031
1032        /* Connect the destroy event of the window with our pgui_quit function
1033        *  When the window is about to be destroyed we get a notificaiton and
1034        *  stop the main GTK loop
1035        */
1036        g_signal_connect (G_OBJECT (window_main), "destroy", G_CALLBACK (pgui_quit), NULL);
1037
1038        /*
1039        ** Shape file selector
1040        */
1041        frame_shape = gtk_frame_new("Shape File");
1042        gtk_container_set_border_width (GTK_CONTAINER (frame_shape), 0);
1043        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_CANCEL, GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, NULL);
1044        file_chooser_button_shape = gtk_file_chooser_button_new_with_dialog( file_chooser_dialog_shape );
1045        gtk_container_set_border_width (GTK_CONTAINER (file_chooser_button_shape), 8);
1046        /* Filter for .shp files */
1047        file_filter_shape = gtk_file_filter_new();
1048        gtk_file_filter_add_pattern(GTK_FILE_FILTER(file_filter_shape), "*.shp");
1049        gtk_file_filter_set_name(GTK_FILE_FILTER(file_filter_shape), "Shape Files (*.shp)");
1050        gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(file_chooser_button_shape), file_filter_shape);
1051        /* Filter for .dbf files */
1052        file_filter_shape = gtk_file_filter_new();
1053        gtk_file_filter_add_pattern(GTK_FILE_FILTER(file_filter_shape), "*.dbf");
1054        gtk_file_filter_set_name(GTK_FILE_FILTER(file_filter_shape), "DBF Files (*.dbf)");
1055        gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(file_chooser_button_shape), file_filter_shape);
1056       
1057        gtk_container_add (GTK_CONTAINER (frame_shape), file_chooser_button_shape);
1058        g_signal_connect (G_OBJECT (file_chooser_button_shape), "file-set", G_CALLBACK (pgui_action_shape_file_set), NULL);
1059
1060
1061        /*
1062        ** PostGIS info in a table
1063        */
1064        frame_pg = gtk_frame_new("PostGIS Connection");
1065        table_pg = gtk_table_new(5, 3, TRUE);
1066        gtk_container_set_border_width (GTK_CONTAINER (table_pg), 8);
1067        gtk_table_set_col_spacings(GTK_TABLE(table_pg), 7);
1068        gtk_table_set_row_spacings(GTK_TABLE(table_pg), 3);
1069        /* User name row */
1070        label = gtk_label_new("Username:");
1071        entry_pg_user = gtk_entry_new();
1072        if ( conn->username )
1073                gtk_entry_set_text(GTK_ENTRY(entry_pg_user), conn->username);
1074        gtk_table_attach_defaults(GTK_TABLE(table_pg), label, 0, 1, 0, 1 );
1075        gtk_table_attach_defaults(GTK_TABLE(table_pg), entry_pg_user, 1, 3, 0, 1 );
1076        /* Password row */
1077        label = gtk_label_new("Password:");
1078        entry_pg_pass = gtk_entry_new();
1079        if ( conn->password )
1080                gtk_entry_set_text(GTK_ENTRY(entry_pg_pass), conn->password);
1081        gtk_entry_set_visibility( GTK_ENTRY(entry_pg_pass), FALSE);
1082        gtk_table_attach_defaults(GTK_TABLE(table_pg), label, 0, 1, 1, 2 );
1083        gtk_table_attach_defaults(GTK_TABLE(table_pg), entry_pg_pass, 1, 3, 1, 2 );
1084        /* Host and port row */
1085        label = gtk_label_new("Server Host:");
1086        entry_pg_host = gtk_entry_new();
1087        if ( conn->host )
1088                gtk_entry_set_text(GTK_ENTRY(entry_pg_host), conn->host);
1089        else
1090                gtk_entry_set_text(GTK_ENTRY(entry_pg_host), "localhost");
1091        gtk_entry_set_width_chars(GTK_ENTRY(entry_pg_host), text_width);
1092        gtk_table_attach_defaults(GTK_TABLE(table_pg), label, 0, 1, 2, 3 );
1093        gtk_table_attach_defaults(GTK_TABLE(table_pg), entry_pg_host, 1, 2, 2, 3 );
1094        entry_pg_port = gtk_entry_new();
1095        if ( conn->port )
1096                gtk_entry_set_text(GTK_ENTRY(entry_pg_port), conn->port);
1097        else
1098                gtk_entry_set_text(GTK_ENTRY(entry_pg_port), "5432");
1099        gtk_entry_set_width_chars(GTK_ENTRY(entry_pg_port), 8);
1100        gtk_table_attach_defaults(GTK_TABLE(table_pg), entry_pg_port, 2, 3, 2, 3 );
1101        /* Database row */
1102        label = gtk_label_new("Database:");
1103        entry_pg_db   = gtk_entry_new();
1104        if ( conn->database )
1105                gtk_entry_set_text(GTK_ENTRY(entry_pg_db), conn->database);
1106        gtk_table_attach_defaults(GTK_TABLE(table_pg), label, 0, 1, 3, 4 );
1107        gtk_table_attach_defaults(GTK_TABLE(table_pg), entry_pg_db, 1, 3, 3, 4 );
1108        /* Test button row */
1109        button_pg_test = gtk_button_new_with_label("Test Connection...");
1110        gtk_table_attach_defaults(GTK_TABLE(table_pg), button_pg_test, 1, 2, 4, 5 );
1111        g_signal_connect (G_OBJECT (button_pg_test), "clicked", G_CALLBACK (pgui_action_connection_test), NULL);
1112        label_pg_connection_test = gtk_label_new("");
1113        gtk_table_attach_defaults(GTK_TABLE(table_pg), label_pg_connection_test, 2, 3, 4, 5 );
1114        /* Add table into containing frame */
1115        gtk_container_add (GTK_CONTAINER (frame_pg), table_pg);
1116
1117        /*
1118        ** Configuration in a table
1119        */
1120        frame_config = gtk_frame_new("Configuration");
1121        table_config = gtk_table_new(2, 4, TRUE);
1122        gtk_table_set_col_spacings(GTK_TABLE(table_config), 7);
1123        gtk_table_set_row_spacings(GTK_TABLE(table_config), 3);
1124        gtk_container_set_border_width (GTK_CONTAINER (table_config), 8);
1125        /* Destination schemea row */
1126        label = gtk_label_new("Destination Schema:");
1127        entry_config_schema = gtk_entry_new();
1128        gtk_entry_set_text(GTK_ENTRY(entry_config_schema), "public");
1129        gtk_entry_set_width_chars(GTK_ENTRY(entry_config_schema), text_width);
1130        gtk_table_attach_defaults(GTK_TABLE(table_config), label, 0, 1, 0, 1 );
1131        gtk_table_attach_defaults(GTK_TABLE(table_config), entry_config_schema, 1, 2, 0, 1 );
1132        /* Destination table row */
1133        label = gtk_label_new("Destination Table:");
1134        entry_config_table = gtk_entry_new();
1135        gtk_entry_set_width_chars(GTK_ENTRY(entry_config_table), text_width);
1136        gtk_table_attach_defaults(GTK_TABLE(table_config), label, 0, 1, 1, 2 );
1137        gtk_table_attach_defaults(GTK_TABLE(table_config), entry_config_table, 1, 2, 1, 2 );
1138        /* SRID row */
1139        label = gtk_label_new("SRID:");
1140        entry_config_srid = gtk_entry_new();
1141        gtk_entry_set_width_chars(GTK_ENTRY(entry_config_srid), text_width);
1142        gtk_entry_set_text(GTK_ENTRY(entry_config_srid), "-1");
1143        gtk_table_attach_defaults(GTK_TABLE(table_config), label, 2, 3, 0, 1 );
1144        gtk_table_attach_defaults(GTK_TABLE(table_config), entry_config_srid, 3, 4, 0, 1 );
1145        /* Geom column row */
1146        label = gtk_label_new("Geometry Column:");
1147        entry_config_geocolumn = gtk_entry_new();
1148        gtk_entry_set_width_chars(GTK_ENTRY(entry_config_geocolumn), text_width);
1149        gtk_entry_set_text(GTK_ENTRY(entry_config_geocolumn), GEOMETRY_DEFAULT);
1150        gtk_table_attach_defaults(GTK_TABLE(table_config), label, 2, 3, 1, 2 );
1151        gtk_table_attach_defaults(GTK_TABLE(table_config), entry_config_geocolumn, 3, 4, 1, 2 );
1152
1153        /* Add table into containing frame */
1154        gtk_container_add (GTK_CONTAINER (frame_config), table_config);
1155
1156        /* Progress bar for the import */
1157        progress = gtk_progress_bar_new();
1158        gtk_progress_bar_set_orientation(GTK_PROGRESS_BAR(progress), GTK_PROGRESS_LEFT_TO_RIGHT);
1159        gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(progress), 0.0);
1160
1161        /*
1162        ** Row of action buttons
1163        */
1164        hbox_buttons = gtk_hbox_new(TRUE, 15);
1165        gtk_container_set_border_width (GTK_CONTAINER (hbox_buttons), 0);
1166        /* Create the buttons themselves */
1167        button_options = gtk_button_new_with_label("Options...");
1168        button_import = gtk_button_new_with_label("Import");
1169        button_cancel = gtk_button_new_with_label("Cancel");
1170        button_about = gtk_button_new_with_label("About");
1171        /* Add actions to the buttons */
1172        g_signal_connect (G_OBJECT (button_import), "clicked", G_CALLBACK (pgui_action_import), NULL);
1173        g_signal_connect (G_OBJECT (button_options), "clicked", G_CALLBACK (pgui_action_options_open), NULL);
1174        g_signal_connect (G_OBJECT (button_cancel), "clicked", G_CALLBACK (pgui_action_cancel), NULL);
1175        g_signal_connect (G_OBJECT (button_about), "clicked", G_CALLBACK (pgui_action_about_open), NULL);
1176        /* And insert the buttons into the hbox */
1177        gtk_box_pack_start(GTK_BOX(hbox_buttons), button_options, TRUE, TRUE, 0);
1178        gtk_box_pack_end(GTK_BOX(hbox_buttons), button_cancel, TRUE, TRUE, 0);
1179        gtk_box_pack_end(GTK_BOX(hbox_buttons), button_about, TRUE, TRUE, 0);
1180        gtk_box_pack_end(GTK_BOX(hbox_buttons), button_import, TRUE, TRUE, 0);
1181
1182        /*
1183        ** Log window
1184        */
1185        frame_log = gtk_frame_new("Import Log");
1186        gtk_container_set_border_width (GTK_CONTAINER (frame_log), 0);
1187        textview_log = gtk_text_view_new();
1188        textbuffer_log = gtk_text_buffer_new(NULL);
1189        scrolledwindow_log = gtk_scrolled_window_new(NULL, NULL);
1190        gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW(scrolledwindow_log), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
1191        gtk_text_view_set_buffer(GTK_TEXT_VIEW(textview_log), textbuffer_log);
1192        gtk_container_set_border_width (GTK_CONTAINER (textview_log), 5);
1193        gtk_text_view_set_editable(GTK_TEXT_VIEW(textview_log), FALSE);
1194        gtk_text_view_set_cursor_visible(GTK_TEXT_VIEW(textview_log), FALSE);
1195        gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(textview_log), GTK_WRAP_WORD);
1196        gtk_container_add (GTK_CONTAINER (scrolledwindow_log), textview_log);
1197        gtk_container_add (GTK_CONTAINER (frame_log), scrolledwindow_log);
1198
1199#ifdef MAC_INTEGRATION
1200        /*
1201        ** OS/X menu integration for command-Q
1202        */
1203        menu_item_quit = gtk_menu_item_new();
1204        g_signal_connect (G_OBJECT (menu_item_quit), "activate", G_CALLBACK (pgui_action_cancel), NULL);
1205        ige_mac_menu_set_quit_menu_item (GTK_MENU_ITEM (menu_item_quit));
1206#endif
1207
1208        /*
1209        ** Main window
1210        */
1211        vbox_main = gtk_vbox_new(FALSE, 10);
1212        gtk_container_set_border_width (GTK_CONTAINER (vbox_main), 0);
1213        /* Add the frames into the main vbox */
1214        gtk_box_pack_start(GTK_BOX(vbox_main), frame_shape, FALSE, TRUE, 0);
1215        gtk_box_pack_start(GTK_BOX(vbox_main), frame_pg, FALSE, TRUE, 0);
1216        gtk_box_pack_start(GTK_BOX(vbox_main), frame_config, FALSE, TRUE, 0);
1217        gtk_box_pack_start(GTK_BOX(vbox_main), hbox_buttons, FALSE, FALSE, 0);
1218        gtk_box_pack_start(GTK_BOX(vbox_main), progress, FALSE, FALSE, 0);
1219        gtk_box_pack_start(GTK_BOX(vbox_main), frame_log, TRUE, TRUE, 0);
1220        /* and insert the vbox into the main window  */
1221        gtk_container_add (GTK_CONTAINER (window_main), vbox_main);
1222        /* make sure that everything, window and label, are visible */
1223        gtk_widget_show_all (window_main);
1224
1225        return;
1226}
1227
1228static void
1229usage()
1230{
1231        printf("RCSID: %s RELEASE: %s\n", RCSID, POSTGIS_VERSION);
1232        printf("USAGE: shp2pgsql-gui [options]\n");
1233        printf("OPTIONS:\n");
1234        printf("  -U <username>\n");
1235        printf("  -W <password>\n");
1236        printf("  -h <host>\n");
1237        printf("  -p <port>\n");
1238        printf("  -d <database>\n");
1239        printf("  -? Display this help screen\n");
1240}
1241
1242int
1243main(int argc, char *argv[])
1244{
1245        char c;
1246
1247        /* Set default configuration */
1248        config = malloc(sizeof(SHPLOADERCONFIG));
1249        set_config_defaults(config);
1250
1251        /* Here we override any defaults for the GUI */
1252        config->createindex = 1;
1253
1254        /* Prepare our shape connection */
1255        conn = malloc(sizeof(SHPCONNECTIONCONFIG));
1256        memset(conn, 0, sizeof(SHPCONNECTIONCONFIG));
1257
1258    /* Read any environment values */
1259    conn->port = getenv("PGPORT");
1260    conn->username = getenv("PGUSER");
1261    conn->database = getenv("PGDATABASE");
1262    conn->host = getenv("PGHOST");
1263
1264        /* Over-ride the environment with any command line options */
1265        while ((c = pgis_getopt(argc, argv, "U:p:W:d:h:")) != -1)
1266        {
1267                switch (c)
1268                {
1269                case 'U':
1270                        conn->username = pgis_optarg;
1271                        break;
1272                case 'p':
1273                        conn->port = pgis_optarg;
1274                        break;
1275                case 'W':
1276                        conn->password = pgis_optarg;
1277                        break;
1278                case 'd':
1279                        conn->database = pgis_optarg;
1280                        break;
1281                case 'h':
1282                        conn->host = pgis_optarg;
1283                        break;
1284                default:
1285                        usage();
1286                        free(conn);
1287                        free(config);
1288                        exit(0);
1289                }
1290        }
1291
1292        /* initialize the GTK stack */
1293        gtk_init(&argc, &argv);
1294
1295        /* set up the user interface */
1296        pgui_create_main_window(conn);
1297
1298        /* start the main loop */
1299        gtk_main();
1300
1301        /* Free the configuration */
1302        free(conn);
1303        free(config);
1304
1305        return 0;
1306}
Note: See TracBrowser for help on using the repository browser.