use crate::core::{reflect::prelude::*, visitor::prelude::*};
use std::fmt::Display;
use std::ops::Index;
use std::path::PathBuf;
use std::{
fmt::{Debug, Formatter},
path::Path,
};
#[derive(Default, Clone, Debug, Visit, Reflect, PartialEq)]
pub struct FileType {
pub description: String,
pub extension: String,
}
impl FileType {
pub fn new() -> Self {
Self::default()
}
pub fn new_extension(extension: impl AsRef<str>) -> Self {
Self {
description: Default::default(),
extension: extension.as_ref().to_string(),
}
}
pub fn with_description(mut self, description: impl AsRef<str>) -> Self {
self.description = description.as_ref().to_string();
self
}
pub fn with_extension(mut self, extension: impl AsRef<str>) -> Self {
self.extension = extension.as_ref().to_string();
self
}
pub fn matches(&self, path: &Path) -> bool {
path.extension()
.is_some_and(|ext| ext.to_string_lossy() == self.extension)
}
pub fn make_file_name(&self, name: &str) -> PathBuf {
let mut file_name = PathBuf::from(name);
file_name.set_extension(&self.extension);
file_name
}
}
impl Display for FileType {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{} (*.{})", self.description, self.extension)
}
}
#[derive(Default, Clone, Debug, Visit, Reflect, PartialEq)]
pub struct PathFilter {
pub folders_only: bool,
pub types: Vec<FileType>,
}
impl Index<usize> for PathFilter {
type Output = FileType;
fn index(&self, index: usize) -> &Self::Output {
self.types.index(index)
}
}
impl PathFilter {
pub fn new() -> Self {
Self::default()
}
pub fn with_file_type(mut self, file_type: FileType) -> Self {
self.types.push(file_type);
self
}
pub fn folder() -> Self {
Self {
folders_only: true,
types: Default::default(),
}
}
pub fn supports_all(&self, path: &Path) -> bool {
if self.folders_only {
path.is_dir()
} else {
path.is_dir()
|| self.is_empty()
|| self.types.iter().any(|file_type| file_type.matches(path))
}
}
pub fn supports_specific_type(&self, path: &Path, index: Option<usize>) -> bool {
if self.folders_only {
path.is_dir()
} else if let Some(index) = index {
self.types
.get(index)
.is_some_and(|file_type| file_type.matches(path))
} else {
self.is_empty() || self.types.iter().any(|file_type| file_type.matches(path))
}
}
pub fn len(&self) -> usize {
self.types.len()
}
pub fn is_empty(&self) -> bool {
self.types.is_empty()
}
pub fn iter(&self) -> impl Iterator<Item = &FileType> {
self.types.iter()
}
pub fn get(&self, i: usize) -> Option<&FileType> {
self.types.get(i)
}
}