1
0
Fork 0
mirror of synced 2024-04-25 00:02:07 +12:00

Add ability to stop task from GUI (#55)

This commit is contained in:
Rafał Mikrut 2020-10-10 11:15:20 +02:00 committed by GitHub
parent 085da0369e
commit 8bbb12c7d4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 487 additions and 343 deletions

2
Cargo.lock generated
View file

@ -344,6 +344,7 @@ name = "czkawka_core"
version = "1.0.1"
dependencies = [
"blake3",
"crossbeam-channel",
"humansize",
]
@ -352,6 +353,7 @@ name = "czkawka_gui"
version = "1.0.1"
dependencies = [
"chrono",
"crossbeam-channel",
"czkawka_core",
"gdk",
"gio",

View file

@ -1,4 +1,9 @@
## Version 1.x
- Improve code quality/Simplify codebase [#52](https://github.com/qarmin/czkawka/pull/52)
- Fixed skipping some correct results in specific situations [#52](https://github.com/qarmin/czkawka/pull/52#discussion_r502613895)
- Added support for searching in other thread [#51](https://github.com/qarmin/czkawka/pull/51)
- Divide CI across files [#48](https://github.com/qarmin/czkawka/pull/48)
- Added ability to stop task from GUI [#55](https://github.com/qarmin/czkawka/pull/55)
## Version 1.0.1 - 06.10.2020r
- Replaced default argument parser with StructOpt [#37](https://github.com/qarmin/czkawka/pull/37)

View file

@ -1,7 +1,7 @@
[package]
name = "czkawka_cli"
version = "1.0.1"
authors = ["Rafał Mikrut <mikrutrafal54@gmail.com>"]
authors = ["Rafał Mikrut <mikrutrafal@protonmail.com>"]
edition = "2018"
description = "CLI frontend of Czkawka"
license = "MIT"

View file

@ -49,7 +49,7 @@ fn main() {
df.set_delete_method(delete_method);
df.set_recursive_search(!not_recursive.not_recursive);
df.find_duplicates();
df.find_duplicates(None);
if let Some(file_name) = file_to_save.file_name() {
if !df.save_results_to_file(file_name) {
@ -68,7 +68,7 @@ fn main() {
ef.set_included_directory(path_list_to_str(directories.directories));
ef.set_delete_folder(delete_folders);
ef.find_empty_folders();
ef.find_empty_folders(None);
if let Some(file_name) = file_to_save.file_name() {
if !ef.save_results_to_file(file_name) {
@ -99,7 +99,7 @@ fn main() {
bf.set_number_of_files_to_check(number_of_files);
bf.set_recursive_search(!not_recursive.not_recursive);
bf.find_big_files();
bf.find_big_files(None);
if let Some(file_name) = file_to_save.file_name() {
if !bf.save_results_to_file(file_name) {
@ -133,7 +133,7 @@ fn main() {
ef.set_delete_method(empty_files::DeleteMethod::Delete);
}
ef.find_empty_files();
ef.find_empty_files(None);
if let Some(file_name) = file_to_save.file_name() {
if !ef.save_results_to_file(file_name) {
@ -165,7 +165,7 @@ fn main() {
tf.set_delete_method(temporary::DeleteMethod::Delete);
}
tf.find_temporary_files();
tf.find_temporary_files(None);
if let Some(file_name) = file_to_save.file_name() {
if !tf.save_results_to_file(file_name) {

View file

@ -12,4 +12,5 @@ repository = "https://github.com/qarmin/czkawka"
[dependencies]
humansize = "1"
blake3 = "0.3"
#rayon = "1"
#rayon = "1"
crossbeam-channel = "0.4.4"

View file

@ -4,6 +4,7 @@ use crate::common_extensions::Extensions;
use crate::common_items::ExcludedItems;
use crate::common_messages::Messages;
use crate::common_traits::{DebugPrint, PrintResults, SaveResults};
use crossbeam_channel::Receiver;
use humansize::{file_size_opts as options, FileSize};
use std::collections::BTreeMap;
use std::fs;
@ -45,6 +46,7 @@ pub struct BigFile {
allowed_extensions: Extensions,
recursive_search: bool,
number_of_files_to_check: usize,
stopped_search: bool,
}
impl BigFile {
@ -58,14 +60,21 @@ impl BigFile {
allowed_extensions: Extensions::new(),
recursive_search: true,
number_of_files_to_check: 50,
stopped_search: false,
}
}
pub fn find_big_files(&mut self) {
pub fn find_big_files(&mut self, rx: Option<&Receiver<()>>) {
self.optimize_directories();
self.look_for_big_files();
if !self.look_for_big_files(rx) {
self.stopped_search = true;
return;
}
self.debug_print();
}
pub fn get_stopped_search(&self) -> bool {
self.stopped_search
}
pub const fn get_big_files(&self) -> &BTreeMap<u64, Vec<FileEntry>> {
&self.big_files
@ -88,7 +97,7 @@ impl BigFile {
self.allowed_extensions.set_allowed_extensions(allowed_extensions, &mut self.text_messages);
}
fn look_for_big_files(&mut self) {
fn look_for_big_files(&mut self, rx: Option<&Receiver<()>>) -> bool {
let start_time: SystemTime = SystemTime::now();
let mut folders_to_check: Vec<String> = Vec::with_capacity(1024 * 2); // This should be small enough too not see to big difference and big enough to store most of paths without needing to resize vector
@ -101,6 +110,9 @@ impl BigFile {
let mut current_folder: String;
let mut next_folder: String;
while !folders_to_check.is_empty() {
if rx.is_some() && rx.unwrap().try_recv().is_ok() {
return false;
}
current_folder = folders_to_check.pop().unwrap();
let read_dir = match fs::read_dir(&current_folder) {
@ -127,10 +139,6 @@ impl BigFile {
};
if metadata.is_dir() {
self.information.number_of_checked_folders += 1;
// if entry_data.file_name().into_string().is_err() { // Probably this can be removed, if crash still will be happens, then uncomment this line
// self.text_messages.warnings.push("Cannot read folder name in dir ".to_string() + current_folder.as_str());
// continue; // Permissions denied
// }
if !self.recursive_search {
continue;
@ -163,11 +171,13 @@ impl BigFile {
.to_lowercase();
// Checking allowed extensions
let allowed = self.allowed_extensions.file_extensions.iter().any(|e| file_name_lowercase.ends_with((".".to_string() + e.to_lowercase().as_str()).as_str()));
if !allowed {
// Not an allowed extension, ignore it.
self.information.number_of_ignored_files += 1;
continue 'dir;
if !self.allowed_extensions.file_extensions.is_empty() {
let allowed = self.allowed_extensions.file_extensions.iter().any(|e| file_name_lowercase.ends_with((".".to_string() + e.to_lowercase().as_str()).as_str()));
if !allowed {
// Not an allowed extension, ignore it.
self.information.number_of_ignored_files += 1;
continue 'dir;
}
}
// Checking files
let current_file_name = "".to_owned()
@ -236,6 +246,7 @@ impl BigFile {
self.big_files = new_map;
Common::print_time(start_time, SystemTime::now(), "look_for_big_files".to_string());
true
}
pub fn set_number_of_files_to_check(&mut self, number_of_files_to_check: usize) {

View file

@ -85,7 +85,6 @@ impl Common {
}
// `*home` shouldn't be true for `/homeowner`
if !expression.ends_with('*') && !directory.ends_with(splits.last().unwrap()) {
// && !directory.ends_with(&(splits.last().unwrap().to_string() + "/")){
return false;
}

View file

@ -1,3 +1,4 @@
use crossbeam_channel::Receiver;
use humansize::{file_size_opts as options, FileSize};
use std::collections::{BTreeMap, HashMap};
use std::fs;
@ -76,6 +77,7 @@ pub struct DuplicateFinder {
minimal_file_size: u64,
check_method: CheckingMethod,
delete_method: DeleteMethod,
stopped_search: bool,
}
impl DuplicateFinder {
@ -92,15 +94,22 @@ impl DuplicateFinder {
minimal_file_size: 1024,
directories: Directories::new(),
excluded_items: ExcludedItems::new(),
stopped_search: false,
}
}
/// Finding duplicates, save results to internal struct variables
pub fn find_duplicates(&mut self) {
pub fn find_duplicates(&mut self, rx: Option<&Receiver<()>>) {
self.directories.optimize_directories(self.recursive_search, &mut self.text_messages);
self.check_files_size();
if !self.check_files_size(rx) {
self.stopped_search = true;
return;
}
#[allow(clippy::collapsible_if)]
if self.check_method == CheckingMethod::Hash || self.check_method == CheckingMethod::HashMB {
self.check_files_hash();
if !self.check_files_hash(rx) {
self.stopped_search = true;
return;
}
}
self.delete_files();
self.debug_print();
@ -110,6 +119,10 @@ impl DuplicateFinder {
&self.check_method
}
pub fn get_stopped_search(&self) -> bool {
self.stopped_search
}
pub const fn get_files_sorted_by_size(&self) -> &BTreeMap<u64, Vec<FileEntry>> {
&self.files_with_identical_size
}
@ -162,7 +175,7 @@ impl DuplicateFinder {
/// Read file length and puts it to different boxes(each for different lengths)
/// If in box is only 1 result, then it is removed
fn check_files_size(&mut self) {
fn check_files_size(&mut self, rx: Option<&Receiver<()>>) -> bool {
// TODO maybe add multithreading checking for file hash
let start_time: SystemTime = SystemTime::now();
let mut folders_to_check: Vec<String> = Vec::with_capacity(1024 * 2); // This should be small enough too not see to big difference and big enough to store most of paths without needing to resize vector
@ -176,6 +189,9 @@ impl DuplicateFinder {
let mut current_folder: String;
let mut next_folder: String;
while !folders_to_check.is_empty() {
if rx.is_some() && rx.unwrap().try_recv().is_ok() {
return false;
}
current_folder = folders_to_check.pop().unwrap();
// Read current dir, if permission are denied just go to next
@ -205,10 +221,6 @@ impl DuplicateFinder {
};
if metadata.is_dir() {
self.information.number_of_checked_folders += 1;
// if entry_data.file_name().into_string().is_err() { // Probably this can be removed, if crash still will be happens, then uncomment this line
// self.text_messages.warnings.push("Cannot read folder name in dir ".to_string() + current_folder.as_str());
// continue; // Permissions denied
// }
if !self.recursive_search {
continue;
@ -242,11 +254,13 @@ impl DuplicateFinder {
.to_lowercase();
// Checking allowed extensions
let allowed = self.allowed_extensions.file_extensions.iter().any(|e| file_name_lowercase.ends_with((".".to_string() + e.to_lowercase().as_str()).as_str()));
if !allowed {
// Not an allowed extension, ignore it.
self.information.number_of_ignored_files += 1;
continue 'dir;
if !self.allowed_extensions.file_extensions.is_empty() {
let allowed = self.allowed_extensions.file_extensions.iter().any(|e| file_name_lowercase.ends_with((".".to_string() + e.to_lowercase().as_str()).as_str()));
if !allowed {
// Not an allowed extension, ignore it.
self.information.number_of_ignored_files += 1;
continue 'dir;
}
}
// Checking files
if metadata.len() >= self.minimal_file_size {
@ -315,10 +329,11 @@ impl DuplicateFinder {
self.files_with_identical_size = new_map;
Common::print_time(start_time, SystemTime::now(), "check_files_size".to_string());
true
}
/// The slowest checking type, which must be applied after checking for size
fn check_files_hash(&mut self) {
fn check_files_hash(&mut self, rx: Option<&Receiver<()>>) -> bool {
let start_time: SystemTime = SystemTime::now();
let mut file_handler: File;
let mut hashmap_with_hash: HashMap<String, Vec<FileEntry>>;
@ -327,6 +342,9 @@ impl DuplicateFinder {
hashmap_with_hash = Default::default();
for file_entry in vector {
if rx.is_some() && rx.unwrap().try_recv().is_ok() {
return false;
}
file_handler = match File::open(&file_entry.path) {
Ok(t) => t,
Err(_) => {
@ -384,6 +402,7 @@ impl DuplicateFinder {
}
Common::print_time(start_time, SystemTime::now(), "check_files_hash".to_string());
true
}
/// Function to delete files, from filed before BTreeMap

View file

@ -9,6 +9,7 @@ use crate::common_extensions::Extensions;
use crate::common_items::ExcludedItems;
use crate::common_messages::Messages;
use crate::common_traits::*;
use crossbeam_channel::Receiver;
#[derive(Eq, PartialEq, Clone, Debug)]
pub enum DeleteMethod {
@ -49,6 +50,7 @@ pub struct EmptyFiles {
excluded_items: ExcludedItems,
recursive_search: bool,
delete_method: DeleteMethod,
stopped_search: bool,
}
impl EmptyFiles {
@ -62,17 +64,25 @@ impl EmptyFiles {
excluded_items: ExcludedItems::new(),
empty_files: vec![],
delete_method: DeleteMethod::None,
stopped_search: false,
}
}
/// Finding empty files, save results to internal struct variables
pub fn find_empty_files(&mut self) {
pub fn find_empty_files(&mut self, rx: Option<&Receiver<()>>) {
self.directories.optimize_directories(self.recursive_search, &mut self.text_messages);
self.check_files();
if !self.check_files(rx) {
self.stopped_search = true;
return;
}
self.delete_files();
self.debug_print();
}
pub fn get_stopped_search(&self) -> bool {
self.stopped_search
}
pub const fn get_empty_files(&self) -> &Vec<FileEntry> {
&self.empty_files
}
@ -109,7 +119,7 @@ impl EmptyFiles {
}
/// Check files for any with size == 0
fn check_files(&mut self) {
fn check_files(&mut self, rx: Option<&Receiver<()>>) -> bool {
let start_time: SystemTime = SystemTime::now();
let mut folders_to_check: Vec<String> = Vec::with_capacity(1024 * 2); // This should be small enough too not see to big difference and big enough to store most of paths without needing to resize vector
@ -122,6 +132,9 @@ impl EmptyFiles {
let mut current_folder: String;
let mut next_folder: String;
while !folders_to_check.is_empty() {
if rx.is_some() && rx.unwrap().try_recv().is_ok() {
return false;
}
current_folder = folders_to_check.pop().unwrap();
// Read current dir, if permission are denied just go to next
@ -151,10 +164,6 @@ impl EmptyFiles {
};
if metadata.is_dir() {
self.information.number_of_checked_folders += 1;
// if entry_data.file_name().into_string().is_err() { // Probably this can be removed, if crash still will be happens, then uncomment this line
// self.text_messages.warnings.push("Cannot read folder name in dir ".to_string() + current_folder.as_str());
// continue; // Permissions denied
// }
if !self.recursive_search {
continue;
@ -187,11 +196,13 @@ impl EmptyFiles {
.to_lowercase();
// Checking allowed extensions
let allowed = self.allowed_extensions.file_extensions.iter().any(|e| file_name_lowercase.ends_with((".".to_string() + e.to_lowercase().as_str()).as_str()));
if !allowed {
// Not an allowed extension, ignore it.
self.information.number_of_ignored_files += 1;
continue 'dir;
if !self.allowed_extensions.file_extensions.is_empty() {
let allowed = self.allowed_extensions.file_extensions.iter().any(|e| file_name_lowercase.ends_with((".".to_string() + e.to_lowercase().as_str()).as_str()));
if !allowed {
// Not an allowed extension, ignore it.
self.information.number_of_ignored_files += 1;
continue 'dir;
}
}
// Checking files
if metadata.len() == 0 {
@ -243,6 +254,7 @@ impl EmptyFiles {
self.information.number_of_empty_files = self.empty_files.len();
Common::print_time(start_time, SystemTime::now(), "check_files_size".to_string());
true
}
/// Function to delete files, from filed Vector

View file

@ -2,6 +2,7 @@ use crate::common::Common;
use crate::common_directory::Directories;
use crate::common_messages::Messages;
use crate::common_traits::{DebugPrint, PrintResults, SaveResults};
use crossbeam_channel::Receiver;
use std::collections::BTreeMap;
use std::fs;
use std::fs::{File, Metadata};
@ -31,6 +32,7 @@ pub struct EmptyFolder {
text_messages: Messages,
empty_folder_list: BTreeMap<String, FolderEntry>, // Path, FolderEntry
directories: Directories,
stopped_search: bool,
}
/// Info struck with helpful information's about results
@ -55,9 +57,14 @@ impl EmptyFolder {
text_messages: Messages::new(),
empty_folder_list: Default::default(),
directories: Directories::new(),
stopped_search: false,
}
}
pub fn get_stopped_search(&self) -> bool {
self.stopped_search
}
pub const fn get_empty_folder_list(&self) -> &BTreeMap<String, FolderEntry> {
&self.empty_folder_list
}
@ -70,10 +77,12 @@ impl EmptyFolder {
}
/// Public function used by CLI to search for empty folders
pub fn find_empty_folders(&mut self) {
pub fn find_empty_folders(&mut self, rx: Option<&Receiver<()>>) {
self.directories.optimize_directories(true, &mut self.text_messages);
self.check_for_empty_folders(true);
//self.check_for_empty_folders(false); // Second check, should be done before deleting to be sure that empty folder is still empty
if !self.check_for_empty_folders(rx) {
self.stopped_search = true;
return;
}
self.optimize_folders();
if self.delete_folders {
self.delete_empty_folders();
@ -108,42 +117,30 @@ impl EmptyFolder {
/// Function to check if folder are empty.
/// Parameter initial_checking for second check before deleting to be sure that checked folder is still empty
fn check_for_empty_folders(&mut self, initial_checking: bool) {
fn check_for_empty_folders(&mut self, rx: Option<&Receiver<()>>) -> bool {
let start_time: SystemTime = SystemTime::now();
let mut folders_to_check: Vec<String> = Vec::with_capacity(1024 * 2); // This should be small enough too not see to big difference and big enough to store most of paths without needing to resize vector
let mut folders_checked: BTreeMap<String, FolderEntry> = Default::default();
if initial_checking {
// Add root folders for finding
for id in &self.directories.included_directories {
folders_checked.insert(
id.clone(),
FolderEntry {
parent_path: None,
is_empty: FolderEmptiness::Maybe,
modified_date: 0,
},
);
folders_to_check.push(id.clone());
}
} else {
// Add folders searched before
for (name, folder_entry) in &self.empty_folder_list {
folders_checked.insert(
name.clone(),
FolderEntry {
parent_path: None,
is_empty: FolderEmptiness::Maybe,
modified_date: folder_entry.modified_date,
},
);
folders_to_check.push(name.clone());
}
// Add root folders for finding
for id in &self.directories.included_directories {
folders_checked.insert(
id.clone(),
FolderEntry {
parent_path: None,
is_empty: FolderEmptiness::Maybe,
modified_date: 0,
},
);
folders_to_check.push(id.clone());
}
let mut current_folder: String;
let mut next_folder: String;
while !folders_to_check.is_empty() {
if rx.is_some() && rx.unwrap().try_recv().is_ok() {
return false;
}
self.information.number_of_checked_folders += 1;
current_folder = folders_to_check.pop().unwrap();
// Checked folder may be deleted or we may not have permissions to open it so we assume that this folder is not be empty
@ -214,26 +211,15 @@ impl EmptyFolder {
}
}
// Now we check if checked folders are really empty, and if are, then
if initial_checking {
// We need to set empty folder list
for (name, folder_entry) in folders_checked {
if folder_entry.is_empty != FolderEmptiness::No {
self.empty_folder_list.insert(name, folder_entry);
}
// We need to set empty folder list
for (name, folder_entry) in folders_checked {
if folder_entry.is_empty != FolderEmptiness::No {
self.empty_folder_list.insert(name, folder_entry);
}
} else {
// We need to check if parent of folder isn't also empty, because we want to delete only parent with two empty folders except this folders and at the end parent folder
let mut new_folders_list: BTreeMap<String, FolderEntry> = Default::default();
for (name, folder_entry) in folders_checked {
if folder_entry.is_empty != FolderEmptiness::No && self.empty_folder_list.contains_key(&name) {
new_folders_list.insert(name, folder_entry);
}
}
self.empty_folder_list = new_folders_list;
}
Common::print_time(start_time, SystemTime::now(), "check_for_empty_folder".to_string());
true
}
/// Deletes earlier found empty folders

View file

@ -8,6 +8,7 @@ use crate::common_directory::Directories;
use crate::common_items::ExcludedItems;
use crate::common_messages::Messages;
use crate::common_traits::*;
use crossbeam_channel::Receiver;
#[derive(Eq, PartialEq, Clone, Debug)]
pub enum DeleteMethod {
@ -47,6 +48,7 @@ pub struct Temporary {
excluded_items: ExcludedItems,
recursive_search: bool,
delete_method: DeleteMethod,
stopped_search: bool,
}
impl Temporary {
@ -59,16 +61,23 @@ impl Temporary {
excluded_items: ExcludedItems::new(),
delete_method: DeleteMethod::None,
temporary_files: vec![],
stopped_search: false,
}
}
/// Finding temporary files, save results to internal struct variables
pub fn find_temporary_files(&mut self) {
pub fn find_temporary_files(&mut self, rx: Option<&Receiver<()>>) {
self.directories.optimize_directories(self.recursive_search, &mut self.text_messages);
self.check_files();
if !self.check_files(rx) {
self.stopped_search = true;
return;
}
self.delete_files();
self.debug_print();
}
pub fn get_stopped_search(&self) -> bool {
self.stopped_search
}
pub const fn get_temporary_files(&self) -> &Vec<FileEntry> {
&self.temporary_files
@ -101,7 +110,7 @@ impl Temporary {
self.excluded_items.set_excluded_items(excluded_items, &mut self.text_messages);
}
fn check_files(&mut self) {
fn check_files(&mut self, rx: Option<&Receiver<()>>) -> bool {
let start_time: SystemTime = SystemTime::now();
let mut folders_to_check: Vec<String> = Vec::with_capacity(1024 * 2); // This should be small enough too not see to big difference and big enough to store most of paths without needing to resize vector
@ -114,6 +123,9 @@ impl Temporary {
let mut current_folder: String;
let mut next_folder: String;
while !folders_to_check.is_empty() {
if rx.is_some() && rx.unwrap().try_recv().is_ok() {
return false;
}
current_folder = folders_to_check.pop().unwrap();
// Read current dir, if permission are denied just go to next
@ -143,10 +155,6 @@ impl Temporary {
};
if metadata.is_dir() {
self.information.number_of_checked_folders += 1;
// if entry_data.file_name().into_string().is_err() { // Probably this can be removed, if crash still will be happens, then uncomment this line
// self.text_messages.warnings.push("Cannot read folder name in dir ".to_string() + current_folder.as_str());
// continue; // Permissions denied
// }
if !self.recursive_search {
continue;
@ -232,6 +240,7 @@ impl Temporary {
self.information.number_of_temporary_files = self.temporary_files.len();
Common::print_time(start_time, SystemTime::now(), "check_files_size".to_string());
true
}
/// Function to delete files, from filed Vector

View file

@ -1,7 +1,7 @@
[package]
name = "czkawka_gui"
version = "1.0.1"
authors = ["Rafał Mikrut <mikrutrafal54@gmail.com>"]
authors = ["Rafał Mikrut <mikrutrafal@protonmail.com>"]
edition = "2018"
description = "GTK frontend of Czkawka"
license = "MIT"
@ -17,6 +17,7 @@ glib = "0.10.1"
humansize = "1"
chrono = "0.4"
crossbeam-channel = "0.4.4"
[dependencies.gtk]
version = "0.9.2"

View file

@ -24,20 +24,17 @@ pub enum ColumnsDirectory {
Path = 0,
}
pub enum ColumnsBigFiles {
// Columns for Big Files
Size = 0,
Name,
Path,
Modification,
}
pub enum ColumnsEmptyFiles {
// Columns for Big Files
Name = 0,
Path,
Modification,
}
pub enum ColumnsTemporaryFiles {
// Columns for Big Files
Name = 0,
Path,
Modification,

View file

@ -6,6 +6,7 @@ use humansize::{file_size_opts as options, FileSize};
extern crate gtk;
use crate::help_functions::*;
use chrono::NaiveDateTime;
use crossbeam_channel::unbounded;
use czkawka_core::big_file::BigFile;
use czkawka_core::common_traits::SaveResults;
use czkawka_core::duplicate::CheckingMethod;
@ -184,7 +185,7 @@ fn main() {
let scrolled_window_excluded_directories: gtk::ScrolledWindow = builder.get_object("scrolled_window_excluded_directories").unwrap();
//// Threads
// Messages
// Types of messages to send to main thread where gui can be draw.
enum Message {
Duplicates(DuplicateFinder),
EmptyFolders(EmptyFolder),
@ -192,10 +193,14 @@ fn main() {
BigFiles(BigFile),
Temporary(Temporary),
}
// Sender/Reciver
// Used for getting data from thread
let (sender, receiver) = glib::MainContext::channel(glib::PRIORITY_DEFAULT);
//// Setup default look for
// Used for sending stop signal to thread
let (sx, rx): (crossbeam_channel::Sender<()>, crossbeam_channel::Receiver<()>) = unbounded();
//// Setup default look(duplicate finder)
{
entry_info.set_text("Duplicated Files");
@ -395,7 +400,7 @@ fn main() {
//// Connect Buttons
// Down notepad
// Main buttons
{
assert!(notebook_main_children_names.contains(&"notebook_main_duplicate_finder_label".to_string()));
assert!(notebook_main_children_names.contains(&"scrolled_window_main_empty_folder_finder".to_string()));
@ -444,7 +449,7 @@ fn main() {
let delete_method = duplicate::DeleteMethod::None;
let sender = sender.clone();
let receiver_stop = rx.clone();
// Find duplicates
thread::spawn(move || {
let mut df = DuplicateFinder::new();
@ -456,24 +461,26 @@ fn main() {
df.set_minimal_file_size(minimal_file_size);
df.set_check_method(check_method);
df.set_delete_method(delete_method);
df.find_duplicates();
df.find_duplicates(Option::from(&receiver_stop)); //&rc_stop_signal.borrow().1);
let _ = sender.send(Message::Duplicates(df));
});
}
"scrolled_window_main_empty_folder_finder" => {
let sender = sender.clone();
let receiver_stop = rx.clone();
// Find empty folders
thread::spawn(move || {
let mut ef = EmptyFolder::new();
ef.set_included_directory(included_directories);
ef.set_delete_folder(false);
ef.find_empty_folders();
ef.find_empty_folders(Option::from(&receiver_stop));
let _ = sender.send(Message::EmptyFolders(ef));
});
}
"scrolled_window_main_empty_files_finder" => {
let sender = sender.clone();
let receiver_stop = rx.clone();
// Find empty files
thread::spawn(move || {
@ -484,12 +491,13 @@ fn main() {
vf.set_recursive_search(recursive_search);
vf.set_excluded_items(excluded_items);
vf.set_allowed_extensions(allowed_extensions);
vf.find_empty_files();
vf.find_empty_files(Option::from(&receiver_stop));
let _ = sender.send(Message::EmptyFiles(vf));
});
}
"scrolled_window_main_temporary_files_finder" => {
let sender = sender.clone();
let receiver_stop = rx.clone();
// Find temporary files
thread::spawn(move || {
@ -499,7 +507,7 @@ fn main() {
tf.set_excluded_directory(excluded_directories);
tf.set_recursive_search(recursive_search);
tf.set_excluded_items(excluded_items);
tf.find_temporary_files();
tf.find_temporary_files(Option::from(&receiver_stop));
let _ = sender.send(Message::Temporary(tf));
});
}
@ -510,6 +518,7 @@ fn main() {
};
let sender = sender.clone();
let receiver_stop = rx.clone();
// Find big files
thread::spawn(move || {
@ -520,7 +529,7 @@ fn main() {
bf.set_recursive_search(recursive_search);
bf.set_excluded_items(excluded_items);
bf.set_number_of_files_to_check(numbers_of_files_to_check);
bf.find_big_files();
bf.find_big_files(Option::from(&receiver_stop));
let _ = sender.send(Message::BigFiles(bf));
});
}
@ -616,6 +625,7 @@ fn main() {
let name = tree_model.get_value(&tree_model.get_iter(tree_path).unwrap(), ColumnsEmptyFolders::Name as i32).get::<String>().unwrap().unwrap();
let path = tree_model.get_value(&tree_model.get_iter(tree_path).unwrap(), ColumnsEmptyFolders::Path as i32).get::<String>().unwrap().unwrap();
// TODO this should be fs::remove_dir_all(), because it doesn't delete folders with empty folders inside
match fs::remove_dir(format!("{}/{}", path, name)) {
Ok(_) => {
list_store.remove(&list_store.get_iter(tree_path).unwrap());
@ -819,6 +829,12 @@ fn main() {
e => panic!("Not existent {}", e),
});
}
// Stop button
{
buttons_stop.connect_clicked(move |_| {
sx.send(()).unwrap();
});
}
}
// Popover Buttons
{
@ -1072,7 +1088,6 @@ fn main() {
// All one newest
{
let scrolled_window_duplicate_finder = scrolled_window_duplicate_finder.clone();
// let popover_select = popover_select.clone();
buttons_popover_select_one_newest.connect_clicked(move |_| {
let tree_view = scrolled_window_duplicate_finder.get_children().get(0).unwrap().clone().downcast::<gtk::TreeView>().unwrap();
let selection = tree_view.get_selection();
@ -1188,7 +1203,6 @@ fn main() {
}
// Remove Excluded Folder
{
//let scrolled_window_excluded_directories = scrolled_window_excluded_directories.clone();
buttons_remove_excluded_directory.connect_clicked(move |_| {
let tree_view = scrolled_window_excluded_directories.get_children().get(0).unwrap().clone().downcast::<gtk::TreeView>().unwrap();
let list_store = tree_view.get_model().unwrap().downcast::<gtk::ListStore>().unwrap();
@ -1205,7 +1219,6 @@ fn main() {
}
// Remove Included Folder
{
//let scrolled_window_included_directories = scrolled_window_included_directories.clone();
buttons_remove_included_directory.connect_clicked(move |_| {
let tree_view = scrolled_window_included_directories.get_children().get(0).unwrap().clone().downcast::<gtk::TreeView>().unwrap();
let list_store = tree_view.get_model().unwrap().downcast::<gtk::ListStore>().unwrap();
@ -1235,34 +1248,11 @@ fn main() {
match msg {
Message::Duplicates(df) => {
let information = df.get_information();
let text_messages = df.get_text_messages();
if df.get_stopped_search() {
entry_info.set_text("Searching for duplicated was stopped by user");
let duplicates_number: usize;
let duplicates_size: u64;
let duplicates_group: usize;
match df.get_check_method() {
CheckingMethod::Hash | CheckingMethod::HashMB => {
duplicates_number = information.number_of_duplicated_files_by_hash;
duplicates_size = information.lost_space_by_hash;
duplicates_group = information.number_of_groups_by_hash;
}
CheckingMethod::Size => {
duplicates_number = information.number_of_duplicated_files_by_size;
duplicates_size = information.lost_space_by_size;
duplicates_group = information.number_of_groups_by_size;
}
CheckingMethod::None => {
panic!();
}
}
entry_info.set_text(format!("Found {} duplicates files in {} groups which took {}.", duplicates_number, duplicates_group, duplicates_size.file_size(options::BINARY).unwrap()).as_str());
// Create GUI
{
let list_store = scrolled_window_duplicate_finder
//Also clear list
scrolled_window_duplicate_finder
.get_children()
.get(0)
.unwrap()
@ -1272,17 +1262,87 @@ fn main() {
.get_model()
.unwrap()
.downcast::<gtk::ListStore>()
.unwrap();
list_store.clear();
.unwrap()
.clear();
} else {
let information = df.get_information();
let text_messages = df.get_text_messages();
let col_indices = [0, 1, 2, 3, 4, 5];
let duplicates_number: usize;
let duplicates_size: u64;
let duplicates_group: usize;
match df.get_check_method() {
CheckingMethod::Hash | CheckingMethod::HashMB => {
let btreemap = df.get_files_sorted_by_hash();
duplicates_number = information.number_of_duplicated_files_by_hash;
duplicates_size = information.lost_space_by_hash;
duplicates_group = information.number_of_groups_by_hash;
}
CheckingMethod::Size => {
duplicates_number = information.number_of_duplicated_files_by_size;
duplicates_size = information.lost_space_by_size;
duplicates_group = information.number_of_groups_by_size;
}
CheckingMethod::None => {
panic!();
}
}
for (size, vectors_vector) in btreemap.iter().rev() {
for vector in vectors_vector {
entry_info.set_text(format!("Found {} duplicates files in {} groups which took {}.", duplicates_number, duplicates_group, duplicates_size.file_size(options::BINARY).unwrap()).as_str());
// Create GUI
{
let list_store = scrolled_window_duplicate_finder
.get_children()
.get(0)
.unwrap()
.clone()
.downcast::<gtk::TreeView>()
.unwrap()
.get_model()
.unwrap()
.downcast::<gtk::ListStore>()
.unwrap();
list_store.clear();
let col_indices = [0, 1, 2, 3, 4, 5];
match df.get_check_method() {
CheckingMethod::Hash | CheckingMethod::HashMB => {
let btreemap = df.get_files_sorted_by_hash();
for (size, vectors_vector) in btreemap.iter().rev() {
for vector in vectors_vector {
let values: [&dyn ToValue; 6] = [
&(vector.len().to_string() + " x " + size.to_string().as_str()),
&(format!("{} ({} bytes) lost", ((vector.len() - 1) as u64 * *size as u64).file_size(options::BINARY).unwrap(), (vector.len() - 1) as u64 * *size as u64)),
&"".to_string(), // No text in 3 column
&(0), // Not used here
&(HEADER_ROW_COLOR.to_string()),
&(TEXT_COLOR.to_string()),
];
list_store.set(&list_store.append(), &col_indices, &values);
for entry in vector {
let path = &entry.path;
let index = path.rfind('/').unwrap();
let values: [&dyn ToValue; 6] = [
&(path[index + 1..].to_string()),
&(path[..index].to_string()),
&(NaiveDateTime::from_timestamp(entry.modified_date as i64, 0).to_string()),
&(entry.modified_date),
&(MAIN_ROW_COLOR.to_string()),
&(TEXT_COLOR.to_string()),
];
list_store.set(&list_store.append(), &col_indices, &values);
}
}
}
}
CheckingMethod::Size => {
let btreemap = df.get_files_sorted_by_size();
for (size, vector) in btreemap.iter().rev() {
let values: [&dyn ToValue; 6] = [
&(vector.len().to_string() + " x " + size.to_string().as_str()),
&(format!("{} ({} bytes) lost", ((vector.len() - 1) as u64 * *size as u64).file_size(options::BINARY).unwrap(), (vector.len() - 1) as u64 * *size as u64)),
@ -1308,71 +1368,37 @@ fn main() {
}
}
}
}
CheckingMethod::Size => {
let btreemap = df.get_files_sorted_by_size();
for (size, vector) in btreemap.iter().rev() {
let values: [&dyn ToValue; 6] = [
&(vector.len().to_string() + " x " + size.to_string().as_str()),
&(format!("{} ({} bytes) lost", ((vector.len() - 1) as u64 * *size as u64).file_size(options::BINARY).unwrap(), (vector.len() - 1) as u64 * *size as u64)),
&"".to_string(), // No text in 3 column
&(0), // Not used here
&(HEADER_ROW_COLOR.to_string()),
&(TEXT_COLOR.to_string()),
];
list_store.set(&list_store.append(), &col_indices, &values);
for entry in vector {
let path = &entry.path;
let index = path.rfind('/').unwrap();
let values: [&dyn ToValue; 6] = [
&(path[index + 1..].to_string()),
&(path[..index].to_string()),
&(NaiveDateTime::from_timestamp(entry.modified_date as i64, 0).to_string()),
&(entry.modified_date),
&(MAIN_ROW_COLOR.to_string()),
&(TEXT_COLOR.to_string()),
];
list_store.set(&list_store.append(), &col_indices, &values);
}
CheckingMethod::None => {
panic!();
}
}
CheckingMethod::None => {
panic!();
print_text_messages_to_text_view(text_messages, &text_view_errors);
}
// Set state
{
*shared_duplication_state.borrow_mut() = df;
if duplicates_size > 0 {
*shared_buttons.borrow_mut().get_mut("duplicate").unwrap().get_mut("save").unwrap() = true;
*shared_buttons.borrow_mut().get_mut("duplicate").unwrap().get_mut("delete").unwrap() = true;
*shared_buttons.borrow_mut().get_mut("duplicate").unwrap().get_mut("select").unwrap() = true;
} else {
*shared_buttons.borrow_mut().get_mut("duplicate").unwrap().get_mut("save").unwrap() = false;
*shared_buttons.borrow_mut().get_mut("duplicate").unwrap().get_mut("delete").unwrap() = false;
*shared_buttons.borrow_mut().get_mut("duplicate").unwrap().get_mut("select").unwrap() = false;
}
set_buttons(&mut *shared_buttons.borrow_mut().get_mut("duplicate").unwrap(), &buttons_array, &buttons_names);
}
print_text_messages_to_text_view(text_messages, &text_view_errors);
}
// Set state
{
*shared_duplication_state.borrow_mut() = df;
if duplicates_size > 0 {
*shared_buttons.borrow_mut().get_mut("duplicate").unwrap().get_mut("save").unwrap() = true;
*shared_buttons.borrow_mut().get_mut("duplicate").unwrap().get_mut("delete").unwrap() = true;
*shared_buttons.borrow_mut().get_mut("duplicate").unwrap().get_mut("select").unwrap() = true;
} else {
*shared_buttons.borrow_mut().get_mut("duplicate").unwrap().get_mut("save").unwrap() = false;
*shared_buttons.borrow_mut().get_mut("duplicate").unwrap().get_mut("delete").unwrap() = false;
*shared_buttons.borrow_mut().get_mut("duplicate").unwrap().get_mut("select").unwrap() = false;
}
set_buttons(&mut *shared_buttons.borrow_mut().get_mut("duplicate").unwrap(), &buttons_array, &buttons_names);
}
}
Message::EmptyFolders(ef) => {
let information = ef.get_information();
let text_messages = ef.get_text_messages();
if ef.get_stopped_search() {
entry_info.set_text("Searching for empty folders was stopped by user");
let empty_folder_number: usize = information.number_of_empty_folders;
entry_info.set_text(format!("Found {} empty folders.", empty_folder_number).as_str());
// Create GUI
{
let list_store = scrolled_window_main_empty_folder_finder
//Also clear list
scrolled_window_main_empty_folder_finder
.get_children()
.get(0)
.unwrap()
@ -1382,47 +1408,65 @@ fn main() {
.get_model()
.unwrap()
.downcast::<gtk::ListStore>()
.unwrap();
list_store.clear();
.unwrap()
.clear();
} else {
let information = ef.get_information();
let text_messages = ef.get_text_messages();
let col_indices = [0, 1, 2];
let empty_folder_number: usize = information.number_of_empty_folders;
let hashmap = ef.get_empty_folder_list();
entry_info.set_text(format!("Found {} empty folders.", empty_folder_number).as_str());
for (name, entry) in hashmap {
let name: String = name[..(name.len() - 1)].to_string();
let index = name.rfind('/').unwrap();
let values: [&dyn ToValue; 3] = [&(name[index + 1..].to_string()), &(name[..index].to_string()), &(NaiveDateTime::from_timestamp(entry.modified_date as i64, 0).to_string())];
list_store.set(&list_store.append(), &col_indices, &values);
// Create GUI
{
let list_store = scrolled_window_main_empty_folder_finder
.get_children()
.get(0)
.unwrap()
.clone()
.downcast::<gtk::TreeView>()
.unwrap()
.get_model()
.unwrap()
.downcast::<gtk::ListStore>()
.unwrap();
list_store.clear();
let col_indices = [0, 1, 2];
let hashmap = ef.get_empty_folder_list();
for (name, entry) in hashmap {
let name: String = name[..(name.len() - 1)].to_string();
let index = name.rfind('/').unwrap();
let values: [&dyn ToValue; 3] = [&(name[index + 1..].to_string()), &(name[..index].to_string()), &(NaiveDateTime::from_timestamp(entry.modified_date as i64, 0).to_string())];
list_store.set(&list_store.append(), &col_indices, &values);
}
print_text_messages_to_text_view(text_messages, &text_view_errors);
}
print_text_messages_to_text_view(text_messages, &text_view_errors);
}
// Set state
{
*shared_empty_folders_state.borrow_mut() = ef;
// Set state
{
*shared_empty_folders_state.borrow_mut() = ef;
if empty_folder_number > 0 {
*shared_buttons.borrow_mut().get_mut("empty_folder").unwrap().get_mut("save").unwrap() = true;
*shared_buttons.borrow_mut().get_mut("empty_folder").unwrap().get_mut("delete").unwrap() = true;
} else {
*shared_buttons.borrow_mut().get_mut("empty_folder").unwrap().get_mut("save").unwrap() = false;
*shared_buttons.borrow_mut().get_mut("empty_folder").unwrap().get_mut("delete").unwrap() = false;
if empty_folder_number > 0 {
*shared_buttons.borrow_mut().get_mut("empty_folder").unwrap().get_mut("save").unwrap() = true;
*shared_buttons.borrow_mut().get_mut("empty_folder").unwrap().get_mut("delete").unwrap() = true;
} else {
*shared_buttons.borrow_mut().get_mut("empty_folder").unwrap().get_mut("save").unwrap() = false;
*shared_buttons.borrow_mut().get_mut("empty_folder").unwrap().get_mut("delete").unwrap() = false;
}
set_buttons(&mut *shared_buttons.borrow_mut().get_mut("empty_folder").unwrap(), &buttons_array, &buttons_names);
}
set_buttons(&mut *shared_buttons.borrow_mut().get_mut("empty_folder").unwrap(), &buttons_array, &buttons_names);
}
}
Message::EmptyFiles(vf) => {
let information = vf.get_information();
let text_messages = vf.get_text_messages();
if vf.get_stopped_search() {
entry_info.set_text("Searching for empty files was stopped by user");
let empty_files_number: usize = information.number_of_empty_files;
entry_info.set_text(format!("Found {} empty files.", empty_files_number).as_str());
// Create GUI
{
let list_store = scrolled_window_main_empty_files_finder
//Also clear list
scrolled_window_main_empty_files_finder
.get_children()
.get(0)
.unwrap()
@ -1432,104 +1476,65 @@ fn main() {
.get_model()
.unwrap()
.downcast::<gtk::ListStore>()
.unwrap();
list_store.clear();
let col_indices = [0, 1, 2];
let vector = vf.get_empty_files();
for file_entry in vector {
let name: String = file_entry.path.to_string();
let index = name.rfind('/').unwrap();
let values: [&dyn ToValue; 3] = [&(name[index + 1..].to_string()), &(name[..index].to_string()), &(NaiveDateTime::from_timestamp(file_entry.modified_date as i64, 0).to_string())];
list_store.set(&list_store.append(), &col_indices, &values);
}
print_text_messages_to_text_view(text_messages, &text_view_errors);
}
// Set state
{
*shared_empty_files_state.borrow_mut() = vf;
if empty_files_number > 0 {
*shared_buttons.borrow_mut().get_mut("empty_file").unwrap().get_mut("save").unwrap() = true;
*shared_buttons.borrow_mut().get_mut("empty_file").unwrap().get_mut("delete").unwrap() = true;
} else {
*shared_buttons.borrow_mut().get_mut("empty_file").unwrap().get_mut("save").unwrap() = false;
*shared_buttons.borrow_mut().get_mut("empty_file").unwrap().get_mut("delete").unwrap() = false;
}
set_buttons(&mut *shared_buttons.borrow_mut().get_mut("empty_file").unwrap(), &buttons_array, &buttons_names);
}
}
Message::BigFiles(bf) => {
let information = bf.get_information();
let text_messages = bf.get_text_messages();
let biggest_files_number: usize = information.number_of_real_files;
entry_info.set_text(format!("Found {} biggest files.", biggest_files_number).as_str());
// Create GUI
{
let list_store = scrolled_window_big_files_finder
.get_children()
.get(0)
.unwrap()
.clone()
.downcast::<gtk::TreeView>()
.unwrap()
.get_model()
.unwrap()
.downcast::<gtk::ListStore>()
.unwrap();
list_store.clear();
.clear();
} else {
let information = vf.get_information();
let text_messages = vf.get_text_messages();
let col_indices = [0, 1, 2, 3];
let empty_files_number: usize = information.number_of_empty_files;
let btreemap = bf.get_big_files();
entry_info.set_text(format!("Found {} empty files.", empty_files_number).as_str());
// Create GUI
{
let list_store = scrolled_window_main_empty_files_finder
.get_children()
.get(0)
.unwrap()
.clone()
.downcast::<gtk::TreeView>()
.unwrap()
.get_model()
.unwrap()
.downcast::<gtk::ListStore>()
.unwrap();
list_store.clear();
let col_indices = [0, 1, 2];
let vector = vf.get_empty_files();
for (size, vector) in btreemap.iter().rev() {
for file_entry in vector {
let name: String = file_entry.path.to_string();
let index = name.rfind('/').unwrap();
let values: [&dyn ToValue; 4] = [
&(format!("{} ({} bytes)", size.file_size(options::BINARY).unwrap(), size)),
&(name[index + 1..].to_string()),
&(name[..index].to_string()),
&(NaiveDateTime::from_timestamp(file_entry.modified_date as i64, 0).to_string()),
];
let values: [&dyn ToValue; 3] = [&(name[index + 1..].to_string()), &(name[..index].to_string()), &(NaiveDateTime::from_timestamp(file_entry.modified_date as i64, 0).to_string())];
list_store.set(&list_store.append(), &col_indices, &values);
}
print_text_messages_to_text_view(text_messages, &text_view_errors);
}
print_text_messages_to_text_view(text_messages, &text_view_errors);
}
// Set state
{
*shared_big_files_state.borrow_mut() = bf;
// Set state
{
*shared_empty_files_state.borrow_mut() = vf;
if biggest_files_number > 0 {
*shared_buttons.borrow_mut().get_mut("big_file").unwrap().get_mut("save").unwrap() = true;
*shared_buttons.borrow_mut().get_mut("big_file").unwrap().get_mut("delete").unwrap() = true;
} else {
*shared_buttons.borrow_mut().get_mut("big_file").unwrap().get_mut("save").unwrap() = false;
*shared_buttons.borrow_mut().get_mut("big_file").unwrap().get_mut("delete").unwrap() = false;
if empty_files_number > 0 {
*shared_buttons.borrow_mut().get_mut("empty_file").unwrap().get_mut("save").unwrap() = true;
*shared_buttons.borrow_mut().get_mut("empty_file").unwrap().get_mut("delete").unwrap() = true;
} else {
*shared_buttons.borrow_mut().get_mut("empty_file").unwrap().get_mut("save").unwrap() = false;
*shared_buttons.borrow_mut().get_mut("empty_file").unwrap().get_mut("delete").unwrap() = false;
}
set_buttons(&mut *shared_buttons.borrow_mut().get_mut("empty_file").unwrap(), &buttons_array, &buttons_names);
}
set_buttons(&mut *shared_buttons.borrow_mut().get_mut("big_file").unwrap(), &buttons_array, &buttons_names);
}
}
Message::Temporary(tf) => {
let information = tf.get_information();
let text_messages = tf.get_text_messages();
Message::BigFiles(bf) => {
if bf.get_stopped_search() {
entry_info.set_text("Searching for big files was stopped by user");
let temporary_files_number: usize = information.number_of_temporary_files;
entry_info.set_text(format!("Found {} temporary files.", temporary_files_number).as_str());
// Create GUI
{
let list_store = scrolled_window_main_temporary_files_finder
//Also clear list
scrolled_window_duplicate_finder
.get_children()
.get(0)
.unwrap()
@ -1539,39 +1544,136 @@ fn main() {
.get_model()
.unwrap()
.downcast::<gtk::ListStore>()
.unwrap();
list_store.clear();
.unwrap()
.clear();
} else {
let information = bf.get_information();
let text_messages = bf.get_text_messages();
let col_indices = [0, 1, 2];
let biggest_files_number: usize = information.number_of_real_files;
let vector = tf.get_temporary_files();
entry_info.set_text(format!("Found {} biggest files.", biggest_files_number).as_str());
for file_entry in vector {
let name: String = file_entry.path.to_string();
let index = name.rfind('/').unwrap();
let values: [&dyn ToValue; 3] = [&(name[index + 1..].to_string()), &(name[..index].to_string()), &(NaiveDateTime::from_timestamp(file_entry.modified_date as i64, 0).to_string())];
list_store.set(&list_store.append(), &col_indices, &values);
// Create GUI
{
let list_store = scrolled_window_big_files_finder
.get_children()
.get(0)
.unwrap()
.clone()
.downcast::<gtk::TreeView>()
.unwrap()
.get_model()
.unwrap()
.downcast::<gtk::ListStore>()
.unwrap();
list_store.clear();
let col_indices = [0, 1, 2, 3];
let btreemap = bf.get_big_files();
for (size, vector) in btreemap.iter().rev() {
for file_entry in vector {
let name: String = file_entry.path.to_string();
let index = name.rfind('/').unwrap();
let values: [&dyn ToValue; 4] = [
&(format!("{} ({} bytes)", size.file_size(options::BINARY).unwrap(), size)),
&(name[index + 1..].to_string()),
&(name[..index].to_string()),
&(NaiveDateTime::from_timestamp(file_entry.modified_date as i64, 0).to_string()),
];
list_store.set(&list_store.append(), &col_indices, &values);
}
}
print_text_messages_to_text_view(text_messages, &text_view_errors);
}
// Set state
{
*shared_big_files_state.borrow_mut() = bf;
if biggest_files_number > 0 {
*shared_buttons.borrow_mut().get_mut("big_file").unwrap().get_mut("save").unwrap() = true;
*shared_buttons.borrow_mut().get_mut("big_file").unwrap().get_mut("delete").unwrap() = true;
} else {
*shared_buttons.borrow_mut().get_mut("big_file").unwrap().get_mut("save").unwrap() = false;
*shared_buttons.borrow_mut().get_mut("big_file").unwrap().get_mut("delete").unwrap() = false;
}
set_buttons(&mut *shared_buttons.borrow_mut().get_mut("big_file").unwrap(), &buttons_array, &buttons_names);
}
print_text_messages_to_text_view(text_messages, &text_view_errors);
}
}
Message::Temporary(tf) => {
if tf.get_stopped_search() {
entry_info.set_text("Searching for temporary files was stopped by user");
// Set state
{
*shared_temporary_files_state.borrow_mut() = tf;
//Also clear list
scrolled_window_duplicate_finder
.get_children()
.get(0)
.unwrap()
.clone()
.downcast::<gtk::TreeView>()
.unwrap()
.get_model()
.unwrap()
.downcast::<gtk::ListStore>()
.unwrap()
.clear();
} else {
let information = tf.get_information();
let text_messages = tf.get_text_messages();
if temporary_files_number > 0 {
*shared_buttons.borrow_mut().get_mut("temporary_file").unwrap().get_mut("save").unwrap() = true;
*shared_buttons.borrow_mut().get_mut("temporary_file").unwrap().get_mut("delete").unwrap() = true;
} else {
*shared_buttons.borrow_mut().get_mut("temporary_file").unwrap().get_mut("save").unwrap() = false;
*shared_buttons.borrow_mut().get_mut("temporary_file").unwrap().get_mut("delete").unwrap() = false;
let temporary_files_number: usize = information.number_of_temporary_files;
entry_info.set_text(format!("Found {} temporary files.", temporary_files_number).as_str());
// Create GUI
{
let list_store = scrolled_window_main_temporary_files_finder
.get_children()
.get(0)
.unwrap()
.clone()
.downcast::<gtk::TreeView>()
.unwrap()
.get_model()
.unwrap()
.downcast::<gtk::ListStore>()
.unwrap();
list_store.clear();
let col_indices = [0, 1, 2];
let vector = tf.get_temporary_files();
for file_entry in vector {
let name: String = file_entry.path.to_string();
let index = name.rfind('/').unwrap();
let values: [&dyn ToValue; 3] = [&(name[index + 1..].to_string()), &(name[..index].to_string()), &(NaiveDateTime::from_timestamp(file_entry.modified_date as i64, 0).to_string())];
list_store.set(&list_store.append(), &col_indices, &values);
}
print_text_messages_to_text_view(text_messages, &text_view_errors);
}
// Set state
{
*shared_temporary_files_state.borrow_mut() = tf;
if temporary_files_number > 0 {
*shared_buttons.borrow_mut().get_mut("temporary_file").unwrap().get_mut("save").unwrap() = true;
*shared_buttons.borrow_mut().get_mut("temporary_file").unwrap().get_mut("delete").unwrap() = true;
} else {
*shared_buttons.borrow_mut().get_mut("temporary_file").unwrap().get_mut("save").unwrap() = false;
*shared_buttons.borrow_mut().get_mut("temporary_file").unwrap().get_mut("delete").unwrap() = false;
}
set_buttons(&mut *shared_buttons.borrow_mut().get_mut("temporary_file").unwrap(), &buttons_array, &buttons_names);
}
set_buttons(&mut *shared_buttons.borrow_mut().get_mut("temporary_file").unwrap(), &buttons_array, &buttons_names);
}
}
}
// Returning false here would close the receiver
// and have senders fail
// Returning false here would close the receiver and have senders fail
glib::Continue(true)
});

View file

@ -1,7 +1,7 @@
[package]
name = "czkawka_gui_orbtk"
version = "1.0.1"
authors = ["Rafał Mikrut <mikrutrafal54@gmail.com>"]
authors = ["Rafał Mikrut <mikrutrafal@protonmail.com>"]
edition = "2018"
description = "Orbtk frontend of Czkawka"
license = "MIT"