Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CommonJob: Move scan_dir and this depending functions to Vala #2514

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
200 changes: 194 additions & 6 deletions libcore/FileOperations/CommonJob.vala
Original file line number Diff line number Diff line change
Expand Up @@ -23,20 +23,24 @@ public class Files.FileOperations.CommonJob {
[Compact]
[CCode (cname = "SourceInfo")]
protected class SourceInfo {
[CCode (has_target = false, cname = "CountProgressCallback")]
internal delegate void CountProgressCallback (Files.FileOperations.CommonJob job, Files.FileOperations.CommonJob.SourceInfo info);

internal int num_files;
internal size_t num_bytes;
internal int64 num_bytes;
internal int num_files_since_progress;
internal weak CountProgressCallback count_callback;

public SourceInfo copy () {
return new SourceInfo () {
num_files = this.num_files,
num_bytes = this.num_bytes,
num_files_since_progress = this.num_files_since_progress,
};
}
}

[Compact]
[CCode (cname = "TransferInfo")]
protected class TransferInfo {
internal int num_files;
internal size_t num_bytes;
internal int64 num_bytes;
internal uint64 last_report_time;
internal int last_reported_files_left;
}
Expand Down Expand Up @@ -67,6 +71,15 @@ public class Files.FileOperations.CommonJob {
}
}

protected virtual unowned string get_scan_primary () {
GLib.warn_if_reached ();
return _("Error while copying.");
}

protected virtual void report_count_progress (CommonJob.SourceInfo source_info) {
GLib.warn_if_reached ();
}

protected void inhibit_power_manager (string message) {
weak Gtk.Application app = (Gtk.Application) GLib.Application.get_default ();
inhibit_cookie = app.inhibit (
Expand Down Expand Up @@ -257,6 +270,181 @@ public class Files.FileOperations.CommonJob {
}
}

private void count_file (GLib.FileInfo info, SourceInfo source_info) {
source_info.num_files += 1;
source_info.num_bytes += info.get_size ();
if (source_info.num_files_since_progress++ > 100) {
report_count_progress (source_info);
source_info.num_files_since_progress = 0;
}
}

private void scan_dir (GLib.File dir, SourceInfo source_info, GLib.Queue<GLib.File> dirs) {
var saved_source_info = source_info.copy ();
GLib.FileEnumerator? enumerator = null;
try {
enumerator = dir.enumerate_children (GLib.FileAttribute.STANDARD_NAME + "," +
GLib.FileAttribute.STANDARD_TYPE + "," +
GLib.FileAttribute.STANDARD_SIZE,
GLib.FileQueryInfoFlags.NOFOLLOW_SYMLINKS,
cancellable);
} catch (Error e) {
if (e is GLib.IOError.CANCELLED) {
// Do nothing
} else {
var dir_basename = FileUtils.custom_basename_from_file (dir);
unowned string primary = get_scan_primary ();
string secondary;
string? details = null;
if (e is GLib.IOError.PERMISSION_DENIED) {
/// TRANSLATORS: '\"%s\"' is a placeholder for the quoted basename of a file. It may change position but must not be translated or removed
/// '\"' is an escaped quoted mark. This may be replaced with another suitable character (escaped if necessary)
secondary = _("The folder \"%s\" cannot be handled because you do not have permissions to read it.").printf (dir_basename);
} else {
/// TRANSLATORS: '\"%s\"' is a placeholder for the quoted basename of a file. It may change position but must not be translated or removed
/// '\"' is an escaped quoted mark. This may be replaced with another suitable character (escaped if necessary)
secondary = _("There was an error reading the folder \"%s\".").printf (dir_basename);
details = e.message;
}

var response = run_warning (primary, secondary, details, false, CANCEL, RETRY, SKIP);

if (response == 0 || response == Gtk.ResponseType.DELETE_EVENT) {
abort_job ();
} else if (response == 1) {
source_info.num_files = saved_source_info.num_files;
source_info.num_bytes = saved_source_info.num_bytes;
source_info.num_files_since_progress = saved_source_info.num_files_since_progress;
scan_dir (dir, source_info, dirs);
} else if (response == 2) {
skip_readdir_error (dir);
} else {
GLib.assert_not_reached ();
}
}

return;
}

try {
unowned GLib.FileInfo? info = null;
while ((info = enumerator.next_file (cancellable)) != null) {
count_file (info, source_info);
if (info.get_file_type () == FileType.DIRECTORY) {
/* Push to head, since we want depth-first */
var subdir = dir.get_child (info.get_name ());
dirs.push_head (subdir);
}
}
} catch (Error e) {
if (e is GLib.IOError.CANCELLED) {
// Do nothing
} else {
var dir_basename = FileUtils.custom_basename_from_file (dir);
unowned string primary = get_scan_primary ();
string secondary;
string? details = null;
if (e is GLib.IOError.PERMISSION_DENIED) {
/// TRANSLATORS: '\"%s\"' is a placeholder for the quoted basename of a file. It may change position but must not be translated or removed
/// '\"' is an escaped quoted mark. This may be replaced with another suitable character (escaped if necessary)
secondary = _("Files in the folder \"%s\" cannot be handled because you do not have permissions to see them.").printf (dir_basename);
} else {
/// TRANSLATORS: '\"%s\"' is a placeholder for the quoted basename of a file. It may change position but must not be translated or removed
/// '\"' is an escaped quoted mark. This may be replaced with another suitable character (escaped if necessary)
secondary = _("There was an error getting information about the files in the folder \"%s\".").printf (dir_basename);
details = e.message;
}

var response = run_warning (primary, secondary, details, false, CANCEL, SKIP_ALL, SKIP, RETRY);

if (response == 0 || response == Gtk.ResponseType.DELETE_EVENT) {
abort_job ();
} else if (response == 1) {
source_info = saved_source_info;
scan_dir (dir, source_info, dirs);
} else if (response == 2) {
skip_readdir_error (dir);
} else {
GLib.assert_not_reached ();
}
}
}
}

private void scan_file (GLib.File file, SourceInfo source_info, GLib.Queue<GLib.File> dirs = new GLib.Queue<GLib.File> ()) {
try {
var info = file.query_info (GLib.FileAttribute.STANDARD_TYPE + "," + GLib.FileAttribute.STANDARD_SIZE, NOFOLLOW_SYMLINKS, cancellable);
count_file (info, source_info);
if (info.get_file_type () == GLib.FileType.DIRECTORY) {
dirs.push_head (file);
}
} catch (Error e) {
if (skip_all_error) {
skip_file (file);
} else if (e is GLib.IOError.CANCELLED) {
// Do nothing
} else {
var file_basename = FileUtils.custom_basename_from_file (file);
unowned string? primary = get_scan_primary ();
string secondary;
string? details = null;

if (e is GLib.IOError.PERMISSION_DENIED) {
/// TRANSLATORS: '\"%s\"' is a placeholder for the quoted basename of a file. It may change position but must not be translated or removed
/// '\"' is an escaped quoted mark. This may be replaced with another suitable character (escaped if necessary)
secondary = _("The file \"%s\" cannot be handled because you do not have permissions to read it.").printf (file_basename);
} else {
/// TRANSLATORS: '\"%s\"' is a placeholder for the quoted basename of a file. It may change position but must not be translated or removed
/// '\"' is an escaped quoted mark. This may be replaced with another suitable character (escaped if necessary)
secondary = _("There was an error getting information about \"%s\".").printf (file_basename);
details = e.message;
}

/* set show_all to TRUE here, as we don't know how many
* files we'll end up processing yet.
*/
var response = run_warning (primary, secondary, details, true, CANCEL, SKIP_ALL, SKIP, RETRY);

if (response == 0 || response == Gtk.ResponseType.DELETE_EVENT) {
abort_job ();
} else if (response == 1 || response == 2) {
if (response == 1) {
skip_all_error = true;
}

skip_file (file);
} else if (response == 3) {
scan_file (file, source_info, dirs);
} else {
GLib.assert_not_reached ();
}
}
}

GLib.File? dir = null;
while (!aborted () && (dir = dirs.pop_head ()) != null) {
scan_dir (dir, source_info, dirs);
}
}

protected SourceInfo scan_sources (GLib.List<GLib.File> files) {
var source_info = new SourceInfo ();

report_count_progress (source_info);
foreach (var file in files) {
if (aborted ()) {
return source_info;
}

scan_file (file, source_info);
}

/* Make sure we report the final count */
report_count_progress (source_info);
return source_info;
}


private int run_simple_dialog_va (Gtk.MessageType message_type,
owned string primary_text,
owned string secondary_text,
Expand Down
12 changes: 10 additions & 2 deletions libcore/FileOperations/CopyMoveJob.vala
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,15 @@ public class Files.FileOperations.CopyMoveJob : CommonJob {
is_move = true;
}

protected void report_copy_move_count_progress (CommonJob.SourceInfo source_info) {
protected override unowned string get_scan_primary () {
if (is_move) {
return _("Error while moving.");
} else {
return _("Error while copying.");
}
}

protected override void report_count_progress (CommonJob.SourceInfo source_info) {
string s;
string num_bytes_format = GLib.format_size (source_info.num_bytes);

Expand Down Expand Up @@ -190,7 +198,7 @@ public class Files.FileOperations.CopyMoveJob : CommonJob {
progress.take_status ((owned) s);
}

var total_size = size_t.max (source_info.num_bytes, transfer_info.num_bytes);
var total_size = int64.max (source_info.num_bytes, transfer_info.num_bytes);

double elapsed = time.elapsed ();
double transfer_rate = 0;
Expand Down
6 changes: 5 additions & 1 deletion libcore/FileOperations/DeleteJob.vala
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ public class Files.FileOperations.DeleteJob : CommonJob {
this.user_cancel = false;
}

protected override unowned string get_scan_primary () {
return _("Error while deleting.");
}

protected bool confirm_delete_from_trash (GLib.List<GLib.File> to_delete_files) {
string prompt;

Expand Down Expand Up @@ -131,7 +135,7 @@ public class Files.FileOperations.DeleteJob : CommonJob {
}
}

protected void report_delete_count_progress (CommonJob.SourceInfo source_info) {
protected override void report_count_progress (CommonJob.SourceInfo source_info) {
/// TRANSLATORS: %'d is a placeholder for a number. It must not be translated or removed.
/// %s is a placeholder for a size like "2 bytes" or "3 MB". It must not be translated or removed.
/// So this represents something like "Preparing to delete 100 files (200 MB)"
Expand Down
Loading
Loading