From f1c6e6da17b0ad43527f6b9b022ce440843757ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mikrut?= <41945903+qarmin@users.noreply.github.com> Date: Sun, 19 Feb 2023 10:21:14 +0100 Subject: [PATCH] Add sort button (#894) * Add sort button * Update lofty and gtk-rs * Fix bug with invalid music tags with reference folders * Remove try at * Fix loading of certain directories with disabled loading settings at start * Change FileChooserDialog to FileChooserNative * Any * Copy Clone * Popover sort basic * Builder using * Basic sorting * Fix not working sorting by size * Changelog --- Cargo.lock | 371 ++++++++++-------- Cargo.toml | 2 +- Changelog.md | 14 + LICENSE | 2 +- README.md | 2 +- czkawka_core/Cargo.toml | 10 +- czkawka_core/src/big_file.rs | 4 +- czkawka_core/src/broken_files.rs | 60 +-- czkawka_core/src/common.rs | 2 +- czkawka_core/src/common_dir_traversal.rs | 4 +- czkawka_core/src/duplicate.rs | 2 +- czkawka_core/src/invalid_symlinks.rs | 2 +- czkawka_core/src/same_music.rs | 4 +- czkawka_core/src/similar_images.rs | 2 +- czkawka_core/src/similar_videos.rs | 7 +- czkawka_core/src/temporary.rs | 2 +- czkawka_gui/Cargo.toml | 14 +- czkawka_gui/i18n/en/czkawka_gui.ftl | 10 +- czkawka_gui/icons/czk_sort.svg | 62 +++ czkawka_gui/src/compute_results.rs | 104 +++-- .../connect_things/connect_button_delete.rs | 21 +- .../connect_things/connect_button_hardlink.rs | 10 +- .../src/connect_things/connect_button_move.rs | 25 +- .../connect_things/connect_button_select.rs | 40 +- .../src/connect_things/connect_button_sort.rs | 46 +++ ...popovers.rs => connect_popovers_select.rs} | 105 ++--- .../connect_things/connect_popovers_sort.rs | 210 ++++++++++ .../connect_selection_of_directories.rs | 32 +- .../src/connect_things/connect_settings.rs | 11 +- czkawka_gui/src/connect_things/mod.rs | 4 +- .../src/gui_structs/gui_bottom_buttons.rs | 25 +- czkawka_gui/src/gui_structs/gui_data.rs | 83 ++-- .../src/gui_structs/gui_main_notebook.rs | 44 +-- ...gui_popovers.rs => gui_popovers_select.rs} | 4 +- .../src/gui_structs/gui_popovers_sort.rs | 46 +++ .../src/gui_structs/gui_progress_dialog.rs | 2 +- .../src/gui_structs/gui_upper_notebook.rs | 8 +- czkawka_gui/src/gui_structs/mod.rs | 3 +- czkawka_gui/src/help_functions.rs | 17 +- czkawka_gui/src/initialize_gui.rs | 23 +- czkawka_gui/src/main.rs | 10 +- czkawka_gui/src/notebook_enums.rs | 4 +- czkawka_gui/src/notebook_info.rs | 14 +- czkawka_gui/src/saving_loading.rs | 151 +++---- czkawka_gui/ui/czkawka.cmb | 55 ++- czkawka_gui/ui/main_window.ui | 23 ++ czkawka_gui/ui/popover_sort.ui | 49 +++ instructions/Compilation.md | 8 +- 48 files changed, 1185 insertions(+), 568 deletions(-) create mode 100644 czkawka_gui/icons/czk_sort.svg create mode 100644 czkawka_gui/src/connect_things/connect_button_sort.rs rename czkawka_gui/src/connect_things/{connect_popovers.rs => connect_popovers_select.rs} (89%) create mode 100644 czkawka_gui/src/connect_things/connect_popovers_sort.rs rename czkawka_gui/src/gui_structs/{gui_popovers.rs => gui_popovers_select.rs} (99%) create mode 100644 czkawka_gui/src/gui_structs/gui_popovers_sort.rs create mode 100644 czkawka_gui/ui/popover_sort.ui diff --git a/Cargo.lock b/Cargo.lock index 13a8925..d993636 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -46,9 +46,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.68" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2cb2f989d18dd141ab8ae82f64d1a8cdd37e0840f73a406896cf5e99502fab61" +checksum = "224afbd727c3d6e4b90103ece64b8d1b67fbb1973b1046c2281eed3f3803f800" [[package]] name = "arc-swap" @@ -70,9 +70,9 @@ checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6" [[package]] name = "async-trait" -version = "0.1.63" +version = "0.1.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eff18d764974428cf3a9328e23fc5c986f5fbed46e6cd4cdf42544df5d297ec1" +checksum = "1cd7fce9ba8c3c042128ce72d8b2ddbf3a05747efb67ea0313c635e10bda47a2" dependencies = [ "proc-macro2", "quote", @@ -102,9 +102,9 @@ checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" [[package]] name = "base64" -version = "0.20.0" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ea22880d78093b0cbe17c89f64a7d457941e65759157ec6cb31a31d652b05e5" +checksum = "a4a4ddaa51a5bc52a6948f74c06d20aaaddb71924eab79b8c97a8c556e942d6a" [[package]] name = "base64ct" @@ -229,9 +229,9 @@ dependencies = [ [[package]] name = "cairo-rs" -version = "0.16.7" +version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3125b15ec28b84c238f6f476c6034016a5f6cc0221cb514ca46c532139fc97d" +checksum = "a8af54f5d48af1226928adc1f57edd22f5df1349e7da1fc96ae15cf43db0e871" dependencies = [ "bitflags", "cairo-sys-rs", @@ -243,9 +243,9 @@ dependencies = [ [[package]] name = "cairo-sys-rs" -version = "0.16.3" +version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c48f4af05fabdcfa9658178e1326efa061853f040ce7d72e33af6885196f421" +checksum = "f55382a01d30e5e53f185eee269124f5e21ab526595b872751278dfbb463594e" dependencies = [ "glib-sys", "libc", @@ -254,9 +254,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.78" +version = "1.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a20104e2335ce8a659d6dd92a51a767a0c062599c73b343fd152cb401e828c3d" +checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" [[package]] name = "cfb" @@ -310,9 +310,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.1.4" +version = "4.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f13b9c79b5d1dd500d20ef541215a6423c75829ef43117e1b4d17fd8af0b5d76" +checksum = "ec0b0588d44d4d63a87dbd75c136c166bbfd9a86a31cb89e09906521c7d3f5e3" dependencies = [ "bitflags", "clap_derive", @@ -458,9 +458,9 @@ dependencies = [ [[package]] name = "cxx" -version = "1.0.88" +version = "1.0.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "322296e2f2e5af4270b54df9e85a02ff037e271af20ba3e7fe1575515dc840b8" +checksum = "86d3488e7665a7a483b57e25bdd90d0aeb2bc7608c8d0346acf2ad3f1caf1d62" dependencies = [ "cc", "cxxbridge-flags", @@ -470,9 +470,9 @@ dependencies = [ [[package]] name = "cxx-build" -version = "1.0.88" +version = "1.0.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "017a1385b05d631e7875b1f151c9f012d37b53491e2a87f65bff5c262b2111d8" +checksum = "48fcaf066a053a41a81dfb14d57d99738b767febb8b735c3016e469fac5da690" dependencies = [ "cc", "codespan-reporting", @@ -485,15 +485,15 @@ dependencies = [ [[package]] name = "cxxbridge-flags" -version = "1.0.88" +version = "1.0.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c26bbb078acf09bc1ecda02d4223f03bdd28bd4874edcb0379138efc499ce971" +checksum = "a2ef98b8b717a829ca5603af80e1f9e2e48013ab227b68ef37872ef84ee479bf" [[package]] name = "cxxbridge-macro" -version = "1.0.88" +version = "1.0.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "357f40d1f06a24b60ae1fe122542c1fb05d28d32acb2aed064e84bc2ad1e252e" +checksum = "086c685979a698443656e5cf7856c95c642295a38599f12fb1ff76fb28d19892" dependencies = [ "proc-macro2", "quote", @@ -675,9 +675,9 @@ checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" [[package]] name = "encoding_rs" -version = "0.8.31" +version = "0.8.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9852635589dc9f9ea1b6fe9f05b50ef208c85c834a562f0c6abb1c475736ec2b" +checksum = "071a31f4ee85403370b58aca746f01041ede6f0da2730960ad001edc2b71b394" dependencies = [ "cfg-if", ] @@ -716,9 +716,9 @@ dependencies = [ [[package]] name = "exr" -version = "1.5.2" +version = "1.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8eb5f255b5980bb0c8cf676b675d1a99be40f316881444f44e0462eaf5df5ded" +checksum = "e8af5ef47e2ed89d23d0ecbc1b681b30390069de70260937877514377fc24feb" dependencies = [ "bit_field", "flume", @@ -727,13 +727,14 @@ dependencies = [ "miniz_oxide", "smallvec", "threadpool", + "zune-inflate", ] [[package]] name = "fastrand" -version = "1.8.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7a407cfaa3385c4ae6b23e84623d48c2798d06e3e6a1878f7f59f17b3f86499" +checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" dependencies = [ "instant", ] @@ -874,16 +875,22 @@ dependencies = [ ] [[package]] -name = "fs_extra" -version = "1.2.0" +name = "four-cc" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2022715d62ab30faffd124d40b76f4134a550a87792276512b18d63272333394" +checksum = "92d73a076bdabd78c2f9045dba1b90664a655fa8372581c238596e1eb3a5e1b7" + +[[package]] +name = "fs_extra" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" [[package]] name = "futures" -version = "0.3.25" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38390104763dc37a5145a53c29c63c1290b5d316d6086ec32c293f6736051bb0" +checksum = "13e2792b0ff0340399d58445b88fd9770e3489eff258a4cbc1523418f12abf84" dependencies = [ "futures-channel", "futures-core", @@ -896,9 +903,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.25" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52ba265a92256105f45b719605a571ffe2d1f0fea3807304b522c1d778f79eed" +checksum = "2e5317663a9089767a1ec00a487df42e0ca174b61b4483213ac24448e4664df5" dependencies = [ "futures-core", "futures-sink", @@ -906,15 +913,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.25" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04909a7a7e4633ae6c4a9ab280aeb86da1236243a77b694a49eacd659a4bd3ac" +checksum = "ec90ff4d0fe1f57d600049061dc6bb68ed03c7d2fbd697274c41805dcb3f8608" [[package]] name = "futures-executor" -version = "0.3.25" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7acc85df6714c176ab5edf386123fafe217be88c0840ec11f199441134a074e2" +checksum = "e8de0a35a6ab97ec8869e32a2473f4b1324459e14c29275d14b10cb1fd19b50e" dependencies = [ "futures-core", "futures-task", @@ -923,15 +930,15 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.25" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00f5fb52a06bdcadeb54e8d3671f8888a39697dcb0b81b23b55174030427f4eb" +checksum = "bfb8371b6fb2aeb2d280374607aeabfc99d95c72edfe51692e42d3d7f0d08531" [[package]] name = "futures-macro" -version = "0.3.25" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdfb8ce053d86b91919aad980c220b1fb8401a9394410e1c289ed7e66b61835d" +checksum = "95a73af87da33b5acf53acfebdc339fe592ecf5357ac7c0a7734ab9d8c876a70" dependencies = [ "proc-macro2", "quote", @@ -940,21 +947,21 @@ dependencies = [ [[package]] name = "futures-sink" -version = "0.3.25" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39c15cf1a4aa79df40f1bb462fb39676d0ad9e366c2a33b590d7c66f4f81fcf9" +checksum = "f310820bb3e8cfd46c80db4d7fb8353e15dfff853a127158425f31e0be6c8364" [[package]] name = "futures-task" -version = "0.3.25" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ffb393ac5d9a6eaa9d3fdf37ae2776656b706e200c8e16b1bdb227f5198e6ea" +checksum = "dcf79a1bf610b10f42aea489289c5a2c478a786509693b80cd39c44ccd936366" [[package]] name = "futures-util" -version = "0.3.25" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "197676987abd2f9cadff84926f410af1c183608d36641465df73ae8211dc65d6" +checksum = "9c1d6de3acfef38d2be4b1f543f553131788603495be83da675e180c8d6b7bd1" dependencies = [ "futures-channel", "futures-core", @@ -970,22 +977,23 @@ dependencies = [ [[package]] name = "gdk-pixbuf" -version = "0.16.7" +version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3578c60dee9d029ad86593ed88cb40f35c1b83360e12498d055022385dd9a05" +checksum = "b023fbe0c6b407bd3d9805d107d9800da3829dc5a676653210f1d5f16d7f59bf" dependencies = [ "bitflags", "gdk-pixbuf-sys", "gio", "glib", "libc", + "once_cell", ] [[package]] name = "gdk-pixbuf-sys" -version = "0.16.3" +version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3092cf797a5f1210479ea38070d9ae8a5b8e9f8f1be9f32f4643c529c7d70016" +checksum = "7b41bd2b44ed49d99277d3925652a163038bd5ed943ec9809338ffb2f4391e3b" dependencies = [ "gio-sys", "glib-sys", @@ -996,9 +1004,9 @@ dependencies = [ [[package]] name = "gdk4" -version = "0.5.5" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb2181330ebf9d091f8ea7fed6877f7adc92114128592e1fdaeb1da28e0d01e9" +checksum = "6e4887e17b6926db51f1e538d871a8b1f5ceb5dfa3bd0034dc42ec355b390d8f" dependencies = [ "bitflags", "cairo-rs", @@ -1012,9 +1020,9 @@ dependencies = [ [[package]] name = "gdk4-sys" -version = "0.5.5" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de55cb49432901fe2b3534177fa06844665b9b0911d85d8601a8d8b88b7791db" +checksum = "f4993c019bf03d18137c00ddafb2b23e73f7cbb45ae244f52af2542a3f4a9452" dependencies = [ "cairo-sys-rs", "gdk-pixbuf-sys", @@ -1075,9 +1083,9 @@ dependencies = [ [[package]] name = "gio" -version = "0.16.7" +version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a1c84b4534a290a29160ef5c6eff2a9c95833111472e824fc5cb78b513dd092" +checksum = "1981edf8679d2f2c8ec3120015867f45aa0a1c2d5e3e129ca2f7dda174d3d2a9" dependencies = [ "bitflags", "futures-channel", @@ -1095,9 +1103,9 @@ dependencies = [ [[package]] name = "gio-sys" -version = "0.16.3" +version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9b693b8e39d042a95547fc258a7b07349b1f0b48f4b2fa3108ba3c51c0b5229" +checksum = "b5d3076ecb86c8c3a672c9843d6232b3a344fb81d304d0ba1ac64b23343efa46" dependencies = [ "glib-sys", "gobject-sys", @@ -1108,9 +1116,9 @@ dependencies = [ [[package]] name = "glib" -version = "0.16.7" +version = "0.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddd4df61a866ed7259d6189b8bcb1464989a77f1d85d25d002279bbe9dd38b2f" +checksum = "91b429154ec5943185aeeaf79e646297567b6a056965f1e89da2657a0e23255b" dependencies = [ "bitflags", "futures-channel", @@ -1123,6 +1131,7 @@ dependencies = [ "glib-sys", "gobject-sys", "libc", + "memchr", "once_cell", "smallvec", "thiserror", @@ -1130,9 +1139,9 @@ dependencies = [ [[package]] name = "glib-macros" -version = "0.16.3" +version = "0.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e084807350b01348b6d9dbabb724d1a0bb987f47a2c85de200e98e12e30733bf" +checksum = "9bc80ac951300ca288dd9ab3863743c37a608fb0e5ca12863495640ec6b781ab" dependencies = [ "anyhow", "heck", @@ -1145,9 +1154,9 @@ dependencies = [ [[package]] name = "glib-sys" -version = "0.16.3" +version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c61a4f46316d06bfa33a7ac22df6f0524c8be58e3db2d9ca99ccb1f357b62a65" +checksum = "9ddcb73fa8236277bedadaaadb76aef49c85d66340f83bece244f46c2d4f0e01" dependencies = [ "libc", "system-deps", @@ -1170,9 +1179,9 @@ dependencies = [ [[package]] name = "gobject-sys" -version = "0.16.3" +version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3520bb9c07ae2a12c7f2fbb24d4efc11231c8146a86956413fb1a79bb760a0f1" +checksum = "9a0155d388840c77d61b033b66ef4f9bc7f4133d83df83572d6b4fb234a3be7d" dependencies = [ "glib-sys", "libc", @@ -1181,9 +1190,9 @@ dependencies = [ [[package]] name = "graphene-rs" -version = "0.16.3" +version = "0.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95ecb4d347e6d09820df3bdfd89a74a8eec07753a06bb92a3aac3ad31d04447b" +checksum = "21cf11565bb0e4dfc2f99d4775b6c329f0d40a2cff9c0066214d31a0e1b46256" dependencies = [ "glib", "graphene-sys", @@ -1192,9 +1201,9 @@ dependencies = [ [[package]] name = "graphene-sys" -version = "0.16.3" +version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9aa82337d3972b4eafdea71e607c23f47be6f27f749aab613f1ad8ddbe6dcd6" +checksum = "cf80a4849a8d9565410a8fec6fc3678e9c617f4ac7be182ca55ab75016e07af9" dependencies = [ "glib-sys", "libc", @@ -1204,9 +1213,9 @@ dependencies = [ [[package]] name = "gsk4" -version = "0.5.5" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "591239f5c52ca803b222124ac9c47f230cd180cee9b114c4d672e4a94b74f491" +checksum = "432f981e4ea9f0739a5731d8a649acb794a3a729d2254e559ce7d613b17caf95" dependencies = [ "bitflags", "cairo-rs", @@ -1220,9 +1229,9 @@ dependencies = [ [[package]] name = "gsk4-sys" -version = "0.5.5" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "195a63f0be42529f98c3eb3bae0decfd0428ba2cc683b3e20ced88f340904ec5" +checksum = "096cb59175b0915ebf69c05a45263c0c989bd8537b8f2169912d0de644ba6a76" dependencies = [ "cairo-sys-rs", "gdk4-sys", @@ -1236,9 +1245,9 @@ dependencies = [ [[package]] name = "gtk4" -version = "0.5.5" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd89dba65def483a233dc4fdd3f3dab01576e3d83f80f6c9303ebe421661855e" +checksum = "73421200ad9c3919d0720779b345b05d31a6ce9998e74fc27012f12580822e46" dependencies = [ "bitflags", "cairo-rs", @@ -1259,9 +1268,9 @@ dependencies = [ [[package]] name = "gtk4-macros" -version = "0.5.5" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "832687a415d9d8bc11fe9c17dda1bf13ee262c41b995dd4df1d1cce33cead405" +checksum = "db4676c4f90d8b010e88cb4558f61f47d76d6f6b8e6f6b89e62640f443907f61" dependencies = [ "anyhow", "proc-macro-crate", @@ -1273,9 +1282,9 @@ dependencies = [ [[package]] name = "gtk4-sys" -version = "0.5.5" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e370564e3fdacff7cffc99f7366b6a4689feb44e819d3ccee598a9a215b71605" +checksum = "e13cf3bc9559f71963c957eb639060b643e1276ae47b892ef6091d5bc15c3e1b" dependencies = [ "cairo-sys-rs", "gdk-pixbuf-sys", @@ -1313,9 +1322,9 @@ checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" [[package]] name = "heck" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" [[package]] name = "hermit-abi" @@ -1326,6 +1335,12 @@ dependencies = [ "libc", ] +[[package]] +name = "hermit-abi" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286" + [[package]] name = "hmac" version = "0.12.1" @@ -1558,24 +1573,24 @@ dependencies = [ [[package]] name = "io-lifetimes" -version = "1.0.4" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7d6c6f8c91b4b9ed43484ad1a938e393caf35960fce7f82a040497207bd8e9e" +checksum = "1abeb7a0dd0f8181267ff8adc397075586500b81b28a73e8a0208b00fc170fb3" dependencies = [ "libc", - "windows-sys", + "windows-sys 0.45.0", ] [[package]] name = "is-terminal" -version = "0.4.2" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28dfb6c8100ccc63462345b67d1bbc3679177c75ee4bf59bf29c8b1d110b8189" +checksum = "22e18b0a45d56fe973d6db23972bf5bc46f988a4a2385deac9cc29572f09daef" dependencies = [ - "hermit-abi", + "hermit-abi 0.3.1", "io-lifetimes", "rustix", - "windows-sys", + "windows-sys 0.45.0", ] [[package]] @@ -1613,9 +1628,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.60" +version = "0.3.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49409df3e3bf0856b916e2ceaca09ee28e6871cf7d9ce97a692cacfdb2a25a47" +checksum = "445dde2150c55e483f3d8416706b97ec8e8237c307e5b7b4b8dd15e6af2a0730" dependencies = [ "wasm-bindgen", ] @@ -1640,19 +1655,20 @@ checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79" [[package]] name = "libheif-rs" -version = "0.15.1" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edf58b5301fc9c13d446e2a75e363ebf848f624ab7026d5cda567b11a6f21056" +checksum = "0b324293a40899ce7fa7077d5ab5ccfc3bf54bac4fdf06d2328cecbedf9bfe41" dependencies = [ "enumn", + "four-cc", "libheif-sys", ] [[package]] name = "libheif-sys" -version = "1.12.0" +version = "1.14.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9426b3c799fe53b9636aac80ddc60efa5060c1959faee2e9d3edf0da6b8536a" +checksum = "6af8b7a4151ae10f6d2e8684f7172c43f09c0258c84190fd9704422588ceec63" dependencies = [ "libc", ] @@ -1709,11 +1725,11 @@ dependencies = [ [[package]] name = "lofty" -version = "0.10.0" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "935294f6c058df75c16721ac510398d42afb4cb6a4e3752737e362166fe2ba67" +checksum = "fed685b48b30ef8f5213a32422d08c80b765f954ad5b6f6b634f901e7844ca52" dependencies = [ - "base64 0.20.0", + "base64 0.21.0", "byteorder", "cfg-if", "flate2", @@ -1726,9 +1742,9 @@ dependencies = [ [[package]] name = "lofty_attr" -version = "0.5.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02f2d46cb443ab8285492be02e5dda3e3a3f39f07cd50e5655069567e67a7de2" +checksum = "336dfabb2fdfd932cebfcaa5d0fc57abac0d49f6ae9ddaa7c47a51bf9f74f966" dependencies = [ "proc-macro2", "quote", @@ -1923,7 +1939,7 @@ version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b" dependencies = [ - "hermit-abi", + "hermit-abi 0.2.6", "libc", ] @@ -1958,18 +1974,18 @@ dependencies = [ [[package]] name = "ogg_pager" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a05065bb6e0b933aef28cae4c5469b85011aa0d0285bd5fe3f568bed1f1a1bc" +checksum = "0d218a406e5de88e1c492d0162d569916f7436efe851ba5cc40a4bf4fa97cb40" dependencies = [ "byteorder", ] [[package]] name = "once_cell" -version = "1.17.0" +version = "1.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f61fba1741ea2b3d6a1e3178721804bb716a68a6aeba1149b5d52e3d464ea66" +checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" [[package]] name = "opaque-debug" @@ -1984,7 +2000,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2078c0039e6a54a0c42c28faa984e115fb4c2d5bf2208f77d1961002df8576f8" dependencies = [ "pathdiff", - "windows-sys", + "windows-sys 0.42.0", ] [[package]] @@ -2001,9 +2017,9 @@ checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" [[package]] name = "pango" -version = "0.16.5" +version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdff66b271861037b89d028656184059e03b0b6ccb36003820be19f7200b1e94" +checksum = "243c048be90312220fb3bd578176eed8290568274a93c95040289d39349384bc" dependencies = [ "bitflags", "gio", @@ -2015,9 +2031,9 @@ dependencies = [ [[package]] name = "pango-sys" -version = "0.16.3" +version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e134909a9a293e04d2cc31928aa95679c5e4df954d0b85483159bd20d8f047f" +checksum = "4293d0f0b5525eb5c24734d30b0ed02cd02aa734f216883f376b54de49625de8" dependencies = [ "glib-sys", "gobject-sys", @@ -2037,15 +2053,15 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.6" +version = "0.9.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba1ef8814b5c993410bb3adfad7a5ed269563e4a2f90c41f5d85be7fb47133bf" +checksum = "9069cbb9f99e3a5083476ccb29ceb1de18b9118cafa53e90c9551235de2b9521" dependencies = [ "cfg-if", "libc", "redox_syscall", "smallvec", - "windows-sys", + "windows-sys 0.45.0", ] [[package]] @@ -2129,9 +2145,9 @@ checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" [[package]] name = "pest" -version = "2.5.4" +version = "2.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ab62d2fa33726dbe6321cc97ef96d8cde531e3eeaf858a058de53a8a6d40d8f" +checksum = "028accff104c4e513bad663bbcd2ad7cfd5304144404c31ed0a77ac103d00660" dependencies = [ "thiserror", "ucd-trie", @@ -2238,9 +2254,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.50" +version = "1.0.51" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ef7d57beacfaf2d8aee5937dab7b7f28de3cb8b1828479bb5de2a7106f2bae2" +checksum = "5d727cae5b39d21da60fa540906919ad737832fe0b1c165da3a34d6548c849d6" dependencies = [ "unicode-ident", ] @@ -2483,16 +2499,16 @@ dependencies = [ [[package]] name = "rustix" -version = "0.36.7" +version = "0.36.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4fdebc4b395b7fbb9ab11e462e20ed9051e7b16e42d24042c776eca0ac81b03" +checksum = "f43abb88211988493c1abb44a70efa56ff0ce98f233b7b276146f1f3f7ba9644" dependencies = [ "bitflags", "errno", "io-lifetimes", "libc", "linux-raw-sys", - "windows-sys", + "windows-sys 0.45.0", ] [[package]] @@ -2592,9 +2608,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.91" +version = "1.0.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "877c235533714907a8c2464236f5c4b2a17262ef1bd71f38f35ea592c8da6883" +checksum = "cad406b69c91885b5107daf2c29572f6c8cdb3c66826821e286c533490c0bc76" dependencies = [ "itoa", "ryu", @@ -2644,6 +2660,12 @@ dependencies = [ "lazy_static", ] +[[package]] +name = "simd-adler32" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14a5df39617d7c8558154693a1bb8157a4aab8179209540cc0b10e5dc24e0b18" + [[package]] name = "slab" version = "0.4.7" @@ -2683,9 +2705,9 @@ dependencies = [ [[package]] name = "spin" -version = "0.9.4" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f6002a767bff9e83f8eeecf883ecb8011875a21ae8da43bffb817a57e78cc09" +checksum = "7dccf47db1b41fa1573ed27ccf5e08e3ca771cb994f776668c5ebda893b248fc" dependencies = [ "lock_api", ] @@ -2979,10 +3001,11 @@ dependencies = [ [[package]] name = "thread_local" -version = "1.1.4" +version = "1.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5516c27b78311c50bf42c071425c560ac799b11c30b31f87e3081965fe5e0180" +checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152" dependencies = [ + "cfg-if", "once_cell", ] @@ -3019,14 +3042,12 @@ dependencies = [ [[package]] name = "time" -version = "0.3.17" +version = "0.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a561bf4617eebd33bca6434b988f39ed798e527f51a1e797d0ee4f61c0a38376" +checksum = "53250a3b3fed8ff8fd988587d8925d26a83ac3845d9e03b220b37f34c2b8d6c2" dependencies = [ - "itoa", "serde", "time-core", - "time-macros", ] [[package]] @@ -3035,15 +3056,6 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2e153e1f1acaef8acc537e68b44906d2db6436e2b35ac2c6b42640fff91f00fd" -[[package]] -name = "time-macros" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d967f99f534ca7e495c575c62638eebc2898a8c84c119b89e250477bc4ba16b2" -dependencies = [ - "time-core", -] - [[package]] name = "tinystr" version = "0.7.1" @@ -3064,9 +3076,9 @@ dependencies = [ [[package]] name = "tinyvec_macros" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "toml" @@ -3168,9 +3180,9 @@ dependencies = [ [[package]] name = "trash" -version = "3.0.0" +version = "3.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f74274f95c7e7340d7c5bcd4863af87a9ed6a117cf73cf483c71cb4d744a948" +checksum = "a27b2a127810fceb959593bbc6c7b8e0282c2d318d76f0749252197c52a1dd0c" dependencies = [ "chrono", "libc", @@ -3179,7 +3191,7 @@ dependencies = [ "once_cell", "scopeguard", "url", - "windows 0.43.0", + "windows 0.44.0", ] [[package]] @@ -3277,9 +3289,9 @@ dependencies = [ [[package]] name = "uuid" -version = "1.2.2" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "422ee0de9031b5b948b97a8fc04e3aa35230001a722ddd27943e0be31564ce4c" +checksum = "1674845326ee10d37ca60470760d4288a6f80f304007d92e5c53bab78c9cfd79" [[package]] name = "valuable" @@ -3341,9 +3353,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.83" +version = "0.2.84" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eaf9f5aceeec8be17c128b2e93e031fb8a4d469bb9c4ae2d7dc1888b26887268" +checksum = "31f8dcbc21f30d9b8f2ea926ecb58f6b91192c17e9d33594b3df58b2007ca53b" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -3351,9 +3363,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.83" +version = "0.2.84" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c8ffb332579b0557b52d268b91feab8df3615f265d5270fec2a8c95b17c1142" +checksum = "95ce90fd5bcc06af55a641a86428ee4229e44e07033963a2290a8e241607ccb9" dependencies = [ "bumpalo", "log", @@ -3366,9 +3378,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.83" +version = "0.2.84" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "052be0f94026e6cbc75cdefc9bae13fd6052cdcaf532fa6c45e7ae33a1e6c810" +checksum = "4c21f77c0bedc37fd5dc21f897894a5ca01e7bb159884559461862ae90c0b4c5" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -3376,9 +3388,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.83" +version = "0.2.84" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07bc0c051dc5f23e307b13285f9d75df86bfdf816c5721e573dec1f9b8aa193c" +checksum = "2aff81306fcac3c7515ad4e177f521b5c9a15f2b08f4e32d823066102f35a5f6" dependencies = [ "proc-macro2", "quote", @@ -3389,9 +3401,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.83" +version = "0.2.84" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c38c045535d93ec4f0b4defec448e4291638ee608530863b1e2ba115d4fff7f" +checksum = "0046fef7e28c3804e5e38bfa31ea2a0f73905319b677e57ebe37e49358989b5d" [[package]] name = "weezl" @@ -3445,9 +3457,18 @@ dependencies = [ [[package]] name = "windows" -version = "0.43.0" +version = "0.44.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04662ed0e3e5630dfa9b26e4cb823b817f1a9addda855d973a9458c236556244" +checksum = "9e745dab35a0c4c77aa3ce42d595e13d2003d6902d6b08c9ef5fc326d08da12b" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-sys" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" dependencies = [ "windows_aarch64_gnullvm", "windows_aarch64_msvc 0.42.1", @@ -3460,9 +3481,18 @@ dependencies = [ [[package]] name = "windows-sys" -version = "0.42.0" +version = "0.45.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" +checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.42.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e2522491fbfcd58cc84d47aeb2958948c4b8982e9a2d8a2a35bbaed431390e7" dependencies = [ "windows_aarch64_gnullvm", "windows_aarch64_msvc 0.42.1", @@ -3562,9 +3592,9 @@ dependencies = [ [[package]] name = "zip" -version = "0.6.3" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "537ce7411d25e54e8ae21a7ce0b15840e7bfcff15b51d697ec3266cc76bdf080" +checksum = "0445d0fbc924bb93539b4316c11afb121ea39296f99a3c4c9edad09e3658cdef" dependencies = [ "aes", "byteorder", @@ -3576,5 +3606,14 @@ dependencies = [ "hmac", "pbkdf2", "sha1", - "time 0.3.17", + "time 0.3.19", +] + +[[package]] +name = "zune-inflate" +version = "0.2.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589245df6230839c305984dcc0a8385cc72af1fd223f360ffd5d65efa4216d40" +dependencies = [ + "simd-adler32", ] diff --git a/Cargo.toml b/Cargo.toml index a6bda00..32987c3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,6 +14,6 @@ panic = "unwind" # LTO setting is disabled by default, because release mode is usually needed to develop app and compilation with LTO would take a lot of time #lto = "fat" -# Optimize all dependencies except application/workspaces +# Optimize all dependencies except application/workspaces, even in debug builds [profile.dev.package."*"] opt-level = 3 \ No newline at end of file diff --git a/Changelog.md b/Changelog.md index 3213fa9..48ac1e2 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,3 +1,17 @@ +## Version 5.1.0 - 19.02.2023r +- Added sort button - [#894](https://github.com/qarmin/czkawka/pull/894) +- Allow to set number of thread used to scan - [#839](https://github.com/qarmin/czkawka/pull/839) +- Faster similar images comparing with reference folders - [#826](https://github.com/qarmin/czkawka/pull/826) +- Update to clap 4 - [#878](https://github.com/qarmin/czkawka/pull/878) +- Use FileChooserNative instead FileChooserDialog - [#894](https://github.com/qarmin/czkawka/pull/894) +- Fix invalid music tags in music files when using reference folders - [#894](https://github.com/qarmin/czkawka/pull/894) +- Updated pdf dependency(a lot of less amount of broken pdf false positives) - [#894](https://github.com/qarmin/czkawka/pull/894) +- Changed strange PDF error message - "Try at" - [#894](https://github.com/qarmin/czkawka/pull/894) +- Treat extensions Mp4 and m4v as identical - [#834](https://github.com/qarmin/czkawka/pull/834) +- Improve thumbnail quality - [#895](https://github.com/qarmin/czkawka/pull/895) +- Verify if hardlinking works, and if not, disable button with proper message - [#881](https://github.com/qarmin/czkawka/pull/881) +- Apply some pydantic clippy lints on project - [#901](https://github.com/qarmin/czkawka/pull/901) + ## Version 5.0.2 - 30.08.2022r - Fixed problem with missing some similar images when using similarity > 0 - [#799](https://github.com/qarmin/czkawka/pull/799) - Prebuilt Linux binaries are compiled without heif support - [24b](https://github.com/qarmin/czkawka/commit/24b64a32c65904c506b54270f0977ccbe5098cc8) diff --git a/LICENSE b/LICENSE index 1fcf762..02e3f2e 100644 --- a/LICENSE +++ b/LICENSE @@ -369,7 +369,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. Icons used inside GUI version -Reshot license +Reshot license - https://www.reshot.com/ czkawka_gui/icons/* diff --git a/README.md b/README.md index cf8ecb9..2c08ee4 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ ![com github qarmin czkawka](https://user-images.githubusercontent.com/41945903/102616149-66490400-4137-11eb-9cd6-813b2b070834.png) -**Czkawka** (_tch•kav•ka_ (IPA: [ʈ͡ʂkafka]), "hiccup" in Polish) is a simple, fast and free app to remove unnecessary files from your computer. +**Czkawka** (_tch•kav•ka_ (IPA: [ˈʧ̑kafka]), "hiccup" in Polish) is a simple, fast and free app to remove unnecessary files from your computer. ## Features - Written in memory-safe Rust diff --git a/czkawka_core/Cargo.toml b/czkawka_core/Cargo.toml index d955843..893ab95 100644 --- a/czkawka_core/Cargo.toml +++ b/czkawka_core/Cargo.toml @@ -26,13 +26,13 @@ hamming = "0.1.3" # Needed by same music bitflags = "1.3.2" -lofty = "0.10.0" +lofty = "0.11.0" # Futures - needed by async progress sender -futures = "0.3.25" +futures = "0.3.26" # Needed by broken files -zip = { version = "0.6.3", features = ["aes-crypto", "bzip2", "deflate", "time"], default-features = false } +zip = { version = "0.6.4", features = ["aes-crypto", "bzip2", "deflate", "time"], default-features = false } audio_checker = "0.1.0" pdf = "0.8.0" @@ -56,7 +56,7 @@ serde_json = "1.0" i18n-embed = { version = "0.13.8", features = ["fluent-system", "desktop-requester"] } i18n-embed-fl = "0.6.5" rust-embed = "6.4.2" -once_cell = "1.17.0" +once_cell = "1.17.1" # Raw image files rawloader = "0.37.1" @@ -69,7 +69,7 @@ infer = "0.12.0" num_cpus = "1.15.0" # Heif/Heic -libheif-rs = { version = "0.15.1", optional = true } +libheif-rs = { version = "0.16.0", optional = true } anyhow = { version = "1.0", optional = true } state="0.5.3" diff --git a/czkawka_core/src/big_file.rs b/czkawka_core/src/big_file.rs index 97acab3..b4a8412 100644 --- a/czkawka_core/src/big_file.rs +++ b/czkawka_core/src/big_file.rs @@ -43,7 +43,7 @@ pub enum SearchMode { SmallestFiles, } -#[derive(Eq, PartialEq, Clone, Debug)] +#[derive(Eq, PartialEq, Clone, Debug, Copy)] pub enum DeleteMethod { None, Delete, @@ -394,7 +394,7 @@ impl BigFile { match self.delete_method { DeleteMethod::Delete => { for (_, file_entry) in &self.big_files { - if fs::remove_file(file_entry.path.clone()).is_err() { + if fs::remove_file(&file_entry.path).is_err() { self.text_messages.warnings.push(file_entry.path.display().to_string()); } } diff --git a/czkawka_core/src/broken_files.rs b/czkawka_core/src/broken_files.rs index a10df35..3fda348 100644 --- a/czkawka_core/src/broken_files.rs +++ b/czkawka_core/src/broken_files.rs @@ -10,6 +10,7 @@ use std::time::{Duration, SystemTime, UNIX_EPOCH}; use std::{fs, mem, panic, thread}; use crossbeam_channel::Receiver; +use pdf::object::ParseOptions; use pdf::PdfError; use pdf::PdfError::Try; use rayon::prelude::*; @@ -33,7 +34,7 @@ pub struct ProgressData { pub files_to_check: usize, } -#[derive(Eq, PartialEq, Clone, Debug)] +#[derive(Eq, PartialEq, Clone, Debug, Copy)] pub enum DeleteMethod { None, Delete, @@ -521,41 +522,40 @@ impl BrokenFiles { Err(_inspected) => Some(None), }, - TypeOfFile::PDF => { - match fs::read(&file_entry.path) { - Ok(content) => { - // Will be available in pdf > 0.7.2 - // let parser_options = ParseOptions { - // allow_error_in_option: true, - // allow_xref_error: true, - // allow_invalid_ops: true, - // allow_missing_endobj: true, - // }; - // if let Err(e) = pdf::file::File::from_data_with_options(content, parser_options) { + TypeOfFile::PDF => match fs::read(&file_entry.path) { + Ok(content) => { + let parser_options = ParseOptions::tolerant(); // Only show as broken files with really big bugs - let mut file_entry_clone = file_entry.clone(); - let result = panic::catch_unwind(|| { - if let Err(e) = pdf::file::File::from_data(content) { - file_entry.error_string = e.to_string(); - let error = unpack_pdf_error(e); - if let PdfError::InvalidPassword = error { - return Some(None); + let mut file_entry_clone = file_entry.clone(); + let result = panic::catch_unwind(|| { + if let Err(e) = pdf::file::File::from_data_with_options(content, parser_options) { + let mut error_string = e.to_string(); + // Workaround for strange error message https://github.com/qarmin/czkawka/issues/898 + if error_string.starts_with("Try at") { + if let Some(start_index) = error_string.find("/pdf-") { + error_string = format!("Decoding error in pdf-rs library - {}", &error_string[start_index..]); } } - Some(Some(file_entry)) - }); - if let Ok(pdf_result) = result { - pdf_result - } else { - let message = create_crash_message("PDF-rs", &file_entry_clone.path.to_string_lossy(), "https://github.com/pdf-rs/pdf"); - println!("{message}"); - file_entry_clone.error_string = message; - Some(Some(file_entry_clone)) + + file_entry.error_string = error_string; + let error = unpack_pdf_error(e); + if let PdfError::InvalidPassword = error { + return Some(None); + } } + Some(Some(file_entry)) + }); + if let Ok(pdf_result) = result { + pdf_result + } else { + let message = create_crash_message("PDF-rs", &file_entry_clone.path.to_string_lossy(), "https://github.com/pdf-rs/pdf"); + println!("{message}"); + file_entry_clone.error_string = message; + Some(Some(file_entry_clone)) } - Err(_inspected) => Some(None), } - } + Err(_inspected) => Some(None), + }, // This means that cache read invalid value because maybe cache comes from different czkawka version TypeOfFile::Unknown => Some(None), diff --git a/czkawka_core/src/common.rs b/czkawka_core/src/common.rs index f7bd589..bcd25ae 100644 --- a/czkawka_core/src/common.rs +++ b/czkawka_core/src/common.rs @@ -128,7 +128,7 @@ pub fn open_cache_folder(cache_file_name: &str, save_to_cache: bool, use_json: b pub fn get_dynamic_image_from_heic(path: &str) -> Result { let im = HeifContext::read_from_file(path)?; let handle = im.primary_image_handle()?; - let image = handle.decode(ColorSpace::Rgb(RgbChroma::Rgb), false)?; + let image = handle.decode(ColorSpace::Rgb(RgbChroma::Rgb), None)?; let width = image.width(Channel::Interleaved).map_err(|e| anyhow::anyhow!("{}", e))?; let height = image.height(Channel::Interleaved).map_err(|e| anyhow::anyhow!("{}", e))?; let planes = image.planes(); diff --git a/czkawka_core/src/common_dir_traversal.rs b/czkawka_core/src/common_dir_traversal.rs index f187bd7..462e6df 100644 --- a/czkawka_core/src/common_dir_traversal.rs +++ b/czkawka_core/src/common_dir_traversal.rs @@ -53,7 +53,7 @@ pub struct SymlinkInfo { pub type_of_error: ErrorType, } -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Debug, PartialEq, Eq, Copy)] pub enum ErrorType { InfiniteRecursion, NonExistentFile, @@ -87,7 +87,7 @@ pub enum Collect { Files, } -#[derive(Eq, PartialEq)] +#[derive(Eq, PartialEq, Copy, Clone)] enum EntryType { File, Dir, diff --git a/czkawka_core/src/duplicate.rs b/czkawka_core/src/duplicate.rs index ea9c606..0a43aee 100644 --- a/czkawka_core/src/duplicate.rs +++ b/czkawka_core/src/duplicate.rs @@ -49,7 +49,7 @@ impl HashType { } } -#[derive(Eq, PartialEq, Clone, Debug)] +#[derive(Eq, PartialEq, Clone, Debug, Copy)] pub enum DeleteMethod { None, AllExceptNewest, diff --git a/czkawka_core/src/invalid_symlinks.rs b/czkawka_core/src/invalid_symlinks.rs index 97e1a93..ba1a8c8 100644 --- a/czkawka_core/src/invalid_symlinks.rs +++ b/czkawka_core/src/invalid_symlinks.rs @@ -15,7 +15,7 @@ use crate::common_items::ExcludedItems; use crate::common_messages::Messages; use crate::common_traits::*; -#[derive(Eq, PartialEq, Clone, Debug)] +#[derive(Eq, PartialEq, Clone, Debug, Copy)] pub enum DeleteMethod { None, Delete, diff --git a/czkawka_core/src/same_music.rs b/czkawka_core/src/same_music.rs index 3da523d..d82f0e3 100644 --- a/czkawka_core/src/same_music.rs +++ b/czkawka_core/src/same_music.rs @@ -24,7 +24,7 @@ use crate::common_items::ExcludedItems; use crate::common_messages::Messages; use crate::common_traits::*; -#[derive(Eq, PartialEq, Clone, Debug)] +#[derive(Eq, PartialEq, Clone, Debug, Copy)] pub enum DeleteMethod { None, Delete, @@ -666,7 +666,7 @@ impl SameMusic { for file_entry in vec_file_entry { let thing = file_entry.genre.trim().to_lowercase(); if !thing.is_empty() { - hash_map.entry(thing.clone()).or_insert_with(Vec::new).push(file_entry); + hash_map.entry(thing).or_insert_with(Vec::new).push(file_entry); } } for (_title, vec_file_entry) in hash_map { diff --git a/czkawka_core/src/similar_images.rs b/czkawka_core/src/similar_images.rs index 33f4ccc..83c6559 100644 --- a/czkawka_core/src/similar_images.rs +++ b/czkawka_core/src/similar_images.rs @@ -59,7 +59,7 @@ pub struct FileEntry { } /// Used by CLI tool when we cannot use directly values -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Copy)] pub enum SimilarityPreset { Original, VeryHigh, diff --git a/czkawka_core/src/similar_videos.rs b/czkawka_core/src/similar_videos.rs index 3ee4b23..947d781 100644 --- a/czkawka_core/src/similar_videos.rs +++ b/czkawka_core/src/similar_videos.rs @@ -391,6 +391,7 @@ impl SimilarVideos { if self.excluded_items.is_excluded(¤t_file_name) { continue 'dir; } + let current_file_name_str = current_file_name.to_string_lossy().to_string(); let fe: FileEntry = FileEntry { path: current_file_name.clone(), @@ -401,7 +402,7 @@ impl SimilarVideos { Err(_inspected) => { warnings.push(flc!( "core_file_modified_before_epoch", - generate_translation_hashmap(vec![("name", current_file_name.display().to_string())]) + generate_translation_hashmap(vec![("name", current_file_name_str.clone())]) )); 0 } @@ -409,7 +410,7 @@ impl SimilarVideos { Err(e) => { warnings.push(flc!( "core_file_no_modification_date", - generate_translation_hashmap(vec![("name", current_file_name.display().to_string()), ("reason", e.to_string())]) + generate_translation_hashmap(vec![("name", current_file_name_str.clone()), ("reason", e.to_string())]) )); 0 } @@ -418,7 +419,7 @@ impl SimilarVideos { error: String::new(), }; - fe_result.push((current_file_name.to_string_lossy().to_string(), fe)); + fe_result.push((current_file_name_str, fe)); } } } diff --git a/czkawka_core/src/temporary.rs b/czkawka_core/src/temporary.rs index f9a2568..a94dfd3 100644 --- a/czkawka_core/src/temporary.rs +++ b/czkawka_core/src/temporary.rs @@ -26,7 +26,7 @@ pub struct ProgressData { pub files_checked: usize, } -#[derive(Eq, PartialEq, Clone, Debug)] +#[derive(Eq, PartialEq, Clone, Debug, Copy)] pub enum DeleteMethod { None, Delete, diff --git a/czkawka_gui/Cargo.toml b/czkawka_gui/Cargo.toml index 3b6fb7d..b9f7576 100644 --- a/czkawka_gui/Cargo.toml +++ b/czkawka_gui/Cargo.toml @@ -10,8 +10,8 @@ homepage = "https://github.com/qarmin/czkawka" repository = "https://github.com/qarmin/czkawka" [dependencies] -gdk4 = "0.5.5" -glib = "0.16.7" +gdk4 = "0.6.0" +glib = "0.17.1" humansize = "2.1.3" chrono = "0.4.23" @@ -20,7 +20,7 @@ chrono = "0.4.23" crossbeam-channel = "0.5.6" # To get information about progress -futures = "0.3.25" +futures = "0.3.26" # For saving/loading config files to specific directories directories-next = "2.0.0" @@ -38,22 +38,22 @@ regex = "1.7.1" image_hasher = "1.1.2" # Move files to trash -trash = "3.0.0" +trash = "3.0.1" # For moving files(why std::fs doesn't have such features) -fs_extra = "1.2.0" +fs_extra = "1.3.0" # Language i18n-embed = { version = "0.13.8", features = ["fluent-system", "desktop-requester"] } i18n-embed-fl = "0.6.5" rust-embed = "6.4.2" -once_cell = "1.17.0" +once_cell = "1.17.1" [target.'cfg(windows)'.dependencies] winapi = { version = "0.3.9", features = ["combaseapi", "objbase", "shobjidl_core", "windef", "winerror", "wtypesbase", "winuser"] } [dependencies.gtk4] -version = "0.5.5" +version = "0.6.1" default-features = false features = ["v4_6"] diff --git a/czkawka_gui/i18n/en/czkawka_gui.ftl b/czkawka_gui/i18n/en/czkawka_gui.ftl index 19f4521..a0074f2 100644 --- a/czkawka_gui/i18n/en/czkawka_gui.ftl +++ b/czkawka_gui/i18n/en/czkawka_gui.ftl @@ -238,6 +238,11 @@ popover_custom_all_in_group_label = Don't select all records in group popover_custom_mode_unselect = Unselect Custom popover_custom_mode_select = Select Custom +popover_sort_file_name = File name +popover_sort_folder_name = Folder name +popover_sort_full_name = Full name +popover_sort_size = Size +popover_sort_selection = Selection popover_invalid_regex = Regex is invalid popover_valid_regex = Regex is valid @@ -250,6 +255,7 @@ bottom_save_button = Save bottom_symlink_button = Symlink bottom_hardlink_button = Hardlink bottom_move_button = Move +bottom_sort_button = Sort bottom_search_button_tooltip = Start search bottom_select_button_tooltip = Select records. Only selected files/folders can be later processed. @@ -268,10 +274,12 @@ bottom_hardlink_button_not_available_tooltip = Button is disabled, because hardlinks cannot be created. Hardlinks only works with administrator privileges on Windows, so be sure to run app as administrator. If app already works with such privileges check for similar issues on Github. -bottom_move_button_tooltip = +bottom_move_button_tooltip = Moves files to chosen directory. It copies all files to the directory without preserving the directory tree. When trying to move two files with identical name to folder, second will fail and show error. +bottom_sort_button_tooltip = + Sorts files/folders according to selected method. bottom_show_errors_tooltip = Show/Hide bottom text panel. bottom_show_upper_notebook_tooltip = Show/Hide upper notebook panel. diff --git a/czkawka_gui/icons/czk_sort.svg b/czkawka_gui/icons/czk_sort.svg new file mode 100644 index 0000000..658a200 --- /dev/null +++ b/czkawka_gui/icons/czk_sort.svg @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/czkawka_gui/src/compute_results.rs b/czkawka_gui/src/compute_results.rs index 2a3ae7b..550f417 100644 --- a/czkawka_gui/src/compute_results.rs +++ b/czkawka_gui/src/compute_results.rs @@ -79,6 +79,7 @@ pub fn connect_compute_results(gui_data: &GuiData, glib_stop_receiver: Receiver< match msg { Message::Duplicates(df) => { + const COLUMNS_NUMBER: usize = 11; if df.get_stopped_search() { entry_info.set_text(&flg!("compute_stopped_by_user")); } else { @@ -169,10 +170,11 @@ pub fn connect_compute_results(gui_data: &GuiData, glib_stop_receiver: Receiver< // HEADER let (directory, file) = split_path(&base_file_entry.path); - let values: [(u32, &dyn ToValue); 10] = [ + let values: [(u32, &dyn ToValue); COLUMNS_NUMBER] = [ (ColumnsDuplicates::ActivatableSelectButton as u32, &false), (ColumnsDuplicates::SelectionButton as u32, &false), (ColumnsDuplicates::Size as u32, (&format_size(base_file_entry.size, BINARY))), + (ColumnsDuplicates::SizeAsBytes as u32, &base_file_entry.size), (ColumnsDuplicates::Name as u32, &file), (ColumnsDuplicates::Path as u32, &directory), ( @@ -190,10 +192,12 @@ pub fn connect_compute_results(gui_data: &GuiData, glib_stop_receiver: Receiver< // MEAT for entry in vector { let (directory, file) = split_path(&entry.path); - let values: [(u32, &dyn ToValue); 10] = [ + println!("{}", entry.size); + let values: [(u32, &dyn ToValue); COLUMNS_NUMBER] = [ (ColumnsDuplicates::ActivatableSelectButton as u32, &true), (ColumnsDuplicates::SelectionButton as u32, &false), (ColumnsDuplicates::Size as u32, (&format_size(entry.size, BINARY))), + (ColumnsDuplicates::SizeAsBytes as u32, &entry.size), (ColumnsDuplicates::Name as u32, &file), (ColumnsDuplicates::Path as u32, &directory), ( @@ -228,10 +232,11 @@ pub fn connect_compute_results(gui_data: &GuiData, glib_stop_receiver: Receiver< // HEADER let (directory, file) = split_path(&base_file_entry.path); - let values: [(u32, &dyn ToValue); 10] = [ + let values: [(u32, &dyn ToValue); COLUMNS_NUMBER] = [ (ColumnsDuplicates::ActivatableSelectButton as u32, &false), (ColumnsDuplicates::SelectionButton as u32, &false), (ColumnsDuplicates::Size as u32, (&format_size(base_file_entry.size, BINARY))), + (ColumnsDuplicates::SizeAsBytes as u32, &base_file_entry.size), (ColumnsDuplicates::Name as u32, &file), (ColumnsDuplicates::Path as u32, &directory), ( @@ -249,10 +254,11 @@ pub fn connect_compute_results(gui_data: &GuiData, glib_stop_receiver: Receiver< for entry in vector { let (directory, file) = split_path(&entry.path); - let values: [(u32, &dyn ToValue); 10] = [ + let values: [(u32, &dyn ToValue); COLUMNS_NUMBER] = [ (ColumnsDuplicates::ActivatableSelectButton as u32, &true), (ColumnsDuplicates::SelectionButton as u32, &false), (ColumnsDuplicates::Size as u32, (&format_size(entry.size, BINARY))), + (ColumnsDuplicates::SizeAsBytes as u32, &entry.size), (ColumnsDuplicates::Name as u32, &file), (ColumnsDuplicates::Path as u32, &directory), ( @@ -288,10 +294,11 @@ pub fn connect_compute_results(gui_data: &GuiData, glib_stop_receiver: Receiver< // HEADER let (directory, file) = split_path(&base_file_entry.path); - let values: [(u32, &dyn ToValue); 10] = [ + let values: [(u32, &dyn ToValue); COLUMNS_NUMBER] = [ (ColumnsDuplicates::ActivatableSelectButton as u32, &false), (ColumnsDuplicates::SelectionButton as u32, &false), (ColumnsDuplicates::Size as u32, (&format_size(base_file_entry.size, BINARY))), + (ColumnsDuplicates::SizeAsBytes as u32, &base_file_entry.size), (ColumnsDuplicates::Name as u32, &file), (ColumnsDuplicates::Path as u32, &directory), ( @@ -308,10 +315,11 @@ pub fn connect_compute_results(gui_data: &GuiData, glib_stop_receiver: Receiver< list_store.set(&list_store.append(), &values); for entry in vector { let (directory, file) = split_path(&entry.path); - let values: [(u32, &dyn ToValue); 10] = [ + let values: [(u32, &dyn ToValue); COLUMNS_NUMBER] = [ (ColumnsDuplicates::ActivatableSelectButton as u32, &true), (ColumnsDuplicates::SelectionButton as u32, &false), (ColumnsDuplicates::Size as u32, (&format_size(entry.size, BINARY))), + (ColumnsDuplicates::SizeAsBytes as u32, &entry.size), (ColumnsDuplicates::Name as u32, &file), (ColumnsDuplicates::Path as u32, &directory), ( @@ -349,10 +357,11 @@ pub fn connect_compute_results(gui_data: &GuiData, glib_stop_receiver: Receiver< vector.clone() }; - let values: [(u32, &dyn ToValue); 10] = [ + let values: [(u32, &dyn ToValue); COLUMNS_NUMBER] = [ (ColumnsDuplicates::ActivatableSelectButton as u32, &false), (ColumnsDuplicates::SelectionButton as u32, &false), (ColumnsDuplicates::Size as u32, (&String::new())), + (ColumnsDuplicates::SizeAsBytes as u32, &0), (ColumnsDuplicates::Name as u32, (&String::new())), (ColumnsDuplicates::Path as u32, (&(format!("{} results", vector.len())))), (ColumnsDuplicates::Modification as u32, (&String::new())), // No text in 3 column @@ -365,10 +374,11 @@ pub fn connect_compute_results(gui_data: &GuiData, glib_stop_receiver: Receiver< list_store.set(&list_store.append(), &values); for entry in vector { let (directory, file) = split_path(&entry.path); - let values: [(u32, &dyn ToValue); 10] = [ + let values: [(u32, &dyn ToValue); COLUMNS_NUMBER] = [ (ColumnsDuplicates::ActivatableSelectButton as u32, &true), (ColumnsDuplicates::SelectionButton as u32, &false), (ColumnsDuplicates::Size as u32, (&format_size(entry.size, BINARY))), + (ColumnsDuplicates::SizeAsBytes as u32, &entry.size), (ColumnsDuplicates::Name as u32, &file), (ColumnsDuplicates::Path as u32, &directory), ( @@ -405,10 +415,11 @@ pub fn connect_compute_results(gui_data: &GuiData, glib_stop_receiver: Receiver< vector.clone() }; - let values: [(u32, &dyn ToValue); 10] = [ + let values: [(u32, &dyn ToValue); COLUMNS_NUMBER] = [ (ColumnsDuplicates::ActivatableSelectButton as u32, &false), (ColumnsDuplicates::SelectionButton as u32, &false), (ColumnsDuplicates::Size as u32, (&String::new())), + (ColumnsDuplicates::SizeAsBytes as u32, &0), (ColumnsDuplicates::Name as u32, (&String::new())), (ColumnsDuplicates::Path as u32, (&String::new())), (ColumnsDuplicates::Modification as u32, &String::new()), // No text in 3 column @@ -422,10 +433,11 @@ pub fn connect_compute_results(gui_data: &GuiData, glib_stop_receiver: Receiver< for entry in vector { let (directory, file) = split_path(&entry.path); - let values: [(u32, &dyn ToValue); 10] = [ + let values: [(u32, &dyn ToValue); COLUMNS_NUMBER] = [ (ColumnsDuplicates::ActivatableSelectButton as u32, &true), (ColumnsDuplicates::SelectionButton as u32, &false), (ColumnsDuplicates::Size as u32, (&format_size(entry.size, BINARY))), + (ColumnsDuplicates::SizeAsBytes as u32, &entry.size), (ColumnsDuplicates::Name as u32, &file), (ColumnsDuplicates::Path as u32, &directory), ( @@ -458,10 +470,11 @@ pub fn connect_compute_results(gui_data: &GuiData, glib_stop_receiver: Receiver< } else { vector.clone() }; - let values: [(u32, &dyn ToValue); 10] = [ + let values: [(u32, &dyn ToValue); COLUMNS_NUMBER] = [ (ColumnsDuplicates::ActivatableSelectButton as u32, &false), (ColumnsDuplicates::SelectionButton as u32, &false), (ColumnsDuplicates::Size as u32, (&String::new())), + (ColumnsDuplicates::SizeAsBytes as u32, &0), (ColumnsDuplicates::Name as u32, (&String::new())), (ColumnsDuplicates::Path as u32, (&String::new())), (ColumnsDuplicates::Modification as u32, &String::new()), // No text in 3 column @@ -474,10 +487,11 @@ pub fn connect_compute_results(gui_data: &GuiData, glib_stop_receiver: Receiver< list_store.set(&list_store.append(), &values); for entry in vector { let (directory, file) = split_path(&entry.path); - let values: [(u32, &dyn ToValue); 10] = [ + let values: [(u32, &dyn ToValue); COLUMNS_NUMBER] = [ (ColumnsDuplicates::ActivatableSelectButton as u32, &true), (ColumnsDuplicates::SelectionButton as u32, &false), (ColumnsDuplicates::Size as u32, (&format_size(entry.size, BINARY))), + (ColumnsDuplicates::SizeAsBytes as u32, &entry.size), (ColumnsDuplicates::Name as u32, &file), (ColumnsDuplicates::Path as u32, &directory), ( @@ -512,6 +526,7 @@ pub fn connect_compute_results(gui_data: &GuiData, glib_stop_receiver: Receiver< BottomButtonsEnum::Save, BottomButtonsEnum::Delete, BottomButtonsEnum::Select, + BottomButtonsEnum::Sort, BottomButtonsEnum::Symlink, BottomButtonsEnum::Hardlink, BottomButtonsEnum::Move, @@ -528,6 +543,7 @@ pub fn connect_compute_results(gui_data: &GuiData, glib_stop_receiver: Receiver< } } Message::EmptyFolders(ef) => { + const COLUMNS_NUMBER: usize = 5; if ef.get_stopped_search() { entry_info.set_text(&flg!("compute_stopped_by_user")); } else { @@ -558,7 +574,7 @@ pub fn connect_compute_results(gui_data: &GuiData, glib_stop_receiver: Receiver< for path in vector { let (directory, file) = split_path(&path); - let values: [(u32, &dyn ToValue); 5] = [ + let values: [(u32, &dyn ToValue); COLUMNS_NUMBER] = [ (ColumnsEmptyFolders::SelectionButton as u32, &false), (ColumnsEmptyFolders::Name as u32, &file), (ColumnsEmptyFolders::Path as u32, &directory), @@ -593,6 +609,7 @@ pub fn connect_compute_results(gui_data: &GuiData, glib_stop_receiver: Receiver< } } Message::EmptyFiles(vf) => { + const COLUMNS_NUMBER: usize = 5; if vf.get_stopped_search() { entry_info.set_text(&flg!("compute_stopped_by_user")); } else { @@ -624,7 +641,7 @@ pub fn connect_compute_results(gui_data: &GuiData, glib_stop_receiver: Receiver< for file_entry in vector { let (directory, file) = split_path(&file_entry.path); - let values: [(u32, &dyn ToValue); 5] = [ + let values: [(u32, &dyn ToValue); COLUMNS_NUMBER] = [ (ColumnsEmptyFiles::SelectionButton as u32, &false), (ColumnsEmptyFiles::Name as u32, &file), (ColumnsEmptyFiles::Path as u32, &directory), @@ -659,6 +676,7 @@ pub fn connect_compute_results(gui_data: &GuiData, glib_stop_receiver: Receiver< } } Message::BigFiles(bf) => { + const COLUMNS_NUMBER: usize = 7; if bf.get_stopped_search() { entry_info.set_text(&flg!("compute_stopped_by_user")); } else { @@ -683,7 +701,7 @@ pub fn connect_compute_results(gui_data: &GuiData, glib_stop_receiver: Receiver< for (size, file_entry) in vector.iter() { let (directory, file) = split_path(&file_entry.path); - let values: [(u32, &dyn ToValue); 7] = [ + let values: [(u32, &dyn ToValue); COLUMNS_NUMBER] = [ (ColumnsBigFiles::SelectionButton as u32, &false), (ColumnsBigFiles::Size as u32, &(format_size(*size, BINARY))), (ColumnsBigFiles::Name as u32, &file), @@ -720,6 +738,7 @@ pub fn connect_compute_results(gui_data: &GuiData, glib_stop_receiver: Receiver< } } Message::Temporary(tf) => { + const COLUMNS_NUMBER: usize = 5; if tf.get_stopped_search() { entry_info.set_text(&flg!("compute_stopped_by_user")); } else { @@ -750,7 +769,7 @@ pub fn connect_compute_results(gui_data: &GuiData, glib_stop_receiver: Receiver< for file_entry in vector { let (directory, file) = split_path(&file_entry.path); - let values: [(u32, &dyn ToValue); 5] = [ + let values: [(u32, &dyn ToValue); COLUMNS_NUMBER] = [ (ColumnsTemporaryFiles::SelectionButton as u32, &false), (ColumnsTemporaryFiles::Name as u32, &file), (ColumnsTemporaryFiles::Path as u32, &directory), @@ -785,6 +804,7 @@ pub fn connect_compute_results(gui_data: &GuiData, glib_stop_receiver: Receiver< } } Message::SimilarImages(sf) => { + const COLUMNS_NUMBER: usize = 13; if sf.get_stopped_search() { entry_info.set_text(&flg!("compute_stopped_by_user")); } else { @@ -828,7 +848,7 @@ pub fn connect_compute_results(gui_data: &GuiData, glib_stop_receiver: Receiver< // Header let (directory, file) = split_path(&base_file_entry.path); - let values: [(u32, &dyn ToValue); 13] = [ + let values: [(u32, &dyn ToValue); COLUMNS_NUMBER] = [ (ColumnsSimilarImages::ActivatableSelectButton as u32, &false), (ColumnsSimilarImages::SelectionButton as u32, &false), (ColumnsSimilarImages::Similarity as u32, &String::new()), @@ -851,7 +871,7 @@ pub fn connect_compute_results(gui_data: &GuiData, glib_stop_receiver: Receiver< // Meat for file_entry in &vec_file_entry { let (directory, file) = split_path(&file_entry.path); - let values: [(u32, &dyn ToValue); 13] = [ + let values: [(u32, &dyn ToValue); COLUMNS_NUMBER] = [ (ColumnsSimilarImages::ActivatableSelectButton as u32, &true), (ColumnsSimilarImages::SelectionButton as u32, &false), ( @@ -889,7 +909,7 @@ pub fn connect_compute_results(gui_data: &GuiData, glib_stop_receiver: Receiver< }; // Header - let values: [(u32, &dyn ToValue); 13] = [ + let values: [(u32, &dyn ToValue); COLUMNS_NUMBER] = [ (ColumnsSimilarImages::ActivatableSelectButton as u32, &false), (ColumnsSimilarImages::SelectionButton as u32, &false), (ColumnsSimilarImages::Similarity as u32, &String::new()), @@ -909,7 +929,7 @@ pub fn connect_compute_results(gui_data: &GuiData, glib_stop_receiver: Receiver< // Meat for file_entry in &vec_file_entry { let (directory, file) = split_path(&file_entry.path); - let values: [(u32, &dyn ToValue); 13] = [ + let values: [(u32, &dyn ToValue); COLUMNS_NUMBER] = [ (ColumnsSimilarImages::ActivatableSelectButton as u32, &true), (ColumnsSimilarImages::SelectionButton as u32, &false), ( @@ -949,6 +969,7 @@ pub fn connect_compute_results(gui_data: &GuiData, glib_stop_receiver: Receiver< BottomButtonsEnum::Save, BottomButtonsEnum::Delete, BottomButtonsEnum::Select, + BottomButtonsEnum::Sort, BottomButtonsEnum::Symlink, BottomButtonsEnum::Hardlink, BottomButtonsEnum::Move, @@ -966,6 +987,7 @@ pub fn connect_compute_results(gui_data: &GuiData, glib_stop_receiver: Receiver< } } Message::SimilarVideos(ff) => { + const COLUMNS_NUMBER: usize = 11; if ff.get_stopped_search() { entry_info.set_text(&flg!("compute_stopped_by_user")); } else { @@ -1011,7 +1033,7 @@ pub fn connect_compute_results(gui_data: &GuiData, glib_stop_receiver: Receiver< // Header let (directory, file) = split_path(&base_file_entry.path); - let values: [(u32, &dyn ToValue); 11] = [ + let values: [(u32, &dyn ToValue); COLUMNS_NUMBER] = [ (ColumnsSimilarVideos::ActivatableSelectButton as u32, &false), (ColumnsSimilarVideos::SelectionButton as u32, &false), (ColumnsSimilarVideos::Size as u32, &format_size(base_file_entry.size, BINARY)), @@ -1032,7 +1054,7 @@ pub fn connect_compute_results(gui_data: &GuiData, glib_stop_receiver: Receiver< // Meat for file_entry in &vec_file_entry { let (directory, file) = split_path(&file_entry.path); - let values: [(u32, &dyn ToValue); 11] = [ + let values: [(u32, &dyn ToValue); COLUMNS_NUMBER] = [ (ColumnsSimilarVideos::ActivatableSelectButton as u32, &true), (ColumnsSimilarVideos::SelectionButton as u32, &false), (ColumnsSimilarVideos::Size as u32, &format_size(file_entry.size, BINARY)), @@ -1068,7 +1090,7 @@ pub fn connect_compute_results(gui_data: &GuiData, glib_stop_receiver: Receiver< }; // Header - let values: [(u32, &dyn ToValue); 11] = [ + let values: [(u32, &dyn ToValue); COLUMNS_NUMBER] = [ (ColumnsSimilarVideos::ActivatableSelectButton as u32, &false), (ColumnsSimilarVideos::SelectionButton as u32, &false), (ColumnsSimilarVideos::Size as u32, &String::new()), @@ -1086,7 +1108,7 @@ pub fn connect_compute_results(gui_data: &GuiData, glib_stop_receiver: Receiver< // Meat for file_entry in &vec_file_entry { let (directory, file) = split_path(&file_entry.path); - let values: [(u32, &dyn ToValue); 11] = [ + let values: [(u32, &dyn ToValue); COLUMNS_NUMBER] = [ (ColumnsSimilarVideos::ActivatableSelectButton as u32, &true), (ColumnsSimilarVideos::SelectionButton as u32, &false), (ColumnsSimilarVideos::Size as u32, &format_size(file_entry.size, BINARY)), @@ -1121,6 +1143,7 @@ pub fn connect_compute_results(gui_data: &GuiData, glib_stop_receiver: Receiver< BottomButtonsEnum::Save, BottomButtonsEnum::Delete, BottomButtonsEnum::Select, + BottomButtonsEnum::Sort, BottomButtonsEnum::Symlink, BottomButtonsEnum::Hardlink, BottomButtonsEnum::Move, @@ -1137,6 +1160,7 @@ pub fn connect_compute_results(gui_data: &GuiData, glib_stop_receiver: Receiver< } } Message::SameMusic(mf) => { + const COLUMNS_NUMBER: usize = 18; if mf.get_stopped_search() { entry_info.set_text(&flg!("compute_stopped_by_user")); } else { @@ -1192,7 +1216,7 @@ pub fn connect_compute_results(gui_data: &GuiData, glib_stop_receiver: Receiver< }; let (directory, file) = split_path(&base_file_entry.path); - let values: [(u32, &dyn ToValue); 18] = [ + let values: [(u32, &dyn ToValue); COLUMNS_NUMBER] = [ (ColumnsSameMusic::ActivatableSelectButton as u32, &false), (ColumnsSameMusic::SelectionButton as u32, &false), (ColumnsSameMusic::Size as u32, &format_size(base_file_entry.size, BINARY)), @@ -1218,20 +1242,20 @@ pub fn connect_compute_results(gui_data: &GuiData, glib_stop_receiver: Receiver< list_store.set(&list_store.append(), &values); for file_entry in vec_file_entry { let (directory, file) = split_path(&file_entry.path); - let values: [(u32, &dyn ToValue); 18] = [ + let values: [(u32, &dyn ToValue); COLUMNS_NUMBER] = [ (ColumnsSameMusic::ActivatableSelectButton as u32, &true), (ColumnsSameMusic::SelectionButton as u32, &false), (ColumnsSameMusic::Size as u32, &format_size(file_entry.size, BINARY)), (ColumnsSameMusic::SizeAsBytes as u32, &file_entry.size), (ColumnsSameMusic::Name as u32, &file), (ColumnsSameMusic::Path as u32, &directory), - (ColumnsSameMusic::Title as u32, &base_file_entry.track_title), - (ColumnsSameMusic::Artist as u32, &base_file_entry.track_artist), - (ColumnsSameMusic::Year as u32, &base_file_entry.year.to_string()), - (ColumnsSameMusic::Genre as u32, &base_file_entry.genre), - (ColumnsSameMusic::Bitrate as u32, &(format!("{} kbps", base_file_entry.bitrate))), - (ColumnsSameMusic::BitrateAsNumber as u32, &(base_file_entry.bitrate)), - (ColumnsSameMusic::Length as u32, &base_file_entry.length), + (ColumnsSameMusic::Title as u32, &file_entry.track_title), + (ColumnsSameMusic::Artist as u32, &file_entry.track_artist), + (ColumnsSameMusic::Year as u32, &file_entry.year.to_string()), + (ColumnsSameMusic::Genre as u32, &file_entry.genre), + (ColumnsSameMusic::Bitrate as u32, &(format!("{} kbps", file_entry.bitrate))), + (ColumnsSameMusic::BitrateAsNumber as u32, &(file_entry.bitrate)), + (ColumnsSameMusic::Length as u32, &file_entry.length), ( ColumnsSameMusic::Modification as u32, &(NaiveDateTime::from_timestamp_opt(file_entry.modified_date as i64, 0).unwrap().to_string()), @@ -1262,7 +1286,7 @@ pub fn connect_compute_results(gui_data: &GuiData, glib_stop_receiver: Receiver< vec_file_entry.clone() }; - let values: [(u32, &dyn ToValue); 18] = [ + let values: [(u32, &dyn ToValue); COLUMNS_NUMBER] = [ (ColumnsSameMusic::ActivatableSelectButton as u32, &false), (ColumnsSameMusic::SelectionButton as u32, &false), (ColumnsSameMusic::Size as u32, &String::new()), @@ -1285,7 +1309,7 @@ pub fn connect_compute_results(gui_data: &GuiData, glib_stop_receiver: Receiver< list_store.set(&list_store.append(), &values); for file_entry in vec_file_entry { let (directory, file) = split_path(&file_entry.path); - let values: [(u32, &dyn ToValue); 18] = [ + let values: [(u32, &dyn ToValue); COLUMNS_NUMBER] = [ (ColumnsSameMusic::ActivatableSelectButton as u32, &true), (ColumnsSameMusic::SelectionButton as u32, &false), (ColumnsSameMusic::Size as u32, &format_size(file_entry.size, BINARY)), @@ -1326,6 +1350,7 @@ pub fn connect_compute_results(gui_data: &GuiData, glib_stop_receiver: Receiver< BottomButtonsEnum::Save, BottomButtonsEnum::Delete, BottomButtonsEnum::Select, + BottomButtonsEnum::Sort, BottomButtonsEnum::Symlink, BottomButtonsEnum::Hardlink, BottomButtonsEnum::Move, @@ -1342,6 +1367,7 @@ pub fn connect_compute_results(gui_data: &GuiData, glib_stop_receiver: Receiver< } } Message::InvalidSymlinks(ifs) => { + const COLUMNS_NUMBER: usize = 7; if ifs.get_stopped_search() { entry_info.set_text(&flg!("compute_stopped_by_user")); } else { @@ -1375,7 +1401,7 @@ pub fn connect_compute_results(gui_data: &GuiData, glib_stop_receiver: Receiver< for file_entry in vector { let (directory, file) = split_path(&file_entry.path); let symlink_info = file_entry.symlink_info.clone().expect("invalid traversal result"); - let values: [(u32, &dyn ToValue); 7] = [ + let values: [(u32, &dyn ToValue); COLUMNS_NUMBER] = [ (ColumnsInvalidSymlinks::SelectionButton as u32, &false), (ColumnsInvalidSymlinks::Name as u32, &file), (ColumnsInvalidSymlinks::Path as u32, &directory), @@ -1415,6 +1441,7 @@ pub fn connect_compute_results(gui_data: &GuiData, glib_stop_receiver: Receiver< } } Message::BrokenFiles(br) => { + const COLUMNS_NUMBER: usize = 6; if br.get_stopped_search() { entry_info.set_text(&flg!("compute_stopped_by_user")); } else { @@ -1446,7 +1473,7 @@ pub fn connect_compute_results(gui_data: &GuiData, glib_stop_receiver: Receiver< for file_entry in vector { let (directory, file) = split_path(&file_entry.path); - let values: [(u32, &dyn ToValue); 6] = [ + let values: [(u32, &dyn ToValue); COLUMNS_NUMBER] = [ (ColumnsBrokenFiles::SelectionButton as u32, &false), (ColumnsBrokenFiles::Name as u32, &file), (ColumnsBrokenFiles::Path as u32, &directory), @@ -1482,6 +1509,7 @@ pub fn connect_compute_results(gui_data: &GuiData, glib_stop_receiver: Receiver< } } Message::BadExtensions(be) => { + const COLUMNS_NUMBER: usize = 7; if be.get_stopped_search() { entry_info.set_text(&flg!("compute_stopped_by_user")); } else { @@ -1512,7 +1540,7 @@ pub fn connect_compute_results(gui_data: &GuiData, glib_stop_receiver: Receiver< for file_entry in vector { let (directory, file) = split_path(&file_entry.path); - let values: [(u32, &dyn ToValue); 7] = [ + let values: [(u32, &dyn ToValue); COLUMNS_NUMBER] = [ (ColumnsBadExtensions::SelectionButton as u32, &false), (ColumnsBadExtensions::Name as u32, &file), (ColumnsBadExtensions::Path as u32, &directory), diff --git a/czkawka_gui/src/connect_things/connect_button_delete.rs b/czkawka_gui/src/connect_things/connect_button_delete.rs index 703825e..a6d6b02 100644 --- a/czkawka_gui/src/connect_things/connect_button_delete.rs +++ b/czkawka_gui/src/connect_things/connect_button_delete.rs @@ -140,7 +140,7 @@ pub async fn check_if_can_delete_files( } fn create_dialog_ask_for_deletion(window_main: >k4::Window, number_of_selected_items: u64, number_of_selected_groups: u64) -> (Dialog, CheckButton) { - let dialog = Dialog::builder().title(&flg!("delete_title_dialog")).transient_for(window_main).modal(true).build(); + let dialog = Dialog::builder().title(flg!("delete_title_dialog")).transient_for(window_main).modal(true).build(); let button_ok = dialog.add_button(&flg!("general_ok_button"), ResponseType::Ok); dialog.add_button(&flg!("general_close_button"), ResponseType::Cancel); @@ -157,9 +157,13 @@ fn create_dialog_ask_for_deletion(window_main: >k4::Window, number_of_selected generate_translation_hashmap(vec![("items", number_of_selected_items.to_string()), ("groups", number_of_selected_groups.to_string())]) ))), }; - let check_button: CheckButton = CheckButton::with_label(&flg!("dialogs_ask_next_time")); - check_button.set_active(true); - check_button.set_halign(Align::Center); + + let check_button: CheckButton = CheckButton::builder() + .label(flg!("dialogs_ask_next_time")) + .active(true) + .halign(Align::Center) + .margin_top(5) + .build(); button_ok.grab_focus(); @@ -169,16 +173,13 @@ fn create_dialog_ask_for_deletion(window_main: >k4::Window, number_of_selected parent.insert_child_after(&label2, Some(&label)); parent.insert_child_after(&check_button, Some(&label2)); - // parent.set_margin(5); // TODO - check_button.set_margin_top(5); - dialog.show(); (dialog, check_button) } fn create_dialog_group_deletion(window_main: >k4::Window) -> (Dialog, CheckButton) { let dialog = Dialog::builder() - .title(&flg!("delete_all_files_in_group_title")) + .title(flg!("delete_all_files_in_group_title")) .transient_for(window_main) .modal(true) .build(); @@ -187,9 +188,7 @@ fn create_dialog_group_deletion(window_main: >k4::Window) -> (Dialog, CheckBut let label: gtk4::Label = gtk4::Label::new(Some(&flg!("delete_all_files_in_group_label1"))); let label2: gtk4::Label = gtk4::Label::new(Some(&flg!("delete_all_files_in_group_label2"))); - let check_button: CheckButton = CheckButton::with_label(&flg!("dialogs_ask_next_time")); - check_button.set_active(true); - check_button.set_halign(Align::Center); + let check_button: CheckButton = CheckButton::builder().label(flg!("dialogs_ask_next_time")).active(true).halign(Align::Center).build(); button_ok.grab_focus(); diff --git a/czkawka_gui/src/connect_things/connect_button_hardlink.rs b/czkawka_gui/src/connect_things/connect_button_hardlink.rs index 83ed834..1f570b7 100644 --- a/czkawka_gui/src/connect_things/connect_button_hardlink.rs +++ b/czkawka_gui/src/connect_things/connect_button_hardlink.rs @@ -13,7 +13,7 @@ use crate::localizer_core::generate_translation_hashmap; use crate::notebook_enums::*; use crate::notebook_info::NOTEBOOKS_INFO; -#[derive(PartialEq, Eq)] +#[derive(PartialEq, Eq, Copy, Clone)] enum TypeOfTool { Hardlinking, Symlinking, @@ -262,7 +262,7 @@ fn hardlink_symlink( fn create_dialog_non_group(window_main: >k4::Window) -> Dialog { let dialog = Dialog::builder() - .title(&flg!("hard_sym_invalid_selection_title_dialog")) + .title(flg!("hard_sym_invalid_selection_title_dialog")) .transient_for(window_main) .modal(true) .build(); @@ -370,14 +370,12 @@ pub async fn check_if_can_link_files(check_button_settings_confirm_link: &CheckB } fn create_dialog_ask_for_linking(window_main: >k4::Window) -> (Dialog, CheckButton) { - let dialog = Dialog::builder().title(&flg!("hard_sym_link_title_dialog")).transient_for(window_main).modal(true).build(); + let dialog = Dialog::builder().title(flg!("hard_sym_link_title_dialog")).transient_for(window_main).modal(true).build(); let button_ok = dialog.add_button(&flg!("general_ok_button"), ResponseType::Ok); dialog.add_button(&flg!("general_close_button"), ResponseType::Cancel); let label: gtk4::Label = gtk4::Label::new(Some(&flg!("hard_sym_link_label"))); - let check_button: CheckButton = CheckButton::with_label(&flg!("dialogs_ask_next_time")); - check_button.set_active(true); - check_button.set_halign(Align::Center); + let check_button: CheckButton = CheckButton::builder().label(flg!("dialogs_ask_next_time")).active(true).halign(Align::Center).build(); button_ok.grab_focus(); diff --git a/czkawka_gui/src/connect_things/connect_button_move.rs b/czkawka_gui/src/connect_things/connect_button_move.rs index 5ecb651..2012a07 100644 --- a/czkawka_gui/src/connect_things/connect_button_move.rs +++ b/czkawka_gui/src/connect_things/connect_button_move.rs @@ -1,7 +1,7 @@ use std::path::{Path, PathBuf}; use gtk4::prelude::*; -use gtk4::{ResponseType, TreePath}; +use gtk4::{FileChooserNative, ResponseType, TreePath}; use crate::flg; use crate::gui_structs::gui_data::GuiData; @@ -22,9 +22,8 @@ pub fn connect_button_move(gui_data: &GuiData) { let entry_info = gui_data.entry_info.clone(); let text_view_errors = gui_data.text_view_errors.clone(); - let window_main = gui_data.window_main.clone(); - let preview_path = gui_data.preview_path.clone(); + let file_dialog_move_to_folder = gui_data.file_dialog_move_to_folder.clone(); buttons_move.connect_clicked(move |_| { let nb_number = notebook_main.current_page().unwrap(); @@ -45,7 +44,7 @@ pub fn connect_button_move(gui_data: &GuiData) { nb_object.column_selection, &entry_info, &text_view_errors, - &window_main, + &file_dialog_move_to_folder, ); match &nb_object.notebook_type { @@ -71,26 +70,14 @@ fn move_things( column_selection: i32, entry_info: >k4::Entry, text_view_errors: >k4::TextView, - window_main: >k4::Window, + file_dialog_move_to_folder: &FileChooserNative, ) { reset_text_view(text_view_errors); - let chooser = gtk4::FileChooserDialog::builder() - .title(&flg!("move_files_title_dialog")) - .action(gtk4::FileChooserAction::SelectFolder) - .transient_for(window_main) - .modal(true) - .build(); - chooser.add_button(&flg!("general_ok_button"), ResponseType::Ok); - chooser.add_button(&flg!("general_close_button"), ResponseType::Cancel); - - chooser.set_select_multiple(false); - chooser.show(); - let entry_info = entry_info.clone(); let text_view_errors = text_view_errors.clone(); let tree_view = tree_view.clone(); - chooser.connect_response(move |file_chooser, response_type| { + file_dialog_move_to_folder.connect_response(move |file_chooser, response_type| { if response_type == ResponseType::Ok { let mut folders: Vec = Vec::new(); let g_files = file_chooser.files(); @@ -131,7 +118,7 @@ fn move_things( } } } - file_chooser.close(); + // file_chooser.close(); }); } diff --git a/czkawka_gui/src/connect_things/connect_button_select.rs b/czkawka_gui/src/connect_things/connect_button_select.rs index a5de4f8..07b9692 100644 --- a/czkawka_gui/src/connect_things/connect_button_select.rs +++ b/czkawka_gui/src/connect_things/connect_button_select.rs @@ -1,40 +1,40 @@ use gtk4::prelude::*; use crate::gui_structs::gui_data::GuiData; -use crate::gui_structs::gui_popovers::GuiPopovers; +use crate::gui_structs::gui_popovers_select::GuiSelectPopovers; use crate::help_functions::PopoverTypes; use crate::notebook_enums::*; use crate::notebook_info::NOTEBOOKS_INFO; pub fn connect_button_select(gui_data: &GuiData) { - let popovers = gui_data.popovers.clone(); + let popovers_select = gui_data.popovers_select.clone(); let notebook_main = gui_data.main_notebook.notebook_main.clone(); let gc_buttons_select = gui_data.bottom_buttons.gc_buttons_select.clone(); gc_buttons_select.connect_pressed(move |_, _, _, _| { - show_required_popovers(&popovers, &to_notebook_main_enum(notebook_main.current_page().unwrap())); + show_required_popovers(&popovers_select, &to_notebook_main_enum(notebook_main.current_page().unwrap())); }); } -fn show_required_popovers(popovers: &GuiPopovers, current_mode: &NotebookMainEnum) { - let buttons_popover_select_all = popovers.buttons_popover_select_all.clone(); - let buttons_popover_unselect_all = popovers.buttons_popover_unselect_all.clone(); - let buttons_popover_reverse = popovers.buttons_popover_reverse.clone(); - let buttons_popover_select_all_except_oldest = popovers.buttons_popover_select_all_except_oldest.clone(); - let buttons_popover_select_all_except_newest = popovers.buttons_popover_select_all_except_newest.clone(); - let buttons_popover_select_one_oldest = popovers.buttons_popover_select_one_oldest.clone(); - let buttons_popover_select_one_newest = popovers.buttons_popover_select_one_newest.clone(); - let buttons_popover_select_custom = popovers.buttons_popover_select_custom.clone(); - let buttons_popover_unselect_custom = popovers.buttons_popover_unselect_custom.clone(); - let buttons_popover_select_all_images_except_biggest = popovers.buttons_popover_select_all_images_except_biggest.clone(); - let buttons_popover_select_all_images_except_smallest = popovers.buttons_popover_select_all_images_except_smallest.clone(); +fn show_required_popovers(popovers_select: &GuiSelectPopovers, current_mode: &NotebookMainEnum) { + let buttons_popover_select_all = popovers_select.buttons_popover_select_all.clone(); + let buttons_popover_unselect_all = popovers_select.buttons_popover_unselect_all.clone(); + let buttons_popover_reverse = popovers_select.buttons_popover_reverse.clone(); + let buttons_popover_select_all_except_oldest = popovers_select.buttons_popover_select_all_except_oldest.clone(); + let buttons_popover_select_all_except_newest = popovers_select.buttons_popover_select_all_except_newest.clone(); + let buttons_popover_select_one_oldest = popovers_select.buttons_popover_select_one_oldest.clone(); + let buttons_popover_select_one_newest = popovers_select.buttons_popover_select_one_newest.clone(); + let buttons_popover_select_custom = popovers_select.buttons_popover_select_custom.clone(); + let buttons_popover_unselect_custom = popovers_select.buttons_popover_unselect_custom.clone(); + let buttons_popover_select_all_images_except_biggest = popovers_select.buttons_popover_select_all_images_except_biggest.clone(); + let buttons_popover_select_all_images_except_smallest = popovers_select.buttons_popover_select_all_images_except_smallest.clone(); - let separator_select_custom = popovers.separator_select_custom.clone(); - let separator_select_date = popovers.separator_select_date.clone(); - let separator_select_image_size = popovers.separator_select_image_size.clone(); - let separator_select_reverse = popovers.separator_select_reverse.clone(); + let separator_select_custom = popovers_select.separator_select_custom.clone(); + let separator_select_date = popovers_select.separator_select_date.clone(); + let separator_select_image_size = popovers_select.separator_select_image_size.clone(); + let separator_select_reverse = popovers_select.separator_select_reverse.clone(); - let arr = &NOTEBOOKS_INFO[current_mode.clone() as usize].available_modes; + let arr = &NOTEBOOKS_INFO[*current_mode as usize].available_modes; if arr.contains(&PopoverTypes::All) { buttons_popover_select_all.show(); diff --git a/czkawka_gui/src/connect_things/connect_button_sort.rs b/czkawka_gui/src/connect_things/connect_button_sort.rs new file mode 100644 index 0000000..810dc00 --- /dev/null +++ b/czkawka_gui/src/connect_things/connect_button_sort.rs @@ -0,0 +1,46 @@ +use crate::gui_structs::gui_data::GuiData; +use crate::gui_structs::gui_popovers_sort::GuiSortPopovers; +use crate::help_functions::PopoverTypes; +use crate::notebook_enums::{to_notebook_main_enum, NotebookMainEnum}; +use crate::notebook_info::NOTEBOOKS_INFO; +use gtk4::prelude::*; + +pub fn connect_button_sort(gui_data: &GuiData) { + let popovers_sort = gui_data.popovers_sort.clone(); + let notebook_main = gui_data.main_notebook.notebook_main.clone(); + let gc_buttons_sort = gui_data.bottom_buttons.gc_buttons_sort.clone(); + + gc_buttons_sort.connect_pressed(move |_, _, _, _| { + show_required_popovers(&popovers_sort, &to_notebook_main_enum(notebook_main.current_page().unwrap())); + }); +} + +fn show_required_popovers(popovers_sort: &GuiSortPopovers, current_mode: &NotebookMainEnum) { + let buttons_popover_sort_file_name = popovers_sort.buttons_popover_sort_file_name.clone(); + let buttons_popover_sort_size = popovers_sort.buttons_popover_sort_size.clone(); + let buttons_popover_sort_folder_name = popovers_sort.buttons_popover_sort_folder_name.clone(); + let buttons_popover_sort_full_name = popovers_sort.buttons_popover_sort_full_name.clone(); + let buttons_popover_sort_selection = popovers_sort.buttons_popover_sort_selection.clone(); + + let arr = &NOTEBOOKS_INFO[*current_mode as usize].available_modes; + + buttons_popover_sort_full_name.hide(); + + if arr.contains(&PopoverTypes::All) { + buttons_popover_sort_selection.show(); + buttons_popover_sort_file_name.show(); + buttons_popover_sort_folder_name.show(); + // buttons_popover_sort_full_name.show(); // TODO, this needs to be handled a little different + } else { + buttons_popover_sort_selection.hide(); + buttons_popover_sort_file_name.hide(); + buttons_popover_sort_folder_name.hide(); + // buttons_popover_sort_full_name.hide(); + } + + if arr.contains(&PopoverTypes::Size) { + buttons_popover_sort_size.show(); + } else { + buttons_popover_sort_size.hide(); + } +} diff --git a/czkawka_gui/src/connect_things/connect_popovers.rs b/czkawka_gui/src/connect_things/connect_popovers_select.rs similarity index 89% rename from czkawka_gui/src/connect_things/connect_popovers.rs rename to czkawka_gui/src/connect_things/connect_popovers_select.rs index 0898872..37cc099 100644 --- a/czkawka_gui/src/connect_things/connect_popovers.rs +++ b/czkawka_gui/src/connect_things/connect_popovers_select.rs @@ -245,41 +245,44 @@ fn popover_custom_select_unselect( // Dialog for select/unselect items { - let dialog = gtk4::Dialog::builder().title(&window_title).transient_for(window_main).modal(true).build(); + let dialog = gtk4::Dialog::builder().title(window_title).transient_for(window_main).modal(true).build(); dialog.add_button(&flg!("general_ok_button"), ResponseType::Ok); dialog.add_button(&flg!("general_close_button"), ResponseType::Cancel); - let check_button_path = gtk4::CheckButton::builder().label(&flg!("popover_custom_regex_path_label")).build(); - let check_button_name = gtk4::CheckButton::builder().label(&flg!("popover_custom_regex_name_label")).build(); - let check_button_rust_regex = gtk4::CheckButton::builder().label(&flg!("popover_custom_regex_regex_label")).build(); + let check_button_path = gtk4::CheckButton::builder() + .label(flg!("popover_custom_regex_path_label")) + .tooltip_text(flg!("popover_custom_path_check_button_entry_tooltip")) + .build(); + let check_button_name = gtk4::CheckButton::builder() + .label(flg!("popover_custom_regex_name_label")) + .tooltip_text(flg!("popover_custom_name_check_button_entry_tooltip")) + .build(); + let check_button_rust_regex = gtk4::CheckButton::builder() + .label(flg!("popover_custom_regex_regex_label")) + .tooltip_text(flg!("popover_custom_regex_check_button_entry_tooltip")) + .build(); - let check_button_case_sensitive = gtk4::CheckButton::builder().label(&flg!("popover_custom_case_sensitive_check_button")).build(); - check_button_case_sensitive.set_active(false); + let check_button_case_sensitive = gtk4::CheckButton::builder() + .label(flg!("popover_custom_case_sensitive_check_button")) + .tooltip_text(flg!("popover_custom_case_sensitive_check_button_tooltip")) + .active(false) + .build(); - let check_button_select_not_all_results = gtk4::CheckButton::builder().label(&flg!("popover_custom_all_in_group_label")).build(); - check_button_select_not_all_results.set_active(true); + let check_button_select_not_all_results = gtk4::CheckButton::builder() + .label(flg!("popover_custom_all_in_group_label")) + .tooltip_text(flg!("popover_custom_not_all_check_button_tooltip")) + .active(true) + .build(); - let entry_path = gtk4::Entry::new(); - let entry_name = gtk4::Entry::new(); - let entry_rust_regex = gtk4::Entry::new(); - entry_rust_regex.set_sensitive(false); // By default check button regex is disabled + let entry_path = gtk4::Entry::builder().tooltip_text(flg!("popover_custom_path_check_button_entry_tooltip")).build(); + let entry_name = gtk4::Entry::builder().tooltip_text(flg!("popover_custom_name_check_button_entry_tooltip")).build(); + let entry_rust_regex = gtk4::Entry::builder() + .tooltip_text(flg!("popover_custom_regex_check_button_entry_tooltip")) + .sensitive(false) + .build(); // By default check button regex is disabled let label_regex_valid = gtk4::Label::new(None); - // Tooltips - { - check_button_path.set_tooltip_text(Some(&flg!("popover_custom_path_check_button_entry_tooltip"))); - entry_path.set_tooltip_text(Some(&flg!("popover_custom_path_check_button_entry_tooltip"))); - - check_button_name.set_tooltip_text(Some(&flg!("popover_custom_name_check_button_entry_tooltip"))); - entry_name.set_tooltip_text(Some(&flg!("popover_custom_name_check_button_entry_tooltip"))); - - check_button_rust_regex.set_tooltip_text(Some(&flg!("popover_custom_regex_check_button_entry_tooltip"))); - entry_rust_regex.set_tooltip_text(Some(&flg!("popover_custom_regex_check_button_entry_tooltip"))); - - check_button_case_sensitive.set_tooltip_text(Some(&flg!("popover_custom_case_sensitive_check_button_tooltip"))); - check_button_select_not_all_results.set_tooltip_text(Some(&flg!("popover_custom_not_all_check_button_tooltip"))); - } { let label_regex_valid = label_regex_valid.clone(); entry_rust_regex.connect_changed(move |entry_rust_regex| { @@ -332,9 +335,7 @@ fn popover_custom_select_unselect( // Configure look of things { // TODO Label should have const width, and rest should fill entry, but for now is 50%-50% - let grid = gtk4::Grid::new(); - grid.set_row_homogeneous(true); - grid.set_column_homogeneous(true); + let grid = gtk4::Grid::builder().row_homogeneous(true).column_homogeneous(true).build(); grid.attach(&check_button_name, 0, 1, 1, 1); grid.attach(&check_button_path, 0, 2, 1, 1); @@ -593,9 +594,9 @@ fn popover_all_except_biggest_smallest( popover.popdown(); } -pub fn connect_popovers(gui_data: &GuiData) { - let popover_select = gui_data.popovers.popover_select.clone(); - let buttons_popover_select_all = gui_data.popovers.buttons_popover_select_all.clone(); +pub fn connect_popover_select(gui_data: &GuiData) { + let popover_select = gui_data.popovers_select.popover_select.clone(); + let buttons_popover_select_all = gui_data.popovers_select.buttons_popover_select_all.clone(); let notebook_main = gui_data.main_notebook.notebook_main.clone(); let main_tree_views = gui_data.main_notebook.get_main_tree_views(); @@ -607,8 +608,8 @@ pub fn connect_popovers(gui_data: &GuiData) { popover_select_all(&popover_select, tree_view, nb_object.column_selection as u32, nb_object.column_header); }); - let popover_select = gui_data.popovers.popover_select.clone(); - let buttons_popover_unselect_all = gui_data.popovers.buttons_popover_unselect_all.clone(); + let popover_select = gui_data.popovers_select.popover_select.clone(); + let buttons_popover_unselect_all = gui_data.popovers_select.buttons_popover_unselect_all.clone(); let notebook_main = gui_data.main_notebook.notebook_main.clone(); let main_tree_views = gui_data.main_notebook.get_main_tree_views(); buttons_popover_unselect_all.connect_clicked(move |_| { @@ -619,8 +620,8 @@ pub fn connect_popovers(gui_data: &GuiData) { popover_unselect_all(&popover_select, tree_view, nb_object.column_selection as u32); }); - let popover_select = gui_data.popovers.popover_select.clone(); - let buttons_popover_reverse = gui_data.popovers.buttons_popover_reverse.clone(); + let popover_select = gui_data.popovers_select.popover_select.clone(); + let buttons_popover_reverse = gui_data.popovers_select.buttons_popover_reverse.clone(); let notebook_main = gui_data.main_notebook.notebook_main.clone(); let main_tree_views = gui_data.main_notebook.get_main_tree_views(); buttons_popover_reverse.connect_clicked(move |_| { @@ -631,8 +632,8 @@ pub fn connect_popovers(gui_data: &GuiData) { popover_reverse(&popover_select, tree_view, nb_object.column_selection as u32, nb_object.column_header); }); - let popover_select = gui_data.popovers.popover_select.clone(); - let buttons_popover_select_all_except_oldest = gui_data.popovers.buttons_popover_select_all_except_oldest.clone(); + let popover_select = gui_data.popovers_select.popover_select.clone(); + let buttons_popover_select_all_except_oldest = gui_data.popovers_select.buttons_popover_select_all_except_oldest.clone(); let notebook_main = gui_data.main_notebook.notebook_main.clone(); let main_tree_views = gui_data.main_notebook.get_main_tree_views(); buttons_popover_select_all_except_oldest.connect_clicked(move |_| { @@ -651,8 +652,8 @@ pub fn connect_popovers(gui_data: &GuiData) { ); }); - let popover_select = gui_data.popovers.popover_select.clone(); - let buttons_popover_select_all_except_newest = gui_data.popovers.buttons_popover_select_all_except_newest.clone(); + let popover_select = gui_data.popovers_select.popover_select.clone(); + let buttons_popover_select_all_except_newest = gui_data.popovers_select.buttons_popover_select_all_except_newest.clone(); let notebook_main = gui_data.main_notebook.notebook_main.clone(); let main_tree_views = gui_data.main_notebook.get_main_tree_views(); buttons_popover_select_all_except_newest.connect_clicked(move |_| { @@ -671,8 +672,8 @@ pub fn connect_popovers(gui_data: &GuiData) { ); }); - let popover_select = gui_data.popovers.popover_select.clone(); - let buttons_popover_select_one_oldest = gui_data.popovers.buttons_popover_select_one_oldest.clone(); + let popover_select = gui_data.popovers_select.popover_select.clone(); + let buttons_popover_select_one_oldest = gui_data.popovers_select.buttons_popover_select_one_oldest.clone(); let notebook_main = gui_data.main_notebook.notebook_main.clone(); let main_tree_views = gui_data.main_notebook.get_main_tree_views(); buttons_popover_select_one_oldest.connect_clicked(move |_| { @@ -691,8 +692,8 @@ pub fn connect_popovers(gui_data: &GuiData) { ); }); - let popover_select = gui_data.popovers.popover_select.clone(); - let buttons_popover_select_one_newest = gui_data.popovers.buttons_popover_select_one_newest.clone(); + let popover_select = gui_data.popovers_select.popover_select.clone(); + let buttons_popover_select_one_newest = gui_data.popovers_select.buttons_popover_select_one_newest.clone(); let notebook_main = gui_data.main_notebook.notebook_main.clone(); let main_tree_views = gui_data.main_notebook.get_main_tree_views(); buttons_popover_select_one_newest.connect_clicked(move |_| { @@ -711,8 +712,8 @@ pub fn connect_popovers(gui_data: &GuiData) { ); }); - let popover_select = gui_data.popovers.popover_select.clone(); - let buttons_popover_select_custom = gui_data.popovers.buttons_popover_select_custom.clone(); + let popover_select = gui_data.popovers_select.popover_select.clone(); + let buttons_popover_select_custom = gui_data.popovers_select.buttons_popover_select_custom.clone(); let notebook_main = gui_data.main_notebook.notebook_main.clone(); let main_tree_views = gui_data.main_notebook.get_main_tree_views(); let window_main = gui_data.window_main.clone(); @@ -733,8 +734,8 @@ pub fn connect_popovers(gui_data: &GuiData) { ); }); - let popover_select = gui_data.popovers.popover_select.clone(); - let buttons_popover_unselect_custom = gui_data.popovers.buttons_popover_unselect_custom.clone(); + let popover_select = gui_data.popovers_select.popover_select.clone(); + let buttons_popover_unselect_custom = gui_data.popovers_select.buttons_popover_unselect_custom.clone(); let notebook_main = gui_data.main_notebook.notebook_main.clone(); let main_tree_views = gui_data.main_notebook.get_main_tree_views(); let window_main = gui_data.window_main.clone(); @@ -755,8 +756,8 @@ pub fn connect_popovers(gui_data: &GuiData) { ); }); - let popover_select = gui_data.popovers.popover_select.clone(); - let buttons_popover_select_all_images_except_biggest = gui_data.popovers.buttons_popover_select_all_images_except_biggest.clone(); + let popover_select = gui_data.popovers_select.popover_select.clone(); + let buttons_popover_select_all_images_except_biggest = gui_data.popovers_select.buttons_popover_select_all_images_except_biggest.clone(); let notebook_main = gui_data.main_notebook.notebook_main.clone(); let main_tree_views = gui_data.main_notebook.get_main_tree_views(); buttons_popover_select_all_images_except_biggest.connect_clicked(move |_| { @@ -775,8 +776,8 @@ pub fn connect_popovers(gui_data: &GuiData) { ); }); - let popover_select = gui_data.popovers.popover_select.clone(); - let buttons_popover_select_all_images_except_smallest = gui_data.popovers.buttons_popover_select_all_images_except_smallest.clone(); + let popover_select = gui_data.popovers_select.popover_select.clone(); + let buttons_popover_select_all_images_except_smallest = gui_data.popovers_select.buttons_popover_select_all_images_except_smallest.clone(); let notebook_main = gui_data.main_notebook.notebook_main.clone(); let main_tree_views = gui_data.main_notebook.get_main_tree_views(); buttons_popover_select_all_images_except_smallest.connect_clicked(move |_| { diff --git a/czkawka_gui/src/connect_things/connect_popovers_sort.rs b/czkawka_gui/src/connect_things/connect_popovers_sort.rs new file mode 100644 index 0000000..798fde4 --- /dev/null +++ b/czkawka_gui/src/connect_things/connect_popovers_sort.rs @@ -0,0 +1,210 @@ +use gtk4::prelude::*; +use gtk4::{ListStore, TreeIter}; +use std::fmt::Debug; + +use crate::gui_structs::gui_data::GuiData; +use crate::help_functions::*; +use crate::notebook_info::NOTEBOOKS_INFO; + +fn popover_sort_general(popover: >k4::Popover, tree_view: >k4::TreeView, column_sort: i32, column_header: i32) +where + T: Ord + for<'b> glib::value::FromValue<'b> + 'static + Debug, +{ + let model = get_list_store(tree_view); + + if let Some(curr_iter) = model.iter_first() { + assert!(model.get::(&curr_iter, column_header)); + assert!(model.iter_next(&curr_iter)); // Must be at least one item + loop { + let mut iters = Vec::new(); + let mut all_have = false; + loop { + if model.get::(&curr_iter, column_header) { + assert!(model.iter_next(&curr_iter), "Empty header, this should not happens"); + break; + } + iters.push(curr_iter); + if !model.iter_next(&curr_iter) { + all_have = true; + break; + } + } + if iters.len() == 1 { + continue; // Can be equal 1 in reference folders + } + + sort_iters::(&model, iters, column_sort); + if all_have { + break; + } + } + } + popover.popdown(); +} + +fn sort_iters(model: &ListStore, mut iters: Vec, column_sort: i32) +where + T: Ord + for<'b> glib::value::FromValue<'b> + 'static + Debug, +{ + assert!(iters.len() >= 2); + loop { + let mut changed_item = false; + for idx in 0..(iters.len() - 1) { + if model.get::(&iters[idx], column_sort) > model.get::(&iters[idx + 1], column_sort) { + model.swap(&iters[idx], &iters[idx + 1]); + iters.swap(idx, idx + 1); + changed_item = true; + } + } + if !changed_item { + return; + } + } +} + +pub fn connect_popover_sort(gui_data: &GuiData) { + let popover_sort = gui_data.popovers_sort.popover_sort.clone(); + let buttons_popover_file_name = gui_data.popovers_sort.buttons_popover_sort_file_name.clone(); + let notebook_main = gui_data.main_notebook.notebook_main.clone(); + let main_tree_views = gui_data.main_notebook.get_main_tree_views(); + + buttons_popover_file_name.connect_clicked(move |_| { + let nb_number = notebook_main.current_page().unwrap(); + let tree_view = &main_tree_views[nb_number as usize]; + let nb_object = &NOTEBOOKS_INFO[nb_number as usize]; + + popover_sort_general::(&popover_sort, tree_view, nb_object.column_name, nb_object.column_header.unwrap()); + }); + + let popover_sort = gui_data.popovers_sort.popover_sort.clone(); + let buttons_popover_sort_folder_name = gui_data.popovers_sort.buttons_popover_sort_folder_name.clone(); + let notebook_main = gui_data.main_notebook.notebook_main.clone(); + let main_tree_views = gui_data.main_notebook.get_main_tree_views(); + + buttons_popover_sort_folder_name.connect_clicked(move |_| { + let nb_number = notebook_main.current_page().unwrap(); + let tree_view = &main_tree_views[nb_number as usize]; + let nb_object = &NOTEBOOKS_INFO[nb_number as usize]; + + popover_sort_general::(&popover_sort, tree_view, nb_object.column_path, nb_object.column_header.unwrap()); + }); + + let popover_sort = gui_data.popovers_sort.popover_sort.clone(); + let buttons_popover_sort_selection = gui_data.popovers_sort.buttons_popover_sort_selection.clone(); + let notebook_main = gui_data.main_notebook.notebook_main.clone(); + let main_tree_views = gui_data.main_notebook.get_main_tree_views(); + + buttons_popover_sort_selection.connect_clicked(move |_| { + let nb_number = notebook_main.current_page().unwrap(); + let tree_view = &main_tree_views[nb_number as usize]; + let nb_object = &NOTEBOOKS_INFO[nb_number as usize]; + + popover_sort_general::(&popover_sort, tree_view, nb_object.column_selection, nb_object.column_header.unwrap()); + }); + + let popover_sort = gui_data.popovers_sort.popover_sort.clone(); + let buttons_popover_sort_size = gui_data.popovers_sort.buttons_popover_sort_size.clone(); + let notebook_main = gui_data.main_notebook.notebook_main.clone(); + let main_tree_views = gui_data.main_notebook.get_main_tree_views(); + + buttons_popover_sort_size.connect_clicked(move |_| { + let nb_number = notebook_main.current_page().unwrap(); + let tree_view = &main_tree_views[nb_number as usize]; + let nb_object = &NOTEBOOKS_INFO[nb_number as usize]; + + popover_sort_general::(&popover_sort, tree_view, nb_object.column_size_as_bytes.unwrap(), nb_object.column_header.unwrap()); + }); +} + +#[cfg(test)] +mod test { + use crate::connect_things::connect_popovers_sort::{popover_sort_general, sort_iters}; + use gtk4::prelude::*; + use gtk4::{Popover, TreeView}; + + #[gtk4::test] + fn test_sort_iters() { + let columns_types: &[glib::types::Type] = &[glib::types::Type::U32, glib::types::Type::STRING]; + let list_store = gtk4::ListStore::new(columns_types); + + let values_to_add: &[&[(u32, &dyn ToValue)]] = &[&[(0, &2), (1, &"AAA")], &[(0, &3), (1, &"CCC")], &[(0, &1), (1, &"BBB")]]; + for i in values_to_add { + list_store.set(&list_store.append(), i); + } + let mut iters = Vec::new(); + let iter = list_store.iter_first().unwrap(); + iters.push(iter); + list_store.iter_next(&iter); + iters.push(iter); + list_store.iter_next(&iter); + iters.push(iter); + + sort_iters::(&list_store, iters, 1); + + let expected = [(2, "AAA"), (1, "BBB"), (3, "CCC")]; + let curr_iter = list_store.iter_first().unwrap(); + for exp in expected { + let real_0 = list_store.get::(&curr_iter, 0); + assert_eq!(real_0, exp.0); + let real_1 = list_store.get::(&curr_iter, 1); + assert_eq!(real_1, exp.1); + list_store.iter_next(&curr_iter); + } + } + + #[gtk4::test] + pub fn test_popover_sort_general_simple() { + let columns_types: &[glib::types::Type] = &[glib::types::Type::BOOL, glib::types::Type::STRING]; + let list_store = gtk4::ListStore::new(columns_types); + let tree_view = TreeView::builder().model(&list_store).build(); + let popover = Popover::new(); + + let values_to_add: &[&[(u32, &dyn ToValue)]] = &[&[(0, &true), (1, &"DDD")], &[(0, &false), (1, &"CCC")], &[(0, &false), (1, &"BBB")]]; + for i in values_to_add { + list_store.set(&list_store.append(), i); + } + + popover_sort_general::(&popover, &tree_view, 1, 0); + + let expected = ["DDD", "BBB", "CCC"]; + let curr_iter = list_store.iter_first().unwrap(); + for exp in expected { + let real = list_store.get::(&curr_iter, 1); + assert_eq!(real, exp); + list_store.iter_next(&curr_iter); + } + } + + #[gtk4::test] + pub fn test_popover_sort_general() { + let columns_types: &[glib::types::Type] = &[glib::types::Type::BOOL, glib::types::Type::STRING]; + let list_store = gtk4::ListStore::new(columns_types); + let tree_view = TreeView::builder().model(&list_store).build(); + let popover = Popover::new(); + + let values_to_add: &[&[(u32, &dyn ToValue)]] = &[ + &[(0, &true), (1, &"AAA")], + &[(0, &false), (1, &"CCC")], + &[(0, &false), (1, &"BBB")], + &[(0, &true), (1, &"TTT")], + &[(0, &false), (1, &"PPP")], + &[(0, &false), (1, &"AAA")], + &[(0, &true), (1, &"RRR")], + &[(0, &false), (1, &"WWW")], + &[(0, &false), (1, &"ZZZ")], + ]; + for i in values_to_add { + list_store.set(&list_store.append(), i); + } + + popover_sort_general::(&popover, &tree_view, 1, 0); + + let expected = ["AAA", "BBB", "CCC", "TTT", "AAA", "PPP", "RRR", "WWW", "ZZZ"]; + let curr_iter = list_store.iter_first().unwrap(); + for exp in expected { + let real = list_store.get::(&curr_iter, 1); + assert_eq!(real, exp); + list_store.iter_next(&curr_iter); + } + } +} diff --git a/czkawka_gui/src/connect_things/connect_selection_of_directories.rs b/czkawka_gui/src/connect_things/connect_selection_of_directories.rs index 668533f..bec08f3 100644 --- a/czkawka_gui/src/connect_things/connect_selection_of_directories.rs +++ b/czkawka_gui/src/connect_things/connect_selection_of_directories.rs @@ -1,7 +1,7 @@ use std::path::PathBuf; use gtk4::prelude::*; -use gtk4::{Orientation, ResponseType, TreeView, Window}; +use gtk4::{FileChooserNative, Orientation, ResponseType, TreeView, Window}; #[cfg(target_family = "windows")] use czkawka_core::common::Common; @@ -32,19 +32,19 @@ pub fn connect_selection_of_directories(gui_data: &GuiData) { // Add included directory { let tree_view_included_directories = gui_data.upper_notebook.tree_view_included_directories.clone(); - let window_main = gui_data.window_main.clone(); let buttons_add_included_directory = gui_data.upper_notebook.buttons_add_included_directory.clone(); + let file_dialog_include_exclude_folder_selection = gui_data.file_dialog_include_exclude_folder_selection.clone(); buttons_add_included_directory.connect_clicked(move |_| { - add_chosen_directories(&window_main, &tree_view_included_directories, false); + add_chosen_directories(&file_dialog_include_exclude_folder_selection, &tree_view_included_directories, false); }); } // Add excluded directory { let tree_view_excluded_directories = gui_data.upper_notebook.tree_view_excluded_directories.clone(); - let window_main = gui_data.window_main.clone(); let buttons_add_excluded_directory = gui_data.upper_notebook.buttons_add_excluded_directory.clone(); + let file_dialog_include_exclude_folder_selection = gui_data.file_dialog_include_exclude_folder_selection.clone(); buttons_add_excluded_directory.connect_clicked(move |_| { - add_chosen_directories(&window_main, &tree_view_excluded_directories, true); + add_chosen_directories(&file_dialog_include_exclude_folder_selection, &tree_view_excluded_directories, true); }); } // Remove Excluded Folder @@ -79,28 +79,19 @@ pub fn connect_selection_of_directories(gui_data: &GuiData) { } } -fn add_chosen_directories(window_main: &Window, tree_view: &TreeView, excluded_items: bool) { +fn add_chosen_directories(file_dialog_include_exclude_folder_selection: &FileChooserNative, tree_view: &TreeView, excluded_items: bool) { let folders_to = if excluded_items { flg!("exclude_folders_dialog_title") } else { flg!("include_folders_dialog_title") }; - let file_chooser = gtk4::FileChooserDialog::builder() - .title(&folders_to) - .action(gtk4::FileChooserAction::SelectFolder) - .transient_for(window_main) - .modal(true) - .build(); - file_chooser.add_button(&flg!("general_ok_button"), ResponseType::Ok); - file_chooser.add_button(&flg!("general_close_button"), ResponseType::Cancel); - - file_chooser.set_select_multiple(true); - file_chooser.show(); + file_dialog_include_exclude_folder_selection.show(); + file_dialog_include_exclude_folder_selection.set_title(&folders_to); let tree_view = tree_view.clone(); - file_chooser.connect_response(move |file_chooser, response_type| { - if response_type == ResponseType::Ok { + file_dialog_include_exclude_folder_selection.connect_response(move |file_chooser, response_type| { + if response_type == ResponseType::Accept { let mut folders: Vec = Vec::new(); let g_files = file_chooser.files(); for index in 0..g_files.n_items() { @@ -130,13 +121,12 @@ fn add_chosen_directories(window_main: &Window, tree_view: &TreeView, excluded_i } } } - file_chooser.close(); }); } fn add_manually_directories(window_main: &Window, tree_view: &TreeView, excluded_items: bool) { let dialog = gtk4::Dialog::builder() - .title(&flg!("include_manually_directories_dialog_title")) + .title(flg!("include_manually_directories_dialog_title")) .transient_for(window_main) .modal(true) .build(); diff --git a/czkawka_gui/src/connect_things/connect_settings.rs b/czkawka_gui/src/connect_things/connect_settings.rs index 2cafcba..4f96091 100644 --- a/czkawka_gui/src/connect_things/connect_settings.rs +++ b/czkawka_gui/src/connect_things/connect_settings.rs @@ -2,9 +2,8 @@ use std::collections::BTreeMap; use std::default::Default; use directories_next::ProjectDirs; -use gtk4::builders::LabelBuilder; use gtk4::prelude::*; -use gtk4::{ResponseType, Window}; +use gtk4::{Label, ResponseType, Window}; use image::imageops::FilterType; use image_hasher::HashAlg; @@ -217,10 +216,10 @@ fn create_clear_cache_dialog(title_str: &str, window_settings: &Window) -> gtk4: dialog.add_button(&flg!("general_ok_button"), ResponseType::Ok); dialog.add_button(&flg!("general_close_button"), ResponseType::Cancel); - let label = LabelBuilder::new().label(&flg!("cache_clear_message_label_1")).build(); - let label2 = LabelBuilder::new().label(&flg!("cache_clear_message_label_2")).build(); - let label3 = LabelBuilder::new().label(&flg!("cache_clear_message_label_3")).build(); - let label4 = LabelBuilder::new().label(&flg!("cache_clear_message_label_4")).build(); + let label = Label::builder().label(flg!("cache_clear_message_label_1")).build(); + let label2 = Label::builder().label(flg!("cache_clear_message_label_2")).build(); + let label3 = Label::builder().label(flg!("cache_clear_message_label_3")).build(); + let label4 = Label::builder().label(flg!("cache_clear_message_label_4")).build(); let internal_box = get_dialog_box_child(&dialog); internal_box.append(&label); diff --git a/czkawka_gui/src/connect_things/mod.rs b/czkawka_gui/src/connect_things/mod.rs index 29ab8d6..af49ccb 100644 --- a/czkawka_gui/src/connect_things/mod.rs +++ b/czkawka_gui/src/connect_things/mod.rs @@ -6,12 +6,14 @@ pub mod connect_button_move; pub mod connect_button_save; pub mod connect_button_search; pub mod connect_button_select; +pub mod connect_button_sort; pub mod connect_button_stop; pub mod connect_change_language; pub mod connect_duplicate_buttons; pub mod connect_header_buttons; pub mod connect_notebook_tabs; -pub mod connect_popovers; +pub mod connect_popovers_select; +pub mod connect_popovers_sort; pub mod connect_progress_window; pub mod connect_selection_of_directories; pub mod connect_settings; diff --git a/czkawka_gui/src/gui_structs/gui_bottom_buttons.rs b/czkawka_gui/src/gui_structs/gui_bottom_buttons.rs index d5c1420..66ee5e1 100644 --- a/czkawka_gui/src/gui_structs/gui_bottom_buttons.rs +++ b/czkawka_gui/src/gui_structs/gui_bottom_buttons.rs @@ -1,6 +1,7 @@ use gtk4::prelude::*; use gtk4::{GestureClick, Widget}; +use crate::gui_structs::gui_data::CZK_ICON_SORT; use crate::help_functions::{get_custom_label_from_widget, set_icon_of_button, BottomButtonsEnum}; use crate::{ flg, CZK_ICON_COMPARE, CZK_ICON_HARDLINK, CZK_ICON_HIDE_DOWN, CZK_ICON_HIDE_UP, CZK_ICON_MOVE, CZK_ICON_SAVE, CZK_ICON_SEARCH, CZK_ICON_SELECT, CZK_ICON_SYMLINK, @@ -17,19 +18,22 @@ pub struct GuiBottomButtons { pub buttons_hardlink: gtk4::Button, pub buttons_move: gtk4::Button, pub buttons_compare: gtk4::Button, + pub buttons_sort: gtk4::MenuButton, pub buttons_show_errors: gtk4::Button, pub buttons_show_upper_notebook: gtk4::Button, pub label_buttons_select: gtk4::Label, + pub label_buttons_sort: gtk4::Label, - pub buttons_names: [BottomButtonsEnum; 8], - pub buttons_array: [Widget; 8], + pub buttons_names: [BottomButtonsEnum; 9], + pub buttons_array: [Widget; 9], pub gc_buttons_select: GestureClick, + pub gc_buttons_sort: GestureClick, } impl GuiBottomButtons { - pub fn create_from_builder(builder: >k4::Builder, popover_select: >k4::Popover) -> Self { + pub fn create_from_builder(builder: >k4::Builder, popover_select: >k4::Popover, popover_sort: >k4::Popover) -> Self { let buttons_search: gtk4::Button = builder.object("buttons_search").unwrap(); let buttons_select: gtk4::MenuButton = builder.object("buttons_select").unwrap(); let buttons_delete: gtk4::Button = builder.object("buttons_delete").unwrap(); @@ -38,15 +42,19 @@ impl GuiBottomButtons { let buttons_hardlink: gtk4::Button = builder.object("buttons_hardlink").unwrap(); let buttons_move: gtk4::Button = builder.object("buttons_move").unwrap(); let buttons_compare: gtk4::Button = builder.object("buttons_compare").unwrap(); + let buttons_sort: gtk4::MenuButton = builder.object("buttons_sort").unwrap(); let buttons_show_errors: gtk4::Button = builder.object("buttons_show_errors").unwrap(); let buttons_show_upper_notebook: gtk4::Button = builder.object("buttons_show_upper_notebook").unwrap(); let label_buttons_select: gtk4::Label = builder.object("label_buttons_select").unwrap(); + let label_buttons_sort: gtk4::Label = builder.object("label_buttons_sort").unwrap(); let gc_buttons_select: GestureClick = GestureClick::new(); + let gc_buttons_sort: GestureClick = GestureClick::new(); - buttons_select.add_controller(&gc_buttons_select); + buttons_select.add_controller(gc_buttons_select.clone()); + buttons_sort.add_controller(gc_buttons_sort.clone()); set_icon_of_button(&buttons_search, CZK_ICON_SEARCH); set_icon_of_button(&buttons_select, CZK_ICON_SELECT); @@ -56,6 +64,7 @@ impl GuiBottomButtons { set_icon_of_button(&buttons_hardlink, CZK_ICON_HARDLINK); set_icon_of_button(&buttons_move, CZK_ICON_MOVE); set_icon_of_button(&buttons_compare, CZK_ICON_COMPARE); + set_icon_of_button(&buttons_sort, CZK_ICON_SORT); set_icon_of_button(&buttons_show_errors, CZK_ICON_HIDE_DOWN); set_icon_of_button(&buttons_show_upper_notebook, CZK_ICON_HIDE_UP); @@ -68,6 +77,7 @@ impl GuiBottomButtons { BottomButtonsEnum::Hardlink, BottomButtonsEnum::Move, BottomButtonsEnum::Compare, + BottomButtonsEnum::Sort, ]; let buttons_array = [ buttons_search.clone().upcast::(), @@ -78,9 +88,11 @@ impl GuiBottomButtons { buttons_hardlink.clone().upcast::(), buttons_move.clone().upcast::(), buttons_compare.clone().upcast::(), + buttons_sort.clone().upcast::(), ]; buttons_select.set_popover(Some(popover_select)); + buttons_sort.set_popover(Some(popover_sort)); #[cfg(target_family = "windows")] buttons_hardlink.set_sensitive(test_hardlinks()); @@ -94,12 +106,15 @@ impl GuiBottomButtons { buttons_hardlink, buttons_move, buttons_compare, + buttons_sort, buttons_show_errors, buttons_show_upper_notebook, label_buttons_select, + label_buttons_sort, buttons_names, buttons_array, gc_buttons_select, + gc_buttons_sort, } } pub fn update_language(&self) { @@ -110,6 +125,7 @@ impl GuiBottomButtons { get_custom_label_from_widget(&self.buttons_symlink.clone()).set_text(&flg!("bottom_symlink_button")); get_custom_label_from_widget(&self.buttons_move.clone()).set_text(&flg!("bottom_move_button")); get_custom_label_from_widget(&self.buttons_hardlink.clone()).set_text(&flg!("bottom_hardlink_button")); + self.label_buttons_sort.set_text(&flg!("bottom_sort_button")); self.buttons_search.set_tooltip_text(Some(&flg!("bottom_search_button_tooltip"))); self.buttons_select.set_tooltip_text(Some(&flg!("bottom_select_button_tooltip"))); @@ -117,6 +133,7 @@ impl GuiBottomButtons { self.buttons_save.set_tooltip_text(Some(&flg!("bottom_save_button_tooltip"))); self.buttons_symlink.set_tooltip_text(Some(&flg!("bottom_symlink_button_tooltip"))); self.buttons_move.set_tooltip_text(Some(&flg!("bottom_move_button_tooltip"))); + self.buttons_sort.set_tooltip_text(Some(&flg!("bottom_sort_button_tooltip"))); if self.buttons_hardlink.is_sensitive() { self.buttons_hardlink.set_tooltip_text(Some(&flg!("bottom_hardlink_button_tooltip"))); } else { diff --git a/czkawka_gui/src/gui_structs/gui_data.rs b/czkawka_gui/src/gui_structs/gui_data.rs index 5ae1bfe..ef96646 100644 --- a/czkawka_gui/src/gui_structs/gui_data.rs +++ b/czkawka_gui/src/gui_structs/gui_data.rs @@ -5,7 +5,7 @@ use std::rc::Rc; use crossbeam_channel::bounded; use gdk4::gdk_pixbuf::Pixbuf; use gtk4::prelude::*; -use gtk4::Builder; +use gtk4::{Builder, FileChooserNative}; use czkawka_core::bad_extensions::BadExtensions; use czkawka_core::big_file::BigFile; @@ -25,7 +25,8 @@ use crate::gui_structs::gui_bottom_buttons::GuiBottomButtons; use crate::gui_structs::gui_compare_images::GuiCompareImages; use crate::gui_structs::gui_header::GuiHeader; use crate::gui_structs::gui_main_notebook::GuiMainNotebook; -use crate::gui_structs::gui_popovers::GuiPopovers; +use crate::gui_structs::gui_popovers_select::GuiSelectPopovers; +use crate::gui_structs::gui_popovers_sort::GuiSortPopovers; use crate::gui_structs::gui_progress_dialog::GuiProgressDialog; use crate::gui_structs::gui_settings::GuiSettings; use crate::gui_structs::gui_upper_notebook::GuiUpperNotebook; @@ -33,25 +34,26 @@ use crate::help_functions::BottomButtonsEnum; use crate::notebook_enums::*; use crate::taskbar_progress::TaskbarProgress; -pub const ICON_ABOUT: &[u8; 4458] = include_bytes!("../../icons/icon_about.png"); -pub const CZK_ICON_ADD: &[u8; 677] = include_bytes!("../../icons/czk_add.svg"); -pub const CZK_ICON_COMPARE: &[u8; 5700] = include_bytes!("../../icons/czk_compare.svg"); -pub const CZK_ICON_DELETE: &[u8; 489] = include_bytes!("../../icons/czk_delete.svg"); -pub const CZK_ICON_HARDLINK: &[u8; 17326] = include_bytes!("../../icons/czk_hardlink.svg"); -pub const CZK_ICON_HIDE_DOWN: &[u8; 3057] = include_bytes!("../../icons/czk_hide_down.svg"); -pub const CZK_ICON_HIDE_UP: &[u8; 3310] = include_bytes!("../../icons/czk_hide_up.svg"); -pub const CZK_ICON_INFO: &[u8; 3325] = include_bytes!("../../icons/czk_info.svg"); -pub const CZK_ICON_LEFT: &[u8; 245] = include_bytes!("../../icons/czk_left.svg"); -pub const CZK_ICON_MANUAL_ADD: &[u8; 677] = include_bytes!("../../icons/czk_manual_add.svg"); -pub const CZK_ICON_MOVE: &[u8; 2535] = include_bytes!("../../icons/czk_move.svg"); -pub const CZK_ICON_RIGHT: &[u8; 278] = include_bytes!("../../icons/czk_right.svg"); -pub const CZK_ICON_SAVE: &[u8; 462] = include_bytes!("../../icons/czk_save.svg"); -pub const CZK_ICON_SEARCH: &[u8; 1517] = include_bytes!("../../icons/czk_search.svg"); -pub const CZK_ICON_SELECT: &[u8; 370] = include_bytes!("../../icons/czk_select.svg"); -pub const CZK_ICON_SETTINGS: &[u8; 11677] = include_bytes!("../../icons/czk_settings.svg"); -pub const CZK_ICON_STOP: &[u8; 618] = include_bytes!("../../icons/czk_stop.svg"); -pub const CZK_ICON_SYMLINK: &[u8; 2455] = include_bytes!("../../icons/czk_symlink.svg"); -pub const CZK_ICON_TRASH: &[u8; 709] = include_bytes!("../../icons/czk_trash.svg"); +pub const ICON_ABOUT: &[u8] = include_bytes!("../../icons/icon_about.png"); +pub const CZK_ICON_ADD: &[u8] = include_bytes!("../../icons/czk_add.svg"); +pub const CZK_ICON_COMPARE: &[u8] = include_bytes!("../../icons/czk_compare.svg"); +pub const CZK_ICON_DELETE: &[u8] = include_bytes!("../../icons/czk_delete.svg"); +pub const CZK_ICON_HARDLINK: &[u8] = include_bytes!("../../icons/czk_hardlink.svg"); +pub const CZK_ICON_HIDE_DOWN: &[u8] = include_bytes!("../../icons/czk_hide_down.svg"); +pub const CZK_ICON_HIDE_UP: &[u8] = include_bytes!("../../icons/czk_hide_up.svg"); +pub const CZK_ICON_INFO: &[u8] = include_bytes!("../../icons/czk_info.svg"); +pub const CZK_ICON_LEFT: &[u8] = include_bytes!("../../icons/czk_left.svg"); +pub const CZK_ICON_MANUAL_ADD: &[u8] = include_bytes!("../../icons/czk_manual_add.svg"); +pub const CZK_ICON_MOVE: &[u8] = include_bytes!("../../icons/czk_move.svg"); +pub const CZK_ICON_RIGHT: &[u8] = include_bytes!("../../icons/czk_right.svg"); +pub const CZK_ICON_SAVE: &[u8] = include_bytes!("../../icons/czk_save.svg"); +pub const CZK_ICON_SEARCH: &[u8] = include_bytes!("../../icons/czk_search.svg"); +pub const CZK_ICON_SELECT: &[u8] = include_bytes!("../../icons/czk_select.svg"); +pub const CZK_ICON_SETTINGS: &[u8] = include_bytes!("../../icons/czk_settings.svg"); +pub const CZK_ICON_SORT: &[u8] = include_bytes!("../../icons/czk_sort.svg"); +pub const CZK_ICON_STOP: &[u8] = include_bytes!("../../icons/czk_stop.svg"); +pub const CZK_ICON_SYMLINK: &[u8] = include_bytes!("../../icons/czk_symlink.svg"); +pub const CZK_ICON_TRASH: &[u8] = include_bytes!("../../icons/czk_trash.svg"); #[derive(Clone)] pub struct GuiData { @@ -64,7 +66,8 @@ pub struct GuiData { pub main_notebook: GuiMainNotebook, pub upper_notebook: GuiUpperNotebook, - pub popovers: GuiPopovers, + pub popovers_select: GuiSelectPopovers, + pub popovers_sort: GuiSortPopovers, pub bottom_buttons: GuiBottomButtons, pub progress_window: GuiProgressDialog, pub about: GuiAbout, @@ -72,6 +75,9 @@ pub struct GuiData { pub header: GuiHeader, pub compare_images: GuiCompareImages, + pub file_dialog_include_exclude_folder_selection: FileChooserNative, + pub file_dialog_move_to_folder: FileChooserNative, + // Taskbar state pub taskbar_state: Rc>, @@ -116,14 +122,15 @@ impl GuiData { window_main.set_title(Some(&flg!("window_main_title"))); window_main.show(); - let pixbuf = Pixbuf::from_read(std::io::BufReader::new(&ICON_ABOUT[..])).unwrap(); + let pixbuf = Pixbuf::from_read(std::io::BufReader::new(ICON_ABOUT)).unwrap(); window_main.set_application(Some(application)); let main_notebook = GuiMainNotebook::create_from_builder(&builder); let upper_notebook = GuiUpperNotebook::create_from_builder(&builder); - let popovers = GuiPopovers::create_from_builder(); - let bottom_buttons = GuiBottomButtons::create_from_builder(&builder, &popovers.popover_select); + let popovers_select = GuiSelectPopovers::create_from_builder(); + let popovers_sort = GuiSortPopovers::create_from_builder(); + let bottom_buttons = GuiBottomButtons::create_from_builder(&builder, &popovers_select.popover_select, &popovers_sort.popover_sort); let progress_window = GuiProgressDialog::create_from_builder(&window_main); let about = GuiAbout::create_from_builder(&window_main, &pixbuf); let header = GuiHeader::create_from_builder(&builder); @@ -148,9 +155,25 @@ impl GuiData { temp_hashmap.insert(*button_name, false); } } - shared_buttons.borrow_mut().insert(i.clone(), temp_hashmap); + shared_buttons.borrow_mut().insert(*i, temp_hashmap); } + // File Dialogs - Native file dialogs must exists all the time in opposite to normal dialog + + let file_dialog_include_exclude_folder_selection = FileChooserNative::builder() + .action(gtk4::FileChooserAction::SelectFolder) + .transient_for(&window_main) + .select_multiple(true) + .modal(true) + .build(); + let file_dialog_move_to_folder = FileChooserNative::builder() + .title(flg!("move_files_title_dialog")) + .action(gtk4::FileChooserAction::SelectFolder) + .transient_for(&window_main) + .select_multiple(false) + .modal(true) + .build(); + // State of search results let shared_duplication_state: Rc> = Rc::new(RefCell::new(DuplicateFinder::new())); @@ -184,13 +207,16 @@ impl GuiData { window_main, main_notebook, upper_notebook, - popovers, + popovers_select, + popovers_sort, bottom_buttons, progress_window, about, settings, header, compare_images, + file_dialog_include_exclude_folder_selection, + file_dialog_move_to_folder, taskbar_state, shared_buttons, shared_duplication_state, @@ -218,7 +244,8 @@ impl GuiData { self.main_notebook.update_language(); self.upper_notebook.update_language(); - self.popovers.update_language(); + self.popovers_select.update_language(); + self.popovers_sort.update_language(); self.bottom_buttons.update_language(); self.progress_window.update_language(); self.about.update_language(); diff --git a/czkawka_gui/src/gui_structs/gui_main_notebook.rs b/czkawka_gui/src/gui_structs/gui_main_notebook.rs index 7da8581..8356888 100644 --- a/czkawka_gui/src/gui_structs/gui_main_notebook.rs +++ b/czkawka_gui/src/gui_structs/gui_main_notebook.rs @@ -153,50 +153,50 @@ impl GuiMainNotebook { let tree_view_bad_extensions: TreeView = TreeView::new(); let evk_tree_view_duplicate_finder: EventControllerKey = EventControllerKey::new(); - tree_view_duplicate_finder.add_controller(&evk_tree_view_duplicate_finder); + tree_view_duplicate_finder.add_controller(evk_tree_view_duplicate_finder.clone()); let evk_tree_view_empty_folder_finder: EventControllerKey = EventControllerKey::new(); - tree_view_empty_folder_finder.add_controller(&evk_tree_view_empty_folder_finder); + tree_view_empty_folder_finder.add_controller(evk_tree_view_empty_folder_finder.clone()); let evk_tree_view_empty_files_finder: EventControllerKey = EventControllerKey::new(); - tree_view_empty_files_finder.add_controller(&evk_tree_view_empty_files_finder); + tree_view_empty_files_finder.add_controller(evk_tree_view_empty_files_finder.clone()); let evk_tree_view_temporary_files_finder: EventControllerKey = EventControllerKey::new(); - tree_view_temporary_files_finder.add_controller(&evk_tree_view_temporary_files_finder); + tree_view_temporary_files_finder.add_controller(evk_tree_view_temporary_files_finder.clone()); let evk_tree_view_big_files_finder: EventControllerKey = EventControllerKey::new(); - tree_view_big_files_finder.add_controller(&evk_tree_view_big_files_finder); + tree_view_big_files_finder.add_controller(evk_tree_view_big_files_finder.clone()); let evk_tree_view_similar_images_finder: EventControllerKey = EventControllerKey::new(); - tree_view_similar_images_finder.add_controller(&evk_tree_view_similar_images_finder); + tree_view_similar_images_finder.add_controller(evk_tree_view_similar_images_finder.clone()); let evk_tree_view_similar_videos_finder: EventControllerKey = EventControllerKey::new(); - tree_view_similar_videos_finder.add_controller(&evk_tree_view_similar_videos_finder); + tree_view_similar_videos_finder.add_controller(evk_tree_view_similar_videos_finder.clone()); let evk_tree_view_same_music_finder: EventControllerKey = EventControllerKey::new(); - tree_view_same_music_finder.add_controller(&evk_tree_view_same_music_finder); + tree_view_same_music_finder.add_controller(evk_tree_view_same_music_finder.clone()); let evk_tree_view_invalid_symlinks: EventControllerKey = EventControllerKey::new(); - tree_view_invalid_symlinks.add_controller(&evk_tree_view_invalid_symlinks); + tree_view_invalid_symlinks.add_controller(evk_tree_view_invalid_symlinks.clone()); let evk_tree_view_broken_files: EventControllerKey = EventControllerKey::new(); - tree_view_broken_files.add_controller(&evk_tree_view_broken_files); + tree_view_broken_files.add_controller(evk_tree_view_broken_files.clone()); let evk_tree_view_bad_extensions: EventControllerKey = EventControllerKey::new(); - tree_view_bad_extensions.add_controller(&evk_tree_view_bad_extensions); + tree_view_bad_extensions.add_controller(evk_tree_view_bad_extensions.clone()); let gc_tree_view_duplicate_finder: GestureClick = GestureClick::new(); - tree_view_duplicate_finder.add_controller(&gc_tree_view_duplicate_finder); + tree_view_duplicate_finder.add_controller(gc_tree_view_duplicate_finder.clone()); let gc_tree_view_empty_folder_finder: GestureClick = GestureClick::new(); - tree_view_empty_folder_finder.add_controller(&gc_tree_view_empty_folder_finder); + tree_view_empty_folder_finder.add_controller(gc_tree_view_empty_folder_finder.clone()); let gc_tree_view_empty_files_finder: GestureClick = GestureClick::new(); - tree_view_empty_files_finder.add_controller(&gc_tree_view_empty_files_finder); + tree_view_empty_files_finder.add_controller(gc_tree_view_empty_files_finder.clone()); let gc_tree_view_temporary_files_finder: GestureClick = GestureClick::new(); - tree_view_temporary_files_finder.add_controller(&gc_tree_view_temporary_files_finder); + tree_view_temporary_files_finder.add_controller(gc_tree_view_temporary_files_finder.clone()); let gc_tree_view_big_files_finder: GestureClick = GestureClick::new(); - tree_view_big_files_finder.add_controller(&gc_tree_view_big_files_finder); + tree_view_big_files_finder.add_controller(gc_tree_view_big_files_finder.clone()); let gc_tree_view_similar_images_finder: GestureClick = GestureClick::new(); - tree_view_similar_images_finder.add_controller(&gc_tree_view_similar_images_finder); + tree_view_similar_images_finder.add_controller(gc_tree_view_similar_images_finder.clone()); let gc_tree_view_similar_videos_finder: GestureClick = GestureClick::new(); - tree_view_similar_videos_finder.add_controller(&gc_tree_view_similar_videos_finder); + tree_view_similar_videos_finder.add_controller(gc_tree_view_similar_videos_finder.clone()); let gc_tree_view_same_music_finder: GestureClick = GestureClick::new(); - tree_view_same_music_finder.add_controller(&gc_tree_view_same_music_finder); + tree_view_same_music_finder.add_controller(gc_tree_view_same_music_finder.clone()); let gc_tree_view_invalid_symlinks: GestureClick = GestureClick::new(); - tree_view_invalid_symlinks.add_controller(&gc_tree_view_invalid_symlinks); + tree_view_invalid_symlinks.add_controller(gc_tree_view_invalid_symlinks.clone()); let gc_tree_view_broken_files: GestureClick = GestureClick::new(); - tree_view_broken_files.add_controller(&gc_tree_view_broken_files); + tree_view_broken_files.add_controller(gc_tree_view_broken_files.clone()); let gc_tree_view_bad_extensions: GestureClick = GestureClick::new(); - tree_view_bad_extensions.add_controller(&gc_tree_view_bad_extensions); + tree_view_bad_extensions.add_controller(gc_tree_view_bad_extensions.clone()); let combo_box_duplicate_check_method: ComboBoxText = builder.object("combo_box_duplicate_check_method").unwrap(); let combo_box_duplicate_hash_type: ComboBoxText = builder.object("combo_box_duplicate_hash_type").unwrap(); diff --git a/czkawka_gui/src/gui_structs/gui_popovers.rs b/czkawka_gui/src/gui_structs/gui_popovers_select.rs similarity index 99% rename from czkawka_gui/src/gui_structs/gui_popovers.rs rename to czkawka_gui/src/gui_structs/gui_popovers_select.rs index 4fdc34b..abad813 100644 --- a/czkawka_gui/src/gui_structs/gui_popovers.rs +++ b/czkawka_gui/src/gui_structs/gui_popovers_select.rs @@ -4,7 +4,7 @@ use gtk4::Builder; use crate::flg; #[derive(Clone)] -pub struct GuiPopovers { +pub struct GuiSelectPopovers { pub buttons_popover_select_all: gtk4::Button, pub buttons_popover_unselect_all: gtk4::Button, pub buttons_popover_reverse: gtk4::Button, @@ -29,7 +29,7 @@ pub struct GuiPopovers { pub popover_right_click: gtk4::Popover, } -impl GuiPopovers { +impl GuiSelectPopovers { pub fn create_from_builder() -> Self { let glade_src = include_str!("../../ui/popover_select.ui").to_string(); let builder = Builder::from_string(glade_src.as_str()); diff --git a/czkawka_gui/src/gui_structs/gui_popovers_sort.rs b/czkawka_gui/src/gui_structs/gui_popovers_sort.rs new file mode 100644 index 0000000..7197162 --- /dev/null +++ b/czkawka_gui/src/gui_structs/gui_popovers_sort.rs @@ -0,0 +1,46 @@ +use gtk4::prelude::*; +use gtk4::Builder; + +use crate::flg; + +#[derive(Clone)] +pub struct GuiSortPopovers { + pub buttons_popover_sort_file_name: gtk4::Button, + pub buttons_popover_sort_folder_name: gtk4::Button, + pub buttons_popover_sort_full_name: gtk4::Button, + pub buttons_popover_sort_size: gtk4::Button, + pub buttons_popover_sort_selection: gtk4::Button, + + pub popover_sort: gtk4::Popover, +} + +impl GuiSortPopovers { + pub fn create_from_builder() -> Self { + let glade_src = include_str!("../../ui/popover_sort.ui").to_string(); + let builder = Builder::from_string(glade_src.as_str()); + + let buttons_popover_sort_file_name: gtk4::Button = builder.object("buttons_popover_sort_file_name").unwrap(); + let buttons_popover_sort_folder_name: gtk4::Button = builder.object("buttons_popover_sort_folder_name").unwrap(); + let buttons_popover_sort_full_name: gtk4::Button = builder.object("buttons_popover_sort_full_name").unwrap(); + let buttons_popover_sort_size: gtk4::Button = builder.object("buttons_popover_sort_size").unwrap(); + let buttons_popover_sort_selection: gtk4::Button = builder.object("buttons_popover_sort_selection").unwrap(); + + let popover_sort: gtk4::Popover = builder.object("popover_sort").unwrap(); + + Self { + buttons_popover_sort_file_name, + buttons_popover_sort_folder_name, + buttons_popover_sort_full_name, + buttons_popover_sort_size, + buttons_popover_sort_selection, + popover_sort, + } + } + pub fn update_language(&self) { + self.buttons_popover_sort_file_name.set_label(&flg!("popover_sort_file_name")); + self.buttons_popover_sort_folder_name.set_label(&flg!("popover_sort_folder_name")); + self.buttons_popover_sort_full_name.set_label(&flg!("popover_sort_full_name")); + self.buttons_popover_sort_size.set_label(&flg!("popover_sort_size")); + self.buttons_popover_sort_selection.set_label(&flg!("popover_sort_selection")); + } +} diff --git a/czkawka_gui/src/gui_structs/gui_progress_dialog.rs b/czkawka_gui/src/gui_structs/gui_progress_dialog.rs index c23affa..a424286 100644 --- a/czkawka_gui/src/gui_structs/gui_progress_dialog.rs +++ b/czkawka_gui/src/gui_structs/gui_progress_dialog.rs @@ -42,7 +42,7 @@ impl GuiProgressDialog { let button_stop_in_dialog: gtk4::Button = builder.object("button_stop_in_dialog").unwrap(); let evk_button_stop_in_dialog = EventControllerKey::new(); - button_stop_in_dialog.add_controller(&evk_button_stop_in_dialog); + button_stop_in_dialog.add_controller(evk_button_stop_in_dialog.clone()); set_icon_of_button(&button_stop_in_dialog, CZK_ICON_STOP); diff --git a/czkawka_gui/src/gui_structs/gui_upper_notebook.rs b/czkawka_gui/src/gui_structs/gui_upper_notebook.rs index f30f2e6..0a503f6 100644 --- a/czkawka_gui/src/gui_structs/gui_upper_notebook.rs +++ b/czkawka_gui/src/gui_structs/gui_upper_notebook.rs @@ -54,14 +54,14 @@ impl GuiUpperNotebook { let tree_view_excluded_directories: TreeView = TreeView::new(); let evk_tree_view_included_directories: EventControllerKey = EventControllerKey::new(); - tree_view_included_directories.add_controller(&evk_tree_view_included_directories); + tree_view_included_directories.add_controller(evk_tree_view_included_directories.clone()); let evk_tree_view_excluded_directories: EventControllerKey = EventControllerKey::new(); - tree_view_excluded_directories.add_controller(&evk_tree_view_excluded_directories); + tree_view_excluded_directories.add_controller(evk_tree_view_excluded_directories.clone()); let gc_tree_view_included_directories: GestureClick = GestureClick::new(); - tree_view_included_directories.add_controller(&gc_tree_view_included_directories); + tree_view_included_directories.add_controller(gc_tree_view_included_directories.clone()); let gc_tree_view_excluded_directories: GestureClick = GestureClick::new(); - tree_view_excluded_directories.add_controller(&gc_tree_view_excluded_directories); + tree_view_excluded_directories.add_controller(gc_tree_view_excluded_directories.clone()); let entry_allowed_extensions: gtk4::Entry = builder.object("entry_allowed_extensions").unwrap(); let entry_excluded_items: gtk4::Entry = builder.object("entry_excluded_items").unwrap(); diff --git a/czkawka_gui/src/gui_structs/mod.rs b/czkawka_gui/src/gui_structs/mod.rs index 8cd1e69..ee00b74 100644 --- a/czkawka_gui/src/gui_structs/mod.rs +++ b/czkawka_gui/src/gui_structs/mod.rs @@ -4,7 +4,8 @@ mod gui_compare_images; pub mod gui_data; mod gui_header; pub mod gui_main_notebook; -pub mod gui_popovers; +pub mod gui_popovers_select; +pub mod gui_popovers_sort; mod gui_progress_dialog; pub mod gui_settings; pub mod gui_upper_notebook; diff --git a/czkawka_gui/src/help_functions.rs b/czkawka_gui/src/help_functions.rs index 9579209..5bbd198 100644 --- a/czkawka_gui/src/help_functions.rs +++ b/czkawka_gui/src/help_functions.rs @@ -45,7 +45,7 @@ pub const KEY_SPACE: u32 = 65; // pub const KEY_HOME: u32 = 115; // pub const KEY_END: u32 = 110; -#[derive(Eq, PartialEq)] +#[derive(Eq, PartialEq, Copy, Clone, Debug)] pub enum PopoverTypes { All, Size, @@ -64,6 +64,7 @@ pub enum BottomButtonsEnum { Hardlink, Move, Compare, + Sort, } pub enum Message { @@ -80,11 +81,13 @@ pub enum Message { BadExtensions(BadExtensions), } +#[derive(Clone, Copy)] pub enum ColumnsDuplicates { // Columns for duplicate treeview ActivatableSelectButton = 0, SelectionButton, Size, + SizeAsBytes, Name, Path, Modification, @@ -94,6 +97,7 @@ pub enum ColumnsDuplicates { TextColor, } +#[derive(Clone, Copy)] pub enum ColumnsEmptyFolders { // Columns for empty folder treeview SelectionButton = 0, @@ -103,17 +107,20 @@ pub enum ColumnsEmptyFolders { ModificationAsSecs, } +#[derive(Clone, Copy)] pub enum ColumnsIncludedDirectory { // Columns for Included Directories in upper Notebook Path = 0, ReferenceButton, } +#[derive(Clone, Copy)] pub enum ColumnsExcludedDirectory { // Columns for Excluded Directories in upper Notebook Path = 0, } +#[derive(Clone, Copy)] pub enum ColumnsBigFiles { SelectionButton = 0, Size, @@ -124,6 +131,7 @@ pub enum ColumnsBigFiles { ModificationAsSecs, } +#[derive(Clone, Copy)] pub enum ColumnsEmptyFiles { SelectionButton = 0, Name, @@ -132,6 +140,7 @@ pub enum ColumnsEmptyFiles { ModificationAsSecs, } +#[derive(Clone, Copy)] pub enum ColumnsTemporaryFiles { SelectionButton = 0, Name, @@ -140,6 +149,7 @@ pub enum ColumnsTemporaryFiles { ModificationAsSecs, } +#[derive(Clone, Copy)] pub enum ColumnsSimilarImages { ActivatableSelectButton = 0, SelectionButton, @@ -156,6 +166,7 @@ pub enum ColumnsSimilarImages { TextColor, } +#[derive(Clone, Copy)] pub enum ColumnsSimilarVideos { ActivatableSelectButton = 0, SelectionButton, @@ -170,6 +181,7 @@ pub enum ColumnsSimilarVideos { TextColor, } +#[derive(Clone, Copy)] pub enum ColumnsSameMusic { ActivatableSelectButton = 0, SelectionButton, @@ -191,6 +203,7 @@ pub enum ColumnsSameMusic { TextColor, } +#[derive(Clone, Copy)] pub enum ColumnsInvalidSymlinks { SelectionButton = 0, Name, @@ -201,6 +214,7 @@ pub enum ColumnsInvalidSymlinks { ModificationAsSecs, } +#[derive(Clone, Copy)] pub enum ColumnsBrokenFiles { SelectionButton = 0, Name, @@ -210,6 +224,7 @@ pub enum ColumnsBrokenFiles { ModificationAsSecs, } +#[derive(Clone, Copy)] pub enum ColumnsBadExtensions { SelectionButton = 0, Name, diff --git a/czkawka_gui/src/initialize_gui.rs b/czkawka_gui/src/initialize_gui.rs index 47425eb..c9d1312 100644 --- a/czkawka_gui/src/initialize_gui.rs +++ b/czkawka_gui/src/initialize_gui.rs @@ -31,24 +31,11 @@ use crate::opening_selecting_records::*; pub fn initialize_gui(gui_data: &mut GuiData) { //// Initialize button { - let buttons_search = gui_data.bottom_buttons.buttons_search.clone(); - let buttons_save = gui_data.bottom_buttons.buttons_save.clone(); - let buttons_delete = gui_data.bottom_buttons.buttons_delete.clone(); - let buttons_select = gui_data.bottom_buttons.buttons_select.clone(); - let buttons_symlink = gui_data.bottom_buttons.buttons_symlink.clone(); - let buttons_hardlink = gui_data.bottom_buttons.buttons_hardlink.clone(); - let buttons_move = gui_data.bottom_buttons.buttons_move.clone(); - let buttons_compare = gui_data.bottom_buttons.buttons_compare.clone(); - - // Disable and show buttons - only search button should be visible - buttons_search.show(); - buttons_save.hide(); - buttons_delete.hide(); - buttons_select.hide(); - buttons_symlink.hide(); - buttons_hardlink.hide(); - buttons_move.hide(); - buttons_compare.hide(); + let buttons = &gui_data.bottom_buttons.buttons_array; + for button in buttons { + button.hide(); + } + gui_data.bottom_buttons.buttons_search.show(); } //// Initialize language combo box { diff --git a/czkawka_gui/src/main.rs b/czkawka_gui/src/main.rs index 9563eef..604c914 100644 --- a/czkawka_gui/src/main.rs +++ b/czkawka_gui/src/main.rs @@ -26,7 +26,6 @@ use connect_things::connect_change_language::*; use connect_things::connect_duplicate_buttons::connect_duplicate_combo_box; use connect_things::connect_header_buttons::*; use connect_things::connect_notebook_tabs::*; -use connect_things::connect_popovers::*; use connect_things::connect_progress_window::*; use connect_things::connect_selection_of_directories::*; use connect_things::connect_settings::*; @@ -37,6 +36,9 @@ use czkawka_core::*; use gui_structs::gui_data::*; use crate::compute_results::*; +use crate::connect_things::connect_button_sort::connect_button_sort; +use crate::connect_things::connect_popovers_select::connect_popover_select; +use crate::connect_things::connect_popovers_sort::connect_popover_sort; use crate::initialize_gui::*; use crate::language_functions::LANGUAGES_ALL; use crate::saving_loading::*; @@ -63,7 +65,7 @@ mod taskbar_progress_win; mod tests; fn main() { - let application = Application::new(None, ApplicationFlags::HANDLES_OPEN | ApplicationFlags::HANDLES_COMMAND_LINE); + let application = Application::new(None::, ApplicationFlags::HANDLES_OPEN | ApplicationFlags::HANDLES_COMMAND_LINE); application.connect_command_line(move |app, cmdline| { build_ui(app, &cmdline.arguments()); 0 @@ -160,6 +162,7 @@ fn build_ui(application: &Application, arguments: &[OsString]) { futures_sender_bad_extensions, ); connect_button_select(&gui_data); + connect_button_sort(&gui_data); connect_button_stop(&gui_data); connect_button_hardlink_symlink(&gui_data); connect_button_move(&gui_data); @@ -168,7 +171,8 @@ fn build_ui(application: &Application, arguments: &[OsString]) { connect_duplicate_combo_box(&gui_data); connect_notebook_tabs(&gui_data); connect_selection_of_directories(&gui_data); - connect_popovers(&gui_data); + connect_popover_select(&gui_data); + connect_popover_sort(&gui_data); connect_compute_results(&gui_data, glib_stop_receiver); connect_progress_window( &gui_data, diff --git a/czkawka_gui/src/notebook_enums.rs b/czkawka_gui/src/notebook_enums.rs index 03eeb81..f653433 100644 --- a/czkawka_gui/src/notebook_enums.rs +++ b/czkawka_gui/src/notebook_enums.rs @@ -2,7 +2,7 @@ pub const NUMBER_OF_NOTEBOOK_MAIN_TABS: usize = 11; // pub const NUMBER_OF_NOTEBOOK_UPPER_TABS: usize = 3; // Needs to be updated when changed order of notebook tabs -#[derive(Eq, PartialEq, Hash, Clone, Debug)] +#[derive(Eq, PartialEq, Hash, Clone, Debug, Copy)] pub enum NotebookMainEnum { Duplicate = 0, EmptyDirectories, @@ -50,7 +50,7 @@ pub fn get_all_main_tabs() -> [NotebookMainEnum; NUMBER_OF_NOTEBOOK_MAIN_TABS] { ] } -#[derive(Eq, PartialEq, Hash, Clone, Debug)] +#[derive(Eq, PartialEq, Hash, Clone, Debug, Copy)] pub enum NotebookUpperEnum { IncludedDirectories = 0, ExcludedDirectories, diff --git a/czkawka_gui/src/notebook_info.rs b/czkawka_gui/src/notebook_info.rs index e01d5e7..e5fc2a5 100644 --- a/czkawka_gui/src/notebook_info.rs +++ b/czkawka_gui/src/notebook_info.rs @@ -22,20 +22,28 @@ pub struct NotebookObject { pub static NOTEBOOKS_INFO: [NotebookObject; NUMBER_OF_NOTEBOOK_MAIN_TABS] = [ NotebookObject { notebook_type: NotebookMainEnum::Duplicate, - available_modes: &[PopoverTypes::All, PopoverTypes::Reverse, PopoverTypes::Custom, PopoverTypes::Date], + available_modes: &[ + PopoverTypes::All, + PopoverTypes::Reverse, + PopoverTypes::Custom, + PopoverTypes::Date, + PopoverTypes::Size, + PopoverTypes::All, + ], column_activatable_button: Some(ColumnsDuplicates::ActivatableSelectButton as i32), column_path: ColumnsDuplicates::Path as i32, column_name: ColumnsDuplicates::Name as i32, column_selection: ColumnsDuplicates::SelectionButton as i32, column_header: Some(ColumnsDuplicates::IsHeader as i32), column_dimensions: None, - column_size: None, // Do not add, useless in hash and size mode - column_size_as_bytes: None, // Do not add, useless in hash and size mode + column_size: Some(ColumnsDuplicates::Size as i32), // Useless with duplicates by hash or size, but needed by sorting by name + column_size_as_bytes: Some(ColumnsDuplicates::SizeAsBytes as i32), column_modification_as_secs: Some(ColumnsDuplicates::ModificationAsSecs as i32), columns_types: &[ glib::types::Type::BOOL, // ActivatableSelectButton glib::types::Type::BOOL, // SelectionButton glib::types::Type::STRING, // Size + glib::types::Type::U64, // SizeAsBytes glib::types::Type::STRING, // Name glib::types::Type::STRING, // Path glib::types::Type::STRING, // Modification diff --git a/czkawka_gui/src/saving_loading.rs b/czkawka_gui/src/saving_loading.rs index 490d711..b380d33 100644 --- a/czkawka_gui/src/saving_loading.rs +++ b/czkawka_gui/src/saving_loading.rs @@ -8,7 +8,7 @@ use std::{env, fs}; use czkawka_core::common::get_default_number_of_threads; use directories_next::ProjectDirs; use gtk4::prelude::*; -use gtk4::{ComboBoxText, ScrolledWindow, TextView}; +use gtk4::{ComboBoxText, ScrolledWindow, TextView, TreeView}; use czkawka_core::common_dir_traversal::CheckingMethod; use czkawka_core::similar_images::SIMILAR_VALUES; @@ -157,7 +157,7 @@ impl LoadSaveStruct { if self.loaded_items.contains_key(&key) { let item = self.loaded_items.get(&key).unwrap().clone().into_iter().filter(|e| !e.is_empty()).collect::>(); return if item.len() == 1 { - let text = item[0].clone().trim().to_lowercase(); + let text = item[0].trim().to_lowercase(); if text == "false" || text == "0" { false } else if text == "true" || text == "1" { @@ -199,7 +199,7 @@ impl LoadSaveStruct { self.loaded_items.insert(key, vec![value.to_string()]); } - pub fn save_list_store(&mut self, key: String, tree_view: >k4::TreeView, column_path: i32) { + pub fn save_list_store(&mut self, key: String, tree_view: &TreeView, column_path: i32) { let mut vec_string = vec![]; let list_store = get_list_store(tree_view); if let Some(iter) = list_store.iter_first() { @@ -214,7 +214,6 @@ impl LoadSaveStruct { self.loaded_items.insert(key, vec_string); } - //noinspection RsLift pub fn open_save_file(&self, text_view_errors: &TextView, save_configuration: bool, manual_execution: bool) -> Option<(File, PathBuf)> { if let Some(proj_dirs) = ProjectDirs::from("pl", "Qarmin", "Czkawka") { // Lin: /home/username/.config/czkawka @@ -735,7 +734,7 @@ pub fn load_configuration( let maximal_file_size: String = loaded_entries.get_integer_string(hashmap_ls.get(&LoadText::MaximalFileSize).unwrap().clone(), DEFAULT_MAXIMAL_FILE_SIZE.to_string()); let loading_at_start: bool = loaded_entries.get_bool(hashmap_ls.get(&LoadText::LoadAtStart).unwrap().clone(), DEFAULT_LOAD_AT_START); - let saving_at_exit: bool = loaded_entries.get_bool(hashmap_ls.get(&LoadText::SaveAtExit).unwrap().clone(), DEFAULT_SAVE_ON_EXIT); + let mut saving_at_exit: bool = loaded_entries.get_bool(hashmap_ls.get(&LoadText::SaveAtExit).unwrap().clone(), DEFAULT_SAVE_ON_EXIT); let confirm_deletion: bool = loaded_entries.get_bool(hashmap_ls.get(&LoadText::ConfirmDeletionFiles).unwrap().clone(), DEFAULT_CONFIRM_DELETION); let confirm_group_deletion: bool = loaded_entries.get_bool(hashmap_ls.get(&LoadText::ConfirmDeletionAllFilesInGroup).unwrap().clone(), DEFAULT_CONFIRM_GROUP_DELETION); let show_previews_similar_images: bool = loaded_entries.get_bool(hashmap_ls.get(&LoadText::ImagePreviewImage).unwrap().clone(), DEFAULT_SHOW_IMAGE_PREVIEW); @@ -802,72 +801,69 @@ pub fn load_configuration( let check_button_broken_files_audio = loaded_entries.get_object(hashmap_ls.get(&LoadText::BrokenFilesAudio).unwrap().clone(), DEFAULT_BROKEN_FILES_AUDIO); let thread_number = loaded_entries.get_object(hashmap_ls.get(&LoadText::ThreadNumber).unwrap().clone(), DEFAULT_THREAD_NUMBER); - // Setting data - if manual_execution || loading_at_start { - { - // Handle here arguments that were added to app e.g. czkawka_gui /home --/home/roman - if loading_at_start && arguments.len() > 1 { - let iter_i = arguments.iter().skip(1); - let iter_e = iter_i.clone(); - included_directories = iter_i - .filter_map(|e| { - let r = e.to_string_lossy().to_string(); - if !r.starts_with("--") { - let path = Path::new(&r); - if !path.exists() { - return None; - } - match path.canonicalize() { - Ok(r) => Some(r.to_string_lossy().to_string()), - Err(_) => None, - } - } else { - None + let mut set_start_folders = false; + if !manual_execution { + // Handle here arguments that were added to app e.g. czkawka_gui /home --/home/roman + if arguments.len() > 1 { + let iter_i = arguments.iter().skip(1); + let iter_e = iter_i.clone(); + let inc_dir = iter_i + .filter_map(|e| { + let r = e.to_string_lossy().to_string(); + if !r.starts_with("--") { + let path = Path::new(&r); + if !path.exists() { + return None; } - }) - .collect::>(); - excluded_directories = iter_e - .filter_map(|e| { - let r = e.to_string_lossy().to_string(); - if let Some(r) = r.strip_prefix("--") { - let path = Path::new(&r); - if !path.exists() { - return None; - } - match path.canonicalize() { - Ok(r) => Some(r.to_string_lossy().to_string()), - Err(_) => None, - } - } else { - None + match path.canonicalize() { + Ok(r) => Some(r.to_string_lossy().to_string()), + Err(_) => None, } - }) - .collect::>(); - } + } else { + None + } + }) + .collect::>(); + let exc_dir = iter_e + .filter_map(|e| { + let r = e.to_string_lossy().to_string(); + if let Some(r) = r.strip_prefix("--") { + let path = Path::new(&r); + if !path.exists() { + return None; + } + match path.canonicalize() { + Ok(r) => Some(r.to_string_lossy().to_string()), + Err(_) => None, + } + } else { + None + } + }) + .collect::>(); - // Include Directories - let tree_view_included_directories = upper_notebook.tree_view_included_directories.clone(); - let list_store = get_list_store(&tree_view_included_directories); - list_store.clear(); - - for directory in included_directories { - let values: [(u32, &dyn ToValue); 2] = [ - (ColumnsIncludedDirectory::Path as u32, &directory), - (ColumnsIncludedDirectory::ReferenceButton as u32, &false), - ]; - list_store.set(&list_store.append(), &values); - } - - //// Exclude Directories - let tree_view_excluded_directories = upper_notebook.tree_view_excluded_directories.clone(); - let list_store = get_list_store(&tree_view_excluded_directories); - list_store.clear(); - - for directory in excluded_directories { - let values: [(u32, &dyn ToValue); 1] = [(ColumnsExcludedDirectory::Path as u32, &directory)]; - list_store.set(&list_store.append(), &values); + if inc_dir.is_empty() { + println!("Arguments {arguments:?} should contains at least one directory to include"); + } else { + included_directories = inc_dir; + excluded_directories = exc_dir; + saving_at_exit = false; + set_start_folders = true; } } + } + + if manual_execution || loading_at_start || set_start_folders { + set_directories( + &upper_notebook.tree_view_included_directories, + &upper_notebook.tree_view_excluded_directories, + &included_directories, + &excluded_directories, + ); + } + + // Setting data + if loading_at_start || manual_execution { //// Language ComboBoxText { for (index, lang) in LANGUAGES_ALL.iter().enumerate() { @@ -966,6 +962,29 @@ pub fn load_configuration( } } +fn set_directories(tree_view_included_directories: &TreeView, tree_view_excluded_directories: &TreeView, included_directories: &[String], excluded_directories: &[String]) { + // Include Directories + let list_store = get_list_store(tree_view_included_directories); + list_store.clear(); + + for directory in included_directories { + let values: [(u32, &dyn ToValue); 2] = [ + (ColumnsIncludedDirectory::Path as u32, &directory), + (ColumnsIncludedDirectory::ReferenceButton as u32, &false), + ]; + list_store.set(&list_store.append(), &values); + } + + //// Exclude Directories + let list_store = get_list_store(tree_view_excluded_directories); + list_store.clear(); + + for directory in excluded_directories { + let values: [(u32, &dyn ToValue); 1] = [(ColumnsExcludedDirectory::Path as u32, &directory)]; + list_store.set(&list_store.append(), &values); + } +} + /// Function do not allow to set invalid index to combobox because this would cause to show empty value and function would crash fn save_proper_value_to_combo_box(combo_box: &ComboBoxText, what_to_save: u32) { combo_box.set_active(Some(what_to_save)); diff --git a/czkawka_gui/ui/czkawka.cmb b/czkawka_gui/ui/czkawka.cmb index d9b3a41..7d0ccc4 100755 --- a/czkawka_gui/ui/czkawka.cmb +++ b/czkawka_gui/ui/czkawka.cmb @@ -8,7 +8,8 @@ (6,None,"popover_right_click.ui","popover_right_click.ui",None,None,None,None,None,None), (7,None,"popover_select.ui","popover_select.ui",None,None,None,None,None,None), (8,None,"progress.ui","progress.ui",None,None,None,None,None,None), - (9,None,"settings.ui","settings.ui",None,None,None,None,None,None) + (9,None,"settings.ui","settings.ui",None,None,None,None,None,None), + (10,None,"popover_sort.ui","popover_sort.ui",None,None,None,None,None,None) (3,"gtk","4.0",None), @@ -194,27 +195,27 @@ (5,190,"GtkBox",None,189,None,None,None,None), (5,191,"GtkImage",None,190,None,None,None,None), (5,192,"GtkLabel","label_buttons_select",190,None,None,None,1), - (5,193,"GtkButton","buttons_compare",188,None,None,None,1), + (5,193,"GtkButton","buttons_compare",188,None,None,None,2), (5,194,"GtkBox",None,193,None,None,None,None), (5,195,"GtkImage",None,194,None,None,None,None), (5,196,"GtkLabel",None,194,None,None,None,1), - (5,197,"GtkButton","buttons_delete",188,None,None,None,2), + (5,197,"GtkButton","buttons_delete",188,None,None,None,3), (5,198,"GtkBox",None,197,None,None,None,None), (5,199,"GtkImage",None,198,None,None,None,None), (5,200,"GtkLabel",None,198,None,None,None,1), - (5,201,"GtkButton","buttons_move",188,None,None,None,3), + (5,201,"GtkButton","buttons_move",188,None,None,None,4), (5,202,"GtkBox",None,201,None,None,None,None), (5,203,"GtkImage",None,202,None,None,None,None), (5,204,"GtkLabel",None,202,None,None,None,1), - (5,205,"GtkButton","buttons_save",188,None,None,None,4), + (5,205,"GtkButton","buttons_save",188,None,None,None,5), (5,206,"GtkBox",None,205,None,None,None,None), (5,207,"GtkImage",None,206,None,None,None,None), (5,208,"GtkLabel",None,206,None,None,None,1), - (5,209,"GtkButton","buttons_symlink",188,None,None,None,5), + (5,209,"GtkButton","buttons_symlink",188,None,None,None,6), (5,210,"GtkBox",None,209,None,None,None,None), (5,211,"GtkImage",None,210,None,None,None,None), (5,212,"GtkLabel",None,210,None,None,None,1), - (5,213,"GtkButton","buttons_hardlink",188,None,None,None,6), + (5,213,"GtkButton","buttons_hardlink",188,None,None,None,7), (5,214,"GtkBox",None,213,None,None,None,None), (5,215,"GtkImage",None,214,None,None,None,None), (5,216,"GtkLabel",None,214,None,None,None,1), @@ -230,6 +231,10 @@ (5,226,"GtkCheckButton","check_button_broken_files_pdf",224,None,None,None,1), (5,227,"GtkCheckButton","check_button_broken_files_archive",224,None,None,None,2), (5,228,"GtkCheckButton","check_button_broken_files_image",224,None,None,None,3), + (5,229,"GtkMenuButton","buttons_sort",188,None,None,None,1), + (5,230,"GtkBox",None,229,None,None,None,None), + (5,231,"GtkImage",None,230,None,None,None,None), + (5,232,"GtkLabel","label_buttons_sort",230,None,None,None,1), (6,1,"GtkPopover","popover_right_click",None,None,None,None,None), (6,2,"GtkBox",None,1,None,None,None,None), (6,3,"GtkButton","buttons_popover_right_click_open_file",2,None,None,None,None), @@ -318,7 +323,14 @@ (9,56,"GtkBox",None,9,None,None,None,11), (9,57,"GtkLabel","label_settings_number_of_threads",56,None,None,None,None), (9,58,"GtkScale","scale_settings_number_of_threads",56,None,None,None,1), - (9,59,"GtkLabel","label_restart_needed",8,None,None,None,1) + (9,59,"GtkLabel","label_restart_needed",8,None,None,None,1), + (10,1,"GtkPopover","popover_sort",None,None,None,None,None), + (10,2,"GtkBox",None,1,None,None,None,None), + (10,3,"GtkButton","buttons_popover_sort_file_name",2,None,None,None,None), + (10,4,"GtkButton","buttons_popover_sort_folder_name",2,None,None,None,1), + (10,5,"GtkButton","buttons_popover_sort_full_name",2,None,None,None,2), + (10,6,"GtkButton","buttons_popover_sort_size",2,None,None,None,3), + (10,7,"GtkButton","buttons_popover_sort_selection",2,None,None,None,4) (3,1,"GtkAboutDialog","comments","2020 - 2022 Rafał Mikrut(qarmin)\n\nThis program is free to use and will always be.\n",1,None,None,None,None), @@ -746,6 +758,13 @@ (5,227,"GtkCheckButton","label","Archive",None,None,None,None,None), (5,228,"GtkCheckButton","active","True",None,None,None,None,None), (5,228,"GtkCheckButton","label","Image",None,None,None,None,None), + (5,229,"GtkWidget","focus-on-click","0",None,None,None,None,None), + (5,229,"GtkWidget","focusable","1",None,None,None,None,None), + (5,229,"GtkWidget","receives-default","1",None,None,None,None,None), + (5,230,"GtkBox","spacing","2",None,None,None,None,None), + (5,230,"GtkWidget","halign","center",None,None,None,None,None), + (5,231,"GtkImage","icon-name","image-missing",None,None,None,None,None), + (5,232,"GtkLabel","label","SortMenu",None,None,None,None,None), (6,1,"GtkPopover","child",None,None,None,None,None,2), (6,1,"GtkPopover","position","left",None,None,None,None,None), (6,2,"GtkOrientable","orientation","vertical",None,None,None,None,None), @@ -969,7 +988,25 @@ (9,58,"GtkWidget","hexpand","1",None,None,None,None,None), (9,59,"GtkAccessible","accessible-role","menu-item-checkbox",None,None,None,None,None), (9,59,"GtkWidget","margin-bottom","4",None,None,None,None,None), - (9,59,"GtkWidget","margin-top","5",None,None,None,None,None) + (9,59,"GtkWidget","margin-top","5",None,None,None,None,None), + (10,1,"GtkPopover","child",None,None,None,None,None,2), + (10,1,"GtkPopover","position","top",None,None,None,None,None), + (10,2,"GtkOrientable","orientation","vertical",None,None,None,None,None), + (10,3,"GtkButton","label","File name",None,None,None,None,None), + (10,3,"GtkWidget","focusable","1",None,None,None,None,None), + (10,3,"GtkWidget","receives-default","1",None,None,None,None,None), + (10,4,"GtkButton","label","Folder name",None,None,None,None,None), + (10,4,"GtkWidget","focusable","1",None,None,None,None,None), + (10,4,"GtkWidget","receives-default","1",None,None,None,None,None), + (10,5,"GtkButton","label","Full name",None,None,None,None,None), + (10,5,"GtkWidget","focusable","1",None,None,None,None,None), + (10,5,"GtkWidget","receives-default","1",None,None,None,None,None), + (10,6,"GtkButton","label","Size",None,None,None,None,None), + (10,6,"GtkWidget","focusable","1",None,None,None,None,None), + (10,6,"GtkWidget","receives-default","1",None,None,None,None,None), + (10,7,"GtkButton","label","Selection",None,None,None,None,None), + (10,7,"GtkWidget","focusable","1",None,None,None,None,None), + (10,7,"GtkWidget","receives-default","1",None,None,None,None,None) (8,17,18,"GtkGridLayoutChild","column","0",None,None,None,None), diff --git a/czkawka_gui/ui/main_window.ui b/czkawka_gui/ui/main_window.ui index ac9594f..b24d576 100644 --- a/czkawka_gui/ui/main_window.ui +++ b/czkawka_gui/ui/main_window.ui @@ -900,6 +900,29 @@ + + + 0 + 1 + 1 + + + center + 2 + + + image-missing + + + + + SortMenu + + + + + + 1 diff --git a/czkawka_gui/ui/popover_sort.ui b/czkawka_gui/ui/popover_sort.ui new file mode 100644 index 0000000..9ac7f59 --- /dev/null +++ b/czkawka_gui/ui/popover_sort.ui @@ -0,0 +1,49 @@ + + + + + + + + + vertical + + + 1 + File name + 1 + + + + + 1 + Folder name + 1 + + + + + 1 + Full name + 1 + + + + + 1 + Size + 1 + + + + + 1 + Selection + 1 + + + + + top + + diff --git a/instructions/Compilation.md b/instructions/Compilation.md index e7554c7..32512ec 100644 --- a/instructions/Compilation.md +++ b/instructions/Compilation.md @@ -9,10 +9,10 @@ FFmpeg is not included here because it is not needed to build - it is dynamicall Support for heif images is optional and require to install libheif library. -| Program | Min | What for | -|---------|--------|-------------------------------------------------------------------------------| -| Rust | 1.65.0 | Czkawka, aims to support the latest available version of Rust on Ubuntu 22.04 | -| GTK | 4.6 | Only for the `GTK` backend | +| Program | Min | What for | +|---------|--------|--------------------------------------------------------------------------------------| +| Rust | 1.65.0 | The minimum version of rust does not depend on anything, so it can change frequently | +| GTK | 4.6 | Only for the `GTK` backend | #### Debian / Ubuntu ```shell