/* location.c This file is part of "Pharmacy: A GNOME CVS front-end" Copyright 1998 Reklaw (N. Adam Walker) "Pharmacy" is released under the GPL See the LICENCE for more details. */ #include #include #include #include #include "pharmacy.h" #include "filelist.h" #include "dirtree.h" #define NODE_SIG 93 static LocationData *pLastLocation = NULL; static gchar mk_slashes (gchar * pgcDir) { const int count = strlen (pgcDir); gchar slashes = 0; register int i; g_assert (pgcDir); for (i = 0; i < count; i++) { if (pgcDir[i] == '/') slashes++; } return slashes; } static guint mk_hash (gchar * pgcDir) { const int count = strlen (pgcDir); register guint hash = 0; register int i; g_assert (pgcDir); for (i = 0; i < count; i++) { hash += pgcDir[i]; } return hash; } void dirtreenode_set_dir (DirTreeNode * pNode, gchar * pgcDir) { if (pgcDir) { if (pNode) { if (pNode->pgcDir) g_free (pNode->pgcDir); pNode->pgcDir = g_strdup (pgcDir); pNode->nSlashes = mk_slashes (pgcDir); pNode->nLetters = strlen (pgcDir); pNode->nHash = mk_hash (pgcDir); } } else { if (pNode) { if (pNode->pgcDir) g_free (pNode->pgcDir); pNode->pgcDir = NULL; pNode->nSlashes = 0; pNode->nLetters = 0; pNode->nHash = 0; } } } gpointer dirtreenode_new () { DirTreeNode *pNode = g_malloc (sizeof (DirTreeNode)); pNode->pgcDir = NULL; pNode->pgcName = NULL; pNode->nLetters = pNode->nSlashes = 0; pNode->nHash = 0; pNode->pData = NULL; pNode->sig = NODE_SIG; pNode->uiRef = 1; return pNode; } void dirtreenode_free (DirTreeNode * pNode) { if (pNode) { pNode->uiRef--; if (pNode->uiRef <= 0) { /* Delete the Node */ g_free (pNode->pgcDir); g_free (pNode->pgcName); g_free (pNode); } } } DirTreeNode * dirtreenode_add_ref (DirTreeNode * pNode) { g_assert (pNode); pNode->uiRef++; return pNode; } gpointer dirtreenode_new_root (LocationData * pLoc) { DirTreeNode *pNode = dirtreenode_new (); g_assert (pLoc); dirtreenode_set_dir (pNode, pLoc->pgcWorkDir); pNode->pData = pLoc; return pNode; } static gint dirtreenode_cmp (DirTreeNode * pNode1, DirTreeNode * pNode2) { gint rc = 0; g_assert (pNode1); g_assert (pNode2); if (pNode1->sig == NODE_SIG && pNode2->sig == NODE_SIG) { if (pNode1->nLetters == pNode2->nLetters) { if (pNode1->nSlashes == pNode2->nSlashes) { if (pNode1->nHash == pNode2->nHash) { if (strcmp (pNode1->pgcDir, pNode2->pgcDir)) { g_warning ("dirtreenode_cmp: Hashing failed!!! %i %i %i", pNode1->nLetters, pNode1->nSlashes, pNode1->nHash); } else { rc = 1; } } } } } return rc; } /* Callback: Removes duplicates from the tree. */ static void cleanse (GtkCTree * ctree, GtkCTreeNode * node, DirTreeNode * pCmp) { DirTreeNode *pNode = NULL; if (ctree && node && pCmp) { pNode = (DirTreeNode *) gtk_ctree_node_get_row_data (ctree, node); if (pNode) { if (dirtreenode_cmp (pNode, pCmp)) { gtk_ctree_remove_node (ctree, node); } } } } static void purge_cb (GtkCTree * ctree, GtkCTreeNode * node, gpointer dontcare) { if (ctree && node) { gtk_ctree_remove_node (ctree, node); } } /* Kill everything in the tree */ void dirtree_purge (GtkCTree * ctree, GtkCTreeNode * node) { if (ctree) { gtk_ctree_post_recursive (ctree, node, GTK_CTREE_FUNC (purge_cb), NULL); } } /* Fill the tree with directories */ gint dirtree_fill_tree (GtkCTree * pTree, GtkCTreeNode * pList, const gchar * pgcDir, gint nMax, gint nLevel) { GtkCTreeNode *pItem = NULL; DIR *pDir = NULL; struct dirent *pEntry; gint bCont = TRUE; gint i = 0; gint nAllocated = 0; gint nNeeded = 0; gchar *pgcNextDir = NULL; struct stat sStat; gchar *paText[2]; gint test; DirTreeNode *pdtNode = NULL; gnome_appbar_push (pharmacy_get_appbar (), _ ("Loading directory tree...")); paText[1] = NULL; pgcNextDir = malloc (sizeof (char) * 255); pDir = opendir (pgcDir); if (pDir) { while (bCont) { /* Let window updates happen */ gdk_flush (); pEntry = readdir (pDir); if (pEntry) { /* Not . or .. or CVS */ if (pEntry->d_name[0] != '.' && strcmp (pEntry->d_name, _ ("CVS"))) { paText[0] = pEntry->d_name; nNeeded = strlen (pgcDir) + strlen (pEntry->d_name) + 2; if (nNeeded > nAllocated) { nAllocated = nNeeded; free (pgcNextDir); pgcNextDir = malloc (sizeof (gchar) * nNeeded); } sprintf (pgcNextDir, "%s%s", pgcDir, pEntry->d_name); if (!stat (pgcNextDir, &sStat)) { test = S_ISDIR (sStat.st_mode); if (test) { pdtNode = dirtreenode_new (); pdtNode->pgcName = g_strdup (pEntry->d_name); strcat (pgcNextDir, "/"); dirtreenode_set_dir (pdtNode, pgcNextDir); pdtNode->pData = pLastLocation; gtk_ctree_post_recursive (pTree, pList, GTK_CTREE_FUNC (cleanse), pdtNode); pItem = gtk_ctree_insert_node (pTree, pList, NULL, paText, 4, NULL, NULL, NULL, NULL, FALSE, FALSE); gtk_ctree_node_set_row_data (pTree, pItem, pdtNode); if (nLevel < nMax) { dirtree_fill_tree (pTree, pItem, pgcNextDir, nMax, nLevel + 1); } } } } } else { bCont = FALSE; } } closedir (pDir); } free (pgcNextDir); pgcNextDir = NULL; /* saftey */ gtk_ctree_sort_node (pTree, pList); gtk_widget_show (GTK_WIDGET (pTree)); gnome_appbar_pop (pharmacy_get_appbar ()); return TRUE; } /* Signal: tree_select_row from GtkCTree */ static void dirtree_select_row (GtkCTree * ctree, GtkCTreeNode * row, gint column) { DirTreeNode *pNode = NULL; /* LocationData* pData = NULL; */ gdk_flush(); if (ctree && row) { pNode = (DirTreeNode *) gtk_ctree_node_get_row_data (ctree, row); if (pNode) { console_set_node (pharmacy_get_console (), pNode); /* Clean up */ filelist_cleanse (pharmacy_get_filelist()); filelist_build_list (FILE_LIST (pharmacy_get_filelist ()), pNode); gtk_label_set_text(GTK_LABEL(PHARMACY(pharmacy_get_app()) ->dir_label), pNode->pgcDir); gdk_flush(); } } pharmacy_update_ui ("row-select"); } static void dirtree_unselect_row (GtkCTree * ctree, GList * row, gint column) { console_set_node (pharmacy_get_console (), NULL); pharmacy_update_ui ("row-unselect"); } /* Callback: Recursivly add directories to the tree as it is expanded. */ static GtkCTreeNode * load_more (GtkCTree * ctree, GtkCTreeNode * node, gpointer data) { DirTreeNode *pdtNode = NULL; if (node != data) { /*dirtree_fill_tree */ pdtNode = (DirTreeNode *) gtk_ctree_node_get_row_data (ctree, node); if (pdtNode) { dirtree_fill_tree (ctree, node, pdtNode->pgcDir, 0, 0); } } } /* Signal: tree_expand from GtkCTree */ static void dirtree_expand (GtkCTree * pTree, GtkCTreeNode * pNode) { g_debug_message ("Expanded\n"); /* post order!!!! very important!!!! */ gtk_ctree_post_recursive (pTree, pNode, GTK_CTREE_FUNC (load_more), pNode); } /* Connect signals and whatnot */ void dirtree_init (GtkCTree * pTree) { g_assert (pTree != NULL); gtk_signal_connect (GTK_OBJECT (pTree), "tree_select_row", GTK_SIGNAL_FUNC (dirtree_select_row), NULL); gtk_signal_connect (GTK_OBJECT (pTree), "tree_unselect_row", GTK_SIGNAL_FUNC (dirtree_unselect_row), NULL); gtk_signal_connect (GTK_OBJECT (pTree), "tree_expand", GTK_SIGNAL_FUNC (dirtree_expand), NULL); } #define CONFIG_MW_DIRTREE_WIDTH "/pharmacy/Main Window/dirtreewidth" #define CONFIG_MW_DIRTREE_HEIGHT "/pharmacy/Main Window/dirtreeheight" void dirtree_load_size (GtkWidget * pWidget) { gint16 nWidth; gint16 nHeight; g_assert(pWidget && GTK_IS_WIDGET(pWidget)); nWidth = gnome_config_get_int (CONFIG_MW_DIRTREE_WIDTH); nHeight = gnome_config_get_int (CONFIG_MW_DIRTREE_HEIGHT); if (nWidth == 0) nWidth = 200; if (nHeight == 0) nHeight = 200; gtk_widget_set_usize(pWidget,nWidth,nHeight); } void dirtree_save_size (GtkWidget * pWidget) { gint nWidth, nHeight; g_assert(pWidget && GTK_IS_WIDGET(pWidget)); /* Is there a better way to get these ? */ nWidth = pWidget->allocation.width; nHeight = pWidget->allocation.height; gnome_config_set_int (CONFIG_MW_DIRTREE_WIDTH, nWidth); gnome_config_set_int (CONFIG_MW_DIRTREE_HEIGHT, nHeight); } void dirtree_set_last_location (LocationData * pData) { pLastLocation = pData; }