diff --git a/src/cmd.c b/src/cmd.c index 84f6e071a..fa9965030 100644 --- a/src/cmd.c +++ b/src/cmd.c @@ -37,7 +37,7 @@ #include "global.h" #include "cmd.h" /* Our definitions */ #include "fileopctx.h" /* file_op_context_new() */ -#include "file.h" /* copy_file_file() */ +#include "file.h" /* file operation routines */ #include "find.h" /* do_find() */ #include "hotlist.h" /* hotlist_cmd() */ #include "tree.h" /* tree_chdir() */ @@ -1197,13 +1197,21 @@ single_dirsize_cmd (void) file_entry *entry; off_t marked; double total; + ComputeDirSizeUI *ui; + + ui = compute_dir_size_create_ui (); entry = &(panel->dir.list[panel->selected]); if (S_ISDIR (entry->st.st_mode) && strcmp(entry->fname, "..") != 0) { total = 0.0; - compute_dir_size (entry->fname, &marked, &total); - entry->st.st_size = (off_t) total; - entry->f.dir_size_computed = 1; + + if (compute_dir_size (entry->fname, ui, compute_dir_size_update_ui, + &marked, &total) == FILE_CONT) { + entry->st.st_size = (off_t) total; + entry->f.dir_size_computed = 1; + } + + compute_dir_size_destroy_ui (ui); } if (mark_moves_down) @@ -1213,25 +1221,35 @@ single_dirsize_cmd (void) panel->dirty = 1; } -void +void dirsizes_cmd (void) { WPanel *panel = current_panel; int i; off_t marked; double total; + ComputeDirSizeUI *ui; + + ui = compute_dir_size_create_ui (); for (i = 0; i < panel->count; i++) - if (S_ISDIR (panel->dir.list [i].st.st_mode) && - ((panel->dirs_marked && panel->dir.list [i].f.marked) || - !panel->dirs_marked) && - strcmp (panel->dir.list [i].fname, "..") != 0) { + if (S_ISDIR (panel->dir.list [i].st.st_mode) + && ((panel->dirs_marked && panel->dir.list [i].f.marked) + || !panel->dirs_marked) + && strcmp (panel->dir.list [i].fname, "..") != 0) { total = 0.0l; - compute_dir_size (panel->dir.list [i].fname, &marked, &total); + + if (compute_dir_size (panel->dir.list [i].fname, + ui, compute_dir_size_update_ui, + &marked, &total) != FILE_CONT) + break; + panel->dir.list [i].st.st_size = (off_t) total; panel->dir.list [i].f.dir_size_computed = 1; } - + + compute_dir_size_destroy_ui (ui); + recalculate_panel_summary (panel); panel_re_sort (panel); panel->dirty = 1; diff --git a/src/file.c b/src/file.c index 0cadad84d..297e7b5f6 100644 --- a/src/file.c +++ b/src/file.c @@ -1474,26 +1474,113 @@ panel_get_file (WPanel *panel, struct stat *stat_buf) return NULL; } + +ComputeDirSizeUI * +compute_dir_size_create_ui (void) +{ + ComputeDirSizeUI *ui; + + char *b_name = N_("&Abort"); + +#ifdef ENABLE_NLS + b_name = _(b_name); +#endif + + ui = g_new (ComputeDirSizeUI, 1); + + ui->dlg = create_dlg (0, 0, 8, COLS/2, dialog_colors, NULL, + NULL, _("Directory size"), DLG_CENTER | DLG_TRYUP); + ui->dirname = label_new (3, 3, ""); + add_widget (ui->dlg, ui->dirname); + + add_widget (ui->dlg, + button_new (5, (ui->dlg->cols - strlen (b_name))/2, + FILE_ABORT, NORMAL_BUTTON, b_name, NULL)); + + /* We will manage the dialog without any help, + that's why we have to call init_dlg */ + init_dlg (ui->dlg); + + return ui; +} + +void +compute_dir_size_destroy_ui (ComputeDirSizeUI *ui) +{ + if (ui != NULL) { + /* schedule to update passive panel */ + other_panel->dirty = 1; + + /* close and destroy dialog */ + dlg_run_done (ui->dlg); + destroy_dlg (ui->dlg); + g_free (ui); + } +} + +FileProgressStatus +compute_dir_size_update_ui (const void *ui, const char *dirname) +{ + const ComputeDirSizeUI *this = (const ComputeDirSizeUI *) ui; + char *msg; + int c; + Gpm_Event event; + + if (ui == NULL) + return FILE_CONT; + + msg = g_strdup_printf (_("Scanning: %s"), dirname); + label_set_text (this->dirname, name_trunc (msg, this->dlg->cols - 6)); + g_free (msg); + + event.x = -1; /* Don't show the GPM cursor */ + c = get_event (&event, 0, 0); + if (c == EV_NONE) + return FILE_CONT; + + /* Reinitialize to avoid old values after events other than + selecting a button */ + this->dlg->ret_value = FILE_CONT; + + dlg_process_event (this->dlg, c, &event); + + switch (this->dlg->ret_value) { + case B_CANCEL: + case FILE_ABORT: + return FILE_ABORT; + default: + return FILE_CONT; + } +} + /** * compute_dir_size: * * Computes the number of bytes used by the files in a directory */ -void -compute_dir_size (const char *dirname, off_t *ret_marked, double *ret_total) +FileProgressStatus +compute_dir_size (const char *dirname, const void *ui, + compute_dir_size_callback cback, + off_t *ret_marked, double *ret_total) { DIR *dir; struct dirent *dirent; + FileProgressStatus ret = FILE_CONT; dir = mc_opendir (dirname); - if (!dir) - return; + if (dir == NULL) + return ret; while ((dirent = mc_readdir (dir)) != NULL) { - struct stat s; char *fullname; int res; + struct stat s; + + ret = (cback != NULL) ? cback (ui, dirname) : FILE_CONT; + + if (ret != FILE_CONT) + break; if (strcmp (dirent->d_name, ".") == 0) continue; @@ -1501,19 +1588,23 @@ compute_dir_size (const char *dirname, off_t *ret_marked, double *ret_total) continue; fullname = concat_dir_and_file (dirname, dirent->d_name); - res = mc_lstat (fullname, &s); if (res != 0) { g_free (fullname); - continue; + break; } if (S_ISDIR (s.st_mode)) { off_t subdir_count = 0; double subdir_bytes = 0; - compute_dir_size (fullname, &subdir_count, &subdir_bytes); + ret = compute_dir_size (fullname, ui, cback, &subdir_count, &subdir_bytes); + + if (ret != FILE_CONT) { + g_free (fullname); + break; + } *ret_marked += subdir_count; *ret_total += subdir_bytes; @@ -1521,10 +1612,13 @@ compute_dir_size (const char *dirname, off_t *ret_marked, double *ret_total) (*ret_marked)++; *ret_total += s.st_size; } + g_free (fullname); } mc_closedir (dir); + + return ret; } /** @@ -1535,8 +1629,10 @@ compute_dir_size (const char *dirname, off_t *ret_marked, double *ret_total) * as required. In addition, it checks to see if it will * overwrite any files by doing the copy. */ -static void -panel_compute_totals (WPanel *panel, off_t *ret_marked, double *ret_total) +static FileProgressStatus +panel_compute_totals (WPanel *panel, const void *ui, + compute_dir_size_callback cback, + off_t *ret_marked, double *ret_total) { int i; @@ -1555,19 +1651,27 @@ panel_compute_totals (WPanel *panel, off_t *ret_marked, double *ret_total) char *dir_name; off_t subdir_count = 0; double subdir_bytes = 0; + FileProgressStatus status; dir_name = concat_dir_and_file (panel->cwd, panel->dir.list[i].fname); - compute_dir_size (dir_name, &subdir_count, &subdir_bytes); + + status = compute_dir_size (dir_name, ui, cback, + &subdir_count, &subdir_bytes); + g_free (dir_name); + + if (status != FILE_CONT) + return FILE_ABORT; *ret_marked += subdir_count; *ret_total += subdir_bytes; - g_free (dir_name); } else { (*ret_marked)++; *ret_total += s->st_size; } } + + return FILE_CONT; } /* @@ -1940,8 +2044,18 @@ panel_operate (void *source_panel, FileOperation operation, /* Initialize variables for progress bars */ if (operation != OP_MOVE && verbose && file_op_compute_totals) { - panel_compute_totals (panel, &ctx->progress_count, - &ctx->progress_bytes); + ComputeDirSizeUI *ui; + FileProgressStatus status; + + ui = compute_dir_size_create_ui (); + status = panel_compute_totals (panel, + ui, compute_dir_size_update_ui, + &ctx->progress_count, &ctx->progress_bytes); + compute_dir_size_destroy_ui (ui); + + if (status != FILE_CONT) + goto clean_up; + ctx->progress_totals_computed = 1; } else { ctx->progress_totals_computed = 0; diff --git a/src/file.h b/src/file.h index d95eeeff1..82a45a077 100644 --- a/src/file.h +++ b/src/file.h @@ -1,7 +1,12 @@ +/* File and directory operation routines for Midnight Commander */ + #ifndef MC_FILE_H #define MC_FILE_H +#include "global.h" #include "fileopctx.h" +#include "dialog.h" /* Dlg_head */ +#include "widget.h" /* WLabel */ struct link; @@ -25,9 +30,24 @@ extern int file_op_compute_totals; /* Report error with one file */ FileProgressStatus file_error (const char *format, const char *file); -/* Query routines */ +/* Compute directory size */ +/* callback to update status dialog */ +typedef FileProgressStatus (*compute_dir_size_callback)(const void *ui, const char *dirname); -void compute_dir_size (const char *dirname, off_t *ret_marked, - double *ret_total); +/* return value is FILE_CONT or FILE_ABORT */ +FileProgressStatus compute_dir_size (const char *dirname, const void *ui, + compute_dir_size_callback cback, + off_t *ret_marked, double *ret_total); -#endif +/* status dialog of durectory size computing */ +typedef struct { + Dlg_head *dlg; + WLabel *dirname; +} ComputeDirSizeUI; + +ComputeDirSizeUI *compute_dir_size_create_ui (void); +void compute_dir_size_destroy_ui (ComputeDirSizeUI *ui); +FileProgressStatus compute_dir_size_update_ui (const void *ui, const char *dirname); + + +#endif /* MC_FILE_H */