Allow to set included/excluded directories by command line arguments (#677)
This commit is contained in:
parent
aa07d73bca
commit
c88d347e00
|
@ -53,7 +53,7 @@ pub fn connect_settings(gui_data: &GuiData) {
|
|||
let button_settings_load_configuration = gui_data.settings.button_settings_load_configuration.clone();
|
||||
let scrolled_window_errors = gui_data.scrolled_window_errors.clone();
|
||||
button_settings_load_configuration.connect_clicked(move |_| {
|
||||
load_configuration(true, &upper_notebook, &main_notebook, &settings, &text_view_errors, &scrolled_window_errors);
|
||||
load_configuration(true, &upper_notebook, &main_notebook, &settings, &text_view_errors, &scrolled_window_errors, Vec::new());
|
||||
});
|
||||
}
|
||||
// Connect reset configuration button
|
||||
|
|
|
@ -5,7 +5,11 @@
|
|||
#![allow(clippy::type_complexity)]
|
||||
#![allow(clippy::needless_late_init)]
|
||||
|
||||
use gtk::gio::ApplicationFlags;
|
||||
use gtk::prelude::*;
|
||||
use gtk::Application;
|
||||
use std::env;
|
||||
use std::ffi::OsString;
|
||||
|
||||
use czkawka_core::*;
|
||||
|
||||
|
@ -55,125 +59,134 @@ mod taskbar_progress_win;
|
|||
mod tests;
|
||||
|
||||
fn main() {
|
||||
let application = gtk::Application::builder().build();
|
||||
application.connect_activate(move |application| {
|
||||
let mut gui_data: GuiData = GuiData::new_with_application(application);
|
||||
|
||||
// Used for getting data from thread
|
||||
let (glib_stop_sender, glib_stop_receiver) = glib::MainContext::channel(glib::PRIORITY_DEFAULT);
|
||||
|
||||
// Futures progress report
|
||||
let (futures_sender_duplicate_files, futures_receiver_duplicate_files): (
|
||||
futures::channel::mpsc::UnboundedSender<common_dir_traversal::ProgressData>,
|
||||
futures::channel::mpsc::UnboundedReceiver<common_dir_traversal::ProgressData>,
|
||||
) = futures::channel::mpsc::unbounded();
|
||||
let (futures_sender_empty_files, futures_receiver_empty_files): (
|
||||
futures::channel::mpsc::UnboundedSender<common_dir_traversal::ProgressData>,
|
||||
futures::channel::mpsc::UnboundedReceiver<common_dir_traversal::ProgressData>,
|
||||
) = futures::channel::mpsc::unbounded();
|
||||
let (futures_sender_empty_folder, futures_receiver_empty_folder): (
|
||||
futures::channel::mpsc::UnboundedSender<common_dir_traversal::ProgressData>,
|
||||
futures::channel::mpsc::UnboundedReceiver<common_dir_traversal::ProgressData>,
|
||||
) = futures::channel::mpsc::unbounded();
|
||||
let (futures_sender_big_file, futures_receiver_big_file): (
|
||||
futures::channel::mpsc::UnboundedSender<big_file::ProgressData>,
|
||||
futures::channel::mpsc::UnboundedReceiver<big_file::ProgressData>,
|
||||
) = futures::channel::mpsc::unbounded();
|
||||
let (futures_sender_same_music, futures_receiver_same_music): (
|
||||
futures::channel::mpsc::UnboundedSender<common_dir_traversal::ProgressData>,
|
||||
futures::channel::mpsc::UnboundedReceiver<common_dir_traversal::ProgressData>,
|
||||
) = futures::channel::mpsc::unbounded();
|
||||
let (futures_sender_similar_images, futures_receiver_similar_images): (
|
||||
futures::channel::mpsc::UnboundedSender<similar_images::ProgressData>,
|
||||
futures::channel::mpsc::UnboundedReceiver<similar_images::ProgressData>,
|
||||
) = futures::channel::mpsc::unbounded();
|
||||
let (futures_sender_similar_videos, futures_receiver_similar_videos): (
|
||||
futures::channel::mpsc::UnboundedSender<similar_videos::ProgressData>,
|
||||
futures::channel::mpsc::UnboundedReceiver<similar_videos::ProgressData>,
|
||||
) = futures::channel::mpsc::unbounded();
|
||||
let (futures_sender_temporary, futures_receiver_temporary): (
|
||||
futures::channel::mpsc::UnboundedSender<temporary::ProgressData>,
|
||||
futures::channel::mpsc::UnboundedReceiver<temporary::ProgressData>,
|
||||
) = futures::channel::mpsc::unbounded();
|
||||
let (futures_sender_invalid_symlinks, futures_receiver_invalid_symlinks): (
|
||||
futures::channel::mpsc::UnboundedSender<common_dir_traversal::ProgressData>,
|
||||
futures::channel::mpsc::UnboundedReceiver<common_dir_traversal::ProgressData>,
|
||||
) = futures::channel::mpsc::unbounded();
|
||||
let (futures_sender_broken_files, futures_receiver_broken_files): (
|
||||
futures::channel::mpsc::UnboundedSender<broken_files::ProgressData>,
|
||||
futures::channel::mpsc::UnboundedReceiver<broken_files::ProgressData>,
|
||||
) = futures::channel::mpsc::unbounded();
|
||||
|
||||
initialize_gui(&mut gui_data);
|
||||
validate_notebook_data(&gui_data); // Must be run after initialization of gui, to check if everything was properly setup
|
||||
reset_configuration(false, &gui_data.upper_notebook, &gui_data.main_notebook, &gui_data.settings, &gui_data.text_view_errors); // Fallback for invalid loading setting project
|
||||
load_system_language(&gui_data); // Check for default system language, must be loaded after initializing GUI and before loading settings from file
|
||||
load_configuration(
|
||||
false,
|
||||
&gui_data.upper_notebook,
|
||||
&gui_data.main_notebook,
|
||||
&gui_data.settings,
|
||||
&gui_data.text_view_errors,
|
||||
&gui_data.scrolled_window_errors,
|
||||
);
|
||||
|
||||
// Needs to run when entire GUI is initialized
|
||||
connect_change_language(&gui_data);
|
||||
|
||||
connect_button_delete(&gui_data);
|
||||
connect_button_save(&gui_data);
|
||||
connect_button_search(
|
||||
&gui_data,
|
||||
glib_stop_sender,
|
||||
futures_sender_duplicate_files,
|
||||
futures_sender_empty_files,
|
||||
futures_sender_empty_folder,
|
||||
futures_sender_big_file,
|
||||
futures_sender_same_music,
|
||||
futures_sender_similar_images,
|
||||
futures_sender_similar_videos,
|
||||
futures_sender_temporary,
|
||||
futures_sender_invalid_symlinks,
|
||||
futures_sender_broken_files,
|
||||
);
|
||||
connect_button_select(&gui_data);
|
||||
connect_button_stop(&gui_data);
|
||||
connect_button_hardlink_symlink(&gui_data);
|
||||
connect_button_move(&gui_data);
|
||||
connect_button_compare(&gui_data);
|
||||
|
||||
connect_duplicate_combo_box(&gui_data);
|
||||
connect_notebook_tabs(&gui_data);
|
||||
connect_selection_of_directories(&gui_data);
|
||||
connect_popovers(&gui_data);
|
||||
connect_compute_results(&gui_data, glib_stop_receiver);
|
||||
connect_progress_window(
|
||||
&gui_data,
|
||||
futures_receiver_duplicate_files,
|
||||
futures_receiver_empty_files,
|
||||
futures_receiver_empty_folder,
|
||||
futures_receiver_big_file,
|
||||
futures_receiver_same_music,
|
||||
futures_receiver_similar_images,
|
||||
futures_receiver_similar_videos,
|
||||
futures_receiver_temporary,
|
||||
futures_receiver_invalid_symlinks,
|
||||
futures_receiver_broken_files,
|
||||
);
|
||||
connect_show_hide_ui(&gui_data);
|
||||
connect_settings(&gui_data);
|
||||
connect_button_about(&gui_data);
|
||||
connect_about_buttons(&gui_data);
|
||||
connect_similar_image_size_change(&gui_data);
|
||||
|
||||
let window_main = gui_data.window_main.clone();
|
||||
let taskbar_state = gui_data.taskbar_state.clone();
|
||||
window_main.connect_delete_event(move |_, _| {
|
||||
save_configuration(false, &gui_data.upper_notebook, &gui_data.main_notebook, &gui_data.settings, &gui_data.text_view_errors); // Save configuration at exit
|
||||
taskbar_state.borrow_mut().release();
|
||||
Inhibit(false)
|
||||
});
|
||||
let application = gtk::Application::new(None, ApplicationFlags::HANDLES_OPEN | ApplicationFlags::HANDLES_COMMAND_LINE);
|
||||
application.connect_command_line(move |app, cmdline| {
|
||||
build_ui(app, cmdline.arguments());
|
||||
0
|
||||
});
|
||||
application.run_with_args(&env::args().collect::<Vec<_>>());
|
||||
}
|
||||
fn build_ui(application: &Application, arguments: Vec<OsString>) {
|
||||
let mut gui_data: GuiData = GuiData::new_with_application(application);
|
||||
|
||||
// Used for getting data from thread
|
||||
let (glib_stop_sender, glib_stop_receiver) = glib::MainContext::channel(glib::PRIORITY_DEFAULT);
|
||||
|
||||
// Futures progress report
|
||||
let (futures_sender_duplicate_files, futures_receiver_duplicate_files): (
|
||||
futures::channel::mpsc::UnboundedSender<common_dir_traversal::ProgressData>,
|
||||
futures::channel::mpsc::UnboundedReceiver<common_dir_traversal::ProgressData>,
|
||||
) = futures::channel::mpsc::unbounded();
|
||||
let (futures_sender_empty_files, futures_receiver_empty_files): (
|
||||
futures::channel::mpsc::UnboundedSender<common_dir_traversal::ProgressData>,
|
||||
futures::channel::mpsc::UnboundedReceiver<common_dir_traversal::ProgressData>,
|
||||
) = futures::channel::mpsc::unbounded();
|
||||
let (futures_sender_empty_folder, futures_receiver_empty_folder): (
|
||||
futures::channel::mpsc::UnboundedSender<common_dir_traversal::ProgressData>,
|
||||
futures::channel::mpsc::UnboundedReceiver<common_dir_traversal::ProgressData>,
|
||||
) = futures::channel::mpsc::unbounded();
|
||||
let (futures_sender_big_file, futures_receiver_big_file): (
|
||||
futures::channel::mpsc::UnboundedSender<big_file::ProgressData>,
|
||||
futures::channel::mpsc::UnboundedReceiver<big_file::ProgressData>,
|
||||
) = futures::channel::mpsc::unbounded();
|
||||
let (futures_sender_same_music, futures_receiver_same_music): (
|
||||
futures::channel::mpsc::UnboundedSender<common_dir_traversal::ProgressData>,
|
||||
futures::channel::mpsc::UnboundedReceiver<common_dir_traversal::ProgressData>,
|
||||
) = futures::channel::mpsc::unbounded();
|
||||
let (futures_sender_similar_images, futures_receiver_similar_images): (
|
||||
futures::channel::mpsc::UnboundedSender<similar_images::ProgressData>,
|
||||
futures::channel::mpsc::UnboundedReceiver<similar_images::ProgressData>,
|
||||
) = futures::channel::mpsc::unbounded();
|
||||
let (futures_sender_similar_videos, futures_receiver_similar_videos): (
|
||||
futures::channel::mpsc::UnboundedSender<similar_videos::ProgressData>,
|
||||
futures::channel::mpsc::UnboundedReceiver<similar_videos::ProgressData>,
|
||||
) = futures::channel::mpsc::unbounded();
|
||||
let (futures_sender_temporary, futures_receiver_temporary): (
|
||||
futures::channel::mpsc::UnboundedSender<temporary::ProgressData>,
|
||||
futures::channel::mpsc::UnboundedReceiver<temporary::ProgressData>,
|
||||
) = futures::channel::mpsc::unbounded();
|
||||
let (futures_sender_invalid_symlinks, futures_receiver_invalid_symlinks): (
|
||||
futures::channel::mpsc::UnboundedSender<common_dir_traversal::ProgressData>,
|
||||
futures::channel::mpsc::UnboundedReceiver<common_dir_traversal::ProgressData>,
|
||||
) = futures::channel::mpsc::unbounded();
|
||||
let (futures_sender_broken_files, futures_receiver_broken_files): (
|
||||
futures::channel::mpsc::UnboundedSender<broken_files::ProgressData>,
|
||||
futures::channel::mpsc::UnboundedReceiver<broken_files::ProgressData>,
|
||||
) = futures::channel::mpsc::unbounded();
|
||||
|
||||
initialize_gui(&mut gui_data);
|
||||
validate_notebook_data(&gui_data); // Must be run after initialization of gui, to check if everything was properly setup
|
||||
reset_configuration(false, &gui_data.upper_notebook, &gui_data.main_notebook, &gui_data.settings, &gui_data.text_view_errors); // Fallback for invalid loading setting project
|
||||
load_system_language(&gui_data); // Check for default system language, must be loaded after initializing GUI and before loading settings from file
|
||||
load_configuration(
|
||||
false,
|
||||
&gui_data.upper_notebook,
|
||||
&gui_data.main_notebook,
|
||||
&gui_data.settings,
|
||||
&gui_data.text_view_errors,
|
||||
&gui_data.scrolled_window_errors,
|
||||
arguments.clone(),
|
||||
);
|
||||
|
||||
// Needs to run when entire GUI is initialized
|
||||
connect_change_language(&gui_data);
|
||||
|
||||
connect_button_delete(&gui_data);
|
||||
connect_button_save(&gui_data);
|
||||
connect_button_search(
|
||||
&gui_data,
|
||||
glib_stop_sender,
|
||||
futures_sender_duplicate_files,
|
||||
futures_sender_empty_files,
|
||||
futures_sender_empty_folder,
|
||||
futures_sender_big_file,
|
||||
futures_sender_same_music,
|
||||
futures_sender_similar_images,
|
||||
futures_sender_similar_videos,
|
||||
futures_sender_temporary,
|
||||
futures_sender_invalid_symlinks,
|
||||
futures_sender_broken_files,
|
||||
);
|
||||
connect_button_select(&gui_data);
|
||||
connect_button_stop(&gui_data);
|
||||
connect_button_hardlink_symlink(&gui_data);
|
||||
connect_button_move(&gui_data);
|
||||
connect_button_compare(&gui_data);
|
||||
|
||||
connect_duplicate_combo_box(&gui_data);
|
||||
connect_notebook_tabs(&gui_data);
|
||||
connect_selection_of_directories(&gui_data);
|
||||
connect_popovers(&gui_data);
|
||||
connect_compute_results(&gui_data, glib_stop_receiver);
|
||||
connect_progress_window(
|
||||
&gui_data,
|
||||
futures_receiver_duplicate_files,
|
||||
futures_receiver_empty_files,
|
||||
futures_receiver_empty_folder,
|
||||
futures_receiver_big_file,
|
||||
futures_receiver_same_music,
|
||||
futures_receiver_similar_images,
|
||||
futures_receiver_similar_videos,
|
||||
futures_receiver_temporary,
|
||||
futures_receiver_invalid_symlinks,
|
||||
futures_receiver_broken_files,
|
||||
);
|
||||
connect_show_hide_ui(&gui_data);
|
||||
connect_settings(&gui_data);
|
||||
connect_button_about(&gui_data);
|
||||
connect_about_buttons(&gui_data);
|
||||
connect_similar_image_size_change(&gui_data);
|
||||
|
||||
let window_main = gui_data.window_main.clone();
|
||||
let taskbar_state = gui_data.taskbar_state.clone();
|
||||
let used_additional_arguments = arguments.len() > 1;
|
||||
window_main.connect_delete_event(move |_, _| {
|
||||
// Not save configuration when using non default arguments
|
||||
if !used_additional_arguments {
|
||||
save_configuration(false, &gui_data.upper_notebook, &gui_data.main_notebook, &gui_data.settings, &gui_data.text_view_errors);
|
||||
// Save configuration at exit
|
||||
}
|
||||
taskbar_state.borrow_mut().release();
|
||||
Inhibit(false)
|
||||
});
|
||||
|
||||
application.run();
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use std::collections::HashMap;
|
||||
use std::ffi::OsString;
|
||||
use std::fs::File;
|
||||
use std::io::{Read, Write};
|
||||
use std::path::{Path, PathBuf};
|
||||
|
@ -20,7 +21,6 @@ use crate::help_functions::*;
|
|||
use crate::language_functions::{get_language_from_combo_box_text, LANGUAGES_ALL};
|
||||
use crate::localizer_core::generate_translation_hashmap;
|
||||
|
||||
// TODO organize this better, add specific functions that will allow to load from files specific strings
|
||||
const SAVE_FILE_NAME: &str = "czkawka_gui_config_4.txt";
|
||||
|
||||
const DEFAULT_SAVE_ON_EXIT: bool = true;
|
||||
|
@ -662,6 +662,7 @@ pub fn load_configuration(
|
|||
settings: &GuiSettings,
|
||||
text_view_errors: &TextView,
|
||||
scrolled_window_errors: &ScrolledWindow,
|
||||
arguments: Vec<OsString>,
|
||||
) {
|
||||
let text_view_errors = text_view_errors.clone();
|
||||
|
||||
|
@ -681,8 +682,8 @@ pub fn load_configuration(
|
|||
// Loading data from hashmaps
|
||||
let (hashmap_ls, _hashmap_sl) = create_hash_map();
|
||||
|
||||
let included_directories: Vec<String> = loaded_entries.get_vector_string(hashmap_ls.get(&LoadText::IncludedDirectories).unwrap().clone(), included_directories);
|
||||
let excluded_directories: Vec<String> = loaded_entries.get_vector_string(hashmap_ls.get(&LoadText::ExcludedDirectories).unwrap().clone(), excluded_directories);
|
||||
let mut included_directories: Vec<String> = loaded_entries.get_vector_string(hashmap_ls.get(&LoadText::IncludedDirectories).unwrap().clone(), included_directories);
|
||||
let mut excluded_directories: Vec<String> = loaded_entries.get_vector_string(hashmap_ls.get(&LoadText::ExcludedDirectories).unwrap().clone(), excluded_directories);
|
||||
let excluded_items: String = loaded_entries.get_string(
|
||||
hashmap_ls.get(&LoadText::ExcludedItems).unwrap().clone(),
|
||||
upper_notebook.entry_excluded_items.text().to_string(),
|
||||
|
@ -752,6 +753,46 @@ pub fn load_configuration(
|
|||
// 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
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
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
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
}
|
||||
|
||||
// Include Directories
|
||||
let tree_view_included_directories = upper_notebook.tree_view_included_directories.clone();
|
||||
let list_store = get_list_store(&tree_view_included_directories);
|
||||
|
|
|
@ -36,6 +36,16 @@ To open folder containing selected file, just click twice on it with right mouse
|
|||
|
||||
To invert a selection of files, click on a file with the middle mouse button and it will invert the selection of the other files in the same group.
|
||||
|
||||
### Adding directories
|
||||
|
||||
By default current path is loaded to included directory and excluded directories are filled with default paths.
|
||||
|
||||
It is possible to override this, by adding arguments when opening app e.g. `czkawka_gui /home /usr --/home/rafal --/home/zaba` which means that `/home` and `/usr` directories will be checked and `/home/rafal` and `/home/zaba` will be excluded.
|
||||
|
||||
When using additional command line arguments, saving at exit option become disabled, so this current info about directories will not be saved until user save it manually.
|
||||
|
||||
Both relative and absolute path are supported, so used can use both `../home` and `/home`.
|
||||
|
||||
## CLI
|
||||
Czkawka CLI frontend is great to automate some tasks like removing empty directories.
|
||||
|
||||
|
|
Loading…
Reference in New Issue