mirror of
https://github.com/PrismLauncher/PrismLauncher.git
synced 2025-08-03 11:27:33 -04:00
Merge a478fa60d3016445d076bd9d746aa8e2b40a9e49 into 79b7e277f1f06f6b315e293b029423fe35e57431
This commit is contained in:
commit
48ecb8b11f
@ -49,6 +49,7 @@
|
||||
#include "settings/OverrideSetting.h"
|
||||
#include "settings/Setting.h"
|
||||
|
||||
#include "Application.h"
|
||||
#include "BuildConfig.h"
|
||||
#include "Commandline.h"
|
||||
#include "FileSystem.h"
|
||||
@ -124,6 +125,14 @@ BaseInstance::BaseInstance(SettingsObjectPtr globalSettings, SettingsObjectPtr s
|
||||
m_settings->registerSetting("ManagedPackVersionName", "");
|
||||
|
||||
m_settings->registerSetting("Profiler", "");
|
||||
|
||||
// Shared folders
|
||||
m_settings->registerSetting("UseSharedScreenshotsFolder", false);
|
||||
m_settings->registerSetting("SharedScreenshotsPath", FS::PathCombine(APPLICATION->dataRoot(), "screenshots"));
|
||||
m_settings->registerSetting("UseSharedSavesFolder", false);
|
||||
m_settings->registerSetting("SharedSavesPath", FS::PathCombine(APPLICATION->dataRoot(), "saves"));
|
||||
m_settings->registerSetting("UseSharedResourcePacksFolder", false);
|
||||
m_settings->registerSetting("SharedResourcePacksPath", FS::PathCombine(APPLICATION->dataRoot(), "resourcepacks"));
|
||||
}
|
||||
|
||||
QString BaseInstance::getPreLaunchCommand()
|
||||
|
@ -284,6 +284,11 @@ class BaseInstance : public QObject, public std::enable_shared_from_this<BaseIns
|
||||
|
||||
bool isLegacy();
|
||||
|
||||
/**
|
||||
* \brief Should be called whenever settings have changed that need to be re-applied.
|
||||
*/
|
||||
virtual void applySettings() {}
|
||||
|
||||
protected:
|
||||
void changeStatus(Status newStatus);
|
||||
|
||||
|
@ -1070,6 +1070,8 @@ SET(LAUNCHER_SOURCES
|
||||
ui/dialogs/ExportPackDialog.h
|
||||
ui/dialogs/ExportToModListDialog.cpp
|
||||
ui/dialogs/ExportToModListDialog.h
|
||||
ui/dialogs/FileConflictDialog.cpp
|
||||
ui/dialogs/FileConflictDialog.h
|
||||
ui/dialogs/IconPickerDialog.cpp
|
||||
ui/dialogs/IconPickerDialog.h
|
||||
ui/dialogs/ImportResourceDialog.cpp
|
||||
@ -1124,6 +1126,8 @@ SET(LAUNCHER_SOURCES
|
||||
ui/widgets/CustomCommands.h
|
||||
ui/widgets/EnvironmentVariables.cpp
|
||||
ui/widgets/EnvironmentVariables.h
|
||||
ui/widgets/SharedFolderWidget.cpp
|
||||
ui/widgets/SharedFolderWidget.h
|
||||
ui/widgets/IconLabel.cpp
|
||||
ui/widgets/IconLabel.h
|
||||
ui/widgets/JavaWizardWidget.cpp
|
||||
@ -1238,6 +1242,7 @@ qt_wrap_ui(LAUNCHER_UI
|
||||
ui/pages/modplatform/technic/TechnicPage.ui
|
||||
ui/widgets/CustomCommands.ui
|
||||
ui/widgets/EnvironmentVariables.ui
|
||||
ui/widgets/SharedFolderWidget.ui
|
||||
ui/widgets/InfoFrame.ui
|
||||
ui/widgets/ModFilterWidget.ui
|
||||
ui/widgets/SubTaskProgressBar.ui
|
||||
@ -1255,6 +1260,7 @@ qt_wrap_ui(LAUNCHER_UI
|
||||
ui/dialogs/ExportInstanceDialog.ui
|
||||
ui/dialogs/ExportPackDialog.ui
|
||||
ui/dialogs/ExportToModListDialog.ui
|
||||
ui/dialogs/FileConflictDialog.ui
|
||||
ui/dialogs/IconPickerDialog.ui
|
||||
ui/dialogs/ImportResourceDialog.ui
|
||||
ui/dialogs/MSALoginDialog.ui
|
||||
|
@ -55,6 +55,8 @@
|
||||
#include "DesktopServices.h"
|
||||
#include "PSaveFile.h"
|
||||
#include "StringUtils.h"
|
||||
#include "ui/dialogs/CustomMessageBox.h"
|
||||
#include "ui/dialogs/FileConflictDialog.h"
|
||||
|
||||
#if defined Q_OS_WIN32
|
||||
#define NOMINMAX
|
||||
@ -277,6 +279,11 @@ bool ensureFolderPathExists(const QString folderPathName)
|
||||
return ensureFolderPathExists(QFileInfo(folderPathName));
|
||||
}
|
||||
|
||||
bool checkFolderPathEmpty(const QString& folderPathName)
|
||||
{
|
||||
return QDir(folderPathName).isEmpty(QDir::Filters(QDir::AllEntries | QDir::NoDotAndDotDot | QDir::Hidden | QDir::System));
|
||||
}
|
||||
|
||||
bool copyFileAttributes(QString src, QString dst)
|
||||
{
|
||||
#ifdef Q_OS_WIN32
|
||||
@ -669,6 +676,44 @@ bool move(const QString& source, const QString& dest)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool interactiveMove(const QString& source, const QString& destination, bool recursive /* = false */, QWidget* parent /* = nullptr */)
|
||||
{
|
||||
const QFileInfo sourceInfo(source);
|
||||
|
||||
// Make sure the source exists.
|
||||
if (!sourceInfo.exists())
|
||||
return false;
|
||||
|
||||
// Recursive doesn't make sense if the source isn't a directory.
|
||||
if (recursive && sourceInfo.isDir()) {
|
||||
QDirIterator sourceIt(source, QDir::Filter::Files | QDir::Filter::Dirs | QDir::Filter::Hidden | QDir::Filter::NoDotAndDotDot);
|
||||
|
||||
while (sourceIt.hasNext()) {
|
||||
if (!interactiveMove(sourceIt.next(), FS::PathCombine(destination, sourceIt.fileName()), false))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (QFile(destination).exists()) {
|
||||
FileConflictDialog dialog(source, destination, true, parent);
|
||||
FileConflictDialog::Result result = dialog.execWithResult();
|
||||
|
||||
switch (result) {
|
||||
case FileConflictDialog::Cancel:
|
||||
return false;
|
||||
case FileConflictDialog::ChooseDestination:
|
||||
return FS::deletePath(source);
|
||||
case FileConflictDialog::ChooseSource:
|
||||
FS::deletePath(destination);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return FS::move(source, destination);
|
||||
}
|
||||
|
||||
bool deletePath(QString path)
|
||||
{
|
||||
std::error_code err;
|
||||
@ -1701,4 +1746,76 @@ QString getUniqueResourceName(const QString& filePath)
|
||||
|
||||
return newFileName;
|
||||
}
|
||||
|
||||
bool isSymLink(const QString& path)
|
||||
{
|
||||
return QFileInfo(path).isSymLink();
|
||||
}
|
||||
|
||||
QString getSymLinkTarget(const QString& path)
|
||||
{
|
||||
return QFileInfo(path).symLinkTarget();
|
||||
}
|
||||
|
||||
bool tryCreateSymlink(const QString& source, const QString& destination, const QString& symlinkName /* = "symbolic link" */)
|
||||
{
|
||||
// Make sure that symbolic links are supported.
|
||||
if (!FS::canLink(source, destination)) {
|
||||
CustomMessageBox::selectable(
|
||||
nullptr, QObject::tr("Failed"),
|
||||
QObject::tr("Failed to create %1.\nSymbolic links are not supported on the filesystem").arg(symlinkName), QMessageBox::Warning,
|
||||
QMessageBox::Ok)
|
||||
->exec();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if the destination already exists.
|
||||
// If it's already a symlink, it might already be correct.
|
||||
if (FS::isSymLink(destination)) {
|
||||
// If the target of the symlink is already the source, there's nothing to do.
|
||||
if (FS::getSymLinkTarget(destination) == source) {
|
||||
return true;
|
||||
}
|
||||
|
||||
FS::deletePath(destination);
|
||||
} else if (QFileInfo::exists(destination)) {
|
||||
if (!FS::checkFolderPathEmpty(destination)) {
|
||||
if (!interactiveMove(destination, source, true)) {
|
||||
CustomMessageBox::selectable(
|
||||
nullptr, QObject::tr("Failed"),
|
||||
QObject::tr("Failed to create %1.\nEnsure that \"%2\" is empty.").arg(symlinkName).arg(destination),
|
||||
QMessageBox::Warning, QMessageBox::Ok)
|
||||
->exec();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
FS::deletePath(destination);
|
||||
}
|
||||
|
||||
// Make sure the source folder exists
|
||||
if (!FS::ensureFolderPathExists(source)) {
|
||||
CustomMessageBox::selectable(nullptr, QObject::tr("Failed"),
|
||||
QObject::tr("Failed to create %1.\nEnsure that \"%2\" exists.").arg(symlinkName).arg(source),
|
||||
QMessageBox::Warning, QMessageBox::Ok)
|
||||
->exec();
|
||||
return false;
|
||||
}
|
||||
|
||||
FS::create_link folderLink(source, destination);
|
||||
folderLink.linkRecursively(false);
|
||||
|
||||
if (!folderLink()) {
|
||||
CustomMessageBox::selectable(nullptr, QObject::tr("Failed"),
|
||||
QObject::tr("Failed to create %1. Error %2: %3")
|
||||
.arg(symlinkName)
|
||||
.arg(folderLink.getOSError().value())
|
||||
.arg(folderLink.getOSError().message().c_str()),
|
||||
QMessageBox::Warning, QMessageBox::Ok)
|
||||
->exec();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace FS
|
||||
|
@ -99,6 +99,13 @@ bool ensureFolderPathExists(const QFileInfo folderPath);
|
||||
*/
|
||||
bool ensureFolderPathExists(const QString folderPathName);
|
||||
|
||||
/**
|
||||
* @brief Check if the given folder is empty or doesn't exist
|
||||
* @param folderPathName The path to a folder to check
|
||||
* @return True if the given folder is empty or doesn't exist
|
||||
*/
|
||||
bool checkFolderPathEmpty(const QString& folderPathName);
|
||||
|
||||
/**
|
||||
* @brief Copies a directory and it's contents from src to dest
|
||||
*/
|
||||
@ -286,6 +293,17 @@ class create_link : public QObject {
|
||||
*/
|
||||
bool move(const QString& source, const QString& dest);
|
||||
|
||||
/**
|
||||
* @brief Move a file or folder, and ask the user what to do in case of a conflict.
|
||||
* @param source What to move.
|
||||
* @param destination Where to move it to.
|
||||
* @param recursive If true, all direct children will be moved 1 by 1.
|
||||
* If false, the source will be directly moved to the destination.
|
||||
* @param parent The parent of the dialog.
|
||||
* @return True if everything could be moved.
|
||||
*/
|
||||
bool interactiveMove(const QString& source, const QString& destination, bool recursive = false, QWidget* parent = nullptr);
|
||||
|
||||
/**
|
||||
* Delete a folder recursively
|
||||
*/
|
||||
@ -566,4 +584,20 @@ QString getPathNameInLocal8bit(const QString& file);
|
||||
|
||||
QString getUniqueResourceName(const QString& filePath);
|
||||
|
||||
/**
|
||||
* @brief Check if a file or folder is a symbolic link
|
||||
* @param path The path to check
|
||||
* @return True if the object exists and is an symbolic link
|
||||
*/
|
||||
bool isSymLink(const QString& path);
|
||||
|
||||
/**
|
||||
* @brief Get the target of a symbolic link
|
||||
* @param path The path to check
|
||||
* @return The target of a symbolic link. Empty if path is not a symbolic link.
|
||||
*/
|
||||
QString getSymLinkTarget(const QString& path);
|
||||
|
||||
bool tryCreateSymlink(const QString& source, const QString& destination, const QString& symlinkName = "symbolic link");
|
||||
|
||||
} // namespace FS
|
||||
|
@ -413,6 +413,11 @@ QString MinecraftInstance::dataPacksDir()
|
||||
return QDir(gameRoot()).filePath(relativePath);
|
||||
}
|
||||
|
||||
QString MinecraftInstance::screenshotsDir() const
|
||||
{
|
||||
return FS::PathCombine(gameRoot(), "screenshots");
|
||||
}
|
||||
|
||||
QString MinecraftInstance::resourcePacksDir() const
|
||||
{
|
||||
return FS::PathCombine(gameRoot(), "resourcepacks");
|
||||
@ -1308,4 +1313,39 @@ QList<Mod*> MinecraftInstance::getJarMods() const
|
||||
return mods;
|
||||
}
|
||||
|
||||
void MinecraftInstance::applySettings()
|
||||
{
|
||||
// Shared directories
|
||||
updateSharedDirectories();
|
||||
}
|
||||
|
||||
bool MinecraftInstance::updateSharedDirectories()
|
||||
{
|
||||
const std::vector<std::tuple<QString, QString, QString>> sharedDirectories = {
|
||||
{ "UseSharedScreenshotsFolder", m_settings->get("SharedScreenshotsPath").toString(), screenshotsDir() },
|
||||
{ "UseSharedSavesFolder", m_settings->get("SharedSavesPath").toString(), worldDir() },
|
||||
{ "UseSharedResourcePacksFolder", m_settings->get("SharedResourcePacksPath").toString(), resourcePacksDir() },
|
||||
{ "UseSharedResourcePacksFolder", m_settings->get("SharedResourcePacksPath").toString(), texturePacksDir() }
|
||||
};
|
||||
|
||||
bool success = true;
|
||||
for (const auto& [useSetting, source, destination] : sharedDirectories) {
|
||||
// Create symlink if useSetting is true, remove symlink if false.
|
||||
if (m_settings->get(useSetting).toBool()) {
|
||||
// Try to create symlink, set setting to false if failed.
|
||||
if (!FS::tryCreateSymlink(source, destination, tr("shared folder"))) {
|
||||
m_settings->set(useSetting, false);
|
||||
success = false;
|
||||
}
|
||||
} else {
|
||||
// Safety check
|
||||
if (FS::isSymLink(destination)) {
|
||||
success = FS::deletePath(destination) && success;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
#include "MinecraftInstance.moc"
|
||||
|
@ -75,6 +75,7 @@ class MinecraftInstance : public BaseInstance {
|
||||
|
||||
////// Directories and files //////
|
||||
QString jarModsDir() const;
|
||||
QString screenshotsDir() const;
|
||||
QString resourcePacksDir() const;
|
||||
QString texturePacksDir() const;
|
||||
QString shaderPacksDir() const;
|
||||
@ -158,9 +159,13 @@ class MinecraftInstance : public BaseInstance {
|
||||
|
||||
virtual JavaVersion getJavaVersion();
|
||||
|
||||
virtual void applySettings() override;
|
||||
|
||||
protected:
|
||||
QMap<QString, QString> createCensorFilterFromSession(AuthSessionPtr session);
|
||||
|
||||
bool updateSharedDirectories();
|
||||
|
||||
protected: // data
|
||||
std::shared_ptr<PackProfile> m_components;
|
||||
mutable std::shared_ptr<ModFolderModel> m_loader_mod_list;
|
||||
|
96
launcher/ui/dialogs/FileConflictDialog.cpp
Normal file
96
launcher/ui/dialogs/FileConflictDialog.cpp
Normal file
@ -0,0 +1,96 @@
|
||||
#include "FileConflictDialog.h"
|
||||
#include "ui_FileConflictDialog.h"
|
||||
|
||||
#include <QDialogButtonBox>
|
||||
#include <QDir>
|
||||
#include <QFileInfo>
|
||||
#include <QPushButton>
|
||||
|
||||
#include "Application.h"
|
||||
|
||||
FileConflictDialog::FileConflictDialog(QString source, QString destination, bool move, QWidget* parent)
|
||||
: QDialog(parent), ui(new Ui::FileConflictDialog), m_result(Result::Cancel)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
// Setup buttons
|
||||
connect(ui->buttonBox->button(QDialogButtonBox::Cancel), &QPushButton::clicked, this, &FileConflictDialog::cancel);
|
||||
if (move) {
|
||||
setWindowTitle(tr("File conflict while moving files"));
|
||||
|
||||
auto chooseSourceButton = ui->buttonBox->addButton(tr("Keep source"), QDialogButtonBox::DestructiveRole);
|
||||
chooseSourceButton->setIcon(APPLICATION->getThemedIcon("delete"));
|
||||
connect(chooseSourceButton, &QPushButton::clicked, this, &FileConflictDialog::chooseSource);
|
||||
|
||||
auto chooseDestinationButton = ui->buttonBox->addButton(tr("Keep destination"), QDialogButtonBox::DestructiveRole);
|
||||
chooseDestinationButton->setIcon(APPLICATION->getThemedIcon("delete"));
|
||||
connect(chooseDestinationButton, &QPushButton::clicked, this, &FileConflictDialog::chooseDestination);
|
||||
} else {
|
||||
setWindowTitle(tr("File conflict while copying files"));
|
||||
|
||||
auto chooseSourceButton = ui->buttonBox->addButton(tr("Overwrite destination"), QDialogButtonBox::DestructiveRole);
|
||||
chooseSourceButton->setIcon(APPLICATION->getThemedIcon("delete"));
|
||||
connect(chooseSourceButton, &QPushButton::clicked, this, &FileConflictDialog::chooseSource);
|
||||
|
||||
auto chooseDestinationButton = ui->buttonBox->addButton(tr("Skip"), QDialogButtonBox::DestructiveRole);
|
||||
connect(chooseDestinationButton, &QPushButton::clicked, this, &FileConflictDialog::chooseDestination);
|
||||
}
|
||||
|
||||
// Setup info
|
||||
ui->sourceInfoLabel->setText(GetFileInfoText(source));
|
||||
ui->destinationInfoLabel->setText(GetFileInfoText(destination));
|
||||
}
|
||||
|
||||
FileConflictDialog::~FileConflictDialog()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
FileConflictDialog::Result FileConflictDialog::execWithResult()
|
||||
{
|
||||
exec();
|
||||
return m_result;
|
||||
}
|
||||
|
||||
FileConflictDialog::Result FileConflictDialog::getResult() const
|
||||
{
|
||||
return m_result;
|
||||
}
|
||||
|
||||
void FileConflictDialog::chooseSource()
|
||||
{
|
||||
m_result = Result::ChooseSource;
|
||||
accept();
|
||||
}
|
||||
|
||||
void FileConflictDialog::chooseDestination()
|
||||
{
|
||||
m_result = Result::ChooseDestination;
|
||||
accept();
|
||||
}
|
||||
|
||||
void FileConflictDialog::cancel()
|
||||
{
|
||||
m_result = Result::Cancel;
|
||||
reject();
|
||||
}
|
||||
|
||||
QString FileConflictDialog::GetFileInfoText(const QString& filePath) const
|
||||
{
|
||||
QLocale locale;
|
||||
QFileInfo fileInfo(filePath);
|
||||
|
||||
if (fileInfo.isDir()) {
|
||||
QDir dirInfo(filePath);
|
||||
return tr("<b>Name:</b> %1<br/><b>Size:</b> %2<br/><b>Last modified:</b> %3<br/><b>Items:</b> %4")
|
||||
.arg(filePath)
|
||||
.arg("-")
|
||||
.arg(fileInfo.lastModified().toString(locale.dateTimeFormat()))
|
||||
.arg(dirInfo.entryList(QDir::AllEntries | QDir::NoDotAndDotDot).count());
|
||||
} else {
|
||||
return tr("<b>Name:</b> %1<br/><b>Size:</b> %2<br/><b>Last modified:</b> %3")
|
||||
.arg(filePath)
|
||||
.arg(locale.formattedDataSize(fileInfo.size()))
|
||||
.arg(fileInfo.lastModified().toString(locale.dateTimeFormat()));
|
||||
}
|
||||
}
|
36
launcher/ui/dialogs/FileConflictDialog.h
Normal file
36
launcher/ui/dialogs/FileConflictDialog.h
Normal file
@ -0,0 +1,36 @@
|
||||
#pragma once
|
||||
|
||||
#include <QDialog>
|
||||
|
||||
namespace Ui {
|
||||
class FileConflictDialog;
|
||||
}
|
||||
|
||||
class FileConflictDialog : public QDialog {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
enum Result { Cancel, ChooseSource, ChooseDestination };
|
||||
|
||||
/// @brief Create a new file conflict dialog
|
||||
/// @param source The source path. What to copy/move.
|
||||
/// @param destination The destination path. Where to copy/move.
|
||||
/// @param move Whether the conflict is for a move or copy action
|
||||
/// @param parent The parent of the dialog
|
||||
explicit FileConflictDialog(QString source, QString destination, bool move = false, QWidget* parent = nullptr);
|
||||
~FileConflictDialog() override;
|
||||
|
||||
Result execWithResult();
|
||||
Result getResult() const;
|
||||
|
||||
private slots:
|
||||
void chooseSource();
|
||||
void chooseDestination();
|
||||
void cancel();
|
||||
|
||||
private:
|
||||
QString GetFileInfoText(const QString& filePath) const;
|
||||
|
||||
Ui::FileConflictDialog* ui;
|
||||
Result m_result;
|
||||
};
|
114
launcher/ui/dialogs/FileConflictDialog.ui
Normal file
114
launcher/ui/dialogs/FileConflictDialog.ui
Normal file
@ -0,0 +1,114 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>FileConflictDialog</class>
|
||||
<widget class="QDialog" name="FileConflictDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>411</width>
|
||||
<height>219</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string/>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item alignment="Qt::AlignmentFlag::AlignTop">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Would you like to overwrite the destination?</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<property name="sizeConstraint">
|
||||
<enum>QLayout::SetDefaultConstraint</enum>
|
||||
</property>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="sourceLayout" stretch="0,1">
|
||||
<item>
|
||||
<widget class="QLabel" name="sourceLabel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string><html><head/><body><p><span style=" font-weight:700;">Source</span></p></body></html></string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignHCenter|Qt::AlignTop</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="sourceInfoLabel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string><html><head/><body><p><b>Name:</b></p><p>Size:</p><p>Date:</p></body></html></string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="destinationLayout" stretch="0,1">
|
||||
<item>
|
||||
<widget class="QLabel" name="destinationLabel">
|
||||
<property name="text">
|
||||
<string><html><head/><body><p><span style=" font-weight:700;">Destination</span></p></body></html></string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignHCenter|Qt::AlignTop</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="destinationInfoLabel">
|
||||
<property name="text">
|
||||
<string><html><head/><body><p>Name:</p><p>Size:</p><p>Date:</p></body></html></string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Cancel</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
@ -38,6 +38,7 @@
|
||||
#include "ui_ExternalResourcesPage.h"
|
||||
|
||||
#include "DesktopServices.h"
|
||||
#include "FileSystem.h"
|
||||
#include "Version.h"
|
||||
#include "minecraft/mod/ResourceFolderModel.h"
|
||||
#include "ui/GuiUtil.h"
|
||||
@ -149,6 +150,9 @@ void ExternalResourcesPage::openedImpl()
|
||||
m_wide_bar_setting = APPLICATION->settings()->getOrRegisterSetting(setting_name);
|
||||
|
||||
ui->actionsToolbar->setVisibilityState(QByteArray::fromBase64(m_wide_bar_setting->get().toString().toUtf8()));
|
||||
|
||||
// Enable the symbolic link warning when the folder is a symbolic link
|
||||
ui->isSymlinkWarning->setVisible(FS::isSymLink(m_model->dir().absolutePath()));
|
||||
}
|
||||
|
||||
void ExternalResourcesPage::closedImpl()
|
||||
|
@ -67,6 +67,13 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1" colspan="3">
|
||||
<widget class="QLabel" name="isSymlinkWarning">
|
||||
<property name="text">
|
||||
<string><html><head/><body><p><span style=" font-weight:700; color:#f5c211;">Warning</span><span style=" color:#f5c211;">: This is a shared folder and potentially shared with multiple instances</span></p></body></html></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="WideBar" name="actionsToolbar">
|
||||
|
@ -563,6 +563,9 @@ void ScreenshotsPage::openedImpl()
|
||||
m_wide_bar_setting = APPLICATION->settings()->getOrRegisterSetting(setting_name);
|
||||
|
||||
ui->toolBar->setVisibilityState(QByteArray::fromBase64(m_wide_bar_setting->get().toString().toUtf8()));
|
||||
|
||||
// Enable the symbolic link warning when the screenshots folder is a symbolic link
|
||||
ui->sharedScreenshotsFolderWarninglabel->setVisible(FS::isSymLink(m_folder));
|
||||
}
|
||||
|
||||
void ScreenshotsPage::closedImpl()
|
||||
|
@ -11,7 +11,7 @@
|
||||
</rect>
|
||||
</property>
|
||||
<widget class="QWidget" name="centralwidget">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
@ -24,6 +24,19 @@
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="sharedScreenshotsFolderWarninglabel">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string><html><head/><body><p><span style=" font-weight:600; color:#f5c211;">Warning</span><span style=" color:#f5c211;">: This is a shared folder and potentially shared with multiple instances</span></p></body></html></string>
|
||||
</property>
|
||||
<property name="margin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QListView" name="listView">
|
||||
<property name="selectionMode">
|
||||
|
@ -48,10 +48,10 @@
|
||||
#include <QKeyEvent>
|
||||
#include <QMenu>
|
||||
#include <QMessageBox>
|
||||
#include <QPushButton>
|
||||
#include <QSortFilterProxyModel>
|
||||
#include <QTreeView>
|
||||
#include <Qt>
|
||||
#include <QPushButton>
|
||||
|
||||
#include "FileSystem.h"
|
||||
#include "tools/MCEditTool.h"
|
||||
@ -126,6 +126,9 @@ void WorldListPage::openedImpl()
|
||||
m_wide_bar_setting = APPLICATION->settings()->getOrRegisterSetting(setting_name);
|
||||
|
||||
ui->toolBar->setVisibilityState(QByteArray::fromBase64(m_wide_bar_setting->get().toString().toUtf8()));
|
||||
|
||||
// Enable the symbolic link warning when the saves folder is a symbolic link
|
||||
ui->sharedSavesFolderWarninglabel->setVisible(FS::isSymLink(FS::PathCombine(m_inst->gameRoot(), "saves")));
|
||||
}
|
||||
|
||||
void WorldListPage::closedImpl()
|
||||
|
@ -11,7 +11,7 @@
|
||||
</rect>
|
||||
</property>
|
||||
<widget class="QWidget" name="centralwidget">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
@ -24,6 +24,13 @@
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="sharedSavesFolderWarninglabel">
|
||||
<property name="text">
|
||||
<string><html><head/><body><p><span style=" font-weight:700; color:#f5c211;">Warning</span><span style=" color:#f5c211;">: This is a shared folder and potentially shared with multiple instances</span></p></body></html></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QTreeView" name="worldTreeView">
|
||||
<property name="sizePolicy">
|
||||
|
@ -53,7 +53,8 @@ MinecraftSettingsWidget::MinecraftSettingsWidget(MinecraftInstancePtr instance,
|
||||
m_ui->setupUi(this);
|
||||
|
||||
if (m_instance == nullptr) {
|
||||
m_ui->settingsTabs->removeTab(1);
|
||||
m_ui->settingsTabs->removeTab(m_ui->settingsTabs->indexOf(m_ui->javaPage));
|
||||
m_ui->settingsTabs->removeTab(m_ui->settingsTabs->indexOf(m_ui->sharedFoldersTab));
|
||||
|
||||
m_ui->openGlobalSettingsButton->setVisible(false);
|
||||
m_ui->instanceAccountGroupBox->hide();
|
||||
@ -281,6 +282,13 @@ void MinecraftSettingsWidget::loadSettings()
|
||||
m_ui->fabric->blockSignals(false);
|
||||
m_ui->quilt->blockSignals(false);
|
||||
m_ui->liteLoader->blockSignals(false);
|
||||
|
||||
// Shared folders
|
||||
m_ui->sharedScreenshotsFolder->initialize(settings->get("UseSharedScreenshotsFolder").toBool(),
|
||||
settings->get("SharedScreenshotsPath").toString());
|
||||
m_ui->sharedSavesFolder->initialize(settings->get("UseSharedSavesFolder").toBool(), settings->get("SharedSavesPath").toString());
|
||||
m_ui->sharedResourcePacksFolder->initialize(settings->get("UseSharedResourcePacksFolder").toBool(),
|
||||
settings->get("SharedResourcePacksPath").toString());
|
||||
}
|
||||
|
||||
m_ui->legacySettingsGroupBox->setChecked(settings->get("OverrideLegacySettings").toBool());
|
||||
@ -469,8 +477,21 @@ void MinecraftSettingsWidget::saveSettings()
|
||||
} else {
|
||||
settings->reset("OnlineFixes");
|
||||
}
|
||||
|
||||
if (m_instance != nullptr) {
|
||||
// Shared folders
|
||||
settings->set("UseSharedScreenshotsFolder", m_ui->sharedScreenshotsFolder->isEnabled());
|
||||
settings->set("SharedScreenshotsPath", m_ui->sharedScreenshotsFolder->getPath());
|
||||
settings->set("UseSharedSavesFolder", m_ui->sharedSavesFolder->isEnabled());
|
||||
settings->set("SharedSavesPath", m_ui->sharedSavesFolder->getPath());
|
||||
settings->set("UseSharedResourcePacksFolder", m_ui->sharedResourcePacksFolder->isEnabled());
|
||||
settings->set("SharedResourcePacksPath", m_ui->sharedResourcePacksFolder->getPath());
|
||||
}
|
||||
}
|
||||
|
||||
if (m_instance != nullptr)
|
||||
m_instance->applySettings();
|
||||
|
||||
if (m_javaSettings != nullptr)
|
||||
m_javaSettings->saveSettings();
|
||||
}
|
||||
|
@ -801,6 +801,75 @@ It is most likely you will need to change the path - please refer to the mod's w
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="sharedFoldersTab">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<attribute name="title">
|
||||
<string>Shared Folders</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="sharedFoldersVerticalLayout">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="sharedFoldersGroupBox">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Settings</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="sharedFoldersSettingsVerticalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="sharedFoldersWarning">
|
||||
<property name="text">
|
||||
<string><html><head/><body><p><span style=" font-weight:600; color:#f5c211;">Warning</span><span style=" color:#f5c211;">: After enabling files cannot be automatically restored to their original folder.</span></p></body></html></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="SharedFolderWidget" name="sharedScreenshotsFolder" native="true"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="SharedFolderWidget" name="sharedSavesFolder" native="true"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="SharedFolderWidget" name="sharedResourcePacksFolder" native="true"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="sharedFoldersLabel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>11</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string><html><head/><body><p>A shared folder is a folder that can be shared across instances.</p><p>For example: If two instances share the same shared saves folder, they can both play on the same worlds without having to copy the world over.</p></body></html></string>
|
||||
</property>
|
||||
<property name="scaledContents">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
@ -818,6 +887,12 @@ It is most likely you will need to change the path - please refer to the mod's w
|
||||
<header>ui/widgets/EnvironmentVariables.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>SharedFolderWidget</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>ui/widgets/SharedFolderWidget.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<tabstops>
|
||||
<tabstop>openGlobalSettingsButton</tabstop>
|
||||
|
53
launcher/ui/widgets/SharedFolderWidget.cpp
Normal file
53
launcher/ui/widgets/SharedFolderWidget.cpp
Normal file
@ -0,0 +1,53 @@
|
||||
#include "SharedFolderWidget.h"
|
||||
#include "ui_SharedFolderWidget.h"
|
||||
|
||||
#include <QFileDialog>
|
||||
|
||||
#include "FileSystem.h"
|
||||
|
||||
SharedFolderWidget::SharedFolderWidget(QWidget* parent) : QWidget(parent), ui(new Ui::SharedFolderWidget)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
}
|
||||
|
||||
SharedFolderWidget::~SharedFolderWidget()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void SharedFolderWidget::initialize(bool enabled, const QString& path, const QString& label)
|
||||
{
|
||||
ui->enabledCheckBox->setChecked(enabled);
|
||||
ui->enabledCheckBox->setText(label);
|
||||
|
||||
ui->pathTextBox->setEnabled(enabled);
|
||||
ui->pathTextBox->setText(path);
|
||||
|
||||
ui->pathBrowseBtn->setEnabled(enabled);
|
||||
}
|
||||
|
||||
bool SharedFolderWidget::isEnabled() const
|
||||
{
|
||||
return ui->enabledCheckBox->isChecked();
|
||||
}
|
||||
|
||||
QString SharedFolderWidget::getPath() const
|
||||
{
|
||||
return ui->pathTextBox->text();
|
||||
}
|
||||
|
||||
void SharedFolderWidget::on_enabledCheckBox_toggled(bool checked)
|
||||
{
|
||||
ui->pathTextBox->setEnabled(checked);
|
||||
ui->pathBrowseBtn->setEnabled(checked);
|
||||
}
|
||||
|
||||
void SharedFolderWidget::on_pathBrowseBtn_clicked()
|
||||
{
|
||||
QString path = QFileDialog::getExistingDirectory(this, tr("Select shared folder"), ui->pathTextBox->text());
|
||||
if (path.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
ui->pathTextBox->setText(path);
|
||||
}
|
26
launcher/ui/widgets/SharedFolderWidget.h
Normal file
26
launcher/ui/widgets/SharedFolderWidget.h
Normal file
@ -0,0 +1,26 @@
|
||||
#pragma once
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
namespace Ui {
|
||||
class SharedFolderWidget;
|
||||
}
|
||||
|
||||
class SharedFolderWidget : public QWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit SharedFolderWidget(QWidget* parent = 0);
|
||||
virtual ~SharedFolderWidget();
|
||||
void initialize(bool enabled, const QString& path, const QString& label = "");
|
||||
|
||||
bool isEnabled() const;
|
||||
QString getPath() const;
|
||||
|
||||
private slots:
|
||||
void on_enabledCheckBox_toggled(bool checked);
|
||||
void on_pathBrowseBtn_clicked();
|
||||
|
||||
private:
|
||||
Ui::SharedFolderWidget* ui;
|
||||
};
|
45
launcher/ui/widgets/SharedFolderWidget.ui
Normal file
45
launcher/ui/widgets/SharedFolderWidget.ui
Normal file
@ -0,0 +1,45 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>SharedFolderWidget</class>
|
||||
<widget class="QWidget" name="SharedFolderWidget">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>518</width>
|
||||
<height>44</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string/>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="enabledCheckBox">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="pathTextBox">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="pathBrowseBtn">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Browse</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
Loading…
x
Reference in New Issue
Block a user