/* gmysql -- a graphical frontend to MySQL databases Copyright (C) 1998, 1999 Stephen R. Dodd This program is free software; you can redistribute it and/or modify it under the terms of version 2 of the GNU General Public License as published by the Free Software Foundation. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include "tablelist.h" #include "connectdlg.h" #include "createdbdlg.h" #include "createtabledlg.h" #include "msgbox.h" #include "qbox.h" static void make_menus( TableList *table_list ); static void menu_host_quit( GtkWidget *widget, gpointer data ); static void menu_host_connect( GtkWidget *widget, gpointer data ); static void menu_host_disconnect( GtkWidget *widget, gpointer data ); static void menu_host_refresh( GtkWidget *widget, gpointer data ); static void menu_db_create( GtkWidget *widget, gpointer data ); static void menu_db_drop( GtkWidget *widgt, gpointer data ); static void menu_table_create( GtkWidget *widget, gpointer data ); static void menu_table_modify( GtkWidget *widget, gpointer data ); static void menu_table_drop( GtkWidget *widget, gpointer data ); static void add_host_tables( gpointer key, gpointer data, gpointer user_data ); static void table_list_selected( GtkWidget *widget, gint row, gint col, GdkEventButton *bevent ); static gint table_list_popup( GtkWidget *widget, GdkEventButton *event ); static GtkItemFactoryEntry menu_items[] = { { "/Host/Connect...", NULL, menu_host_connect, 0 }, { "/Host/Disconnect", NULL, menu_host_disconnect, 0 }, { "/Host/Refresh List", NULL, menu_host_refresh, 0 }, { "/Host/Quit", NULL, menu_host_quit, 0 }, { "/Database/Create...", NULL, menu_db_create, 0 }, { "/Database/Drop", NULL, menu_db_drop, 0 }, { "/Table/Create...", NULL, menu_table_create, 0 }, { "/Table/Modify...", NULL, menu_table_modify, 0 }, { "/Table/Drop", NULL, menu_table_drop, 0 } }; static TableList *table_list_active; TableList *table_list_new( void ) { TableList *table_list; GtkWidget *vbox, *scrolled; char *titles[] = { "Host", "Database", "Table" }; table_list = g_malloc( sizeof( TableList ) ); table_list->selected_row = 0; /* make window, create, add and show vbox */ table_list->window = gtk_window_new( GTK_WINDOW_TOPLEVEL ); vbox = gtk_vbox_new( FALSE, 0 ); gtk_container_add( GTK_CONTAINER( table_list->window ), vbox ); gtk_widget_show( vbox ); /* create menu and status bars */ make_menus( table_list ); table_list->status_bar = gtk_statusbar_new(); gtk_box_pack_start( GTK_BOX( vbox ), table_list->menu_bar, FALSE, TRUE, 0 ); /* create and set up the column list */ table_list->table_list = gtk_clist_new_with_titles( 3, titles ); gtk_clist_column_titles_passive( GTK_CLIST( table_list->table_list ) ); gtk_clist_set_column_width( GTK_CLIST( table_list->table_list ), 0, 100 ); gtk_clist_set_column_width( GTK_CLIST( table_list->table_list ), 1, 100 ); gtk_clist_set_column_width( GTK_CLIST( table_list->table_list ), 2, 100 ); gtk_widget_set_usize( table_list->table_list, 350, 200 ); gtk_signal_connect( GTK_OBJECT( table_list->table_list ), "select_row", GTK_SIGNAL_FUNC( table_list_selected ), NULL ); gtk_signal_connect( GTK_OBJECT( table_list->table_list ), "button_press_event", GTK_SIGNAL_FUNC( table_list_popup ), NULL ); #if CONFIG_GTK_MAJOR==1 && CONFIG_GTK_MINOR==0 gtk_clist_set_policy( GTK_CLIST( table_list->table_list ), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC ); gtk_box_pack_start( GTK_BOX( vbox ), table_list->table_list, TRUE, TRUE, 0 ); #else /* not GTK 1.0 */ /* create a scrolled window */ scrolled = gtk_scrolled_window_new( NULL, NULL ); gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW( scrolled ), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC ); gtk_container_add( GTK_CONTAINER( scrolled ), table_list->table_list ); gtk_widget_show( scrolled ); gtk_box_pack_start( GTK_BOX( vbox ), scrolled, TRUE, TRUE, 0 ); #endif /* GTK 1.0 */ gtk_box_pack_start( GTK_BOX( vbox ), table_list->status_bar, FALSE, TRUE, 0 ); /* add a call back to quit the app when the window closes */ gtk_signal_connect( GTK_OBJECT( table_list->window ), "destroy", GTK_SIGNAL_FUNC( menu_host_quit ), NULL ); /* show the menu bar, status bar and clist */ gtk_widget_show( table_list->menu_bar ); gtk_widget_show( table_list->table_list ); gtk_widget_show( table_list->status_bar ); /* create hashtable to hold db connections */ table_list->conns = g_hash_table_new( g_str_hash, g_str_equal ); table_list_active = table_list; return table_list; } void table_list_show( TableList *table_list ) { gtk_widget_show( table_list->window ); menu_host_connect( NULL, NULL ); } void table_list_connect( TableList *table_list, gchar *host, gchar *user, gchar *pw ) { DBConn *db_conn; db_conn = db_conn_new( host, user, pw ); if( db_conn ) { g_hash_table_insert( table_list->conns, db_conn->host, db_conn ); table_list_refresh( table_list ); } } void table_list_create_db( TableList *table_list, gchar *host, gchar *db ) { DBConn *db_conn; db_conn = (DBConn *)g_hash_table_lookup( table_list->conns, host ); if( mysql_create_db( &db_conn->mysql, db ) ) { MsgBox *msg_box; msg_box = msg_box_new( mysql_error( &db_conn->mysql ) ); msg_box_show( msg_box ); } else { table_list_refresh( table_list ); } } void table_list_refresh( TableList *table_list ) { gtk_clist_freeze( GTK_CLIST( table_list->table_list ) ); gtk_clist_clear( GTK_CLIST( table_list->table_list ) ); g_hash_table_foreach( table_list->conns, add_host_tables, table_list ); gtk_clist_thaw( GTK_CLIST( table_list->table_list ) ); } void add_host_tables( gpointer key, gpointer data, gpointer user_data ) { MYSQL_RES *res_dbs; MYSQL_RES *res_tbls; DBConn *db_conn; TableList *table_list; MYSQL_ROW row; char *entry[3]; char *db; int tables; MsgBox *msg_box; GString *errors; db_conn = (DBConn *)data; table_list = (TableList *)user_data; entry[0] = db_conn->host; res_dbs = mysql_list_dbs( &db_conn->mysql, NULL ); if( !res_dbs ) { msg_box = msg_box_new( mysql_error( &db_conn->mysql ) ); msg_box_show( msg_box ); return; } errors = g_string_new( "" ); while( ( row = mysql_fetch_row( res_dbs ) ) ) { db = row[0]; entry[1] = db; if( mysql_select_db( &db_conn->mysql, db ) ) { if( mysql_errno(&db_conn->mysql) != ER_DBACCESS_DENIED_ERROR ) g_string_sprintfa( errors, "%s\n", mysql_error( &db_conn->mysql ) ); else { entry[2] = ""; gtk_clist_append( GTK_CLIST(table_list->table_list), entry); } continue; } res_tbls = mysql_list_tables( &db_conn->mysql, NULL ); if( !res_tbls ) { g_string_sprintfa( errors, "%s\n", mysql_error( &db_conn->mysql ) ); continue; } tables = 0; while( ( row = mysql_fetch_row( res_tbls ) ) ) { entry[2] = row[0]; gtk_clist_append( GTK_CLIST( table_list->table_list ), entry ); tables++; } if( !tables ) { entry[2] = ""; gtk_clist_append( GTK_CLIST( table_list->table_list ), entry ); } } if( errors->len ) { msg_box = msg_box_new( errors->str ); msg_box_show( msg_box ); } g_string_free( errors, TRUE ); } void make_menus( TableList *table_list ) { GtkItemFactory *menu_factory; menu_factory = gtk_item_factory_new( GTK_TYPE_MENU_BAR, "
", NULL ); gtk_item_factory_create_items( menu_factory, sizeof( menu_items ) / sizeof( GtkMenuEntry ), menu_items, NULL ); table_list->menu_bar = gtk_item_factory_get_widget( menu_factory, "
" ); menu_factory = gtk_item_factory_new( GTK_TYPE_MENU, "
", NULL ); gtk_item_factory_create_items( menu_factory, sizeof( menu_items ) / sizeof( GtkMenuEntry ), menu_items, NULL ); table_list->menu_popup = gtk_item_factory_get_widget( menu_factory, "
" ); } void menu_host_quit( GtkWidget *widget, gpointer data ) { gtk_exit( 0 ); } void menu_host_disconnect( GtkWidget *widget, gpointer data ) { TableList *table_list; gchar *host; DBConn *db_conn; table_list = table_list_active; gtk_clist_get_text( GTK_CLIST( table_list->table_list ), table_list->selected_row, 0, &host ); db_conn = g_hash_table_lookup( table_list->conns, host ); if( db_conn ) { g_hash_table_remove( table_list->conns, host ); db_conn_destroy( db_conn ); table_list_refresh( table_list ); } else { g_print( "Couldn't find thingy in hashtable (key=%s)\n", host ); } } void menu_host_connect( GtkWidget *widget, gpointer data ) { ConnectDlg *connect_dlg; connect_dlg = connect_dlg_new( table_list_active ); connect_dlg_show( connect_dlg ); } void menu_host_refresh( GtkWidget *widget, gpointer data ) { table_list_refresh( table_list_active ); } void menu_db_create( GtkWidget *widget, gpointer data ) { CreateDbDlg *create_db_dlg; TableList *table_list; gchar *host; table_list = table_list_active; gtk_clist_get_text( GTK_CLIST( table_list->table_list ), table_list->selected_row, 0, &host ); create_db_dlg = create_db_dlg_new( table_list_active, host ); create_db_dlg_show( create_db_dlg ); } void menu_db_drop( GtkWidget *widget, gpointer data ) { DBConn *db_conn; TableList *table_list; gchar *host; gchar *db; GString *msg; QBox *q_box; table_list = table_list_active; gtk_clist_get_text( GTK_CLIST( table_list->table_list ), table_list->selected_row, 0, &host ); gtk_clist_get_text( GTK_CLIST( table_list->table_list ), table_list->selected_row, 1, &db ); msg = g_string_new( NULL ); g_string_sprintf( msg, "Drop database '%s' (and all its tables)?", db ); q_box = q_box_new( msg->str, "Drop", "Cancel" ); g_string_free( msg, TRUE ); if( q_box_do_modal( q_box ) == 1 ) return; db_conn = (DBConn *)g_hash_table_lookup( table_list->conns, host ); if( mysql_drop_db( &db_conn->mysql, db ) ) { MsgBox *msg_box; msg_box = msg_box_new( mysql_error( &db_conn->mysql ) ); msg_box_show( msg_box ); } else { table_list_refresh( table_list ); } } void menu_table_create( GtkWidget *widget, gpointer data ) { CreateTableDlg *create_table_dlg; TableList *table_list; gchar *host, *db; table_list = table_list_active; gtk_clist_get_text( GTK_CLIST( table_list->table_list ), table_list->selected_row, 0, &host ); gtk_clist_get_text( GTK_CLIST( table_list->table_list ), table_list->selected_row, 1, &db ); create_table_dlg = create_table_dlg_new( table_list_active, host, db ); create_table_dlg_show( create_table_dlg ); } void menu_table_modify( GtkWidget *widget, gpointer data ) { CreateTableDlg *create_table_dlg; DBConn *db_conn; TableList *table_list; gchar *host, *db, *table; GString *sql, *fragment; MsgBox *msg_box; MYSQL_RES *res; MYSQL_ROW row; GSList *fields; gchar *last_index; gint unique; table_list = table_list_active; gtk_clist_get_text( GTK_CLIST( table_list->table_list ), table_list->selected_row, 0, &host ); gtk_clist_get_text( GTK_CLIST( table_list->table_list ), table_list->selected_row, 1, &db ); gtk_clist_get_text( GTK_CLIST( table_list->table_list ), table_list->selected_row, 2, &table ); if( !table || !table[0] || table[0] == '<' ) { msg_box = msg_box_new( "No table to modify" ); msg_box_show( msg_box ); return; } db_conn = (DBConn *)g_hash_table_lookup( table_list->conns, host ); sql = g_string_new( NULL ); fragment = g_string_new( NULL ); g_string_sprintf( sql, "SHOW FIELDS FROM %s", table ); if( mysql_select_db( &db_conn->mysql, db ) ) { msg_box = msg_box_new( mysql_error( &db_conn->mysql ) ); msg_box_show( msg_box ); } else if( mysql_query( &db_conn->mysql, sql->str ) ) { msg_box = msg_box_new( mysql_error( &db_conn->mysql ) ); msg_box_show( msg_box ); } else { res = mysql_store_result( &db_conn->mysql ); create_table_dlg = create_table_dlg_new_modified( table_list_active, host, db, table ); while( (row = mysql_fetch_row( res )) ) { g_string_sprintf( fragment, "%s", row[1] ); if( row[2] && row[2][0] == 'Y' ) g_string_sprintfa( fragment, " NULL" ); else g_string_sprintfa( fragment, " NOT NULL" ); if( row[4] && row[4][0] ) g_string_sprintfa( fragment, " DEFAULT %s", row[4] ); if( row[5] && row[5][0] ) g_string_sprintfa( fragment, " %s", row[5] ); create_table_dlg_add_field( create_table_dlg, row[0], fragment->str, FALSE ); } mysql_free_result( res ); g_string_sprintf( sql, "SHOW INDEX FROM %s", table ); if( mysql_query( &db_conn->mysql, sql->str ) ) { msg_box = msg_box_new( mysql_error( &db_conn->mysql ) ); msg_box_show( msg_box ); } else { res = mysql_store_result( &db_conn->mysql ); fields = NULL; last_index = NULL; unique = 666; /* I have a distinct feeling that this is utterly preposterous... .. and that there's a way to do this in about 5 lines! */ while( (row = mysql_fetch_row( res )) ) { if( !last_index ) { last_index = g_strdup( row[2] ); unique = !atoi( row[1] ); } if( strcmp( last_index, row[2] ) ) { create_table_dlg_add_index( create_table_dlg, last_index, fields, unique, FALSE ); g_free( last_index ); g_slist_foreach( fields, (GFunc)g_free, NULL ); // you like? g_slist_free( fields ); fields = NULL; last_index = g_strdup( row[2] ); unique = !atoi( row[1] ); } if( fields ) g_slist_append( fields, g_strdup( row[4] ) ); else fields = g_slist_append( NULL, g_strdup( row[4] ) ); } if( last_index ) { create_table_dlg_add_index( create_table_dlg, last_index, fields, unique, FALSE ); g_free( last_index ); g_slist_foreach( fields, (GFunc)g_free, NULL ); // you like? g_slist_free( fields ); } } create_table_dlg_show( create_table_dlg ); } g_string_free( sql, TRUE ); g_string_free( fragment, TRUE ); } void menu_table_drop( GtkWidget *widget, gpointer data ) { DBConn *db_conn; TableList *table_list; gchar *host, *db, *table; GString *sql, *msg; MsgBox *msg_box; QBox *q_box; table_list = table_list_active; gtk_clist_get_text( GTK_CLIST( table_list->table_list ), table_list->selected_row, 0, &host ); gtk_clist_get_text( GTK_CLIST( table_list->table_list ), table_list->selected_row, 1, &db ); gtk_clist_get_text( GTK_CLIST( table_list->table_list ), table_list->selected_row, 2, &table ); if( !table || !table[0] || table[0] == '<' ) { msg_box = msg_box_new( "No table to drop" ); msg_box_show( msg_box ); return; } msg = g_string_new( NULL ); g_string_sprintf( msg, "Drop table '%s'?", table ); q_box = q_box_new( msg->str, "Drop", "Cancel" ); g_string_free( msg, TRUE ); if( q_box_do_modal( q_box ) == 1 ) return; db_conn = (DBConn *)g_hash_table_lookup( table_list->conns, host ); sql = g_string_new( NULL ); g_string_sprintf( sql, "DROP TABLE %s", table ); if( mysql_select_db( &db_conn->mysql, db ) ) { msg_box = msg_box_new( mysql_error( &db_conn->mysql ) ); msg_box_show( msg_box ); } else if( mysql_query( &db_conn->mysql, sql->str ) ) { msg_box = msg_box_new( mysql_error( &db_conn->mysql ) ); msg_box_show( msg_box ); } else { table_list_refresh( table_list ); } g_string_free( sql, TRUE ); } DBConn *db_conn_new( gchar *host, gchar *user, gchar *pw ) { DBConn *db_conn; MsgBox *msg_box; if( !host || !host[0] ) host = LOCAL_HOST; db_conn = g_new( DBConn, 1 ); db_conn->host = g_strdup( host ); db_conn->user = g_strdup( user ); db_conn->pw = g_strdup( pw ); if( !mysql_connect( &db_conn->mysql, host, user, pw ) ) { msg_box = msg_box_new( mysql_error( &db_conn->mysql ) ); msg_box_show( msg_box ); g_free( db_conn ); return NULL; } return db_conn; } void db_conn_destroy( DBConn *db_conn ) { mysql_close( &db_conn->mysql ); g_free( db_conn->host ); g_free( db_conn->user ); g_free( db_conn->pw ); g_free( db_conn ); } void table_list_selected( GtkWidget *widget, gint row, gint col, GdkEventButton *bevent ) { table_list_active->selected_row = row; } gint table_list_popup( GtkWidget *widget, GdkEventButton *event ) { if( event->button == 3 ) { gtk_menu_popup( GTK_MENU( table_list_active->menu_popup ), NULL, NULL, NULL, NULL, event->button, event->time ); return TRUE; } return FALSE; }