2023-10-27 11:43:30 -06:00
|
|
|
// SPDX-License-Identifier: GPL-3.0-only
|
|
|
|
|
|
2024-03-04 12:34:02 -07:00
|
|
|
use cosmic::widget::icon;
|
|
|
|
|
use cosmic_files::mime_icon::{mime_for_path, mime_icon};
|
2023-10-26 10:15:09 -06:00
|
|
|
use std::{
|
2023-10-27 12:28:25 -06:00
|
|
|
cmp::Ordering,
|
2023-10-26 10:15:09 -06:00
|
|
|
fs, io,
|
|
|
|
|
path::{Path, PathBuf},
|
|
|
|
|
};
|
|
|
|
|
|
2024-03-04 12:34:02 -07:00
|
|
|
use crate::icon_cache_get;
|
2023-11-13 10:33:26 -07:00
|
|
|
|
2023-10-27 12:28:25 -06:00
|
|
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
2023-10-27 11:43:30 -06:00
|
|
|
pub enum ProjectNode {
|
|
|
|
|
Folder {
|
|
|
|
|
name: String,
|
|
|
|
|
path: PathBuf,
|
|
|
|
|
open: bool,
|
2023-10-27 12:28:25 -06:00
|
|
|
root: bool,
|
2023-10-27 11:43:30 -06:00
|
|
|
},
|
|
|
|
|
File {
|
|
|
|
|
name: String,
|
|
|
|
|
path: PathBuf,
|
|
|
|
|
},
|
2023-10-26 10:15:09 -06:00
|
|
|
}
|
|
|
|
|
|
2023-10-27 11:43:30 -06:00
|
|
|
impl ProjectNode {
|
2023-10-26 10:15:09 -06:00
|
|
|
pub fn new<P: AsRef<Path>>(path: P) -> io::Result<Self> {
|
|
|
|
|
let path = fs::canonicalize(path)?;
|
|
|
|
|
let name = path
|
|
|
|
|
.file_name()
|
|
|
|
|
.ok_or(io::Error::new(
|
|
|
|
|
io::ErrorKind::Other,
|
2023-10-27 11:43:30 -06:00
|
|
|
format!("path {:?} has no file name", path),
|
2023-10-26 10:15:09 -06:00
|
|
|
))?
|
|
|
|
|
.to_str()
|
|
|
|
|
.ok_or(io::Error::new(
|
|
|
|
|
io::ErrorKind::Other,
|
2023-10-27 11:43:30 -06:00
|
|
|
format!("path {:?} is not valid UTF-8", path),
|
2023-10-26 10:15:09 -06:00
|
|
|
))?
|
|
|
|
|
.to_string();
|
2023-10-27 11:43:30 -06:00
|
|
|
Ok(if path.is_dir() {
|
|
|
|
|
Self::Folder {
|
|
|
|
|
path,
|
|
|
|
|
name,
|
|
|
|
|
open: false,
|
2023-10-27 12:28:25 -06:00
|
|
|
root: false,
|
2023-10-27 11:43:30 -06:00
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
Self::File { path, name }
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
2024-03-04 12:34:02 -07:00
|
|
|
pub fn icon(&self, size: u16) -> icon::Icon {
|
2023-10-27 11:43:30 -06:00
|
|
|
match self {
|
2023-10-27 12:28:25 -06:00
|
|
|
//TODO: different icon for project root?
|
2023-11-28 13:07:27 -07:00
|
|
|
Self::Folder { open, .. } => {
|
|
|
|
|
if *open {
|
|
|
|
|
icon_cache_get("go-down-symbolic", size)
|
|
|
|
|
} else {
|
|
|
|
|
icon_cache_get("go-next-symbolic", size)
|
|
|
|
|
}
|
|
|
|
|
}
|
2024-03-04 12:34:02 -07:00
|
|
|
Self::File { path, .. } => icon::icon(mime_icon(mime_for_path(path), size)).size(size),
|
2023-10-27 11:43:30 -06:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn name(&self) -> &str {
|
|
|
|
|
match self {
|
2023-10-27 12:28:25 -06:00
|
|
|
Self::Folder { name, .. } => name,
|
|
|
|
|
Self::File { name, .. } => name,
|
2023-10-27 11:43:30 -06:00
|
|
|
}
|
2023-10-26 10:15:09 -06:00
|
|
|
}
|
|
|
|
|
}
|
2023-10-27 12:28:25 -06:00
|
|
|
|
|
|
|
|
impl Ord for ProjectNode {
|
|
|
|
|
fn cmp(&self, other: &Self) -> Ordering {
|
|
|
|
|
match self {
|
|
|
|
|
// Folders are always before files
|
2023-12-25 13:06:02 -05:00
|
|
|
Self::Folder { .. } => {
|
|
|
|
|
if let Self::File { .. } = other {
|
|
|
|
|
return Ordering::Less;
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-11-02 14:35:20 -06:00
|
|
|
// Files are always after folders
|
2023-12-25 13:06:02 -05:00
|
|
|
Self::File { .. } => {
|
|
|
|
|
if let Self::Folder { .. } = other {
|
|
|
|
|
return Ordering::Greater;
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-10-27 12:28:25 -06:00
|
|
|
}
|
2024-07-09 01:45:13 -04:00
|
|
|
crate::localize::sorter().compare(self.name(), other.name())
|
2023-10-27 12:28:25 -06:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl PartialOrd for ProjectNode {
|
|
|
|
|
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
|
|
|
|
Some(self.cmp(other))
|
|
|
|
|
}
|
|
|
|
|
}
|