Skip to content

Commit

Permalink
Implements data root saving for Linux (#1160)
Browse files Browse the repository at this point in the history
  • Loading branch information
ultimaweapon authored Dec 4, 2024
1 parent ec3fb53 commit 09a081c
Show file tree
Hide file tree
Showing 7 changed files with 137 additions and 116 deletions.
82 changes: 0 additions & 82 deletions gui/initialize_wizard.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
#include "initialize_wizard.hpp"
#include "settings.hpp"

#include <QDir>
#include <QFileDialog>
Expand All @@ -16,89 +15,9 @@
#define FIELD_GAMES_LOCATION "gamesLocation"

enum PageId {
PageGame,
PageFirmware,
};

class GamePage : public QWizardPage {
public:
GamePage() : m_input(nullptr)
{
auto layout = new QVBoxLayout();

// Page properties.
setTitle("Location to install games");
setSubTitle(
"The selected directory will be used for game installation. The directory "
"cannot be the same as the system directory.");

// Widgets.
layout->addLayout(setupInputRow());

setLayout(layout);
}

bool validatePage() override
{
auto path = m_input->text();

if (!QDir::isAbsolutePath(path)) {
QMessageBox::critical(this, "Error", "The specified location must be an absolute path.");
return false;
}

if (!QDir(path).exists()) {
QMessageBox::critical(this, "Error", "The specified location does not exist.");
return false;
}

if (path == field(FIELD_SYSTEM_LOCATION).toString()) {
QMessageBox::critical(this, "Error", "The specified location cannot be the same as the system directory.");
return false;
}

return true;
}
private:
QLayout *setupInputRow()
{
auto layout = new QHBoxLayout();

// Label.
auto label = new QLabel("&Location:");
layout->addWidget(label);

// Input.
m_input = new QLineEdit();
m_input->setText(readGamesDirectorySetting());

label->setBuddy(m_input);
layout->addWidget(m_input);

registerField(FIELD_GAMES_LOCATION "*", m_input);

// Browse button.
auto browse = new QPushButton("...");

connect(browse, &QPushButton::clicked, this, &GamePage::browseDirectory);

layout->addWidget(browse);

return layout;
}

void browseDirectory()
{
auto path = QFileDialog::getExistingDirectory(this, "Location to install games");

if (!path.isEmpty()) {
m_input->setText(QDir::toNativeSeparators(path));
}
}

QLineEdit *m_input;
};

class FirmwarePage : public QWizardPage {
public:
FirmwarePage() : m_input(nullptr)
Expand Down Expand Up @@ -162,7 +81,6 @@ InitializeWizard::InitializeWizard()
#endif

// Pages.
setPage(PageGame, new GamePage());
setPage(PageFirmware, new FirmwarePage());
}

Expand Down
46 changes: 41 additions & 5 deletions gui/src/setup/linux.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,49 @@
use std::ffi::OsString;
use std::io::ErrorKind;
use std::path::PathBuf;
use std::os::unix::ffi::{OsStrExt, OsStringExt};
use std::path::{Path, PathBuf};
use thiserror::Error;
use xdg::BaseDirectories;

pub fn read_data_root() -> Result<Option<PathBuf>, DataRootError> {
// Read config file.
let file = get_config_path()?;
let mut path = match std::fs::read(&file) {
Ok(v) => v,
Err(e) if e.kind() == ErrorKind::NotFound => return Ok(None),
Err(e) => return Err(DataRootError::ReadFile(file, e)),
};

match std::fs::read_to_string(&file) {
Ok(v) => Ok(Some(v.trim().into())),
Err(e) if e.kind() == ErrorKind::NotFound => Ok(None),
Err(e) => Err(DataRootError::ReadFile(file, e)),
// Trim leading whitespaces.
let mut len = 0;

for b in &path {
if !b.is_ascii_whitespace() {
break;
}

len += 1;
}

path.drain(..len);

// Trim trailing whitespaces.
while path.last().is_some_and(|b| b.is_ascii_whitespace()) {
path.pop();
}

Ok(Some(OsString::from_vec(path).into()))
}

pub fn write_data_root(path: impl AsRef<Path>) -> Result<(), DataRootError> {
let file = get_config_path()?;
let path = path.as_ref().as_os_str();

if let Err(e) = std::fs::write(&file, path.as_bytes()) {
return Err(DataRootError::WriteFile(file, e));
}

Ok(())
}

fn get_config_path() -> Result<PathBuf, DataRootError> {
Expand All @@ -31,4 +64,7 @@ pub enum DataRootError {

#[error("couldn't read {0}")]
ReadFile(PathBuf, #[source] std::io::Error),

#[error("couldn't write {0}")]
WriteFile(PathBuf, #[source] std::io::Error),
}
6 changes: 5 additions & 1 deletion gui/src/setup/macos.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
use std::path::PathBuf;
use std::path::{Path, PathBuf};
use thiserror::Error;

pub fn read_data_root() -> Result<Option<PathBuf>, DataRootError> {
todo!()
}

pub fn write_data_root(path: impl AsRef<Path>) -> Result<(), DataRootError> {
todo!()
}

/// Represents an error when read or write data root fails.
#[derive(Debug, Error)]
pub enum DataRootError {}
50 changes: 48 additions & 2 deletions gui/src/setup/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
pub use self::data::DataRootError;

use self::data::read_data_root;
use self::data::{read_data_root, write_data_root};
use crate::data::{DataError, DataMgr};
use crate::dialogs::{open_dir, open_file, FileType};
use crate::ui::SetupWizard;
Expand All @@ -10,7 +10,7 @@ use slint::{ComponentHandle, PlatformError};
use std::cell::Cell;
use std::error::Error;
use std::fs::File;
use std::path::PathBuf;
use std::path::{Path, PathBuf};
use std::rc::Rc;
use thiserror::Error;

Expand Down Expand Up @@ -50,6 +50,12 @@ pub fn run_setup() -> Result<Option<DataMgr>, SetupError> {
}
});

win.on_set_data_root({
let win = win.as_weak();

move || set_data_root(win.unwrap())
});

win.on_browse_firmware({
let win = win.as_weak();

Expand Down Expand Up @@ -104,6 +110,46 @@ async fn browse_data_root(win: SetupWizard) {
win.set_data_root(path.into_os_string().into_string().unwrap().into());
}

fn set_data_root(win: SetupWizard) {
// Get path.
let path = win.get_data_root();

if path.is_empty() {
win.set_error_message("You need to choose where to store data before proceed.".into());
return;
}

// Check if absolute path.
let path = Path::new(path.as_str());

if !path.is_absolute() {
win.set_error_message("Path must be absolute.".into());
return;
} else if !path.is_dir() {
win.set_error_message("Path must be a directory.".into());
return;
}

// Create data manager to see if path is writable.
let mgr = match DataMgr::new(path) {
Ok(v) => v,
Err(e) => {
win.set_error_message(
format!("Failed to create data manager: {}.", e.display()).into(),
);
return;
}
};

// Save.
if let Err(e) = write_data_root(path) {
win.set_error_message(format!("Failed to save data location: {}.", e.display()).into());
return;
}

win.invoke_set_data_root_ok(mgr.part().meta("md0").is_file());
}

async fn browse_firmware(win: SetupWizard) {
// Ask the user to browse for a file.
let path = match open_file(&win, "Select a firmware dump", FileType::Firmware).await {
Expand Down
6 changes: 5 additions & 1 deletion gui/src/setup/windows.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
use std::path::PathBuf;
use std::path::{Path, PathBuf};
use thiserror::Error;

pub fn read_data_root() -> Result<Option<PathBuf>, DataRootError> {
todo!()
}

pub fn write_data_root(path: impl AsRef<Path>) -> Result<(), DataRootError> {
todo!()
}

/// Represents an error when read or write data root fails.
#[derive(Debug, Error)]
pub enum DataRootError {}
Loading

0 comments on commit 09a081c

Please sign in to comment.