2020-11-01 02:23:31 +13:00
extern crate gtk ;
use crate ::gui_data ::GuiData ;
use crate ::help_functions ::* ;
2021-01-11 00:06:25 +13:00
use crate ::notebook_enums ::* ;
2020-11-01 02:23:31 +13:00
use gtk ::prelude ::* ;
2021-03-07 20:57:48 +13:00
use gtk ::Align ;
2020-11-05 06:15:06 +13:00
use std ::collections ::BTreeMap ;
2020-11-01 02:23:31 +13:00
use std ::fs ;
use std ::fs ::Metadata ;
2020-12-22 04:09:39 +13:00
// TODO add support for checking if really symlink doesn't point to correct directory/file
2020-11-01 02:23:31 +13:00
pub fn connect_button_delete ( gui_data : & GuiData ) {
2020-11-05 06:15:06 +13:00
let gui_data = gui_data . clone ( ) ;
2021-01-11 08:12:08 +13:00
let buttons_delete = gui_data . bottom_buttons . buttons_delete . clone ( ) ;
2021-01-11 01:45:05 +13:00
let tree_view_duplicate_finder = gui_data . main_notebook . tree_view_duplicate_finder . clone ( ) ;
2021-01-11 08:12:08 +13:00
let notebook_main = gui_data . main_notebook . notebook_main . clone ( ) ;
2020-11-01 02:23:31 +13:00
let window_main = gui_data . window_main . clone ( ) ;
2021-01-11 01:45:05 +13:00
let tree_view_empty_folder_finder = gui_data . main_notebook . tree_view_empty_folder_finder . clone ( ) ;
let tree_view_big_files_finder = gui_data . main_notebook . tree_view_big_files_finder . clone ( ) ;
let tree_view_empty_files_finder = gui_data . main_notebook . tree_view_empty_files_finder . clone ( ) ;
let tree_view_temporary_files_finder = gui_data . main_notebook . tree_view_temporary_files_finder . clone ( ) ;
let tree_view_similar_images_finder = gui_data . main_notebook . tree_view_similar_images_finder . clone ( ) ;
let tree_view_zeroed_files_finder = gui_data . main_notebook . tree_view_zeroed_files_finder . clone ( ) ;
let tree_view_same_music_finder = gui_data . main_notebook . tree_view_same_music_finder . clone ( ) ;
let tree_view_invalid_symlinks = gui_data . main_notebook . tree_view_invalid_symlinks . clone ( ) ;
2021-01-13 08:06:12 +13:00
let tree_view_broken_files = gui_data . main_notebook . tree_view_broken_files . clone ( ) ;
2021-02-23 21:40:19 +13:00
let check_button_settings_confirm_deletion = gui_data . settings . check_button_settings_confirm_deletion . clone ( ) ;
2021-03-07 03:56:39 +13:00
let check_button_settings_confirm_group_deletion = gui_data . settings . check_button_settings_confirm_group_deletion . clone ( ) ;
2021-01-11 08:12:08 +13:00
let image_preview_similar_images = gui_data . main_notebook . image_preview_similar_images . clone ( ) ;
2020-11-01 02:23:31 +13:00
buttons_delete . connect_clicked ( move | _ | {
2021-03-07 20:57:48 +13:00
if ! check_if_can_delete_files ( & check_button_settings_confirm_deletion , & window_main ) {
return ;
2020-11-01 02:23:31 +13:00
}
2021-06-26 04:07:13 +12:00
match to_notebook_main_enum ( notebook_main . current_page ( ) . unwrap ( ) ) {
2021-01-11 00:06:25 +13:00
NotebookMainEnum ::Duplicate = > {
2021-06-26 04:07:13 +12:00
if ! check_button_settings_confirm_group_deletion . is_active ( ) | | ! check_if_deleting_all_files_in_group ( & tree_view_duplicate_finder . clone ( ) , ColumnsDuplicates ::Color as i32 , & window_main , & check_button_settings_confirm_group_deletion ) {
2021-03-07 03:56:39 +13:00
tree_remove ( & tree_view_duplicate_finder . clone ( ) , ColumnsDuplicates ::Name as i32 , ColumnsDuplicates ::Path as i32 , ColumnsDuplicates ::Color as i32 , & gui_data ) ;
}
2020-11-01 02:23:31 +13:00
}
2021-01-11 00:06:25 +13:00
NotebookMainEnum ::EmptyDirectories = > {
2021-01-11 01:45:05 +13:00
empty_folder_remover ( & tree_view_empty_folder_finder . clone ( ) , ColumnsEmptyFolders ::Name as i32 , ColumnsEmptyFolders ::Path as i32 , & gui_data ) ;
2020-11-05 06:15:06 +13:00
}
2021-01-11 00:06:25 +13:00
NotebookMainEnum ::EmptyFiles = > {
2021-01-11 01:45:05 +13:00
basic_remove ( & tree_view_empty_files_finder . clone ( ) , ColumnsEmptyFiles ::Name as i32 , ColumnsEmptyFiles ::Path as i32 , & gui_data ) ;
2020-11-05 06:15:06 +13:00
}
2021-01-11 00:06:25 +13:00
NotebookMainEnum ::Temporary = > {
2021-01-11 01:45:05 +13:00
basic_remove ( & tree_view_temporary_files_finder . clone ( ) , ColumnsTemporaryFiles ::Name as i32 , ColumnsTemporaryFiles ::Path as i32 , & gui_data ) ;
2020-11-05 06:15:06 +13:00
}
2021-01-11 00:06:25 +13:00
NotebookMainEnum ::BigFiles = > {
2021-01-11 01:45:05 +13:00
basic_remove ( & tree_view_big_files_finder . clone ( ) , ColumnsBigFiles ::Name as i32 , ColumnsBigFiles ::Path as i32 , & gui_data ) ;
2020-11-05 06:15:06 +13:00
}
2021-01-11 00:06:25 +13:00
NotebookMainEnum ::SimilarImages = > {
2021-06-26 04:07:13 +12:00
if ! check_button_settings_confirm_group_deletion . is_active ( )
2021-03-07 03:56:39 +13:00
| | ! check_if_deleting_all_files_in_group ( & tree_view_similar_images_finder . clone ( ) , ColumnsSimilarImages ::Color as i32 , & window_main , & check_button_settings_confirm_group_deletion )
{
tree_remove (
& tree_view_similar_images_finder . clone ( ) ,
ColumnsSimilarImages ::Name as i32 ,
ColumnsSimilarImages ::Path as i32 ,
ColumnsSimilarImages ::Color as i32 ,
& gui_data ,
) ;
image_preview_similar_images . hide ( ) ;
}
2020-11-05 06:15:06 +13:00
}
2021-01-11 00:06:25 +13:00
NotebookMainEnum ::Zeroed = > {
2021-01-11 01:45:05 +13:00
basic_remove ( & tree_view_zeroed_files_finder . clone ( ) , ColumnsZeroedFiles ::Name as i32 , ColumnsZeroedFiles ::Path as i32 , & gui_data ) ;
2020-11-05 06:15:06 +13:00
}
2021-01-11 00:06:25 +13:00
NotebookMainEnum ::SameMusic = > {
2021-06-26 04:07:13 +12:00
if ! check_button_settings_confirm_group_deletion . is_active ( ) | | ! check_if_deleting_all_files_in_group ( & tree_view_same_music_finder . clone ( ) , ColumnsSameMusic ::Color as i32 , & window_main , & check_button_settings_confirm_group_deletion ) {
2021-03-07 03:56:39 +13:00
tree_remove ( & tree_view_same_music_finder . clone ( ) , ColumnsSameMusic ::Name as i32 , ColumnsSameMusic ::Path as i32 , ColumnsSameMusic ::Color as i32 , & gui_data ) ;
}
2020-11-05 06:15:06 +13:00
}
2021-01-11 00:06:25 +13:00
NotebookMainEnum ::Symlinks = > {
2021-01-11 01:45:05 +13:00
basic_remove ( & tree_view_invalid_symlinks . clone ( ) , ColumnsInvalidSymlinks ::Name as i32 , ColumnsInvalidSymlinks ::Path as i32 , & gui_data ) ;
2020-12-22 04:09:39 +13:00
}
2021-01-13 08:06:12 +13:00
NotebookMainEnum ::BrokenFiles = > {
basic_remove ( & tree_view_broken_files . clone ( ) , ColumnsBrokenFiles ::Name as i32 , ColumnsBrokenFiles ::Path as i32 , & gui_data ) ;
}
2020-11-05 06:15:06 +13:00
}
} ) ;
}
2020-11-01 02:23:31 +13:00
2021-03-07 20:57:48 +13:00
pub fn check_if_can_delete_files ( check_button_settings_confirm_deletion : & gtk ::CheckButton , window_main : & gtk ::Window ) -> bool {
2021-06-26 04:07:13 +12:00
if check_button_settings_confirm_deletion . is_active ( ) {
2021-03-07 20:57:48 +13:00
let confirmation_dialog_delete = gtk ::Dialog ::with_buttons (
Some ( " Delete confirmation " ) ,
Some ( window_main ) ,
gtk ::DialogFlags ::DESTROY_WITH_PARENT ,
& [ ( " Ok " , gtk ::ResponseType ::Ok ) , ( " Close " , gtk ::ResponseType ::Cancel ) ] ,
) ;
let label : gtk ::Label = gtk ::Label ::new ( Some ( " Are you sure that you want to delete files? " ) ) ;
let check_button : gtk ::CheckButton = gtk ::CheckButton ::with_label ( " Ask next time " ) ;
check_button . set_active ( true ) ;
check_button . set_halign ( Align ::Center ) ;
2021-06-26 04:07:13 +12:00
let button_box = confirmation_dialog_delete . children ( ) [ 0 ] . clone ( ) . downcast ::< gtk ::Box > ( ) . unwrap ( ) . children ( ) [ 0 ] . clone ( ) . downcast ::< gtk ::Box > ( ) . unwrap ( ) . children ( ) [ 0 ]
2021-03-07 20:57:48 +13:00
. clone ( )
. downcast ::< gtk ::ButtonBox > ( )
. unwrap ( ) ;
2021-06-26 04:07:13 +12:00
let button_ok = button_box . children ( ) [ 0 ] . clone ( ) ;
2021-03-07 20:57:48 +13:00
button_ok . grab_focus ( ) ;
2021-06-26 04:07:13 +12:00
let internal_box = confirmation_dialog_delete . children ( ) [ 0 ] . clone ( ) . downcast ::< gtk ::Box > ( ) . unwrap ( ) ;
2021-03-07 20:57:48 +13:00
internal_box . add ( & label ) ;
internal_box . add ( & check_button ) ;
confirmation_dialog_delete . show_all ( ) ;
let response_type = confirmation_dialog_delete . run ( ) ;
if response_type = = gtk ::ResponseType ::Ok {
2021-06-26 04:07:13 +12:00
if ! check_button . is_active ( ) {
2021-03-07 20:57:48 +13:00
check_button_settings_confirm_deletion . set_active ( false ) ;
}
confirmation_dialog_delete . hide ( ) ;
confirmation_dialog_delete . close ( ) ;
} else {
confirmation_dialog_delete . hide ( ) ;
confirmation_dialog_delete . close ( ) ;
return false ;
} ;
}
true
}
2021-03-07 03:56:39 +13:00
pub fn check_if_deleting_all_files_in_group ( tree_view : & gtk ::TreeView , column_color : i32 , window_main : & gtk ::Window , check_button_settings_confirm_group_deletion : & gtk ::CheckButton ) -> bool {
2021-06-26 04:07:13 +12:00
let selection = tree_view . selection ( ) ;
let ( selection_rows , tree_model ) = selection . selected_rows ( ) ;
2021-03-07 03:56:39 +13:00
if selection_rows . is_empty ( ) {
return false ;
}
let mut current_selected_row = 0 ;
let mut selected_all_records : bool = true ;
2021-06-26 04:07:13 +12:00
if let Some ( first_iter ) = tree_model . iter_first ( ) {
2021-03-07 03:56:39 +13:00
let current_iter = first_iter ;
2021-06-26 04:07:13 +12:00
if tree_model . value ( & current_iter , column_color ) . get ::< String > ( ) . unwrap ( ) ! = HEADER_ROW_COLOR {
2021-03-07 03:56:39 +13:00
panic! ( " First element, should be a header " ) ; // First element should be header
} ;
loop {
if ! tree_model . iter_next ( & current_iter ) {
if selected_all_records {
break ;
}
break ;
}
2021-06-26 04:07:13 +12:00
if tree_model . value ( & current_iter , column_color ) . get ::< String > ( ) . unwrap ( ) = = HEADER_ROW_COLOR {
2021-03-07 03:56:39 +13:00
if selected_all_records {
break ;
}
2021-06-26 04:07:13 +12:00
} else if current_selected_row ! = selection_rows . len ( ) & & selection_rows [ current_selected_row ] = = tree_model . path ( & current_iter ) . unwrap ( ) {
2021-03-07 03:56:39 +13:00
current_selected_row + = 1 ;
} else {
selected_all_records = false ;
}
}
} else {
return false ;
}
if ! selected_all_records {
return false ;
} else {
2021-03-07 20:57:48 +13:00
let confirmation_dialog_group_delete = gtk ::Dialog ::with_buttons (
2021-03-07 03:56:39 +13:00
Some ( " Confirmation of deleting all files in group " ) ,
Some ( window_main ) ,
gtk ::DialogFlags ::MODAL ,
& [ ( " Ok " , gtk ::ResponseType ::Ok ) , ( " Close " , gtk ::ResponseType ::Cancel ) ] ,
) ;
2021-03-07 20:57:48 +13:00
let label : gtk ::Label = gtk ::Label ::new ( Some ( " In some groups there are selected all records. " ) ) ;
let label2 : gtk ::Label = gtk ::Label ::new ( Some ( " Are you sure that you want to delete them? " ) ) ;
2021-03-07 03:56:39 +13:00
let check_button : gtk ::CheckButton = gtk ::CheckButton ::with_label ( " Ask next time " ) ;
check_button . set_active ( true ) ;
2021-03-07 20:57:48 +13:00
check_button . set_halign ( Align ::Center ) ;
2021-03-07 03:56:39 +13:00
2021-06-26 04:07:13 +12:00
let button_box = confirmation_dialog_group_delete . children ( ) [ 0 ] . clone ( ) . downcast ::< gtk ::Box > ( ) . unwrap ( ) . children ( ) [ 0 ]
2021-03-07 20:57:48 +13:00
. clone ( )
. downcast ::< gtk ::Box > ( )
. unwrap ( )
2021-06-26 04:07:13 +12:00
. children ( ) [ 0 ]
2021-03-07 20:57:48 +13:00
. clone ( )
. downcast ::< gtk ::ButtonBox > ( )
. unwrap ( ) ;
2021-03-07 03:56:39 +13:00
2021-06-26 04:07:13 +12:00
let button_ok = button_box . children ( ) [ 0 ] . clone ( ) ;
2021-03-07 20:57:48 +13:00
button_ok . grab_focus ( ) ;
2021-03-07 03:56:39 +13:00
2021-06-26 04:07:13 +12:00
let internal_box = confirmation_dialog_group_delete . children ( ) [ 0 ] . clone ( ) . downcast ::< gtk ::Box > ( ) . unwrap ( ) ;
2021-03-07 20:57:48 +13:00
internal_box . add ( & label ) ;
internal_box . add ( & label2 ) ;
internal_box . add ( & check_button ) ;
confirmation_dialog_group_delete . show_all ( ) ;
let response_type = confirmation_dialog_group_delete . run ( ) ;
2021-03-07 03:56:39 +13:00
if response_type = = gtk ::ResponseType ::Ok {
2021-06-26 04:07:13 +12:00
if ! check_button . is_active ( ) {
2021-03-07 03:56:39 +13:00
check_button_settings_confirm_group_deletion . set_active ( false ) ;
}
} else {
2021-03-07 20:57:48 +13:00
confirmation_dialog_group_delete . hide ( ) ;
confirmation_dialog_group_delete . close ( ) ;
2021-03-07 03:56:39 +13:00
return true ;
}
2021-03-07 20:57:48 +13:00
confirmation_dialog_group_delete . hide ( ) ;
confirmation_dialog_group_delete . close ( ) ;
2021-03-07 03:56:39 +13:00
}
false
}
2021-01-11 01:45:05 +13:00
pub fn empty_folder_remover ( tree_view : & gtk ::TreeView , column_file_name : i32 , column_path : i32 , gui_data : & GuiData ) {
2020-11-05 06:15:06 +13:00
let text_view_errors = gui_data . text_view_errors . clone ( ) ;
2021-06-26 04:07:13 +12:00
let use_trash = gui_data . settings . check_button_settings_use_trash . clone ( ) . is_active ( ) ;
2020-11-01 02:23:31 +13:00
2021-06-26 04:07:13 +12:00
let selection = tree_view . selection ( ) ;
2020-11-05 06:15:06 +13:00
2021-06-26 04:07:13 +12:00
let ( selection_rows , tree_model ) = selection . selected_rows ( ) ;
2020-11-05 06:15:06 +13:00
if selection_rows . is_empty ( ) {
return ;
}
2021-01-11 01:45:05 +13:00
let list_store = get_list_store ( & tree_view ) ;
2020-11-05 06:15:06 +13:00
let mut messages : String = " " . to_string ( ) ;
// Must be deleted from end to start, because when deleting entries, TreePath(and also TreeIter) will points to invalid data
for tree_path in selection_rows . iter ( ) . rev ( ) {
2021-06-26 04:07:13 +12:00
let name = tree_model . value ( & tree_model . iter ( tree_path ) . unwrap ( ) , column_file_name ) . get ::< String > ( ) . unwrap ( ) ;
let path = tree_model . value ( & tree_model . iter ( tree_path ) . unwrap ( ) , column_path ) . get ::< String > ( ) . unwrap ( ) ;
2020-11-05 06:15:06 +13:00
// We must check if folder is really empty or contains only other empty folders
let mut error_happened = false ;
let mut folders_to_check : Vec < String > = vec! [ format! ( " {} / {} " , path , name ) ] ;
let mut current_folder : String ;
let mut next_folder : String ;
' dir : while ! folders_to_check . is_empty ( ) {
current_folder = folders_to_check . pop ( ) . unwrap ( ) ;
let read_dir = match fs ::read_dir ( & current_folder ) {
Ok ( t ) = > t ,
Err ( _ ) = > {
error_happened = true ;
break 'dir ;
}
} ;
for entry in read_dir {
let entry_data = match entry {
Ok ( t ) = > t ,
Err ( _ ) = > {
error_happened = true ;
break 'dir ;
}
} ;
let metadata : Metadata = match entry_data . metadata ( ) {
Ok ( t ) = > t ,
Err ( _ ) = > {
error_happened = true ;
break 'dir ;
}
} ;
if metadata . is_dir ( ) {
next_folder = " " . to_owned ( )
+ & current_folder
+ " / "
+ match & entry_data . file_name ( ) . into_string ( ) {
2020-11-01 02:23:31 +13:00
Ok ( t ) = > t ,
Err ( _ ) = > {
error_happened = true ;
break 'dir ;
}
} ;
2020-11-05 06:15:06 +13:00
folders_to_check . push ( next_folder . clone ( ) ) ;
} else {
error_happened = true ;
2020-11-01 02:23:31 +13:00
}
}
2020-11-05 06:15:06 +13:00
}
2020-11-01 02:23:31 +13:00
2020-11-05 06:15:06 +13:00
if ! error_happened {
2021-03-12 02:31:59 +13:00
if ! use_trash {
match fs ::remove_dir_all ( format! ( " {} / {} " , path , name ) ) {
Ok ( _ ) = > {
2021-06-26 04:07:13 +12:00
list_store . remove ( & list_store . iter ( tree_path ) . unwrap ( ) ) ;
2021-03-12 02:31:59 +13:00
}
Err ( _ ) = > error_happened = true ,
}
} else {
match trash ::delete ( format! ( " {} / {} " , path , name ) ) {
Ok ( _ ) = > {
2021-06-26 04:07:13 +12:00
list_store . remove ( & list_store . iter ( tree_path ) . unwrap ( ) ) ;
2021-03-12 02:31:59 +13:00
}
Err ( _ ) = > error_happened = true ,
2020-11-01 02:23:31 +13:00
}
}
2020-11-05 06:15:06 +13:00
}
if error_happened {
messages + = format! ( " Failed to remove folder {} / {} because folder doesn't exists, you don't have permissions or isn't empty. \n " , path , name ) . as_str ( )
}
}
2020-11-01 02:23:31 +13:00
2021-06-26 04:07:13 +12:00
text_view_errors . buffer ( ) . unwrap ( ) . set_text ( messages . as_str ( ) ) ;
2020-11-05 06:15:06 +13:00
selection . unselect_all ( ) ;
}
2020-11-01 02:23:31 +13:00
2021-01-11 01:45:05 +13:00
pub fn basic_remove ( tree_view : & gtk ::TreeView , column_file_name : i32 , column_path : i32 , gui_data : & GuiData ) {
2020-11-05 06:15:06 +13:00
let text_view_errors = gui_data . text_view_errors . clone ( ) ;
2021-06-26 04:07:13 +12:00
let use_trash = gui_data . settings . check_button_settings_use_trash . clone ( ) . is_active ( ) ;
2020-11-01 02:23:31 +13:00
2021-06-26 04:07:13 +12:00
let selection = tree_view . selection ( ) ;
2020-11-01 02:23:31 +13:00
2021-06-26 04:07:13 +12:00
let ( selection_rows , tree_model ) = selection . selected_rows ( ) ;
2020-11-05 06:15:06 +13:00
if selection_rows . is_empty ( ) {
return ;
}
2021-01-11 01:45:05 +13:00
let list_store = get_list_store ( & tree_view ) ;
2020-11-01 02:23:31 +13:00
2020-11-05 06:15:06 +13:00
let mut messages : String = " " . to_string ( ) ;
2020-11-01 02:23:31 +13:00
2020-11-05 06:15:06 +13:00
// Must be deleted from end to start, because when deleting entries, TreePath(and also TreeIter) will points to invalid data
for tree_path in selection_rows . iter ( ) . rev ( ) {
2021-06-26 04:07:13 +12:00
let name = tree_model . value ( & tree_model . iter ( tree_path ) . unwrap ( ) , column_file_name ) . get ::< String > ( ) . unwrap ( ) ;
let path = tree_model . value ( & tree_model . iter ( tree_path ) . unwrap ( ) , column_path ) . get ::< String > ( ) . unwrap ( ) ;
2020-11-01 02:23:31 +13:00
2021-03-12 02:31:59 +13:00
if ! use_trash {
match fs ::remove_file ( format! ( " {} / {} " , path , name ) ) {
Ok ( _ ) = > {
2021-06-26 04:07:13 +12:00
list_store . remove ( & list_store . iter ( tree_path ) . unwrap ( ) ) ;
2021-03-12 02:31:59 +13:00
}
Err ( _ ) = > messages + = format! ( " Failed to remove file {} / {} because file doesn't exists or you don't have permissions. \n " , path , name ) . as_str ( ) ,
}
} else {
match trash ::delete ( format! ( " {} / {} " , path , name ) ) {
Ok ( _ ) = > {
2021-06-26 04:07:13 +12:00
list_store . remove ( & list_store . iter ( tree_path ) . unwrap ( ) ) ;
2021-03-12 02:31:59 +13:00
}
Err ( _ ) = > messages + = format! ( " Failed to remove file {} / {} because file doesn't exists or you don't have permissions. \n " , path , name ) . as_str ( ) ,
2020-11-05 06:15:06 +13:00
}
}
}
2020-11-01 02:23:31 +13:00
2021-06-26 04:07:13 +12:00
text_view_errors . buffer ( ) . unwrap ( ) . set_text ( messages . as_str ( ) ) ;
2020-11-05 06:15:06 +13:00
selection . unselect_all ( ) ;
2020-11-09 22:09:22 +13:00
}
2020-11-01 02:23:31 +13:00
2020-11-09 22:09:22 +13:00
// Remove all occurrences - remove every element which have same path and name as even non selected ones
2021-01-11 01:45:05 +13:00
pub fn tree_remove ( tree_view : & gtk ::TreeView , column_file_name : i32 , column_path : i32 , column_color : i32 , gui_data : & GuiData ) {
2020-11-05 06:15:06 +13:00
let text_view_errors = gui_data . text_view_errors . clone ( ) ;
2021-06-26 04:07:13 +12:00
let use_trash = gui_data . settings . check_button_settings_use_trash . clone ( ) . is_active ( ) ;
2020-11-01 02:23:31 +13:00
2021-06-26 04:07:13 +12:00
let selection = tree_view . selection ( ) ;
2020-11-01 02:23:31 +13:00
2021-06-26 04:07:13 +12:00
let ( selection_rows , tree_model ) = selection . selected_rows ( ) ;
2020-11-05 06:15:06 +13:00
if selection_rows . is_empty ( ) {
return ;
}
2021-01-11 01:45:05 +13:00
let list_store = get_list_store ( & tree_view ) ;
2020-11-01 02:23:31 +13:00
2020-11-05 06:15:06 +13:00
let mut messages : String = " " . to_string ( ) ;
2020-11-01 02:23:31 +13:00
2020-11-05 06:15:06 +13:00
let mut vec_path_to_delete : Vec < ( String , String ) > = Vec ::new ( ) ;
let mut map_with_path_to_delete : BTreeMap < String , Vec < String > > = Default ::default ( ) ; // BTreeMap<Path,Vec<FileName>>
2020-11-01 02:23:31 +13:00
2020-11-09 22:09:22 +13:00
// Save to variable paths of files, and remove it when not removing all occurrences.
2020-11-05 06:15:06 +13:00
for tree_path in selection_rows . iter ( ) . rev ( ) {
2021-06-26 04:07:13 +12:00
let file_name = tree_model . value ( & tree_model . iter ( tree_path ) . unwrap ( ) , column_file_name ) . get ::< String > ( ) . unwrap ( ) ;
let path = tree_model . value ( & tree_model . iter ( tree_path ) . unwrap ( ) , column_path ) . get ::< String > ( ) . unwrap ( ) ;
2020-11-01 02:23:31 +13:00
2021-06-26 04:07:13 +12:00
list_store . remove ( & list_store . iter ( tree_path ) . unwrap ( ) ) ;
2020-11-09 23:24:01 +13:00
2020-11-05 06:15:06 +13:00
map_with_path_to_delete . entry ( path . clone ( ) ) . or_insert_with ( Vec ::new ) ;
map_with_path_to_delete . get_mut ( path . as_str ( ) ) . unwrap ( ) . push ( file_name ) ;
}
// Delete duplicated entries, and remove real files
for ( path , mut vec_file_name ) in map_with_path_to_delete {
vec_file_name . sort ( ) ;
vec_file_name . dedup ( ) ;
for file_name in vec_file_name {
2021-03-12 02:31:59 +13:00
if ! use_trash {
if fs ::remove_file ( format! ( " {} / {} " , path . clone ( ) , file_name . clone ( ) ) ) . is_err ( ) {
messages + = format! (
" Failed to remove file {}/{}. It is possible that you already deleted it, because similar images shows all possible file doesn't exists or you don't have permissions. \n " ,
path , file_name
)
. as_str ( )
}
} else if trash ::delete ( format! ( " {} / {} " , path . clone ( ) , file_name . clone ( ) ) ) . is_err ( ) {
2020-11-05 06:15:06 +13:00
messages + = format! (
" Failed to remove file {}/{}. It is possible that you already deleted it, because similar images shows all possible file doesn't exists or you don't have permissions. \n " ,
path , file_name
)
. as_str ( )
}
2021-03-12 02:31:59 +13:00
2020-11-05 06:15:06 +13:00
vec_path_to_delete . push ( ( path . clone ( ) , file_name . clone ( ) ) ) ;
}
}
// Remove only child from header
2021-06-26 04:07:13 +12:00
if let Some ( first_iter ) = list_store . iter_first ( ) {
2020-11-09 23:24:01 +13:00
let mut vec_tree_path_to_delete : Vec < gtk ::TreePath > = Vec ::new ( ) ;
let mut current_iter = first_iter ;
2021-06-26 04:07:13 +12:00
if tree_model . value ( & current_iter , column_color ) . get ::< String > ( ) . unwrap ( ) ! = HEADER_ROW_COLOR {
2021-01-11 00:06:25 +13:00
panic! ( " First deleted element, should be a header " ) ; // First element should be header
2020-11-09 23:24:01 +13:00
} ;
let mut next_iter ;
let mut next_next_iter ;
' main : loop {
2021-06-26 04:07:13 +12:00
if tree_model . value ( & current_iter , column_color ) . get ::< String > ( ) . unwrap ( ) ! = HEADER_ROW_COLOR {
2021-01-11 00:06:25 +13:00
panic! ( " First deleted element, should be a header " ) ; // First element should be header
2020-11-05 06:15:06 +13:00
} ;
2020-11-09 23:24:01 +13:00
next_iter = current_iter . clone ( ) ;
if ! list_store . iter_next ( & next_iter ) {
2020-11-10 03:50:28 +13:00
// There is only single header left (H1 -> END) -> (NOTHING)
2021-06-26 04:07:13 +12:00
vec_tree_path_to_delete . push ( list_store . path ( & current_iter ) . unwrap ( ) ) ;
2020-11-09 23:24:01 +13:00
break 'main ;
}
2020-11-05 06:15:06 +13:00
2021-06-26 04:07:13 +12:00
if tree_model . value ( & next_iter , column_color ) . get ::< String > ( ) . unwrap ( ) = = HEADER_ROW_COLOR {
2020-11-10 03:50:28 +13:00
// There are two headers each others(we remove just first) -> (H1 -> H2) -> (H2)
2021-06-26 04:07:13 +12:00
vec_tree_path_to_delete . push ( list_store . path ( & current_iter ) . unwrap ( ) ) ;
2020-11-09 23:24:01 +13:00
current_iter = next_iter . clone ( ) ;
continue 'main ;
}
2020-11-01 02:23:31 +13:00
2020-11-09 23:24:01 +13:00
next_next_iter = next_iter . clone ( ) ;
if ! list_store . iter_next ( & next_next_iter ) {
2020-11-10 03:50:28 +13:00
// There is only one child of header left, so we remove it with header (H1 -> C1 -> END) -> (NOTHING)
2021-06-26 04:07:13 +12:00
vec_tree_path_to_delete . push ( list_store . path ( & current_iter ) . unwrap ( ) ) ;
vec_tree_path_to_delete . push ( list_store . path ( & next_iter ) . unwrap ( ) ) ;
2020-11-09 23:24:01 +13:00
break 'main ;
}
2021-06-26 04:07:13 +12:00
if tree_model . value ( & next_next_iter , column_color ) . get ::< String > ( ) . unwrap ( ) = = HEADER_ROW_COLOR {
2020-11-10 03:50:28 +13:00
// One child between two headers, we can remove them (H1 -> C1 -> H2) -> (H2)
2021-06-26 04:07:13 +12:00
vec_tree_path_to_delete . push ( list_store . path ( & current_iter ) . unwrap ( ) ) ;
vec_tree_path_to_delete . push ( list_store . path ( & next_iter ) . unwrap ( ) ) ;
2020-11-09 23:24:01 +13:00
current_iter = next_next_iter . clone ( ) ;
continue 'main ;
}
2020-11-01 02:23:31 +13:00
2020-11-09 23:24:01 +13:00
loop {
2020-11-10 03:50:28 +13:00
// (H1 -> C1 -> C2 -> Cn -> END) -> (NO CHANGE, BECAUSE IS GOOD)
2020-11-05 06:15:06 +13:00
if ! list_store . iter_next ( & next_next_iter ) {
break 'main ;
}
2020-11-10 03:50:28 +13:00
// Move to next header
2021-06-26 04:07:13 +12:00
if tree_model . value ( & next_next_iter , column_color ) . get ::< String > ( ) . unwrap ( ) = = HEADER_ROW_COLOR {
2020-11-05 06:15:06 +13:00
current_iter = next_next_iter . clone ( ) ;
continue 'main ;
}
}
}
2020-11-09 23:24:01 +13:00
for tree_path in vec_tree_path_to_delete . iter ( ) . rev ( ) {
2021-06-26 04:07:13 +12:00
list_store . remove ( & list_store . iter ( & tree_path ) . unwrap ( ) ) ;
2020-11-01 02:23:31 +13:00
}
2020-11-05 06:15:06 +13:00
}
// Last step, remove orphan header if exists
2021-06-26 04:07:13 +12:00
if let Some ( iter ) = list_store . iter_first ( ) {
2020-11-05 06:15:06 +13:00
if ! list_store . iter_next ( & iter ) {
list_store . clear ( ) ;
}
}
2021-06-26 04:07:13 +12:00
text_view_errors . buffer ( ) . unwrap ( ) . set_text ( messages . as_str ( ) ) ;
2020-11-05 06:15:06 +13:00
selection . unselect_all ( ) ;
2020-11-01 02:23:31 +13:00
}