Add Rename
This commit is contained in:
parent
8fed9dd216
commit
1dc9b9c1b1
4 changed files with 145 additions and 1 deletions
|
|
@ -26,6 +26,10 @@ open-multiple-folders = Open multiple folders
|
||||||
save = Save
|
save = Save
|
||||||
save-file = Save file
|
save-file = Save file
|
||||||
|
|
||||||
|
# Rename Dialog
|
||||||
|
rename-file = Rename file
|
||||||
|
rename-folder = Rename folder
|
||||||
|
|
||||||
# Replace Dialog
|
# Replace Dialog
|
||||||
replace = Replace
|
replace = Replace
|
||||||
replace-title = {$filename} already exists in this location.
|
replace-title = {$filename} already exists in this location.
|
||||||
|
|
@ -78,6 +82,7 @@ restore-from-trash = Restore from trash
|
||||||
file = File
|
file = File
|
||||||
new-tab = New tab
|
new-tab = New tab
|
||||||
new-window = New window
|
new-window = New window
|
||||||
|
rename = Rename
|
||||||
close-tab = Close tab
|
close-tab = Close tab
|
||||||
quit = Quit
|
quit = Quit
|
||||||
|
|
||||||
|
|
|
||||||
122
src/app.rs
122
src/app.rs
|
|
@ -53,6 +53,7 @@ pub enum Action {
|
||||||
Operations,
|
Operations,
|
||||||
Paste,
|
Paste,
|
||||||
Properties,
|
Properties,
|
||||||
|
Rename,
|
||||||
RestoreFromTrash,
|
RestoreFromTrash,
|
||||||
SelectAll,
|
SelectAll,
|
||||||
Settings,
|
Settings,
|
||||||
|
|
@ -82,6 +83,7 @@ impl Action {
|
||||||
Action::Operations => Message::ToggleContextPage(ContextPage::Operations),
|
Action::Operations => Message::ToggleContextPage(ContextPage::Operations),
|
||||||
Action::Paste => Message::Paste(entity_opt),
|
Action::Paste => Message::Paste(entity_opt),
|
||||||
Action::Properties => Message::ToggleContextPage(ContextPage::Properties),
|
Action::Properties => Message::ToggleContextPage(ContextPage::Properties),
|
||||||
|
Action::Rename => Message::Rename(entity_opt),
|
||||||
Action::RestoreFromTrash => Message::RestoreFromTrash(entity_opt),
|
Action::RestoreFromTrash => Message::RestoreFromTrash(entity_opt),
|
||||||
Action::SelectAll => Message::SelectAll(entity_opt),
|
Action::SelectAll => Message::SelectAll(entity_opt),
|
||||||
Action::Settings => Message::ToggleContextPage(ContextPage::Settings),
|
Action::Settings => Message::ToggleContextPage(ContextPage::Settings),
|
||||||
|
|
@ -123,6 +125,7 @@ pub enum Message {
|
||||||
PendingComplete(u64),
|
PendingComplete(u64),
|
||||||
PendingError(u64, String),
|
PendingError(u64, String),
|
||||||
PendingProgress(u64, f32),
|
PendingProgress(u64, f32),
|
||||||
|
Rename(Option<segmented_button::Entity>),
|
||||||
RestoreFromTrash(Option<segmented_button::Entity>),
|
RestoreFromTrash(Option<segmented_button::Entity>),
|
||||||
SelectAll(Option<segmented_button::Entity>),
|
SelectAll(Option<segmented_button::Entity>),
|
||||||
SystemThemeModeChange(cosmic_theme::ThemeMode),
|
SystemThemeModeChange(cosmic_theme::ThemeMode),
|
||||||
|
|
@ -166,6 +169,12 @@ pub enum DialogPage {
|
||||||
name: String,
|
name: String,
|
||||||
dir: bool,
|
dir: bool,
|
||||||
},
|
},
|
||||||
|
RenameItem {
|
||||||
|
from: PathBuf,
|
||||||
|
parent: PathBuf,
|
||||||
|
name: String,
|
||||||
|
dir: bool,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
|
@ -717,6 +726,12 @@ impl Application for App {
|
||||||
Operation::NewFile { path }
|
Operation::NewFile { path }
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
DialogPage::RenameItem {
|
||||||
|
from, parent, name, ..
|
||||||
|
} => {
|
||||||
|
let to = parent.join(name);
|
||||||
|
self.operation(Operation::Rename { from, to });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -831,6 +846,38 @@ impl Application for App {
|
||||||
*progress = new_progress;
|
*progress = new_progress;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Message::Rename(entity_opt) => {
|
||||||
|
let entity = entity_opt.unwrap_or_else(|| self.tab_model.active());
|
||||||
|
if let Some(tab) = self.tab_model.data_mut::<Tab>(entity) {
|
||||||
|
if let Location::Path(parent) = &tab.location {
|
||||||
|
if let Some(items) = &tab.items_opt {
|
||||||
|
let mut selected = Vec::new();
|
||||||
|
for item in items.iter() {
|
||||||
|
if item.selected {
|
||||||
|
selected.push(item.path.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !selected.is_empty() {
|
||||||
|
//TODO: batch rename
|
||||||
|
for path in selected {
|
||||||
|
let name = match path.file_name().and_then(|x| x.to_str()) {
|
||||||
|
Some(some) => some.to_string(),
|
||||||
|
None => continue,
|
||||||
|
};
|
||||||
|
let dir = path.is_dir();
|
||||||
|
self.dialog_pages.push_back(DialogPage::RenameItem {
|
||||||
|
from: path,
|
||||||
|
parent: parent.clone(),
|
||||||
|
name,
|
||||||
|
dir,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return widget::text_input::focus(self.dialog_text_input.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Message::RestoreFromTrash(entity_opt) => {
|
Message::RestoreFromTrash(entity_opt) => {
|
||||||
let mut paths = Vec::new();
|
let mut paths = Vec::new();
|
||||||
let entity = entity_opt.unwrap_or_else(|| self.tab_model.active());
|
let entity = entity_opt.unwrap_or_else(|| self.tab_model.active());
|
||||||
|
|
@ -1136,6 +1183,81 @@ impl Application for App {
|
||||||
.spacing(space_xxs),
|
.spacing(space_xxs),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
DialogPage::RenameItem {
|
||||||
|
from,
|
||||||
|
parent,
|
||||||
|
name,
|
||||||
|
dir,
|
||||||
|
} => {
|
||||||
|
//TODO: combine logic with NewItem
|
||||||
|
let mut dialog = widget::dialog(if *dir {
|
||||||
|
fl!("rename-folder")
|
||||||
|
} else {
|
||||||
|
fl!("rename-file")
|
||||||
|
});
|
||||||
|
|
||||||
|
let complete_maybe = if name.is_empty() {
|
||||||
|
None
|
||||||
|
} else if name == "." || name == ".." {
|
||||||
|
dialog = dialog.tertiary_action(widget::text::body(fl!(
|
||||||
|
"name-invalid",
|
||||||
|
filename = name.as_str()
|
||||||
|
)));
|
||||||
|
None
|
||||||
|
} else if name.contains('/') {
|
||||||
|
dialog = dialog.tertiary_action(widget::text::body(fl!("name-no-slashes")));
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
let path = parent.join(name);
|
||||||
|
if path.exists() {
|
||||||
|
if path.is_dir() {
|
||||||
|
dialog = dialog
|
||||||
|
.tertiary_action(widget::text::body(fl!("folder-already-exists")));
|
||||||
|
} else {
|
||||||
|
dialog = dialog
|
||||||
|
.tertiary_action(widget::text::body(fl!("file-already-exists")));
|
||||||
|
}
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
if name.starts_with('.') {
|
||||||
|
dialog = dialog.tertiary_action(widget::text::body(fl!("name-hidden")));
|
||||||
|
}
|
||||||
|
Some(Message::DialogComplete)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
dialog
|
||||||
|
.primary_action(
|
||||||
|
widget::button::suggested(fl!("rename"))
|
||||||
|
.on_press_maybe(complete_maybe.clone()),
|
||||||
|
)
|
||||||
|
.secondary_action(
|
||||||
|
widget::button::standard(fl!("cancel")).on_press(Message::DialogCancel),
|
||||||
|
)
|
||||||
|
.control(
|
||||||
|
widget::column::with_children(vec![
|
||||||
|
widget::text::body(if *dir {
|
||||||
|
fl!("folder-name")
|
||||||
|
} else {
|
||||||
|
fl!("file-name")
|
||||||
|
})
|
||||||
|
.into(),
|
||||||
|
widget::text_input("", name.as_str())
|
||||||
|
.id(self.dialog_text_input.clone())
|
||||||
|
.on_input(move |name| {
|
||||||
|
Message::DialogUpdate(DialogPage::RenameItem {
|
||||||
|
from: from.clone(),
|
||||||
|
parent: parent.clone(),
|
||||||
|
name,
|
||||||
|
dir: *dir,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.on_submit_maybe(complete_maybe)
|
||||||
|
.into(),
|
||||||
|
])
|
||||||
|
.spacing(space_xxs),
|
||||||
|
)
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Some(dialog.into())
|
Some(dialog.into())
|
||||||
|
|
|
||||||
|
|
@ -52,6 +52,7 @@ pub fn context_menu<'a>(tab: &Tab) -> Element<'a, tab::Message> {
|
||||||
children.push(menu_action(fl!("new-folder"), Action::NewFolder).into());
|
children.push(menu_action(fl!("new-folder"), Action::NewFolder).into());
|
||||||
children.push(horizontal_rule(1).into());
|
children.push(horizontal_rule(1).into());
|
||||||
if selected > 0 {
|
if selected > 0 {
|
||||||
|
children.push(menu_action(fl!("rename"), Action::Rename).into());
|
||||||
children.push(menu_action(fl!("cut"), Action::Cut).into());
|
children.push(menu_action(fl!("cut"), Action::Cut).into());
|
||||||
children.push(menu_action(fl!("copy"), Action::Copy).into());
|
children.push(menu_action(fl!("copy"), Action::Copy).into());
|
||||||
children.push(menu_action(fl!("paste"), Action::Paste).into());
|
children.push(menu_action(fl!("paste"), Action::Paste).into());
|
||||||
|
|
@ -133,9 +134,14 @@ pub fn menu_bar<'a>(key_binds: &HashMap<KeyBind, Action>) -> Element<'a, Message
|
||||||
menu_item(fl!("new-window"), Action::WindowNew),
|
menu_item(fl!("new-window"), Action::WindowNew),
|
||||||
menu_item(fl!("new-file"), Action::NewFile),
|
menu_item(fl!("new-file"), Action::NewFile),
|
||||||
menu_item(fl!("new-folder"), Action::NewFolder),
|
menu_item(fl!("new-folder"), Action::NewFolder),
|
||||||
|
//TODO: open
|
||||||
|
MenuTree::new(horizontal_rule(1)),
|
||||||
|
menu_item(fl!("rename"), Action::Rename),
|
||||||
|
//TOOD: add to sidebar, then divider
|
||||||
|
MenuTree::new(horizontal_rule(1)),
|
||||||
|
menu_item(fl!("move-to-trash"), Action::MoveToTrash),
|
||||||
MenuTree::new(horizontal_rule(1)),
|
MenuTree::new(horizontal_rule(1)),
|
||||||
menu_item(fl!("close-tab"), Action::TabClose),
|
menu_item(fl!("close-tab"), Action::TabClose),
|
||||||
MenuTree::new(horizontal_rule(1)),
|
|
||||||
menu_item(fl!("quit"), Action::WindowClose),
|
menu_item(fl!("quit"), Action::WindowClose),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,10 @@ pub enum Operation {
|
||||||
NewFolder {
|
NewFolder {
|
||||||
path: PathBuf,
|
path: PathBuf,
|
||||||
},
|
},
|
||||||
|
Rename {
|
||||||
|
from: PathBuf,
|
||||||
|
to: PathBuf,
|
||||||
|
},
|
||||||
/// Restore a path from the trash
|
/// Restore a path from the trash
|
||||||
Restore {
|
Restore {
|
||||||
paths: Vec<trash::TrashItem>,
|
paths: Vec<trash::TrashItem>,
|
||||||
|
|
@ -74,6 +78,13 @@ impl Operation {
|
||||||
.map_err(err_str)?;
|
.map_err(err_str)?;
|
||||||
let _ = msg_tx.send(Message::PendingProgress(id, 100.0)).await;
|
let _ = msg_tx.send(Message::PendingProgress(id, 100.0)).await;
|
||||||
}
|
}
|
||||||
|
Self::Rename { from, to } => {
|
||||||
|
tokio::task::spawn_blocking(|| fs::rename(from, to))
|
||||||
|
.await
|
||||||
|
.map_err(err_str)?
|
||||||
|
.map_err(err_str)?;
|
||||||
|
let _ = msg_tx.send(Message::PendingProgress(id, 100.0)).await;
|
||||||
|
}
|
||||||
Self::Restore { paths } => {
|
Self::Restore { paths } => {
|
||||||
let total = paths.len();
|
let total = paths.len();
|
||||||
let mut count = 0;
|
let mut count = 0;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue