Skip to content

Commit afc0ed4

Browse files
committed
I'm so lazy
1 parent c5157a0 commit afc0ed4

2 files changed

Lines changed: 67 additions & 12 deletions

File tree

krokiet/src/connect_row_selection.rs

Lines changed: 37 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
use std::collections::HashMap;
22
use std::hash::{Hash, Hasher};
3-
use std::sync::{RwLock, RwLockWriteGuard};
3+
use std::mem;
4+
use std::sync::{LazyLock, RwLock, RwLockWriteGuard};
45

56
use czkawka_core::TOOLS_NUMBER;
67
use log::trace;
7-
use once_cell::sync::OnceCell;
88
use slint::{ComponentHandle, Model, ModelRc, VecModel};
99

1010
use crate::{CurrentTab, GuiState, MainListModel, MainWindow};
@@ -21,7 +21,7 @@ pub(crate) struct SelectionData {
2121
exceeded_limit: bool,
2222
}
2323

24-
pub(crate) static TOOLS_SELECTION: OnceCell<RwLock<HashMap<CurrentTab, SelectionData>>> = OnceCell::new();
24+
pub(crate) static TOOLS_SELECTION: LazyLock<RwLock<HashMap<CurrentTab, SelectionData>>> = LazyLock::new(|| RwLock::new(HashMap::new()));
2525

2626
pub(crate) fn reset_selection(app: &MainWindow, reset_all_selection: bool) {
2727
if reset_all_selection {
@@ -35,7 +35,31 @@ pub(crate) fn reset_selection(app: &MainWindow, reset_all_selection: bool) {
3535
app.invoke_reset_selection();
3636
}
3737

38-
fn initialize_selection_struct() {
38+
// E.g. when sorting things, selected rows in vector, may be invalid
39+
// So we need to recalculate them
40+
pub(crate) fn recalculate_small_selection_if_needed(model: &ModelRc<MainListModel>, active_tab: CurrentTab) {
41+
let mut lock = get_write_selection_lock();
42+
let selection = lock.get_mut(&active_tab).expect("Failed to get selection data");
43+
44+
if selection.exceeded_limit || selection.selected_rows.is_empty() {
45+
return;
46+
}
47+
48+
let selection_not_changed = selection.selected_rows.iter().all(|e| {
49+
let model_data = model
50+
.row_data(*e)
51+
.unwrap_or_else(|| panic!("Failed to get row data with id {}, with model {} items", e, model.row_count()));
52+
model_data.selected_row
53+
});
54+
55+
if selection_not_changed {
56+
return;
57+
}
58+
59+
selection.selected_rows = model.iter().enumerate().filter_map(|(idx, e)| if e.selected_row { Some(idx) } else { None }).collect();
60+
}
61+
62+
pub(crate) fn initialize_selection_struct() {
3963
let tools: [CurrentTab; TOOLS_NUMBER] = [
4064
CurrentTab::DuplicateFiles,
4165
CurrentTab::EmptyFolders,
@@ -51,16 +75,21 @@ fn initialize_selection_struct() {
5175
];
5276

5377
let map: HashMap<_, _> = tools.into_iter().map(|tool| (tool, SelectionData::default())).collect();
54-
TOOLS_SELECTION.set(RwLock::new(map)).expect("Failed to set selection data, it was already set");
78+
let mut item = TOOLS_SELECTION.write().expect("Failed to get write selection lock");
79+
if !cfg!(test) {
80+
let data = mem::replace(&mut *item, map);
81+
assert!(data.is_empty(), "Selection data is already initialized, but it should be empty");
82+
} else {
83+
let _ = mem::replace(&mut *item, map);
84+
}
5585
}
5686

5787
// fn get_read_selection_lock() -> RwLockReadGuard<'static, HashMap<CurrentTab, SelectionData>> {
5888
// let selection = TOOLS_SELECTION.get().expect("Selection data is not initialized");
5989
// selection.read().expect("Failed to lock selection data")
6090
// }
6191
fn get_write_selection_lock() -> RwLockWriteGuard<'static, HashMap<CurrentTab, SelectionData>> {
62-
let selection = TOOLS_SELECTION.get().expect("Selection data is not initialized");
63-
selection.write().expect("Failed to lock selection data")
92+
TOOLS_SELECTION.write().expect("Selection data is not initialized")
6493
}
6594

6695
impl Hash for CurrentTab {
@@ -305,7 +334,7 @@ fn rows_deselect_all_selected_one_by_one(model: &ModelRc<MainListModel>, selecti
305334
let mut model_data = model
306335
.row_data(*id)
307336
.unwrap_or_else(|| panic!("Failed to get row data with id {id}, with model {} items", model.row_count()));
308-
assert!(model_data.selected_row); // Probably can be removed in future
337+
assert!(model_data.selected_row);
309338
model_data.selected_row = false;
310339
model.set_row_data(*id, model_data);
311340
}

krokiet/src/connect_sort.rs

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use std::mem;
33
use slint::{ComponentHandle, Model, ModelRc, VecModel};
44

55
use crate::common::{connect_i32_into_u64, get_int_size_idx, get_is_header_mode, get_tool_model, set_tool_model};
6+
use crate::connect_row_selection::recalculate_small_selection_if_needed;
67
use crate::{Callabler, CurrentTab, GuiState, MainListModel, MainWindow, SortMode};
78

89
pub fn connect_sort(app: &MainWindow) {
@@ -35,15 +36,19 @@ mod sorts {
3536
if !get_is_header_mode(active_tab) {
3637
let mut items = model.iter().collect::<Vec<_>>();
3738
items.reverse();
38-
return ModelRc::new(VecModel::from(items));
39+
let new_model = ModelRc::new(VecModel::from(items));
40+
recalculate_small_selection_if_needed(&new_model, active_tab);
41+
return new_model;
3942
}
4043

4144
let mut grouped_items = group_by_header(model);
4245
for (_, items) in &mut grouped_items {
4346
items.reverse();
4447
}
4548

46-
convert_group_header_into_rc_model(grouped_items, model.row_count())
49+
let new_model = convert_group_header_into_rc_model(grouped_items, model.row_count());
50+
recalculate_small_selection_if_needed(&new_model, active_tab);
51+
new_model
4752
}
4853

4954
pub(super) fn sort_checked(model: &ModelRc<MainListModel>, active_tab: CurrentTab) -> ModelRc<MainListModel> {
@@ -117,15 +122,19 @@ fn common_sort_function<T: Ord>(model: &ModelRc<MainListModel>, active_tab: Curr
117122
if !get_is_header_mode(active_tab) {
118123
let mut items = model.iter().collect::<Vec<_>>();
119124
items.sort_by_cached_key(&sort_function);
120-
return ModelRc::new(VecModel::from(items));
125+
let new_model = ModelRc::new(VecModel::from(items));
126+
recalculate_small_selection_if_needed(&new_model, active_tab);
127+
return new_model;
121128
}
122129

123130
let mut grouped_items = group_by_header(model);
124131
for (_, items) in &mut grouped_items {
125132
items.sort_by_cached_key(&sort_function);
126133
}
127134

128-
convert_group_header_into_rc_model(grouped_items, model.row_count())
135+
let new_model = convert_group_header_into_rc_model(grouped_items, model.row_count());
136+
recalculate_small_selection_if_needed(&new_model, active_tab);
137+
new_model
129138
}
130139

131140
fn convert_group_header_into_rc_model(grouped: Vec<(MainListModel, Vec<MainListModel>)>, model_size: usize) -> ModelRc<MainListModel> {
@@ -172,13 +181,15 @@ mod tests {
172181
use slint::Model;
173182

174183
use crate::common::{get_int_modification_date_idx, get_int_size_idx, get_is_header_mode, get_str_name_idx, get_str_path_idx};
184+
use crate::connect_row_selection::initialize_selection_struct;
175185
use crate::connect_sort::sorts::{reverse_sort, sort_by_full_name, sort_by_name, sort_by_parent_name, sort_by_size, sort_checked, sort_modification_date, sort_selection};
176186
use crate::connect_sort::{convert_group_header_into_rc_model, group_by_header};
177187
use crate::test_common::{create_model_from_model_vec, get_model_vec};
178188
use crate::{CurrentTab, MainListModel};
179189

180190
#[test]
181191
fn group_by_header_splits_items_into_groups_correctly() {
192+
initialize_selection_struct();
182193
let mut model = get_model_vec(6);
183194
model[0].header_row = true;
184195
model[1].header_row = false;
@@ -203,6 +214,7 @@ mod tests {
203214

204215
#[test]
205216
fn group_by_header_handles_empty_model() {
217+
initialize_selection_struct();
206218
let model = create_model_from_model_vec(&[]);
207219

208220
let grouped = group_by_header(&model);
@@ -213,6 +225,7 @@ mod tests {
213225
#[test]
214226
#[should_panic]
215227
fn group_by_header_panics_when_no_header_before_items() {
228+
initialize_selection_struct();
216229
let mut model = get_model_vec(3);
217230
model[0].header_row = false;
218231
model[1].header_row = false;
@@ -225,6 +238,7 @@ mod tests {
225238
#[test]
226239
#[should_panic]
227240
fn group_by_header_panics_when_group_is_empty() {
241+
initialize_selection_struct();
228242
let mut model = get_model_vec(3);
229243
model[0].header_row = true;
230244
model[1].header_row = true;
@@ -236,6 +250,7 @@ mod tests {
236250

237251
#[test]
238252
fn convert_group_header_into_rc_model_combines_groups_correctly() {
253+
initialize_selection_struct();
239254
let mut model = get_model_vec(6);
240255
model[0].header_row = true;
241256
model[1].header_row = false;
@@ -262,6 +277,7 @@ mod tests {
262277

263278
#[test]
264279
fn convert_group_header_into_rc_model_handles_empty_groups() {
280+
initialize_selection_struct();
265281
let grouped: Vec<(MainListModel, Vec<MainListModel>)> = vec![];
266282

267283
let combined_model = convert_group_header_into_rc_model(grouped, 0);
@@ -271,6 +287,7 @@ mod tests {
271287

272288
#[test]
273289
fn sort_by_size_sorts_flat_model_correctly() {
290+
initialize_selection_struct();
274291
let current_tab = CurrentTab::BigFiles;
275292
// To be sure that we set correct values in val_int, which must be equal to index
276293
assert_eq!(get_int_size_idx(current_tab), 2);
@@ -291,6 +308,7 @@ mod tests {
291308

292309
#[test]
293310
fn sort_by_size_sorts_grouped_model_correctly() {
311+
initialize_selection_struct();
294312
let current_tab = CurrentTab::SimilarImages;
295313
// To be sure that we set correct values in val_int, which must be equal to index
296314
assert_eq!(get_int_size_idx(current_tab), 2);
@@ -321,6 +339,7 @@ mod tests {
321339

322340
#[test]
323341
fn sort_by_size_handles_empty_model() {
342+
initialize_selection_struct();
324343
let model = create_model_from_model_vec(&[]);
325344

326345
let sorted_model = sort_by_size(&model, CurrentTab::SimilarImages);
@@ -330,6 +349,7 @@ mod tests {
330349

331350
#[test]
332351
fn sort_by_parent_name_sorts_flat_model_correctly() {
352+
initialize_selection_struct();
333353
let current_tab = CurrentTab::BigFiles;
334354
// To be sure that we set correct values in val_int, which must be equal to index
335355
assert_eq!(get_str_path_idx(current_tab), 2);
@@ -354,6 +374,7 @@ mod tests {
354374

355375
#[test]
356376
fn sort_by_name_sorts_flat_model_correctly() {
377+
initialize_selection_struct();
357378
let current_tab = CurrentTab::BigFiles;
358379
// To be sure that we set correct values in val_int, which must be equal to index
359380
assert_eq!(get_str_name_idx(current_tab), 1);
@@ -378,6 +399,7 @@ mod tests {
378399

379400
#[test]
380401
fn sort_by_full_name_sorts_flat_model_correctly() {
402+
initialize_selection_struct();
381403
let current_tab = CurrentTab::BigFiles;
382404
// To be sure that we set correct values in val_int, which must be equal to index
383405
assert_eq!(get_str_name_idx(current_tab), 1);
@@ -403,6 +425,7 @@ mod tests {
403425

404426
#[test]
405427
fn sort_by_modification_date_sorts_flat_model_correctly() {
428+
initialize_selection_struct();
406429
let current_tab = CurrentTab::BigFiles;
407430
// To be sure that we set correct values in val_int, which must be equal to index
408431
assert_eq!(get_int_modification_date_idx(current_tab), 0);
@@ -427,6 +450,7 @@ mod tests {
427450

428451
#[test]
429452
fn sort_by_checked_sorts_flat_model_correctly() {
453+
initialize_selection_struct();
430454
let current_tab = CurrentTab::BigFiles;
431455
// To be sure that we set correct values in val_int, which must be equal to index
432456
assert!(!get_is_header_mode(current_tab));
@@ -456,6 +480,7 @@ mod tests {
456480

457481
#[test]
458482
fn sort_by_selection_sorts_flat_model_correctly() {
483+
initialize_selection_struct();
459484
let current_tab = CurrentTab::BigFiles;
460485
// To be sure that we set correct values in val_int, which must be equal to index
461486
assert!(!get_is_header_mode(current_tab));
@@ -485,6 +510,7 @@ mod tests {
485510

486511
#[test]
487512
fn sort_reverse_sorts_flat_model_correctly() {
513+
initialize_selection_struct();
488514
let current_tab = CurrentTab::BigFiles;
489515
// To be sure that we set correct values in val_int, which must be equal to index
490516
assert_eq!(get_int_modification_date_idx(current_tab), 0);

0 commit comments

Comments
 (0)