Программирование кнопки Open
Самое время запрограммировать логику работы кнопок Open, Save, Save As в нашем пользовательском интерфейсе. Начнём с реализации кнопки Open, создав новый метод open_file(), который будет вызван из метода connect_events().
Кнопка Open
Функция кнопки open_file() получит доступ к переменной current_file, которая будет обновлена после успешного открытия выбранного файла.
#![allow(unused_variables)]
fn main() {
pub fn connect_events(self) -> ConnectedApp {
// Внешнее состояние, которое доступно для событий.
let current_file = Arc::new(RwLock::new(None));
// Подсоединить события, обрабатываемые пользовательским интерфейсом.
self.editor_changed(current_file.clone(), &self.header.save.clone());
self.open_file(current_file.clone());
// Обернуть `ConnectedApp` вокруг `App` для того, чтобы дать возможность
// разработчику выполнить программу.
ConnectedApp(self)
}
}
connect_clicked()
Метод open_file() будет получать:
- ссылки на буфер редактора и писать информацию из открытого файла в буфер.
- ссылки на панель web просмотра, так что мы сможем обновлять её после открытия файла.
- ссылку на заголовочную панель, так что мы сможем обновлять название.
- кнопку Open, так что мы сможем отобразить событие connect_clicked() на неё.
#![allow(unused_variables)]
fn main() {
fn open_file(&self, current_file: Arc<RwLock<Option<ActiveMetadata>>>) {
let editor = self.content.source.buff.clone();
let preview = self.content.preview.clone();
let headerbar = self.header.container.clone();
self.header.open.connect_clicked(move |_| {
// Программировать кнопку здесь.
});
}
}
Создание OpenDialog
Создадим новый OpenDialog внутри connect_clicked(). Открывая диалоговое окно, мы попытаемся передать родительскую директорию в current_file, если она существует, поэтому окно для открытия файла по умолчанию использует данную директорию.
Заметьте, я здесь использую if let Some(ref path), а не просто map из-за ограничений на заимствования - если нельзя добиться того, что map будет правильно заимствовать, следует использовать match или if let.
#![allow(unused_variables)]
fn main() {
// Создать диалоговое окно для открытия файла, используя родительскую
// директорию в качестве предпочитаемой, если он установлен.
let open_dialog = OpenDialog::new({
let lock = current_file.read().unwrap();
if let Some(ref path) = *lock {
path.get_dir()
} else {
None
}
});
}
Запуск диалогового окна
После получения переменной open_dialog, мы можем запустить диалог, а также:
- захватить выбранный путь к файлу
- считать данные из файла в буфер
- обновить панель для web просмотра
- обновить название
#![allow(unused_variables)]
fn main() {
// Запускает диалоговое окно и открывает файл, если он был выбран.
if let Some(new_file) = open_dialog.run() {
if let Ok(mut file) = File::open(&new_file) {
// Считать содержимое файла в находящийся в памяти буфер.
let mut contents = String::new();
let _ = file.read_to_string(&mut contents);
// Обновить название.
set_title(&headerbar, &new_file);
if let Some(parent) = new_file.parent() {
let subtitle: &str = &parent.to_string_lossy();
headerbar.set_subtitle(subtitle);
}
// Установить публично доступный путь к файлу.
*current_file.write().unwrap() =
Some(ActiveMetadata::new(new_file, &contents.as_bytes()));
// Обновить содержимое редактора и предпросмотровую панель.
editor.set_text(&contents);
preview.load_html(&render(&contents), None);
}
}
}
Полный код
#![allow(unused_variables)]
fn main() {
fn open_file(&self, current_file: Arc<RwLock<Option<ActiveMetadata>>>) {
let editor = self.content.source.buff.clone();
let preview = self.content.preview.clone();
let headerbar = self.header.container.clone();
self.header.open.connect_clicked(move |_| {
// Создать диалоговое окно для открытия файла, используя родительскую
// директорию в качестве предпочитаемой, если он установлен.
let open_dialog = OpenDialog::new({
let lock = current_file.read().unwrap();
if let Some(ref path) = *lock {
path.get_dir()
} else {
None
}
});
// Запускает диалоговое окно и открывает файл, если он был выбран.
if let Some(new_file) = open_dialog.run() {
if let Ok(mut file) = File::open(&new_file) {
// Считать содержимое файла в находящийся в памяти буфер.
let mut contents = String::new();
let _ = file.read_to_string(&mut contents);
// Обновить название.
set_title(&headerbar, &new_file);
if let Some(parent) = new_file.parent() {
let subtitle: &str = &parent.to_string_lossy();
headerbar.set_subtitle(subtitle);
}
// Установить публично доступный путь к файлу.
*current_file.write().unwrap() =
Some(ActiveMetadata::new(new_file, &contents.as_bytes()));
// Обновить содержимое редактора и предпросмотровую панель.
editor.set_text(&contents);
preview.load_html(&render(&contents), None);
}
}
});
}
}