Skip to content

Commit

Permalink
Support custom properties on the project (#3667)
Browse files Browse the repository at this point in the history
* Derive Project from Object, added ProjectDocument and related enum types
* Support Project in PropertyBrowser
* Extracted PropertiesWidget from PropertiesDock, for reuse in ProjectPropertiesDialog
* Derive EditableProject from EditableAsset
* Implemented saving and loading of custom project properties
* Changed Project to be managed by std::unique_ptr

Rather than passing Project around by value and implementing copy/move
constructor and assignment operators, the instance is now managed by
std::unique_ptr and owned by ProjectDocument, which is in turn owned by
ProjectModel.

The ProjectDocument now owns the EditableProject, which can be used by
scripts and will get invalidated as appropriate when it gets deleted,
for example due to unloading the project.

Co-authored-by: Thorbjørn Lindeijer <bjorn@lindeijer.nl>
  • Loading branch information
dogboydog and bjorn committed Jun 28, 2023
1 parent 3954876 commit 3141a39
Show file tree
Hide file tree
Showing 37 changed files with 983 additions and 600 deletions.
1 change: 1 addition & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
### Unreleased

* Added support for setting custom properties on the project (#2903)
* Removed Space and Ctrl+Space shortcuts from Layers view to avoid conflict with panning (#3672)
* Scripting: Added API for editing tile layers using terrain sets (with a-morphous, #3758)
* Fixed object preview position with parallax factor on group layer (#3669)
Expand Down
2 changes: 1 addition & 1 deletion docs/scripting-doc/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1091,7 +1091,7 @@ declare class TiledObject {
*
* @since 1.10.1
*/
declare class Project {
declare class Project extends TiledObject {
/**
* A project-specific directory where you can put Tiled extensions.
*
Expand Down
2 changes: 2 additions & 0 deletions src/libtiled/logginginterface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,8 @@ SelectCustomProperty::SelectCustomProperty(QString fileName,
// not so helpful... would need WangSet index as well
id = static_cast<const WangColor*>(object)->colorIndex();
break;
case Object::ProjectType:
break;
}
}

Expand Down
15 changes: 8 additions & 7 deletions src/libtiled/object.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,14 @@ class TILEDSHARED_EXPORT Object
public:
// Keep values synchronized with ClassPropertyType::ClassUsageFlag
enum TypeId {
LayerType = 0x02,
MapObjectType = 0x04,
MapType = 0x08,
TilesetType = 0x10,
TileType = 0x20,
WangSetType = 0x40,
WangColorType = 0x80,
LayerType = 0x002,
MapObjectType = 0x004,
MapType = 0x008,
TilesetType = 0x010,
TileType = 0x020,
WangSetType = 0x040,
WangColorType = 0x080,
ProjectType = 0x100,
};

explicit Object(TypeId typeId, const QString &className = QString())
Expand Down
1 change: 1 addition & 0 deletions src/libtiled/propertytype.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,7 @@ static const struct {
{ ClassPropertyType::TilesetClass, QLatin1String("tileset") },
{ ClassPropertyType::WangColorClass, QLatin1String("wangcolor") },
{ ClassPropertyType::WangSetClass, QLatin1String("wangset") },
{ ClassPropertyType::ProjectClass, QLatin1String("project") },
};

QJsonObject ClassPropertyType::toJson(const ExportContext &context) const
Expand Down
20 changes: 10 additions & 10 deletions src/libtiled/propertytype.h
Original file line number Diff line number Diff line change
Expand Up @@ -135,18 +135,18 @@ class TILEDSHARED_EXPORT ClassPropertyType final : public PropertyType
{
public:
enum ClassUsageFlag {
PropertyValueType = 0x01,
PropertyValueType = 0x001,

// Keep values synchronized with Object::TypeId
LayerClass = 0x02,
MapObjectClass = 0x04,
MapClass = 0x08,
TilesetClass = 0x10,
TileClass = 0x20,
WangSetClass = 0x40,
WangColorClass = 0x80,

AnyUsage = 0xFF,
LayerClass = 0x002,
MapObjectClass = 0x004,
MapClass = 0x008,
TilesetClass = 0x010,
TileClass = 0x020,
WangSetClass = 0x040,
WangColorClass = 0x080,
ProjectClass = 0x100,
AnyUsage = 0xFFF,
AnyObjectClass = AnyUsage & ~PropertyValueType,
};

Expand Down
2 changes: 1 addition & 1 deletion src/tiled/automappingmanager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -325,7 +325,7 @@ void AutomappingManager::refreshRulesFile(const QString &ruleFileOverride)
}

if (rulesFile.isEmpty() || !QFileInfo::exists(rulesFile)) {
auto &project = ProjectManager::instance()->project();
const auto &project = ProjectManager::instance()->project();
if (!project.mAutomappingRulesFile.isEmpty())
rulesFile = project.mAutomappingRulesFile;
}
Expand Down
2 changes: 1 addition & 1 deletion src/tiled/commanddialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ CommandDialog::CommandDialog(QWidget *parent)
mUi->tabWidget->addTab(mGlobalCommandsEdit, tr("Global Commands"));
mUi->tabWidget->addTab(mProjectCommandsEdit, tr("Project Commands"));

auto &project = ProjectManager::instance()->project();
const auto &project = ProjectManager::instance()->project();
mUi->tabWidget->setTabEnabled(1, !project.fileName().isEmpty());

Utils::restoreGeometry(this);
Expand Down
2 changes: 1 addition & 1 deletion src/tiled/commandmanager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ const QVector<Command> &CommandManager::globalCommands() const

const QVector<Command> &CommandManager::projectCommands() const
{
auto &project = ProjectManager::instance()->project();
const auto &project = ProjectManager::instance()->project();
return project.mCommands;
}

Expand Down
3 changes: 2 additions & 1 deletion src/tiled/document.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,8 @@ class Document : public QObject,
enum DocumentType {
MapDocumentType,
TilesetDocumentType,
WorldDocumentType
WorldDocumentType,
ProjectDocumentType
};

Document(DocumentType type,
Expand Down
1 change: 1 addition & 0 deletions src/tiled/documentmanager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,7 @@ DocumentManager::DocumentManager(QObject *parent)
break;
}
case Document::WorldDocumentType:
case Document::ProjectDocumentType:
break;
}

Expand Down
1 change: 1 addition & 0 deletions src/tiled/editableobject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ static Map *mapForObject(Object *object)
case Object::TileType:
case Object::WangSetType:
case Object::WangColorType:
case Object::ProjectType:
break;
}
return nullptr;
Expand Down
27 changes: 20 additions & 7 deletions src/tiled/editableproject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,32 +21,45 @@

#include "editableproject.h"

#include "projectdocument.h"

namespace Tiled {

EditableProject::EditableProject(Project *project, QObject *parent)
: QObject(parent)
, mProject(project)
EditableProject::EditableProject(ProjectDocument *projectDocument, QObject *parent)
: EditableAsset(projectDocument, &projectDocument->project(), parent)
{
}

QString EditableProject::extensionsPath() const
{
return mProject->mExtensionsPath;
return project()->mExtensionsPath;
}

QString EditableProject::automappingRulesFile() const
{
return mProject->mAutomappingRulesFile;
return project()->mAutomappingRulesFile;
}

QString EditableProject::fileName() const
{
return mProject->fileName();
return project()->fileName();
}

QStringList EditableProject::folders() const
{
return mProject->folders();
return project()->folders();
}

bool EditableProject::isReadOnly() const
{
return false;
}

QSharedPointer<Document> EditableProject::createDocument()
{
// We don't currently support opening a project in a tab, which this
// function is meant for.
return nullptr;
}

} // namespace Tiled
Expand Down
18 changes: 14 additions & 4 deletions src/tiled/editableproject.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,16 @@

#pragma once

#include "editableasset.h"
#include "project.h"

#include <QObject>

namespace Tiled {

class EditableProject : public QObject
class ProjectDocument;

class EditableProject final : public EditableAsset
{
Q_OBJECT

Expand All @@ -37,17 +40,24 @@ class EditableProject : public QObject
Q_PROPERTY(QStringList folders READ folders)

public:
EditableProject(Project *project, QObject *parent = nullptr);
EditableProject(ProjectDocument *projectDocument, QObject *parent = nullptr);

bool isReadOnly() const override;
QString extensionsPath() const;
QString automappingRulesFile() const;
QString fileName() const;
QStringList folders() const;

private:
Project *mProject;
Project *project() const;

QSharedPointer<Document> createDocument() override;
};

inline Project *EditableProject::project() const
{
return static_cast<Project*>(object());
}

} // namespace Tiled

Q_DECLARE_METATYPE(Tiled::EditableProject*)
1 change: 1 addition & 0 deletions src/tiled/exporthelper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,7 @@ void ExportHelper::resolveProperties(Object *object) const
resolveProperties(color.data());
break;
case Object::WangColorType:
case Object::ProjectType:
break;
}

Expand Down
4 changes: 4 additions & 0 deletions src/tiled/libtilededitor.qbs
Original file line number Diff line number Diff line change
Expand Up @@ -390,6 +390,8 @@ DynamicLibrary {
"project.h",
"projectdock.cpp",
"projectdock.h",
"projectdocument.cpp",
"projectdocument.h",
"projectmanager.cpp",
"projectmanager.h",
"projectmodel.cpp",
Expand All @@ -399,6 +401,8 @@ DynamicLibrary {
"projectpropertiesdialog.ui",
"propertiesdock.cpp",
"propertiesdock.h",
"propertieswidget.cpp",
"propertieswidget.h",
"propertybrowser.cpp",
"propertybrowser.h",
"propertytypeseditor.cpp",
Expand Down
36 changes: 23 additions & 13 deletions src/tiled/mainwindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
#include "newtilesetdialog.h"
#include "offsetmapdialog.h"
#include "projectdock.h"
#include "projectdocument.h"
#include "projectmanager.h"
#include "projectpropertiesdialog.h"
#include "propertytypeseditor.h"
Expand Down Expand Up @@ -991,8 +992,11 @@ void MainWindow::initializeSession()
const auto &session = Session::current();

// Restore associated project if applicable
Project project;
bool projectLoaded = !session.project.isEmpty() && project.load(session.project);
std::unique_ptr<Project> project;
if (!session.project.isEmpty())
project = Project::load(session.project);

const bool projectLoaded = project != nullptr;

if (projectLoaded) {
ProjectManager::instance()->setProject(std::move(project));
Expand Down Expand Up @@ -1379,9 +1383,9 @@ bool MainWindow::closeAllFiles()

bool MainWindow::openProjectFile(const QString &fileName)
{
Project project;
auto project = Project::load(fileName);

if (!project.load(fileName)) {
if (!project) {
QMessageBox::critical(window(),
tr("Error Opening Project"),
tr("An error occurred while opening the project."));
Expand Down Expand Up @@ -1413,10 +1417,10 @@ void MainWindow::newProject()
fileName.append(QStringLiteral(".tiled-project"));
}

Project project;
project.addFolder(QFileInfo(fileName).path());
auto project = std::make_unique<Project>();
project->addFolder(QFileInfo(fileName).path());

if (!project.save(fileName)) {
if (!project->save(fileName)) {
QMessageBox::critical(window(),
tr("Error Saving Project"),
tr("An error occurred while saving the project."));
Expand All @@ -1435,10 +1439,10 @@ bool MainWindow::closeProject()
if (project.fileName().isEmpty())
return true;

return switchProject(Project{});
return switchProject(nullptr);
}

bool MainWindow::switchProject(Project project)
bool MainWindow::switchProject(std::unique_ptr<Project> project)
{
auto prefs = Preferences::instance();
emit prefs->aboutToSwitchSession();
Expand All @@ -1448,11 +1452,15 @@ bool MainWindow::switchProject(Project project)

WorldManager::instance().unloadAllWorlds();

auto &session = Session::switchCurrent(Session::defaultFileNameForProject(project.fileName()));
if (project) {
auto &session = Session::switchCurrent(Session::defaultFileNameForProject(project->fileName()));

if (!project.fileName().isEmpty()) {
session.setProject(project.fileName());
prefs->addRecentProject(project.fileName());
if (!project->fileName().isEmpty()) {
session.setProject(project->fileName());
prefs->addRecentProject(project->fileName());
}
} else {
Session::switchCurrent(Session::defaultFileName());
}

ProjectManager::instance()->setProject(std::move(project));
Expand Down Expand Up @@ -1487,6 +1495,8 @@ void MainWindow::restoreSession()
void MainWindow::projectProperties()
{
Project &project = ProjectManager::instance()->project();
if (project.fileName().length() == 0)
return;

if (ProjectPropertiesDialog(project, this).exec() == QDialog::Accepted) {
project.save();
Expand Down
2 changes: 1 addition & 1 deletion src/tiled/mainwindow.h
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ class TILED_EDITOR_EXPORT MainWindow : public QMainWindow
bool openProjectFile(const QString &fileName);
void newProject();
bool closeProject();
bool switchProject(Project project);
bool switchProject(std::unique_ptr<Project> project);
void restoreSession();
void projectProperties();

Expand Down

0 comments on commit 3141a39

Please sign in to comment.