Skip to content

Commit

Permalink
CommonJob: Move scan_dir and this depending functions to Vala
Browse files Browse the repository at this point in the history
Also make use of the use of class-based objects to add virtual accessors.
  • Loading branch information
tintou committed Nov 26, 2024
1 parent e25f4a5 commit b44c756
Show file tree
Hide file tree
Showing 4 changed files with 226 additions and 331 deletions.
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;
unowned GLib.File? child = null;
while (enumerator.iterate (out info, out child, cancellable)) {
count_file (info, source_info);
if (info.get_file_type () == FileType.DIRECTORY) {
/* Push to head, since we want depth-first */
dirs.push_head (child);
}
}
} 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

0 comments on commit b44c756

Please sign in to comment.