main.rs 2.85 KB
extern crate qml;

use std::io;
use std::fs;
use std::path::{Path, PathBuf};
use qml::*;

Q_LISTMODEL_ITEM!{
    pub QDirModel<FileItem> {
        file_name: String,
        is_dir: bool,
    }
}

pub struct DirLister {
    current_dir: PathBuf,
    model: QDirModel,
}

impl QDirLister {
    fn change_directory(&mut self, dir_name: String) -> Option<&QVariant> {
        let new_dir = if dir_name == ".." {
            // go to parent if there is a parent
            self.current_dir.parent().unwrap_or(&self.current_dir).to_owned()
        } else {
            self.current_dir.join(dir_name)
        };
        if let Err(err) = list_dir(&new_dir, &mut self.model) {
            self.error(format!("Error listing {}: {}",
                               self.current_dir.to_string_lossy(),
                               err));
            return None;
        }
        // listing the directory succeeded so update the current_dir
        self.current_dir = new_dir;
        None
    }
}

Q_OBJECT!{
    pub DirLister as QDirLister {
        signals:
            fn error(message: String);
        slots:
            fn change_directory(dir_name: String);
        properties:
    }
}

fn list_dir(dir: &Path, model: &mut QDirModel) -> io::Result<()> {
    // get sorted list of readable entries
    let mut entries = fs::read_dir(dir)?.filter_map(|e| e.ok()).collect::<Vec<_>>();
    entries.sort_by(|a, b| a.file_name().cmp(&b.file_name()));

    model.clear();
    // add entry .. if not at root
    if dir.parent().is_some() {
        model.append_item(FileItem {
            file_name: "..".into(),
            is_dir: true,
        });
    }
    // add other entries
    for entry in entries {
        if let Ok(metadata) = entry.metadata() {
            if let Ok(file_name) = entry.file_name().into_string() {
                model.append_item(FileItem {
                    file_name: file_name,
                    is_dir: metadata.is_dir(),
                });
            }
        }
    }
    Ok(())
}

fn main() {
    // Create a new QML Engine.
    let mut engine = QmlEngine::new();

    // Create a model with files.
    let dir_str = ".";
    let current_dir = fs::canonicalize(dir_str)
        .expect(&format!("Could not canonicalize {}.", dir_str));
    let mut dir_model = QDirModel::new();
    list_dir(&current_dir, &mut dir_model).expect("Could not read directory.");
    engine.set_and_store_property("dirModel", &dir_model);

    // Create a DirLister and pass it to QML
    let dir_lister = DirLister {
        model: dir_model,
        current_dir: current_dir.into(),
    };
    let q_dir_lister = QDirLister::new(dir_lister);
    engine.set_and_store_property("dirLister", q_dir_lister.get_qobj());

    // Load some QML
#[cfg(debug_assertions)]
    engine.load_file("src/sousa.qml");
#[cfg(not(debug_assertions))]
    engine.load_data(include_str!("sousa.qml"));
    engine.exec();
}