Do not give trash items a path
This commit is contained in:
parent
57fa0cdbc0
commit
94dd1b04d5
3 changed files with 139 additions and 137 deletions
61
src/app.rs
61
src/app.rs
|
|
@ -307,6 +307,23 @@ impl App {
|
||||||
Command::batch(commands)
|
Command::batch(commands)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn selected_paths(&self, entity_opt: Option<Entity>) -> Vec<PathBuf> {
|
||||||
|
let mut paths = Vec::new();
|
||||||
|
let entity = entity_opt.unwrap_or_else(|| self.tab_model.active());
|
||||||
|
if let Some(tab) = self.tab_model.data::<Tab>(entity) {
|
||||||
|
if let Some(ref items) = tab.items_opt() {
|
||||||
|
for item in items.iter() {
|
||||||
|
if item.selected {
|
||||||
|
if let Some(path) = &item.path_opt {
|
||||||
|
paths.push(path.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
paths
|
||||||
|
}
|
||||||
|
|
||||||
fn update_config(&mut self) -> Command<Message> {
|
fn update_config(&mut self) -> Command<Message> {
|
||||||
cosmic::app::command::set_theme(self.config.app_theme.theme())
|
cosmic::app::command::set_theme(self.config.app_theme.theme())
|
||||||
}
|
}
|
||||||
|
|
@ -790,32 +807,12 @@ impl Application for App {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Message::Copy(entity_opt) => {
|
Message::Copy(entity_opt) => {
|
||||||
let mut paths = Vec::new();
|
let paths = self.selected_paths(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 Some(ref items) = tab.items_opt() {
|
|
||||||
for item in items.iter() {
|
|
||||||
if item.selected {
|
|
||||||
paths.push(item.path.clone());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let contents = ClipboardContents::new(ClipboardKind::Copy, &paths);
|
let contents = ClipboardContents::new(ClipboardKind::Copy, &paths);
|
||||||
return clipboard::write_data(contents);
|
return clipboard::write_data(contents);
|
||||||
}
|
}
|
||||||
Message::Cut(entity_opt) => {
|
Message::Cut(entity_opt) => {
|
||||||
let mut paths = Vec::new();
|
let paths = self.selected_paths(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 Some(ref items) = tab.items_opt() {
|
|
||||||
for item in items.iter() {
|
|
||||||
if item.selected {
|
|
||||||
paths.push(item.path.clone());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let contents = ClipboardContents::new(ClipboardKind::Cut, &paths);
|
let contents = ClipboardContents::new(ClipboardKind::Cut, &paths);
|
||||||
return clipboard::write_data(contents);
|
return clipboard::write_data(contents);
|
||||||
}
|
}
|
||||||
|
|
@ -882,17 +879,7 @@ impl Application for App {
|
||||||
self.modifiers = modifiers;
|
self.modifiers = modifiers;
|
||||||
}
|
}
|
||||||
Message::MoveToTrash(entity_opt) => {
|
Message::MoveToTrash(entity_opt) => {
|
||||||
let mut paths = Vec::new();
|
let paths = self.selected_paths(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 Some(ref items) = tab.items_opt() {
|
|
||||||
for item in items.iter() {
|
|
||||||
if item.selected {
|
|
||||||
paths.push(item.path.clone());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !paths.is_empty() {
|
if !paths.is_empty() {
|
||||||
self.operation(Operation::Delete { paths });
|
self.operation(Operation::Delete { paths });
|
||||||
}
|
}
|
||||||
|
|
@ -957,7 +944,9 @@ impl Application for App {
|
||||||
if let Some(items) = tab.items_opt() {
|
if let Some(items) = tab.items_opt() {
|
||||||
for item in items.iter() {
|
for item in items.iter() {
|
||||||
if item.selected {
|
if item.selected {
|
||||||
paths.push(item.path.clone());
|
if let Some(path) = &item.path_opt {
|
||||||
|
paths.push(path.clone());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1032,7 +1021,9 @@ impl Application for App {
|
||||||
let mut selected = Vec::new();
|
let mut selected = Vec::new();
|
||||||
for item in items.iter() {
|
for item in items.iter() {
|
||||||
if item.selected {
|
if item.selected {
|
||||||
selected.push(item.path.clone());
|
if let Some(path) = &item.path_opt {
|
||||||
|
selected.push(path.clone());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !selected.is_empty() {
|
if !selected.is_empty() {
|
||||||
|
|
|
||||||
|
|
@ -471,7 +471,9 @@ impl Application for App {
|
||||||
if let Some(items) = self.tab.items_opt() {
|
if let Some(items) = self.tab.items_opt() {
|
||||||
for item in items.iter() {
|
for item in items.iter() {
|
||||||
if item.selected {
|
if item.selected {
|
||||||
paths.push(item.path.clone());
|
if let Some(path) = &item.path_opt {
|
||||||
|
paths.push(path.clone());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -545,7 +547,7 @@ impl Application for App {
|
||||||
if let Some(click_i) = click_i_opt {
|
if let Some(click_i) = click_i_opt {
|
||||||
if let Some(items) = self.tab.items_opt() {
|
if let Some(items) = self.tab.items_opt() {
|
||||||
if let Some(item) = items.get(click_i) {
|
if let Some(item) = items.get(click_i) {
|
||||||
if item.selected && !item.path.is_dir() {
|
if item.selected && !item.metadata.is_dir() {
|
||||||
*filename = item.name.clone();
|
*filename = item.name.clone();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
79
src/tab.rs
79
src/tab.rs
|
|
@ -271,7 +271,7 @@ pub fn scan_path(tab_path: &PathBuf, sizes: IconSizes) -> Vec<Item> {
|
||||||
name,
|
name,
|
||||||
metadata: ItemMetadata::Path { metadata, children },
|
metadata: ItemMetadata::Path { metadata, children },
|
||||||
hidden,
|
hidden,
|
||||||
path,
|
path_opt: Some(path),
|
||||||
mime,
|
mime,
|
||||||
icon_handle_grid,
|
icon_handle_grid,
|
||||||
icon_handle_list,
|
icon_handle_list,
|
||||||
|
|
@ -336,7 +336,7 @@ pub fn scan_trash(sizes: IconSizes) -> Vec<Item> {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let path = entry.original_path();
|
let original_path = entry.original_path();
|
||||||
let name = entry.name.clone();
|
let name = entry.name.clone();
|
||||||
|
|
||||||
let (mime, icon_handle_grid, icon_handle_list, icon_handle_list_condensed) =
|
let (mime, icon_handle_grid, icon_handle_list, icon_handle_list_condensed) =
|
||||||
|
|
@ -344,12 +344,13 @@ pub fn scan_trash(sizes: IconSizes) -> Vec<Item> {
|
||||||
trash::TrashItemSize::Entries(_) => (
|
trash::TrashItemSize::Entries(_) => (
|
||||||
//TODO: make this a static
|
//TODO: make this a static
|
||||||
"inode/directory".parse().unwrap(),
|
"inode/directory".parse().unwrap(),
|
||||||
folder_icon(&path, sizes.grid()),
|
folder_icon(&original_path, sizes.grid()),
|
||||||
folder_icon(&path, sizes.list()),
|
folder_icon(&original_path, sizes.list()),
|
||||||
folder_icon(&path, sizes.list_condensed()),
|
folder_icon(&original_path, sizes.list_condensed()),
|
||||||
),
|
),
|
||||||
trash::TrashItemSize::Bytes(_) => {
|
trash::TrashItemSize::Bytes(_) => {
|
||||||
let mime = mime_for_path(&path);
|
//TODO: do not use original path
|
||||||
|
let mime = mime_for_path(&original_path);
|
||||||
(
|
(
|
||||||
mime.clone(),
|
mime.clone(),
|
||||||
mime_icon(mime.clone(), sizes.grid()),
|
mime_icon(mime.clone(), sizes.grid()),
|
||||||
|
|
@ -363,7 +364,7 @@ pub fn scan_trash(sizes: IconSizes) -> Vec<Item> {
|
||||||
name,
|
name,
|
||||||
metadata: ItemMetadata::Trash { metadata, entry },
|
metadata: ItemMetadata::Trash { metadata, entry },
|
||||||
hidden: false,
|
hidden: false,
|
||||||
path,
|
path_opt: None,
|
||||||
mime,
|
mime,
|
||||||
icon_handle_grid,
|
icon_handle_grid,
|
||||||
icon_handle_list,
|
icon_handle_list,
|
||||||
|
|
@ -478,7 +479,7 @@ pub struct Item {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub metadata: ItemMetadata,
|
pub metadata: ItemMetadata,
|
||||||
pub hidden: bool,
|
pub hidden: bool,
|
||||||
pub path: PathBuf,
|
pub path_opt: Option<PathBuf>,
|
||||||
pub mime: Mime,
|
pub mime: Mime,
|
||||||
pub icon_handle_grid: widget::icon::Handle,
|
pub icon_handle_grid: widget::icon::Handle,
|
||||||
pub icon_handle_list: widget::icon::Handle,
|
pub icon_handle_list: widget::icon::Handle,
|
||||||
|
|
@ -495,21 +496,32 @@ pub struct Item {
|
||||||
impl Item {
|
impl Item {
|
||||||
fn preview(&self, sizes: IconSizes) -> Element<app::Message> {
|
fn preview(&self, sizes: IconSizes) -> Element<app::Message> {
|
||||||
// This loads the image only if thumbnailing worked
|
// This loads the image only if thumbnailing worked
|
||||||
|
let icon = widget::icon::icon(self.icon_handle_grid.clone())
|
||||||
|
.content_fit(ContentFit::Contain)
|
||||||
|
.size(sizes.grid())
|
||||||
|
.into();
|
||||||
match self
|
match self
|
||||||
.thumbnail_opt
|
.thumbnail_opt
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.unwrap_or(&ItemThumbnail::NotImage)
|
.unwrap_or(&ItemThumbnail::NotImage)
|
||||||
{
|
{
|
||||||
ItemThumbnail::NotImage => widget::icon::icon(self.icon_handle_grid.clone())
|
ItemThumbnail::NotImage => icon,
|
||||||
.content_fit(ContentFit::Contain)
|
|
||||||
.size(sizes.grid())
|
|
||||||
.into(),
|
|
||||||
ItemThumbnail::Rgba(_) => {
|
ItemThumbnail::Rgba(_) => {
|
||||||
widget::image::viewer(widget::image::Handle::from_path(&self.path))
|
if let Some(path) = &self.path_opt {
|
||||||
|
widget::image::viewer(widget::image::Handle::from_path(path))
|
||||||
.min_scale(1.0)
|
.min_scale(1.0)
|
||||||
.into()
|
.into()
|
||||||
|
} else {
|
||||||
|
icon
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ItemThumbnail::Svg => {
|
||||||
|
if let Some(path) = &self.path_opt {
|
||||||
|
widget::Svg::from_path(path).into()
|
||||||
|
} else {
|
||||||
|
icon
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ItemThumbnail::Svg => widget::Svg::from_path(&self.path).into(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -532,6 +544,7 @@ impl Item {
|
||||||
|
|
||||||
column = column.push(widget::text(format!("Type: {}", self.mime)));
|
column = column.push(widget::text(format!("Type: {}", self.mime)));
|
||||||
|
|
||||||
|
if let Some(path) = &self.path_opt {
|
||||||
for app in self.open_with.iter() {
|
for app in self.open_with.iter() {
|
||||||
column = column.push(
|
column = column.push(
|
||||||
widget::button(
|
widget::button(
|
||||||
|
|
@ -546,11 +559,12 @@ impl Item {
|
||||||
.spacing(space_xs),
|
.spacing(space_xs),
|
||||||
)
|
)
|
||||||
//TODO: do not clone so much?
|
//TODO: do not clone so much?
|
||||||
.on_press(app::Message::OpenWith(self.path.clone(), app.clone()))
|
.on_press(app::Message::OpenWith(path.clone(), app.clone()))
|
||||||
.padding(space_xs)
|
.padding(space_xs)
|
||||||
.width(Length::Fill),
|
.width(Length::Fill),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
column.into()
|
column.into()
|
||||||
}
|
}
|
||||||
|
|
@ -928,7 +942,7 @@ impl Tab {
|
||||||
if Some(i) == click_i_opt {
|
if Some(i) == click_i_opt {
|
||||||
// Filter out selection if it does not match dialog kind
|
// Filter out selection if it does not match dialog kind
|
||||||
if let Some(dialog) = &self.dialog {
|
if let Some(dialog) = &self.dialog {
|
||||||
let item_is_dir = item.path.is_dir();
|
let item_is_dir = item.metadata.is_dir();
|
||||||
if item_is_dir != dialog.is_dir() {
|
if item_is_dir != dialog.is_dir() {
|
||||||
// Allow selecting folder if dialog is for files to make it
|
// Allow selecting folder if dialog is for files to make it
|
||||||
// possible to double click
|
// possible to double click
|
||||||
|
|
@ -941,21 +955,18 @@ impl Tab {
|
||||||
item.selected = true;
|
item.selected = true;
|
||||||
if let Some(click_time) = item.click_time {
|
if let Some(click_time) = item.click_time {
|
||||||
if click_time.elapsed() < DOUBLE_CLICK_DURATION {
|
if click_time.elapsed() < DOUBLE_CLICK_DURATION {
|
||||||
match self.location {
|
if let Some(path) = &item.path_opt {
|
||||||
Location::Path(_) => {
|
if path.is_dir() {
|
||||||
if item.path.is_dir() {
|
|
||||||
//TODO: allow opening multiple tabs?
|
//TODO: allow opening multiple tabs?
|
||||||
cd = Some(Location::Path(item.path.clone()));
|
cd = Some(Location::Path(path.clone()));
|
||||||
} else {
|
} else {
|
||||||
commands.push(Command::OpenFile(item.path.clone()));
|
commands.push(Command::OpenFile(path.clone()));
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
Location::Trash => {
|
|
||||||
//TODO: open properties?
|
//TODO: open properties?
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
//TODO: prevent triple-click and beyond from opening file?
|
//TODO: prevent triple-click and beyond from opening file?
|
||||||
item.click_time = Some(Instant::now());
|
item.click_time = Some(Instant::now());
|
||||||
} else if mod_ctrl {
|
} else if mod_ctrl {
|
||||||
|
|
@ -1148,23 +1159,20 @@ impl Tab {
|
||||||
if let Some(ref mut items) = self.items_opt {
|
if let Some(ref mut items) = self.items_opt {
|
||||||
for item in items.iter() {
|
for item in items.iter() {
|
||||||
if item.selected {
|
if item.selected {
|
||||||
match self.location {
|
if let Some(path) = &item.path_opt {
|
||||||
Location::Path(_) => {
|
if path.is_dir() {
|
||||||
if item.path.is_dir() {
|
|
||||||
//TODO: allow opening multiple tabs?
|
//TODO: allow opening multiple tabs?
|
||||||
cd = Some(Location::Path(item.path.clone()));
|
cd = Some(Location::Path(path.clone()));
|
||||||
} else {
|
} else {
|
||||||
commands.push(Command::OpenFile(item.path.clone()));
|
commands.push(Command::OpenFile(path.clone()));
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
Location::Trash => {
|
|
||||||
//TODO: open properties?
|
//TODO: open properties?
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
Message::Resize(size) => {
|
Message::Resize(size) => {
|
||||||
self.size_opt = Some(size);
|
self.size_opt = Some(size);
|
||||||
}
|
}
|
||||||
|
|
@ -1198,7 +1206,7 @@ impl Tab {
|
||||||
Message::Thumbnail(path, thumbnail) => {
|
Message::Thumbnail(path, thumbnail) => {
|
||||||
if let Some(ref mut items) = self.items_opt {
|
if let Some(ref mut items) = self.items_opt {
|
||||||
for item in items.iter_mut() {
|
for item in items.iter_mut() {
|
||||||
if item.path == path {
|
if item.path_opt.as_ref() == Some(&path) {
|
||||||
if let ItemThumbnail::Rgba(rgba) = &thumbnail {
|
if let ItemThumbnail::Rgba(rgba) = &thumbnail {
|
||||||
//TODO: pass handles already generated to avoid blocking main thread
|
//TODO: pass handles already generated to avoid blocking main thread
|
||||||
let handle = widget::icon::from_raster_pixels(
|
let handle = widget::icon::from_raster_pixels(
|
||||||
|
|
@ -1299,7 +1307,7 @@ impl Tab {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
HeadingOptions::Name => items.sort_by(|a, b| {
|
HeadingOptions::Name => items.sort_by(|a, b| {
|
||||||
let ord = match (a.1.path.is_dir(), b.1.path.is_dir()) {
|
let ord = match (a.1.metadata.is_dir(), b.1.metadata.is_dir()) {
|
||||||
(true, false) => Ordering::Less,
|
(true, false) => Ordering::Less,
|
||||||
(false, true) => Ordering::Greater,
|
(false, true) => Ordering::Greater,
|
||||||
_ => lexical_sort::natural_lexical_cmp(&a.1.name, &b.1.name),
|
_ => lexical_sort::natural_lexical_cmp(&a.1.name, &b.1.name),
|
||||||
|
|
@ -1904,7 +1912,7 @@ impl Tab {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let path = item.path.clone();
|
if let Some(path) = item.path_opt.clone() {
|
||||||
subscriptions.push(subscription::channel(
|
subscriptions.push(subscription::channel(
|
||||||
path.clone(),
|
path.clone(),
|
||||||
1,
|
1,
|
||||||
|
|
@ -1950,6 +1958,7 @@ impl Tab {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
));
|
));
|
||||||
|
}
|
||||||
|
|
||||||
if subscriptions.len() >= jobs {
|
if subscriptions.len() >= jobs {
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue