/* * dbMetrix Database Tool v0.1 * Copyright (c) 1998 David E. Storey * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * 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 "global.h" GtkWidget *ds_attach_tree_item(GtkWidget *treeItem, node_ds *nodeInfo, int position); void ds_export_cb(GtkWidget *widget, gpointer data); GtkWidget * add_subtree(GtkWidget *treeItem) { GtkWidget *subTree; if (!treeItem || GTK_TREE_ITEM_SUBTREE(treeItem)) return(NULL); subTree = gtk_tree_new(); gtk_tree_item_set_subtree(GTK_TREE_ITEM(treeItem), subTree); gtk_signal_emit_by_name(GTK_OBJECT(treeItem), "expand"); gtk_widget_show(subTree); return(subTree); } void add_to_menu_bar(GtkWidget *menu_bar, GtkWidget *menu, char *name, int align) { GtkWidget *menu_item = gtk_menu_item_new_with_label(name); if (align == 1) gtk_menu_item_right_justify(GTK_MENU_ITEM(menu_item)); gtk_widget_show(menu_item); gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu_item), menu); gtk_menu_bar_append(GTK_MENU_BAR(menu_bar), menu_item); } void create_db(GtkWidget *dWindow, gpointer data) { char *database = get_entry_text(dWindow, "database", FALSE); GtkWidget *treeItem = gtk_object_get_data(GTK_OBJECT(dbTree), "selected"); node_ds *nodeInfo = (node_ds *)gtk_object_get_data(GTK_OBJECT(treeItem), "info"); if (database && dsFuncs[nodeInfo->conn->class].create_db) { if (dsFuncs[nodeInfo->conn->class].create_db(nodeInfo->conn, database)) { char message[256]; g_snprintf(message, 256, "Successfully created '%s'", database); s_print(message); /* refresh display */ if (dsFuncs[nodeInfo->conn->class].refresh) dsFuncs[nodeInfo->conn->class].refresh(treeItem, nodeInfo); } } gtk_widget_destroy(dWindow); } void create_dbDialog(GtkWidget *widget, gpointer data) { GtkWidget *dWindow; GtkWidget *button; dbx_Dialog entries[] = { {"Database:", "database", FALSE} }; dWindow = gtk_dialog_new(); gtk_window_set_title(GTK_WINDOW(dWindow), "New Database"); gtk_widget_set_usize(GTK_DIALOG(dWindow)->action_area, -1, 32); gtk_container_border_width(GTK_CONTAINER(GTK_DIALOG(dWindow)->action_area), 4); gtk_container_border_width(GTK_CONTAINER(GTK_DIALOG(dWindow)->vbox), 4); gtk_widget_show(dWindow); /* action area buttons */ button = gtk_button_new_with_label("Ok"); gtk_signal_connect_object(GTK_OBJECT(button), "clicked", GTK_SIGNAL_FUNC(create_db), GTK_OBJECT(dWindow)); gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dWindow)->action_area), button, TRUE, TRUE, 0); gtk_widget_show(button); button = gtk_button_new_with_label("Cancel"); gtk_signal_connect_object(GTK_OBJECT(button), "clicked", GTK_SIGNAL_FUNC(gtk_widget_destroy), GTK_OBJECT(dWindow)); gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dWindow)->action_area), button, TRUE, TRUE, 0); gtk_widget_show(button); gtk_object_set_data(GTK_OBJECT(dWindow), "dsClass", data); create_dialogs(dWindow, NULL, NULL, 0, NULL, entries, sizeof(entries)/sizeof(entries[0])); } GtkWidget * create_treeItem_with_pixmap(char *string, char **inpix) { GtkWidget *treeItem = gtk_tree_item_new(); GtkWidget *hbox = gtk_hbox_new(FALSE, 0); GtkWidget *label = gtk_label_new(string); GdkBitmap *mask; GtkStyle *style = gtk_widget_get_style(mainWindow); GdkPixmap *pixmap = gdk_pixmap_create_from_xpm_d(mainWindow->window, &mask, &style->bg[GTK_STATE_NORMAL], inpix); GtkWidget *pix = gtk_pixmap_new(pixmap, mask); gtk_box_pack_start(GTK_BOX(hbox), pix, FALSE, TRUE, 0); gtk_widget_show(pix); gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); gtk_box_pack_start (GTK_BOX(hbox), label, FALSE, TRUE, 3); gtk_widget_show (label); gtk_container_add(GTK_CONTAINER(treeItem), hbox); gtk_widget_show(hbox); gtk_widget_show(treeItem); return(treeItem); } void drop_db(GtkWidget *widget, gpointer data) { GtkWidget *treeItem = gtk_object_get_data(GTK_OBJECT(dbTree), "selected"); node_ds *nodeInfo = (node_ds *)gtk_object_get_data(GTK_OBJECT(treeItem), "info"); if (dsFuncs[nodeInfo->conn->class].drop_db) { if (dsFuncs[nodeInfo->conn->class].drop_db(nodeInfo->conn, nodeInfo->name)) { char message[256]; g_snprintf(message, 256, "Successfully dropped '%s'", nodeInfo->name); s_print(message); /* refresh display */ ds_prune_tree(treeItem, 0); } } } GtkWidget * ds_add(char *name, void *ds_conn, dsClass ds_class, dsType type) { char message[256]; dataSource *conn; node_ds *nodeInfo; g_snprintf(message, 256, "Connected to %s", name); s_print(message); /* create connection info */ conn = (dataSource *)g_malloc(sizeof(dataSource)); conn->info = ds_conn; conn->class = ds_class; conn->name = g_strdup(name); conn->connected = TRUE; gtk_object_set_data(GTK_OBJECT(dbTree), name, conn); /* create node info */ nodeInfo = ds_tree_node_new(NULL, name, type, conn); return(ds_attach_tree_item(NULL, nodeInfo, -1)); } GtkWidget * ds_attach_tree_item(GtkWidget *treeItem, node_ds *nodeInfo, int position) { GtkWidget *newTreeItem = NULL; GtkWidget *subTree = treeItem ? GTK_TREE_ITEM_SUBTREE(treeItem) : dbTree; #include "icons/db.xpm" #include "icons/ds.xpm" #include "icons/table.xpm" #include "icons/field.xpm" if (!nodeInfo) return(NULL); switch(nodeInfo->type) { case Host: newTreeItem = create_treeItem_with_pixmap(nodeInfo->name, ds_xpm); break; case Database: newTreeItem = create_treeItem_with_pixmap(nodeInfo->name, db_xpm); break; case Table: newTreeItem = create_treeItem_with_pixmap(nodeInfo->name, table_xpm); break; case Field: newTreeItem = create_treeItem_with_pixmap(nodeInfo->name, field_xpm); break; } if (newTreeItem) { char *dnd_types[] = { "text/plain" }; int hid; if (!subTree) subTree = add_subtree(treeItem); gtk_object_set_data(GTK_OBJECT(newTreeItem), "info", nodeInfo); gtk_signal_connect(GTK_OBJECT(newTreeItem), "button_press_event", GTK_SIGNAL_FUNC(on_dbTree_clicked), (gpointer)nodeInfo); gtk_signal_connect(GTK_OBJECT(newTreeItem), "select", GTK_SIGNAL_FUNC(on_dbTree_select), (gpointer)nodeInfo); if (position > 0) gtk_tree_insert(GTK_TREE(subTree), newTreeItem, position); else gtk_tree_append(GTK_TREE(subTree), newTreeItem); } return(newTreeItem); } void ds_export(GtkWidget *widget, gpointer data) { GtkWidget *file_selection; GtkWidget *frame; GtkWidget *table; GtkWidget *button; node_ds *nodeInfo = fetch_selected(); if (!nodeInfo) { s_print("don't know what to export!"); return; } g_print("ds_dump(%s)\n", nodeInfo->name); /* popup dialog */ file_selection = gtk_file_selection_new("Export"); gtk_widget_show(file_selection); /* my own shtuff */ frame = gtk_frame_new("Export Options"); gtk_box_pack_start(GTK_BOX(GTK_FILE_SELECTION(file_selection)->main_vbox), frame, TRUE, TRUE, 0); gtk_widget_show(frame); table = gtk_table_new(5, 1, TRUE); gtk_container_add(GTK_CONTAINER(frame), table); gtk_widget_show(table); button = gtk_check_button_new_with_label("Lock Table(s)"); gtk_table_attach(GTK_TABLE(table), button, 0, 1, 0, 1, GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0); gtk_object_set_data(GTK_OBJECT(file_selection), "lock_tables", button); gtk_widget_show(button); button = gtk_check_button_new_with_label("Use Complete Insert Statements"); gtk_table_attach(GTK_TABLE(table), button, 0, 1, 1, 2, GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0); gtk_object_set_data(GTK_OBJECT(file_selection), "complete_inserts", button); gtk_widget_show(button); button = gtk_radio_button_new_with_label(NULL, "Data and Structures"); gtk_table_attach(GTK_TABLE(table), button, 0, 1, 2, 3, GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0); gtk_widget_show(button); button = gtk_radio_button_new_with_label(gtk_radio_button_group(GTK_RADIO_BUTTON(button)), "Table Structures Only"); gtk_table_attach(GTK_TABLE(table), button, 0, 1, 3, 4, GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0); gtk_widget_show(button); button = gtk_radio_button_new_with_label(gtk_radio_button_group(GTK_RADIO_BUTTON(button)), "Data Only"); gtk_table_attach(GTK_TABLE(table), button, 0, 1, 4, 5, GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0); gtk_widget_show(button); /* action area buttons */ gtk_signal_connect_object(GTK_OBJECT(GTK_FILE_SELECTION(file_selection)->ok_button), "clicked", GTK_SIGNAL_FUNC(ds_export_cb), GTK_OBJECT(file_selection)); gtk_signal_connect_object(GTK_OBJECT(GTK_FILE_SELECTION(file_selection)->cancel_button), "clicked", GTK_SIGNAL_FUNC(gtk_widget_destroy), GTK_OBJECT(file_selection)); gtk_object_set_data(GTK_OBJECT(file_selection), "info", (gpointer)nodeInfo); } void ds_export_cb(GtkWidget *dWindow, gpointer data) { export_options exportOptions; GtkWidget *button; node_ds *nodeInfo = gtk_object_get_data(GTK_OBJECT(dWindow), "info"); if (!nodeInfo) return; /* get dialog options */ button = (GtkWidget *)gtk_object_get_data(GTK_OBJECT(dWindow), "lock_tables"); exportOptions.lock = GTK_CHECK_BUTTON(button)->toggle_button.active; button = (GtkWidget *)gtk_object_get_data(GTK_OBJECT(dWindow), "complete_inserts"); exportOptions.complete_inserts = GTK_CHECK_BUTTON(button)->toggle_button.active; /* export */ if (dsFuncs[nodeInfo->conn->class].export) dsFuncs[nodeInfo->conn->class].export(nodeInfo, &exportOptions); else s_print("Data source does not seem to have export capabilities, yet."); gtk_widget_destroy(dWindow); } void ds_prune_tree(gpointer widget, gpointer data) { int i = data ? (int)data : 0; GtkWidget *treeItem = (GtkWidget *)widget; node_ds *nodeInfo; if (!treeItem) return; nodeInfo = (node_ds *)gtk_object_get_data(GTK_OBJECT(treeItem), "info"); if (!nodeInfo) return; ds_tree_node_destroy(&nodeInfo); gtk_object_remove_data(GTK_OBJECT(treeItem), "info"); if (GTK_TREE_ITEM_SUBTREE(treeItem)) { g_list_foreach(GTK_TREE(GTK_TREE_ITEM_SUBTREE(treeItem))->children, ds_prune_tree, (gpointer)(i+1)); gtk_tree_item_remove_subtree(GTK_TREE_ITEM(treeItem)); } if (!data) gtk_widget_destroy(treeItem); } int fetch_ds_key(char *name) { gpointer dbData; dbData = gtk_object_get_data(GTK_OBJECT(dbTree), name); if (dbData) { s_print("already connected in that context"); return(TRUE); } return(FALSE); } node_ds * fetch_selected() { GtkWidget *treeItem = gtk_object_get_data(GTK_OBJECT(dbTree), "selected"); if (!treeItem) return(NULL); return((node_ds *)gtk_object_get_data(GTK_OBJECT(treeItem), "info")); } char * get_entry_text(GtkWidget *widget, char *dbKey, int pass) { char *text = NULL; GtkWidget *entry; if (!widget) { g_print("get_entry_text got a NULL Widget for %s\n", dbKey); return(NULL); } if (pass) text = gtk_object_get_data(GTK_OBJECT(widget), dbKey); else { entry = get_widget(widget, dbKey); if (entry) text = gtk_entry_get_text(GTK_ENTRY(entry)); else g_print("could not fetch widget\n"); } return((text && text[0]) ? text : NULL); } GtkWidget* get_widget(GtkWidget *widget, char *widget_name) { GtkWidget *found_widget; if (widget->parent) widget = gtk_widget_get_toplevel(widget); found_widget = gtk_object_get_data(GTK_OBJECT(widget), widget_name); if (!found_widget) g_warning("Widget not found: %s", widget_name); return(found_widget); } /* gratuitously stolen from menu_factory */ void menu_parse_accel(const char *accelerator, char *accelerator_key, guint8 *accelerator_mods) { int done; g_return_if_fail (accelerator != NULL); g_return_if_fail (accelerator_key != NULL); g_return_if_fail (accelerator_mods != NULL); *accelerator_key = 0; *accelerator_mods = 0; done = FALSE; while (!done) { if (strncmp (accelerator, "", 7) == 0) { accelerator += 7; *accelerator_mods |= GDK_SHIFT_MASK; } else if (strncmp (accelerator, "", 5) == 0) { accelerator += 5; *accelerator_mods |= GDK_MOD1_MASK; } else if (strncmp (accelerator, "", 9) == 0) { accelerator += 9; *accelerator_mods |= GDK_CONTROL_MASK; } else { done = TRUE; *accelerator_key = accelerator[0]; } } } GtkWidget * new_dialog(char *title_window, char *title_frame) { GtkWidget *button; GtkWidget *dWindow; GtkWidget *frame; dWindow = gtk_dialog_new(); gtk_window_set_title(GTK_WINDOW(dWindow), title_window ? title_window : "Properties"); gtk_widget_set_usize(GTK_DIALOG(dWindow)->action_area, -1, 32); gtk_container_border_width(GTK_CONTAINER(GTK_DIALOG(dWindow)->action_area), 4); gtk_container_border_width(GTK_CONTAINER(GTK_DIALOG(dWindow)->vbox), 4); gtk_widget_show(dWindow); button = gtk_button_new_with_label("Ok"); gtk_signal_connect_object(GTK_OBJECT(button), "clicked", GTK_SIGNAL_FUNC(gtk_widget_destroy), GTK_OBJECT(dWindow)); gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dWindow)->action_area), button, TRUE, TRUE, 0); gtk_widget_show(button); frame = gtk_frame_new(title_frame ? title_frame : "Properties"); gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dWindow)->vbox), frame, TRUE, TRUE, 0); gtk_widget_show(frame); return(frame); } void on_dbTree_clicked(GtkWidget *treeItem, GdkEventButton *event, gpointer data) { node_ds *nodeInfo; GtkWidget *menu = NULL; nodeInfo = (node_ds *)gtk_object_get_data(GTK_OBJECT(treeItem), "info"); if (!nodeInfo) { g_print("treeItem had no info\n"); return; } gtk_object_set_data(GTK_OBJECT(dbTree), "selected", treeItem); switch(event->button) { case 3: switch(nodeInfo->type) { case Host: menu = dsMenus[nodeInfo->conn->class].host; break; case Database: menu = dsMenus[nodeInfo->conn->class].database; break; case Table: menu = dsMenus[nodeInfo->conn->class].table; break; case Field: break; } if (menu) gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, 0, event->time); break; } } void on_dbTree_select(GtkWidget *treeItem, gpointer data) { node_ds *nodeInfo = (node_ds *)data; if (!nodeInfo) return; switch(nodeInfo->type) { case Host: case Database: case Table: if (dsFuncs[nodeInfo->conn->class].refresh) dsFuncs[nodeInfo->conn->class].refresh(treeItem, nodeInfo); break; case Field: break; } } int s_print(char *string) { gtk_statusbar_pop(GTK_STATUSBAR(statusBar), 1); return(gtk_statusbar_push(GTK_STATUSBAR(statusBar), 1, string)); } GtkWidget * set_menu(dbxMenuEntry *menu_items, int nmenu_items) { GtkWidget *menu; GtkAcceleratorTable *table = NULL; int i; if (!menu_items) return(NULL); menu = gtk_menu_new(); for (i = 0; i < nmenu_items; i++) { if (menu_items[i].path) menu_items[i].widget = gtk_menu_item_new_with_label(menu_items[i].path); else menu_items[i].widget = gtk_menu_item_new(); if (menu_items[i].accelerator) { char accel_key; guint8 accel_mods; if (!table) table = gtk_accelerator_table_new (); menu_parse_accel(menu_items[i].accelerator, &accel_key, &accel_mods); #ifndef GTK_HAVE_FEATURES_1_1_0 gtk_widget_install_accelerator (menu_items[i].widget, table, "activate", accel_key, accel_mods); #endif } gtk_menu_append(GTK_MENU(menu), menu_items[i].widget); gtk_widget_show(menu_items[i].widget); if (menu_items[i].callback) gtk_signal_connect_object(GTK_OBJECT(menu_items[i].widget), "activate", GTK_SIGNAL_FUNC(menu_items[i].callback), menu_items[i].data); else gtk_widget_set_sensitive(menu_items[i].widget, FALSE); } if (table) { gtk_menu_set_accelerator_table(GTK_MENU(menu), table); gtk_window_add_accelerator_table(GTK_WINDOW(mainWindow), table); } return(menu); } void tree_refresh(GtkWidget *treeItem, node_ds *nodeInfo, int mark, char *name) { GtkWidget *subTree; GList *cTreeList; node_ds *cNodeInfo = NULL, *new_node; int cmp = -1, pos = -1; if (!treeItem) return; if (!(subTree = GTK_TREE_ITEM_SUBTREE(treeItem))) return; cTreeList = g_list_nth(GTK_TREE(subTree)->children, mark); if (cTreeList) { cNodeInfo = (node_ds *)gtk_object_get_data(GTK_OBJECT(cTreeList->data), "info"); if (!cNodeInfo) return; cmp = strcmp(name, cNodeInfo->name); pos = gtk_tree_child_position(GTK_TREE(subTree), cTreeList->data); } switch(cmp) { case -1: new_node = ds_tree_node_new(nodeInfo, name, nodeInfo->type + 1, nodeInfo->conn); ds_attach_tree_item(treeItem, new_node, pos); break; case 0: /* descend */ if (dsFuncs[nodeInfo->conn->class].refresh) dsFuncs[nodeInfo->conn->class].refresh(cTreeList->data, cNodeInfo); break; case 1: /* delete until we can go on */ ds_prune_tree(cTreeList->data, NULL); tree_refresh(treeItem, nodeInfo, mark, name); break; } } /* end of gtk.c */