Logo Search packages:      
Sourcecode: danpei version File versions  Download package

dirtree.c

/*
 * Danpei -- a GTK+ based Image Viewer
 * Copyright (C) 2001-2003 Shinji Moiino
 *
 * 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.
 */
/* dirtree.c */

#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <gdk/gdkx.h>
#include <gdk/gdkkeysyms.h>
#include <gtk/gtk.h>
#include <sys/stat.h>
#include <sys/types.h>

#include "config.h"
#include "dialog.h"
#include "dirtree.h"
#include "edit_menu.h"
#include "image_cache.h"
#include "intl.h"
#include "thumbnail_table.h"
#include "typedefs.h"
#include "version.h"
#include "viewer.h"

/* External variables. */
/* For drag and drop. -- defined in main.c */
extern const GtkTargetEntry dnd_te[];
extern gint  dnd_te_num;

/* Static variables declarations. */

/* Static function declarations. */
static void     dirtree_destroy_node    (gpointer         );

static gboolean dirtree_node_has_subdir  (gchar*         ,
                                          gboolean         );

static void     dirtree_cb_expand_node   (GtkCTree*      ,
                                          GList*         ,
                                          gpointer         );

static void     dirtree_cb_collapse_node (GtkCTree*      ,
                                          GList*         ,
                                          gpointer         );

static gboolean dirtree_cb_clicked       (GtkWidget*     , 
                                          GdkEventButton*, 
                                          gpointer         );

static gboolean dirtree_cb_key_pressed   (GtkWidget*     , 
                                          GdkEventKey*   , 
                                          gpointer         );

static gboolean dirtree_cb_drag_motion   (GtkWidget*     ,
                                          GdkDragContext*,
                                          gint           ,
                                          gint           ,
                                          guint          ,
                                          gpointer         );

static gboolean dirtree_cb_drag_drop     (GtkWidget*     ,
                                          GdkDragContext*,
                                          gint           ,
                                          gint           ,
                                          guint          ,
                                          gpointer         );

/* Function definitions. */
/*
 * @dirtree_create
 *
 *  Create a directory tree panel.
 *
 */
void dirtree_create (TopLevel *tp     ,
                     gchar    *top_dir  ) {
  GtkCTreeNode     *root_node, *node;
  NodeInfo         *nodeinfo;
  gchar            *dummy_node = "dummy";
  gboolean         ret;

  tp->dir_tree.scrolled_window = gtk_scrolled_window_new(NULL, NULL);
  gtk_scrolled_window_set_policy(
                  GTK_SCROLLED_WINDOW(tp->dir_tree.scrolled_window),
                  GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
  gtk_widget_show(tp->dir_tree.scrolled_window);

  tp->dir_tree.ctree = gtk_ctree_new(1, 0);
  gtk_clist_set_column_auto_resize(GTK_CLIST(tp->dir_tree.ctree), 0, TRUE);
  gtk_clist_set_selection_mode(GTK_CLIST(tp->dir_tree.ctree), 
                               GTK_SELECTION_BROWSE);
  gtk_ctree_set_line_style(GTK_CTREE(tp->dir_tree.ctree), 
                           GTK_CTREE_LINES_DOTTED);

  gtk_signal_connect(GTK_OBJECT(tp->dir_tree.ctree), 
                     "tree_expand",
                     GTK_SIGNAL_FUNC(dirtree_cb_expand_node), tp);
  gtk_signal_connect(GTK_OBJECT(tp->dir_tree.ctree), 
                     "tree_collapse",
                     GTK_SIGNAL_FUNC(dirtree_cb_collapse_node), tp);
  gtk_signal_connect(GTK_OBJECT(tp->dir_tree.ctree), 
                     "button_press_event",
                     GTK_SIGNAL_FUNC(dirtree_cb_clicked), tp);
  gtk_signal_connect(GTK_OBJECT(tp->dir_tree.ctree), 
                     "key_press_event",
                     GTK_SIGNAL_FUNC(dirtree_cb_key_pressed), tp);
  gtk_signal_connect(GTK_OBJECT(tp->dir_tree.ctree), 
                     "drag-drop",
                     GTK_SIGNAL_FUNC(dirtree_cb_drag_drop), tp);
  gtk_signal_connect(GTK_OBJECT(tp->dir_tree.ctree), 
                     "drag-motion",
                     GTK_SIGNAL_FUNC(dirtree_cb_drag_motion), tp);
  gtk_container_add(GTK_CONTAINER(tp->dir_tree.scrolled_window), 
                    tp->dir_tree.ctree                           );
  gtk_widget_show(tp->dir_tree.ctree);

  root_node = gtk_ctree_insert_node(GTK_CTREE(tp->dir_tree.ctree), 
                                    NULL, NULL, &top_dir, 4 ,
                                    tp->closed_folder_pixmap,
                                    tp->closed_folder_mask  ,
                                    tp->opened_folder_pixmap,
                                    tp->opened_folder_mask  , FALSE, FALSE);

  if((nodeinfo = (NodeInfo*)malloc(sizeof(NodeInfo))) == NULL) {
    /* Out of memory. */
    fprintf(stderr, "danpei: Out of memory.\n");
    fprintf(stderr, "        dirtree.c: error -- 01.\n");
    gtk_exit(-1);
  }
  tp->dir_tree.top_nodeinfo   = nodeinfo;
  tp->dir_tree.last_nodeinfo  = nodeinfo;

  nodeinfo->is_scan = FALSE;
  nodeinfo->prev = NULL;
  nodeinfo->next = NULL;

  if((nodeinfo->path = strdup(top_dir)) == NULL) {
    /* Out of memory. */
    fprintf(stderr, "danpei: Out of memory.\n");
    fprintf(stderr, "        dirtree.c: error -- 02.\n");
    gtk_exit(-1);
  }
  gtk_ctree_node_set_row_data_full(GTK_CTREE(tp->dir_tree.ctree), 
                                   root_node, nodeinfo, 
                                   dirtree_destroy_node);
  
  ret = dirtree_node_has_subdir(nodeinfo->path, 
                                tp->dot_file_on);
  if (ret == TRUE) {
    node = gtk_ctree_insert_node(GTK_CTREE(tp->dir_tree.ctree), 
                                 root_node, NULL, &dummy_node, 4, 
                                 NULL, NULL, NULL, NULL, TRUE, TRUE);
    gtk_ctree_node_set_row_data(GTK_CTREE(tp->dir_tree.ctree), node, NULL);
    gtk_ctree_expand(GTK_CTREE(tp->dir_tree.ctree), root_node);
  }

  return;
}

/*
 * @dirtree_directory_set_selected
 *
 *  Set the specified directory selected.
 *  -- When is_selected == TRUE, the dir will be set selected and
 *     display at the top of the scrolled window.
 *     Otherwise, this function will only expand the dirtree to the
 *     argument 'dir'.
 *
 */
void dirtree_directory_set_selected(TopLevel *tp        ,
                                    gchar    *dir       ,
                                    gboolean is_selected  ) {
  NodeInfo     *nodeinfo;
  GtkCTreeNode *node;
  gchar        *wk_top, *wk_dir;
  gint         wkgint;
  gboolean     ret;

  /* Get the root node. */
  node = gtk_ctree_node_nth(GTK_CTREE(tp->dir_tree.ctree), 0);
  if (node == NULL) return;

  wk_top = dir;
  while (wk_top[0] != '\0') {
    while ((wk_top[0] != '/') && (wk_top[0] != '\0')) { wk_top++; }
    if (wk_top == dir) {
      wk_dir = (gchar*)malloc(sizeof(gchar) * (strlen(dir) + 1));
      if (wk_dir == NULL) {
        /* Out of memory. */
        fprintf(stderr, "danpei: Out of memory.\n");
        fprintf(stderr, "        dirtree.c: error -- 03.\n");
        gtk_exit(-1);
      }
      else {
        strcpy(wk_dir, "/");
        wk_top++;
      }
    }
    else {
      wk_dir = (gchar*)malloc(sizeof(gchar) * (wk_top - dir + 1 + 1));
      if (wk_dir == NULL) {
        /* Out of memory. */
        fprintf(stderr, "danpei: Out of memory.\n");
        fprintf(stderr, "        dirtree.c: error -- 04.\n");
        gtk_exit(-1);
      }
      else {
        strncpy(wk_dir, dir, wk_top - dir);
        wk_dir[wk_top - dir] = '\0'; 
        if (wk_top[0] != '\0') { wk_top++; }
      }
    }

    nodeinfo = tp->dir_tree.top_nodeinfo;
    while(nodeinfo != NULL) {
      if (strcmp(nodeinfo->path, wk_dir) == 0) {
        break;
      }
      else {
        nodeinfo = nodeinfo->next;
      }
    }
    free(wk_dir);

    if (nodeinfo == NULL) { return; }

    /* Directory check. */
    if (chdir(nodeinfo->path) != 0) {
      switch (errno) {
        case ENOENT:
          dialog_error_dialog_create(FILE_NOT_EXISTS, nodeinfo->path,
                                     GTK_WINDOW(tp->window));
          dirtree_refresh(tp);
          break;

        case EACCES:
          dialog_error_dialog_create(PERMISSION_DENIED, nodeinfo->path,
                                     GTK_WINDOW(tp->window));
          break;

        default:
          dialog_error_dialog_create(CHANGE_DIRECTORY_ERROR, nodeinfo->path,
                                     GTK_WINDOW(tp->window));
          dirtree_refresh(tp);
          break;
      }
      return;
    }
    else {
      node = gtk_ctree_find_by_row_data(GTK_CTREE(tp->dir_tree.ctree), 
                                        GTK_CTREE_NODE(node), nodeinfo);
      if (node != NULL) {
        gtk_clist_freeze(GTK_CLIST(tp->dir_tree.ctree));
        ret = dirtree_node_has_subdir(nodeinfo->path, 
                                      tp->dot_file_on);
        if (ret == TRUE)
          gtk_ctree_expand(GTK_CTREE(tp->dir_tree.ctree), node);
          gtk_clist_thaw(GTK_CLIST(tp->dir_tree.ctree));
      }
      else {
        return;
      }
    }
  }

  if (is_selected == FALSE)
    return;

  /* Display the last directory of the path and set it selected. */
  wk_dir = (gchar*)malloc(sizeof(gchar) * (wk_top - dir + 1 + 1));
  if (wk_dir == NULL) {
    /* Out of memory. */
    fprintf(stderr, "danpei: Out of memory.\n");
    fprintf(stderr, "        dirtree.c: error -- 05.\n");
    gtk_exit(-1);
  }
  else {
    wk_top++;
    strncpy(wk_dir, dir, wk_top - dir);
    wk_dir[wk_top - dir] = '\0'; 
  }

  nodeinfo = tp->dir_tree.top_nodeinfo;
  while(nodeinfo != NULL) {
    if (strcmp(nodeinfo->path, wk_dir) == 0) {
      break;
    }
    else {
      nodeinfo = nodeinfo->next;
    }
  }
  free(wk_dir);
  node = gtk_ctree_find_by_row_data(GTK_CTREE(tp->dir_tree.ctree), 
                                    GTK_CTREE_NODE(node), nodeinfo);
  gtk_clist_freeze(GTK_CLIST(tp->dir_tree.ctree));
  gtk_ctree_select(GTK_CTREE(tp->dir_tree.ctree), GTK_CTREE_NODE(node));

  wkgint = 0;
  while(GTK_CTREE_NODE(node) != 
            gtk_ctree_node_nth(GTK_CTREE(tp->dir_tree.ctree), wkgint)) {
    wkgint++;
  }
  (GTK_CLIST(tp->dir_tree.ctree))->focus_row = wkgint;

  /* Display the specified node at the top od the scrolled window. */
  gtk_ctree_node_moveto(GTK_CTREE(tp->dir_tree.ctree), 
                        GTK_CTREE_NODE(node), 0, 0, 0);

  gtk_clist_thaw(GTK_CLIST(tp->dir_tree.ctree));

  return;
}

/*
 * @dirtree_directory_selected
 *
 *  Destroy the current ThumbnailTable, and create a new ThumbnailTable
 *  and display teh thumbnails.
 *  -- This function use cache files. At this point, this function is
 *     different from thumbnail_table_reload_all().
 *
 */
void dirtree_directory_selected(TopLevel *tp ,
                                gchar    *dir  ) {
  thumbnail_table_destroy_structure(&(tp->thumbnail_table));
  if ((tp->viewer).alive == TRUE) {
    gtk_widget_destroy((tp->viewer).window);
  }
 
  /* TRUE: Display the thumbnails from a head. */
  thumbnail_table_create(tp, dir, TRUE);
}

/*
 * @dirtree_refresh
 *
 *  Refresh the directory tree.
 *
 */
void dirtree_refresh(TopLevel *tp) {
  NodeInfo     *nodeinfo_old, *nodeinfo1, *nodeinfo2;
  GtkWidget    *ctree, *scrolled_window;
  GtkCTreeNode *node_old, *node_new, *node_root;
  gint         row1, row2;
  gboolean     is_leaf, is_expand;

  /* Initialize the local variables. */
  node_old = node_new  = node_root = NULL;
  row1     = row2      = 0;
  is_leaf  = is_expand = FALSE;

  /* Save the current directory tree. */
  scrolled_window              = tp->dir_tree.scrolled_window;
  ctree                        = tp->dir_tree.ctree;
  nodeinfo_old                 = tp->dir_tree.top_nodeinfo;
  tp->dir_tree.ctree           = NULL;
  tp->dir_tree.scrolled_window = NULL;

  /* Create new directory tree. */
  dirtree_create(tp, "/");
  node_root = gtk_ctree_node_nth(GTK_CTREE(tp->dir_tree.ctree), 0);

  gtk_clist_freeze(GTK_CLIST(tp->dir_tree.ctree));

  /* Compare new tree with current tree. */
  node_old = gtk_ctree_node_nth(GTK_CTREE(ctree), 0);
  while (node_old != NULL) {
    gtk_ctree_get_node_info(GTK_CTREE(ctree), node_old, NULL, NULL, NULL, 
                            NULL, NULL, NULL, &is_leaf, &is_expand);
    if (is_expand == TRUE) {
      nodeinfo1 = (NodeInfo*)(gtk_ctree_node_get_row_data(
                                             GTK_CTREE(ctree), node_old));
      row2 = 0;
      node_new = gtk_ctree_node_nth(GTK_CTREE(tp->dir_tree.ctree), row2);
      while(node_new != NULL) {
        nodeinfo2 = (NodeInfo*)(gtk_ctree_node_get_row_data(
                                    GTK_CTREE(tp->dir_tree.ctree), node_new));
        if ((nodeinfo1 != NULL) && (nodeinfo2 != NULL)) {
          if (strcmp(nodeinfo1->path, nodeinfo2->path) == 0) { break; }
        }
        row2++;
        node_new = gtk_ctree_node_nth(GTK_CTREE(tp->dir_tree.ctree), row2);
      }
      if (node_new != NULL) {
          gtk_ctree_expand(GTK_CTREE(tp->dir_tree.ctree), node_new);
      }
    }
    row1++;
    node_old = gtk_ctree_node_nth(GTK_CTREE(ctree), row1);
  } 
  
  gtk_clist_thaw(GTK_CLIST(tp->dir_tree.ctree));

  /* Destroy the current directory tree. */
  gtk_widget_destroy(ctree);
  gtk_widget_destroy(scrolled_window);

  /* Set drag and drop */
  gtk_drag_dest_set(tp->dir_tree.ctree  ,
                    GTK_DEST_DEFAULT_ALL,
                    dnd_te, dnd_te_num  ,
                    GDK_ACTION_ASK  | GDK_ACTION_COPY | 
                    GDK_ACTION_MOVE | GDK_ACTION_LINK    );

  /* About the new tree, set the current directory selected. */
  dirtree_directory_set_selected(tp, tp->thumbnail_table.dir_name, TRUE);
  gtk_paned_add1(GTK_PANED(tp->hpaned), tp->dir_tree.scrolled_window);

  return;
}

/*
 * @dirtree_set_directory_non_hilighted
 *
 *  Set the directory ,which is high-lited by drag and drop operation, 
 *  non-high-lighted.
 *
 */
void dirtree_set_directory_non_hilighted(TopLevel *tp) {
  gtk_clist_set_foreground(
                GTK_CLIST(tp->dir_tree.ctree), 
                tp->dnd_selected_row,
                &((tp->dir_tree.ctree)->style->fg[GTK_STATE_NORMAL]));
  gtk_clist_set_background(
                GTK_CLIST(tp->dir_tree.ctree), 
                tp->dnd_selected_row,
                &((tp->dir_tree.ctree)->style->bg[GTK_STATE_NORMAL]));
  gtk_clist_set_background(
                GTK_CLIST(tp->dir_tree.ctree), 
                tp->dnd_selected_row,
                &((tp->dir_tree.ctree)->style->base[GTK_STATE_NORMAL]));

  return;
}

/* Static function definitions. */
/*
 * @dirtree_destroy_node
 *
 *  Free the NodeInfo structure object.
 *  This function will be called when a node is destoied.
 *
 */
static void dirtree_destroy_node(gpointer data) {
  NodeInfo *nodeinfo;

  /* Initialize the local variables. */
  nodeinfo = (NodeInfo*)data;

  if (nodeinfo->next != NULL) {
    (nodeinfo->next)->prev = nodeinfo->prev;
  }
  if (nodeinfo->prev != NULL) {
    (nodeinfo->prev)->next = nodeinfo->next;
  }
  free(nodeinfo->path);
  free(nodeinfo);

  return;
}

/*
 * @dirtree_node_has_subdir
 *
 *  Return TRUE when the directory specified by '*path' has sub
 *  directory(ies).
 *
 */
static gboolean dirtree_node_has_subdir(gchar    *path      ,
                                        gboolean dot_file_on  ) {
  gint          wkgint;
  gchar         *full_path;
  DIR           *dirp;
  struct stat   sb;
  struct dirent *ent;
  
  if ((dirp = opendir(path)) == NULL) { return FALSE; }

  while((ent = readdir(dirp)) != NULL) {
    full_path = (gchar*)malloc(sizeof(gchar) *
                               (strlen(path)        +
                                strlen("/")         +
                                strlen(ent->d_name) + 1));
    if (full_path == NULL) {
      /* Out of memory. */
      fprintf(stderr, "danpei: Out of memory.\n");
      fprintf(stderr, "        dirtree.c: error -- 06.\n");
      gtk_exit(-1);
    }
    else {
      sprintf(full_path, "%s/%s", path, ent->d_name);
      if ((!strcmp(ent->d_name, ".")) || (!strcmp(ent->d_name, ".."))) ;
      else {
        if ((dot_file_on == TRUE)                              ||
            ((dot_file_on == FALSE) && (ent->d_name[0] != '.'))   ) {
          if ((wkgint = stat(full_path, &sb)) < 0) {
            free(full_path);
            break;
          }
          else {
            if (S_ISDIR(sb.st_mode)) {
              free(full_path); closedir(dirp);
              return TRUE;
            }
          }
        }
      }
    }
    free(full_path);
  }
  closedir(dirp);

  return FALSE;
}

/* Callback function definitions. */
/*
 * @dirtree_cb_expand_node
 *
 *  Expand the directory which was double clicked.
 *
 */
static void dirtree_cb_expand_node(GtkCTree *ctree, 
                                   GList    *node , 
                                   gpointer data    ) {
  TopLevel      *tp;
  DIR           *dirp;
  struct dirent *ent;
  struct stat   sb;
  gchar         *full_path, *wk_name;
  gchar         *dummy_node_str = "dummy";
  gint          wkgint;
  NodeInfo      *parent_nodeinfo, *nodeinfo;
  GtkCTreeNode  *wk_node, *dummy_node;
  gboolean      is_leaf, is_expanded, ret;

  tp = (TopLevel*)data;

  parent_nodeinfo = gtk_ctree_node_get_row_data(ctree, 
                                                GTK_CTREE_NODE(node));
  if(parent_nodeinfo == NULL) { return; }

  gtk_ctree_get_node_info(ctree, 
                          GTK_CTREE_NODE(node),
                          NULL, NULL, NULL, NULL, NULL, NULL, 
                          &is_leaf, &is_expanded);

/**************************************************************
  if ((is_leaf == TRUE) || (is_expanded == TRUE)) { return; }
**************************************************************/
  if (is_expanded == TRUE) { return; }

  if (parent_nodeinfo->is_scan == FALSE) {
    wk_node = gtk_ctree_find_by_row_data(ctree,
                                         GTK_CTREE_NODE(node), NULL);
    if(wk_node == NULL) {
      return;
    }
    else {
      gtk_ctree_remove_node(ctree, wk_node);
      parent_nodeinfo->is_scan = TRUE;
      dirp = opendir(parent_nodeinfo->path);
      if (dirp == NULL) { return; }
    }
    gtk_clist_freeze(GTK_CLIST(ctree));
    while((ent = readdir(dirp)) != NULL) {
      wk_name = strdup(ent->d_name);
      if (wk_name == NULL) {
        /* Out of memory. */
        fprintf(stderr, "danpei: Out of memory.\n");
        fprintf(stderr, "        dirtree.c: error -- 07.\n");
        gtk_exit(-1);
      }
      full_path = (gchar*)malloc(sizeof(gchar) * 
                                 (strlen(parent_nodeinfo->path) +
                                  strlen("/")                   +
                                  strlen(ent->d_name)           + 1));
      if (full_path == NULL) {
        /* Out of memory. */
        fprintf(stderr, "danpei: Out of memory.\n");
        fprintf(stderr, "        dirtree.c: error -- 08.\n");
        gtk_exit(-1);
      }
      strcpy(full_path, parent_nodeinfo->path);
      if (strcmp(full_path, "/") != 0) { strcat(full_path, "/"); }
      strcat(full_path, ent->d_name);

      if ((!strcmp(ent->d_name, ".")) || (!strcmp(ent->d_name, ".."))) ;
      else {
        if ((wkgint = stat(full_path, &sb)) < 0) ;
        else {
          if ((tp->dot_file_on  == TRUE      ) ||
              ((tp->dot_file_on == FALSE) &&
               (ent->d_name[0] != '.')               )    ) {
            if (S_ISDIR(sb.st_mode)) {
              wk_node = gtk_ctree_insert_node(GTK_CTREE(ctree), 
                                              GTK_CTREE_NODE(node), 
                                              NULL, &wk_name, 4,
                                              tp->closed_folder_pixmap, 
                                              tp->closed_folder_mask  ,
                                              tp->opened_folder_pixmap,
                                              tp->opened_folder_mask  ,
                                              FALSE, FALSE              );
              nodeinfo = (NodeInfo*)malloc(sizeof(NodeInfo));
              if(nodeinfo == NULL) {
                /* Out of memory. */
                fprintf(stderr, "danpei: Out of memory.\n");
                fprintf(stderr, "        dirtree.c: error -- 09.\n");
                gtk_exit(-1);
              }
              nodeinfo->is_scan = FALSE;
              nodeinfo->prev    = (tp->dir_tree).last_nodeinfo;
              nodeinfo->next    = NULL;
              (tp->dir_tree.last_nodeinfo)->next = nodeinfo;
              (tp->dir_tree).last_nodeinfo       = nodeinfo;
              if((nodeinfo->path = strdup(full_path)) == NULL) {
                /* Out of memory. */
                fprintf(stderr, "danpei: Out of memory.\n");
                fprintf(stderr, "        dirtree.c: error -- 10.\n");
                gtk_exit(-1);
              }
              gtk_ctree_node_set_row_data_full(GTK_CTREE(ctree) , 
                                               wk_node, nodeinfo,
                                               dirtree_destroy_node);
              ret = dirtree_node_has_subdir(nodeinfo->path,
                                            tp->dot_file_on);
              if (ret == TRUE) {
                dummy_node = gtk_ctree_insert_node(GTK_CTREE(ctree), 
                                                   wk_node         , NULL, 
                                                   &dummy_node_str , 4   , 
                                                   NULL, NULL, NULL, NULL, 
                                                   FALSE, FALSE           );
                gtk_ctree_node_set_row_data(GTK_CTREE(ctree),  
                                            dummy_node      , NULL);
              }
            }
          }
        }
      }
      free(wk_name);
      free(full_path);
    }
    closedir(dirp);
    gtk_ctree_sort_node(GTK_CTREE(ctree), GTK_CTREE_NODE(node));
    gtk_ctree_select(ctree, GTK_CTREE_NODE(node));
    wkgint = 0;
    while(GTK_CTREE_NODE(node) != 
              gtk_ctree_node_nth(GTK_CTREE(ctree), wkgint)) { wkgint++; }
    GTK_CLIST(ctree)->focus_row = wkgint;
    gtk_clist_thaw(GTK_CLIST(ctree));
  }  

  return;
}

/*
 * @dirtree_cb_collapse_node
 *
 *  Set the collapsed node selected(focused & hilighted).
 *
 */
static void dirtree_cb_collapse_node (GtkCTree *ctree, 
                                      GList    *node , 
                                      gpointer data    ) {
  TopLevel      *tp;

  /* Initialize the local variables. */
  tp = (TopLevel*)data;

  gtk_ctree_select(GTK_CTREE(tp->dir_tree.ctree), GTK_CTREE_NODE(node));

  return;
}

/*
 * @dirtree_cb_clicked
 *
 *
 *
 */
static gboolean dirtree_cb_clicked(GtkWidget      *widget, 
                                   GdkEventButton *ev    , 
                                   gpointer       data     ) {
  TopLevel     *tp;
  NodeInfo     *nodeinfo;
  GtkCTreeNode *node;
  gint         row;

  tp = (TopLevel*)data;

  gtk_clist_get_selection_info(GTK_CLIST(widget), 
                               ev->x, ev->y, &row, NULL);
  node = gtk_ctree_node_nth(GTK_CTREE(widget), row);
  if (node == NULL) { return FALSE; }

  nodeinfo = gtk_ctree_node_get_row_data(GTK_CTREE(widget), node);

  if (nodeinfo == NULL) { return FALSE; }

  if (access(nodeinfo->path, F_OK) != 0) {
    dialog_error_dialog_create(DIRECTORY_NOT_EXISTS, nodeinfo->path,
                               GTK_WINDOW(tp->window));
    dirtree_refresh(tp);
    return FALSE;
  }

  /* When double clicked, create a new thumbnail table. */
  if ((ev->type == GDK_2BUTTON_PRESS) && (ev->button == 1)) {
    /* If the clicked directory has sub directory(ies), GtkCList widget
     * will be grab all of the mouse event.
     * To this, call gdk_pointer_ungrab().
     */
    gdk_pointer_ungrab(GDK_CURRENT_TIME);
    dirtree_directory_selected(tp, nodeinfo->path);
  }

  /* When right button clicked, dirtree menu pop-up. */
  if ((ev->type == GDK_BUTTON_PRESS) && (ev->button == 3)) {
    tp->dnd_selected_row = row;
    gtk_clist_set_foreground(GTK_CLIST(widget), row,
                &(GTK_WIDGET(widget)->style->fg[GTK_STATE_PRELIGHT]));
    gtk_clist_set_background(GTK_CLIST(widget), row,
                &(GTK_WIDGET(widget)->style->bg[GTK_STATE_PRELIGHT]));
    gtk_item_factory_popup(tp->popup_dirtree.item_factory, 
                           ev->x_root, ev->y_root, 2, GDK_CURRENT_TIME);
  }

  return FALSE;
}

/*
 * @dirtree_cb_key_pressed
 *
 *
 *
 */
static gboolean dirtree_cb_key_pressed(GtkWidget   *widget, 
                                       GdkEventKey *ev    , 
                                       gpointer    data     ) {
  TopLevel     *tp;
  NodeInfo     *nodeinfo;
  GtkCTreeNode *node;
  gboolean     ret;

  tp = (TopLevel*)data;

  node = gtk_ctree_node_nth(GTK_CTREE(widget), 
                            GTK_CLIST(widget)->focus_row);
  if (node == NULL) { return FALSE; }

  nodeinfo = gtk_ctree_node_get_row_data(GTK_CTREE(widget), node);

  if (nodeinfo == NULL) { return FALSE; }

  if (access(nodeinfo->path, F_OK) != 0) {
    dialog_error_dialog_create(DIRECTORY_NOT_EXISTS, nodeinfo->path,
                               GTK_WINDOW(tp->window));
    dirtree_refresh(tp);
    return FALSE;
  }

  switch (ev->keyval) {
    case GDK_Left:
      if (nodeinfo != NULL) {
        gtk_clist_freeze(GTK_CLIST(widget));
        ret = dirtree_node_has_subdir(nodeinfo->path,
                                      tp->dot_file_on);
        if (ret == TRUE)
          gtk_ctree_collapse(GTK_CTREE(widget), node);

        gtk_clist_thaw(GTK_CLIST(widget));
      }
      break;

    case GDK_Right:
      if (nodeinfo != NULL) {
        gtk_clist_freeze(GTK_CLIST(widget));
        ret = dirtree_node_has_subdir(nodeinfo->path,
                                      tp->dot_file_on);
        if (ret == TRUE)
          gtk_ctree_expand(GTK_CTREE(widget), node);

        gtk_clist_thaw(GTK_CLIST(widget));
      }
      break;

    case GDK_Return:
      if (nodeinfo != NULL) {
        dirtree_directory_selected(tp, nodeinfo->path);
      }
      break;

    case GDK_Delete:
      if (nodeinfo != NULL) {
        directory_menu_cb_remove(NULL, tp, 0);
      }
      break;
  }

  return FALSE;
}

/*
 * @dirtree_cb_drag_motion
 *
 *  High-light the folder icon on which the mouse cursor is now.
 *
 */
static gboolean dirtree_cb_drag_motion(GtkWidget      *widget      ,
                                       GdkDragContext *drag_context,
                                       gint           x            ,
                                       gint           y            ,
                                       guint          time         ,
                                       gpointer       data           ) {
  TopLevel     *tp;
  NodeInfo     *nodeinfo;
  GtkCTreeNode *node;
  gint         row;

  /* Initialize th elocal variables. */
  tp       = (TopLevel*)data;
  nodeinfo = NULL;
  node     = NULL;
  row      = 0;

  /* Get the node which the mouse cursor on. */
  gtk_clist_get_selection_info(GTK_CLIST(widget), x, y, &row, NULL);
  node = gtk_ctree_node_nth(GTK_CTREE(widget), row);
  if (node == NULL) { return FALSE; }

  nodeinfo = gtk_ctree_node_get_row_data(GTK_CTREE(widget), node);

  if (tp->dnd_selected_row != row) {
    if (tp->dnd_selected_row != -1) {
      dirtree_set_directory_non_hilighted(tp);
    }
    gtk_clist_set_foreground(GTK_CLIST(widget), row,
                              &(widget->style->fg[GTK_STATE_PRELIGHT]));
    gtk_clist_set_background(GTK_CLIST(widget), row,
                              &(widget->style->bg[GTK_STATE_PRELIGHT]));
  }
  tp->dnd_selected_row = row;

  return FALSE;
}

/*
 * @dirtree_cb_drag_drop
 *
 *  Copy files which are selected to the drag-droped directory.
 *
 */
static gboolean dirtree_cb_drag_drop(GtkWidget      *widget ,
                                     GdkDragContext *context,
                                     gint           x       ,
                                     gint           y       ,
                                     guint          time    ,
                                     gpointer       data      ) {
  TopLevel        *tp;
  Thumbnail       *thumb, *save_thumb;
  gchar           *src, *dest;
  gint            wkgint1, wkgint2, wkgint3;
  GtkCTreeNode    *node;
  NodeInfo        *nodeinfo;
  AppDialogResult ret;
  gchar           *progressbar_msg[] = { "     "                        ,
                                         N_("  Moving files now ...  ") ,
                                         "     "                        ,
                                         ""                               };


  /* Initialize the local variables. */
  tp       = (TopLevel*)data;
  thumb    = save_thumb = NULL;
  src      = dest       = NULL;
  wkgint1  = wkgint2    = wkgint3 = 0;
  node     = NULL;
  nodeinfo = NULL;
  ret      = APP_RET_CANCEL;

  /* If 'src' directory equal 'dest' directory, then return doing 
   * nothing.
   */
  if (GTK_CLIST(tp->dir_tree.ctree)->focus_row == tp->dnd_selected_row) {
    return FALSE;
  }

  /* Get 'dest' directory. */
  node = gtk_ctree_node_nth(GTK_CTREE(tp->dir_tree.ctree),
                            tp->dnd_selected_row);
  if (node == NULL) { return FALSE; }

  nodeinfo = gtk_ctree_node_get_row_data(GTK_CTREE(tp->dir_tree.ctree), node);
  if (nodeinfo == NULL) { return FALSE; }

  /* Count selected thumbnails. */
  thumb = save_thumb = tp->thumbnail_table.top_thumbnail;
  for (wkgint3 = 0; wkgint3 < tp->thumbnail_table.start_pos; wkgint3++) {
    thumb = thumb->next;
  }
  save_thumb = thumb;
  while (thumb != NULL) {
    if ((thumb->selected == TRUE) && (thumb->disabled == FALSE)) {
      wkgint2++;
    }
    thumb = thumb->next;
  }
  
  /* Create progressbar dialog. */
  tp->progressbar_dialog.window = GTK_WINDOW(tp->window);
  dialog_progressbar_dialog_create(progressbar_msg,
                                   &(tp->progressbar_dialog));

  /* Pasted. */
  tp->all_yes = FALSE;
  thumb = save_thumb;
  while (thumb != NULL) {
    /* Update the progressbar dialog. */
    if (tp->progressbar_dialog.is_cancel == TRUE) {
      thumb = NULL;
      break;
    }
    if ((thumb->selected == TRUE) && (thumb->disabled == FALSE)) {
      dialog_progressbar_dialog_update(&(tp->progressbar_dialog),
                                       wkgint1, wkgint2);
      src = (gchar*)malloc(sizeof(gchar) *
                           (strlen(thumb->path)     +
                            strlen("/")             +
                            strlen(thumb->filename) + 1));
      if (src == NULL) {
        /* Out of memory. */
        fprintf(stderr, "danpei: Out of memory.\n");
        fprintf(stderr, "        dirtree.c: error -- 11.\n");
        gtk_exit(-1);
      }
      else {
        sprintf(src, "%s/%s", thumb->path, thumb->filename);
      }

      dest = (gchar*)malloc(sizeof(gchar) *
                            (strlen(nodeinfo->path)  +
                             strlen("/")             +
                             strlen(thumb->filename) + 1));
      if (dest == NULL) {
        /* Out of memory. */
        fprintf(stderr, "danpei: Out of memory.\n");
        fprintf(stderr, "        dirtree.c: error -- 12.\n");
        gtk_exit(-1);
      }
      else {
        sprintf(dest, "%s/%s", nodeinfo->path, thumb->filename);
      }

      ret = APP_RET_OK;
      if (tp->app_option.dialog.overwrite == TRUE) {
        if ((access(dest, F_OK) == 0) && (tp->all_yes == FALSE)) {
          ret = dialog_message_dialog_create(FILE_OVERWRITTEN,
                                             thumb->filename,
                                             APP_OK_CANCEL_SKIP_ALL_DIALOG,
                                             APP_CANCEL_BUTTON,
                                             GTK_WINDOW(tp->window));
        }
      }
      if ((ret == APP_RET_OK) || (ret == APP_RET_OK_ALL)) {
        if (ret == APP_RET_OK_ALL) { tp->all_yes = TRUE; }
        if (edit_menu_copy_file(dest, src, tp) == TRUE) {
          if (remove(src) == 0) {
            if (tp->app_option.image_cache.cache_on == TRUE) {
              /* Rename the cache file, src to dest. */
              image_cache_rename(&(tp->cache), src, dest);
            }
            thumbnail_change_link(&(tp->thumbnail_table), thumb);
            if (GTK_IS_WIDGET(thumb->ev_box) == TRUE) {
              gtk_widget_destroy(thumb->ev_box);
            }
            thumbnail_free_structure(thumb);
            thumbnail_count_selected_thumbnails(tp, -1);
          }
          else {
            dialog_message_dialog_create(COPY_INSTEAD, src ,
                                         APP_OK_ONLY_DIALOG,
                                         APP_OK_BUTTON     ,
                                         GTK_WINDOW(tp->window));
          }
        }
      }
      else {
        if (ret != APP_RET_SKIP) {
          free(src); free(dest);
          break;
        }
      }
      free(src); free(dest);
      wkgint1++;
    }
    thumb = thumb->next;
  }
  dialog_progressbar_dialog_destroy(&(tp->progressbar_dialog));
  tp->all_yes = FALSE;
  dirtree_set_directory_non_hilighted(tp);

  /* Refresh the current thumbnail table. */
  thumbnail_table_refresh(tp);

  return FALSE;
}


Generated by  Doxygen 1.6.0   Back to index