native-dialog 0.9.6

A library to display dialogs. Supports GNU/Linux, BSD Unix, macOS and Windows.
Documentation
use objc2::rc::Retained as Id;
use objc2::{DefinedClass, MainThreadOnly, define_class, msg_send};
use objc2_app_kit::{NSOpenPanel, NSOpenSavePanelDelegate};
use objc2_foundation::{NSObject, NSObjectProtocol, NSURL};

use super::{NSOpenPanelExt, NSURLExt};
use crate::dialog::FileFiltersBag;

pub struct OpenPanelDelegateIvars {
    filters: FileFiltersBag,
}

define_class! {
    #[unsafe(super = NSObject)]
    #[thread_kind = MainThreadOnly]
    #[ivars = OpenPanelDelegateIvars]
    pub struct OpenPanelDelegate;

    unsafe impl NSObjectProtocol for OpenPanelDelegate {}

    unsafe impl NSOpenSavePanelDelegate for OpenPanelDelegate {
        #[unsafe(method(panel:shouldEnableURL:))]
        unsafe fn should_enable_url(&self, _sender: &NSOpenPanel, url: &NSURL) -> bool {
            self.selectable(url)
        }
    }
}

impl OpenPanelDelegate {
    pub fn attach(panel: &NSOpenPanel, filters: &FileFiltersBag) -> Id<Self> {
        let ivars = OpenPanelDelegateIvars {
            filters: filters.to_owned(),
        };

        let this = Self::alloc(panel.mtm()).set_ivars(ivars);
        let this: Id<Self> = unsafe { msg_send![super(this), init] };

        panel.set_delegate(&this);

        this
    }

    fn selectable(&self, url: &NSURL) -> bool {
        if url.hasDirectoryPath() {
            return true;
        }

        let Some(path) = url.to_path_buf() else {
            return false;
        };

        self.ivars().filters.accepts(&path)
    }
}