dialogs: use FileChooserNative whenever possible

we still have a missing one until the latest in xdg-desktop-poratls
gets distributed widely, for now we will have to live with home permission :(
parent f7ee00a1
Pipeline #184739 passed with stage
in 16 minutes and 36 seconds
......@@ -51,7 +51,6 @@
.recents-listbox{
background: @theme_bg_color;
border: 1px solid mix(@theme_fg_color, @theme_bg_color, 0.8);
}
.recents-listbox row {
border-bottom: 1px solid mix(@theme_fg_color, @theme_bg_color, 0.9);
......
......@@ -12,6 +12,9 @@
<object class="GtkScrolledWindow">
<property name="visible">True</property>
<property name="can_focus">True</property>
<style>
<class name="frame"/>
</style>
<child>
<object class="GtkViewport">
<property name="visible">True</property>
......@@ -23,7 +26,6 @@
<property name="can_focus">False</property>
<property name="selection_mode">none</property>
<style>
<class name="frame"/>
<class name="recents-listbox"/>
</style>
</object>
......
......@@ -8,7 +8,6 @@ use std::env;
use std::rc::Rc;
use crate::config;
use crate::recents::RecentManager;
use crate::widgets::Window;
pub enum Action {
......@@ -21,7 +20,6 @@ pub struct Application {
windows: Rc<RefCell<HashMap<gtk::Window, Rc<Window>>>>,
sender: Sender<Action>,
receiver: RefCell<Option<Receiver<Action>>>,
history: RecentManager,
}
impl Application {
......@@ -36,7 +34,6 @@ impl Application {
windows: Rc::new(RefCell::new(HashMap::new())),
sender,
receiver,
history: RecentManager::new(),
});
application.setup_signals(application.clone());
......@@ -50,7 +47,7 @@ impl Application {
}
fn create_window(&self) -> Rc<Window> {
let window = Window::new(&self.history, self.sender.clone());
let window = Window::new(self.sender.clone());
window.widget.set_application(Some(&self.app));
self.app.add_window(&window.widget);
......@@ -132,7 +129,6 @@ impl Application {
fn do_action(&self, action: Action) -> glib::Continue {
match action {
Action::OpenProject(project) => {
self.history.add(project.path());
self.get_window().set_open_project(project);
}
Action::NewProject(project_dest) => match Project::from_template(project_dest) {
......
......@@ -16,7 +16,6 @@ mod common;
mod config;
mod object_wrapper;
mod project;
mod recents;
mod settings;
mod static_resources;
mod widgets;
......
......@@ -53,7 +53,6 @@ sources = files(
'main.rs',
'object_wrapper.rs',
'project.rs',
'recents.rs',
'settings.rs',
'static_resources.rs',
)
......
......@@ -4,7 +4,6 @@ use gettextrs::gettext;
use gio::prelude::FileExt;
use gtk::prelude::*;
use librsvg::{CairoRenderer, Loader};
use std::path::PathBuf;
#[derive(PartialEq, Debug, Clone)]
pub enum ProjectType {
......@@ -59,8 +58,8 @@ impl Project {
filename.to_string()
}
pub fn path(&self) -> PathBuf {
self.file.get_path().unwrap()
pub fn uri(&self) -> String {
self.file.get_uri().to_string()
}
#[allow(dead_code)]
......
use gio::prelude::*;
use std::path::{Path, PathBuf};
use crate::object_wrapper::ObjectWrapper;
use crate::settings::{Key, SettingsManager};
#[derive(Clone, Serialize, Deserialize)]
pub struct RecentItem {
pub path: PathBuf,
}
pub struct RecentManager {
pub model: gio::ListStore,
}
impl RecentManager {
pub fn new() -> Self {
let model = gio::ListStore::new(ObjectWrapper::static_type());
let recents_manager = Self { model };
recents_manager.init();
recents_manager
}
fn init(&self) {
let history = RecentManager::get_history();
for item in history {
let object = ObjectWrapper::new(Box::new(RecentItem { path: item }));
self.model.insert(0, &object);
}
}
pub fn get_history() -> Vec<PathBuf> {
// As gtk-rs doesn't have bindings for array gvariants
// we will store the history in gsettings as a comma sperated string instead
// Hopefully we can ditch this in the future.
let recent_files = SettingsManager::get_string(Key::RecentFiles);
recent_files.split(';').map(|file| Path::new(file).to_path_buf()).filter(|path| path.exists()).collect::<Vec<PathBuf>>()
}
pub fn store(history: Vec<PathBuf>) {
let recent_files = history.iter().map(|path| path.to_str().unwrap()).collect::<Vec<&str>>().join(";");
SettingsManager::set_string(Key::RecentFiles, recent_files);
}
fn index(&self, item: &RecentItem) -> Option<u32> {
for i in 0..self.model.get_n_items() {
let gobject = self.model.get_object(i).unwrap();
let a: RecentItem = gobject.downcast_ref::<ObjectWrapper>().unwrap().deserialize();
if item.path == a.path {
return Some(i);
}
}
None
}
pub fn add(&self, path: PathBuf) {
if path.exists() {
let mut history = RecentManager::get_history();
let item = RecentItem { path };
if history.contains(&item.path) {
history.retain(|p| p != &item.path); // Delete the old elements
}
if let Some(index) = self.index(&item) {
self.model.remove(index);
}
history.push(item.path.clone());
self.model.insert(0, &ObjectWrapper::new(Box::new(item)));
RecentManager::store(history);
}
}
}
......@@ -8,16 +8,9 @@ pub enum Key {
WindowHeight,
WindowX,
WindowY,
RecentFiles,
IsMaximized,
}
impl PartialEq<&str> for Key {
fn eq(&self, other: &&str) -> bool {
other == &self.to_string().as_str()
}
}
pub struct SettingsManager {}
impl SettingsManager {
......@@ -26,19 +19,6 @@ impl SettingsManager {
gio::Settings::new(app_id)
}
pub fn get_string(key: Key) -> String {
let settings = Self::get_settings();
settings.get_string(&key.to_string()).unwrap().to_string()
}
pub fn set_string(key: Key, value: String) {
let settings = Self::get_settings();
if let Err(err) = settings.set_string(&key.to_string(), &value) {
warn!("Failed to set {} to {} due to {}", key.to_string(), value, err);
}
}
pub fn get_boolean(key: Key) -> bool {
let settings = Self::get_settings();
settings.get_boolean(&key.to_string())
......
......@@ -50,18 +50,23 @@ impl NewProjectDialog {
(&gettext("Select"), gtk::ResponseType::Accept),
(&gettext("Cancel"), gtk::ResponseType::Cancel)
]);
if dialog.run() == gtk::ResponseType::Accept {
get_widget!(builder, gtk::Entry, project_path);
let home = glib::get_home_dir().unwrap();
let home = home.to_str().unwrap();
let dest = dialog.get_file().unwrap().get_path().unwrap();
let dest = dest.to_str().unwrap();
let dest = dest.replacen(&home, "~", 1);
dialog.connect_response(clone!(@strong builder => move |dialog, response| {
project_path.set_text(&dest);
}
dialog.destroy();
if response == gtk::ResponseType::Accept {
get_widget!(builder, gtk::Entry, project_path);
let home = glib::get_home_dir().unwrap();
let home = home.to_str().unwrap();
let dest = dialog.get_file().unwrap().get_path().unwrap();
let dest = dest.to_str().unwrap();
let dest = dest.replacen(&home, "~", 1);
project_path.set_text(&dest);
}
}));
dialog.show();
}));
get_widget!(self.builder, gtk::Entry, project_name);
......
......@@ -2,6 +2,11 @@ use gtk::prelude::*;
use crate::project::Project;
#[derive(Clone, Serialize, Deserialize)]
pub struct RecentItem {
pub uri: String,
}
pub struct RecentItemRow {
pub widget: gtk::FlowBoxChild,
pub event_box: gtk::EventBox,
......
mod item;
mod popover;
use item::RecentItem;
pub use popover::RecentsPopover;
use super::item::RecentItemRow;
use gio::prelude::*;
use glib::Sender;
use gtk::prelude::*;
use crate::application::Action;
use crate::object_wrapper::ObjectWrapper;
use crate::project::Project;
use crate::recents::RecentItem;
use crate::widgets::recents::RecentItem;
pub struct RecentsPopover {
pub widget: gtk::Popover,
builder: gtk::Builder,
sender: Sender<Action>,
model: gio::ListStore,
}
impl RecentsPopover {
pub fn new(history_model: &gio::ListStore, sender: Sender<Action>) -> Self {
pub fn new(sender: Sender<Action>) -> Self {
let builder = gtk::Builder::new_from_resource("/org/gnome/design/AppIconPreview/recents_popover.ui");
get_widget!(builder, gtk::Popover, recents_popover);
let model = gio::ListStore::new(ObjectWrapper::static_type());
let recents = Self {
widget: recents_popover,
builder,
sender,
model,
};
recents.init(history_model);
recents.init();
recents
}
fn init(&self, history_model: &gio::ListStore) {
fn init(&self) {
get_widget!(self.builder, gtk::ListBox, items_listbox);
items_listbox.bind_model(
Some(history_model),
Some(&self.model),
clone!(@strong self.sender as sender, @strong self.widget as popover => move |item| {
let item: RecentItem = item.downcast_ref::<ObjectWrapper>().unwrap().deserialize();
let project = Project::parse(gio::File::new_for_path(item.path)).unwrap();
let project = Project::parse(gio::File::new_for_uri(&item.uri)).unwrap();
let row = RecentItemRow::new(project.clone());
row.event_box.connect_button_press_event(clone!(@strong project, @strong sender, @strong popover => move |_, _| {
......@@ -44,5 +49,31 @@ impl RecentsPopover {
row.widget.upcast::<gtk::Widget>()
}),
);
if let Some(manager) = gtk::RecentManager::get_default() {
let model = self.model.clone();
let on_manager_changed = move |manager: &gtk::RecentManager| {
manager.get_items().into_iter().for_each(clone!(@strong model => move |item| {
let uri = item.get_uri().unwrap().to_string();
let file = gio::File::new_for_uri(&uri);
let mut exist_already = false;
for i in 0..model.get_n_items() {
let current_item: RecentItem = model.get_object(i).unwrap()
.downcast_ref::<ObjectWrapper>().unwrap().deserialize();
if current_item.uri == uri {
exist_already = true;
break;
}
}
if !exist_already && Project::parse(file).is_ok() {
let object = ObjectWrapper::new(Box::new(RecentItem { uri }));
model.append(&object);
}
}));
};
on_manager_changed(&manager);
manager.connect_changed(on_manager_changed);
}
}
}
......@@ -2,7 +2,6 @@ use super::{ExportPopover, NewProjectDialog, ProjectPreviewer, RecentsPopover, S
use crate::application::Action;
use crate::config::PROFILE;
use crate::project::Project;
use crate::recents::RecentManager;
use crate::settings::{Key, SettingsManager};
use gettextrs::gettext;
......@@ -28,7 +27,7 @@ pub struct Window {
}
impl Window {
pub fn new(history: &RecentManager, sender: glib::Sender<Action>) -> Rc<Self> {
pub fn new(sender: glib::Sender<Action>) -> Rc<Self> {
let builder = gtk::Builder::new_from_resource("/org/gnome/design/AppIconPreview/window.ui");
get_widget!(builder, gtk::ApplicationWindow, window);
let previewer = ProjectPreviewer::new();
......@@ -44,7 +43,7 @@ impl Window {
});
window_widget.init();
window_widget.setup_widgets(history);
window_widget.setup_widgets();
window_widget.setup_actions();
window_widget.set_view(View::Initial);
window_widget
......@@ -55,6 +54,10 @@ impl Window {
self.previewer.preview(&project);
self.exporter.set_project(&project);
if let Some(recent_manager) = gtk::RecentManager::get_default() {
recent_manager.add_item(&project.uri());
}
let monitor = project.file.monitor_file(gio::FileMonitorFlags::all(), gio::NONE_CANCELLABLE).unwrap();
self.monitor.borrow_mut().replace(monitor);
......@@ -96,7 +99,7 @@ impl Window {
};
}
fn setup_widgets(&self, history: &RecentManager) {
fn setup_widgets(&self) {
get_widget!(self.builder, gtk::MenuButton, open_menu_btn);
let builder = gtk::Builder::new_from_resource("/org/gnome/design/AppIconPreview/help-overlay.ui");
......@@ -112,7 +115,7 @@ impl Window {
// Recents Popover
get_widget!(self.builder, gtk::MenuButton, recents_btn);
let recents_popover = RecentsPopover::new(&history.model, self.sender.clone());
let recents_popover = RecentsPopover::new(self.sender.clone());
recents_btn.set_popover(Some(&recents_popover.widget));
// Export Popover
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment