use crate::qml::{QmlFile, QmlUri};
use std::ffi::OsStr;
use std::io;
pub struct QmlDirBuilder {
class_name: Option<String>,
depends: Vec<QmlUri>,
plugin: Option<(bool, String)>,
type_info: Option<String>,
uri: QmlUri,
qml_files: Vec<QmlFile>,
}
impl QmlDirBuilder {
pub fn new(uri: QmlUri) -> Self {
Self {
class_name: None,
depends: vec![],
plugin: None,
type_info: None,
qml_files: vec![],
uri,
}
}
pub fn write(self, writer: &mut impl io::Write) -> io::Result<()> {
writeln!(writer, "module {}", self.uri.as_dots())?;
if let Some((optional, name)) = self.plugin {
if optional {
writeln!(writer, "optional plugin {name}")?;
} else {
writeln!(writer, "plugin {name}")?;
}
}
if let Some(name) = self.class_name {
writeln!(writer, "classname {name}")?;
}
if let Some(file) = self.type_info {
writeln!(writer, "typeinfo {file}")?;
}
for depend in self.depends {
writeln!(writer, "depends {depend}")?;
}
writeln!(writer, "prefer :/qt/qml/{}/", self.uri.as_dirs())?;
for qml_file in &self.qml_files {
let is_qml_file = qml_file
.get_path()
.extension()
.map(|ext| ext.eq_ignore_ascii_case("qml"))
.unwrap_or_default();
if !is_qml_file {
panic!(
"QML file does not end with .qml: {}",
qml_file.get_path().display(),
);
}
let path = qml_file.get_path().display();
let qml_component_name = qml_file
.get_path()
.file_stem()
.and_then(OsStr::to_str)
.expect("Could not get qml file stem");
let singleton = if qml_file.is_singleton() {
"singleton "
} else {
""
};
let version = if let Some((major, minor)) = qml_file.get_version() {
format!("{}.{}", major, minor)
} else {
"254.0".to_string()
};
writeln!(writer, "{singleton}{qml_component_name} {version} {path}",)
.expect("Could not write qmldir file");
}
Ok(())
}
pub fn class_name(mut self, class_name: impl Into<String>) -> Self {
self.class_name = Some(class_name.into());
self
}
pub fn depend(mut self, depend: impl Into<QmlUri>) -> Self {
self.depends.push(depend.into());
self
}
pub fn depends<T: Into<QmlUri>>(mut self, depends: impl IntoIterator<Item = T>) -> Self {
self.depends.extend(depends.into_iter().map(Into::into));
self
}
pub fn plugin(mut self, name: impl Into<String>, optional: bool) -> Self {
if self.plugin.is_some() {
panic!("Only zero or one plugin is supported currently");
}
self.plugin = Some((optional, name.into()));
self
}
pub fn qml_files(mut self, qml_files: impl IntoIterator<Item = impl Into<QmlFile>>) -> Self {
self.qml_files
.extend(qml_files.into_iter().map(|p| p.into()));
self
}
pub fn type_info(mut self, file: impl Into<String>) -> Self {
self.type_info = Some(file.into());
self
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn qml_dir() {
let mut result = Vec::new();
QmlDirBuilder::new(QmlUri::new(["com", "kdab"]))
.class_name("C")
.depends(["QtQuick", "com.kdab.a"])
.plugin("P", true)
.type_info("T")
.qml_files(["qml/Test.qml"])
.qml_files([QmlFile::from("qml/MySingleton.qml")
.singleton(true)
.version(1, 0)])
.qml_files([QmlFile::from("../AnotherFile.qml").version(2, 123)])
.write(&mut result)
.unwrap();
assert_eq!(
String::from_utf8(result).unwrap(),
"module com.kdab
optional plugin P
classname C
typeinfo T
depends QtQuick
depends com.kdab.a
prefer :/qt/qml/com/kdab/
Test 254.0 qml/Test.qml
singleton MySingleton 1.0 qml/MySingleton.qml
AnotherFile 2.123 ../AnotherFile.qml
"
);
}
}