1 /*
2 * document.h
3 * Copyright 2015, Thorbjørn Lindeijer <bjorn@lindeijer.nl>
4 *
5 * This file is part of Tiled.
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the Free
9 * Software Foundation; either version 2 of the License, or (at your option)
10 * any later version.
11 *
12 * This program is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * more details.
16 *
17 * You should have received a copy of the GNU General Public License along with
18 * this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #pragma once
22
23 #include "properties.h"
24
25 #include <QDateTime>
26 #include <QObject>
27 #include <QSharedPointer>
28 #include <QString>
29 #include <QVariant>
30
31 #include <memory>
32
33 class QUndoStack;
34
35 namespace Tiled {
36
37 class FileFormat;
38 class Object;
39 class Tile;
40
41 class ChangeEvent;
42 class EditableAsset;
43
44 /**
45 * Keeps track of a file and its undo history.
46 */
47 class Document : public QObject,
48 public QEnableSharedFromThis<Document>
49 {
50 Q_OBJECT
51
52 Q_PROPERTY(QString fileName READ fileName NOTIFY fileNameChanged)
53 Q_PROPERTY(bool modified READ isModified NOTIFY modifiedChanged)
54
55 public:
56 enum DocumentType {
57 MapDocumentType,
58 TilesetDocumentType,
59 WorldDocumentType
60 };
61
62 Document(DocumentType type,
63 const QString &fileName = QString(),
64 QObject *parent = nullptr);
65 ~Document() override;
66
type()67 DocumentType type() const { return mType; }
68
69 QString fileName() const;
70 QString canonicalFilePath() const;
71
72 /**
73 * Returns the name with which to display this document. It is the file name
74 * without its path, or 'untitled' when the document has no file name.
75 */
76 virtual QString displayName() const = 0;
77
78 /**
79 * Saves the document to the file at \a fileName. Returns whether or not
80 * the file was saved successfully. If not, <i>error</i> will be set to the
81 * error message if it is not 0.
82 *
83 * If the save was successful, the file name of this document will be set
84 * to \a fileName.
85 *
86 * The file format will be the same as this map was opened with.
87 */
88 virtual bool save(const QString &fileName, QString *error = nullptr) = 0;
89
90 virtual FileFormat *writerFormat() const = 0;
91
lastSaved()92 QDateTime lastSaved() const { return mLastSaved; }
93
94 QUndoStack *undoStack() const;
95 bool isModified() const;
96
97 Q_INVOKABLE virtual Tiled::EditableAsset *editable() = 0;
98
currentObject()99 Object *currentObject() const { return mCurrentObject; }
100 void setCurrentObject(Object *object);
101 void setCurrentObject(Object *object, Document *owningDocument);
102
103 virtual QList<Object*> currentObjects() const;
104
105 void setProperty(Object *object, const QString &name, const QVariant &value);
106 void setProperties(Object *object, const Properties &properties);
107 void removeProperty(Object *object, const QString &name);
108
109 bool ignoreBrokenLinks() const;
110 void setIgnoreBrokenLinks(bool ignoreBrokenLinks);
111
112 bool changedOnDisk() const;
113 void setChangedOnDisk(bool changedOnDisk);
114
115 virtual QString lastExportFileName() const = 0;
116 virtual void setLastExportFileName(const QString &fileName) = 0;
117
118 virtual FileFormat *exportFormat() const = 0;
119 virtual void setExportFormat(FileFormat *format) = 0;
120
checkIssues()121 virtual void checkIssues() {}
122
123 static const QHash<QString, Document *> &documentInstances();
124
125 signals:
126 void changed(const ChangeEvent &change);
127 void saved();
128
129 void fileNameChanged(const QString &fileName,
130 const QString &oldFileName);
131 void modifiedChanged();
132
133 void currentObjectChanged(Object *object);
134
135 /**
136 * Makes the Properties window visible and take focus.
137 */
138 void editCurrentObject();
139
140 void propertyAdded(Object *object, const QString &name);
141 void propertyRemoved(Object *object, const QString &name);
142 void propertyChanged(Object *object, const QString &name);
143 void propertiesChanged(Object *object);
144
145 void ignoreBrokenLinksChanged(bool ignoreBrokenLinks);
146
147 protected:
148 void setFileName(const QString &fileName);
149
150 void checkFilePathProperties(const Object *object) const;
151
152 QDateTime mLastSaved;
153
154 Object *mCurrentObject = nullptr; /**< Current properties object. */
155 Document *mCurrentObjectDocument = nullptr;
156
157 std::unique_ptr<EditableAsset> mEditable;
158
159 private:
160 void currentObjectDocumentChanged(const ChangeEvent &change);
161 void currentObjectDocumentDestroyed();
162
163 const DocumentType mType;
164
165 QString mFileName;
166 QString mCanonicalFilePath;
167
168 QUndoStack * const mUndoStack;
169
170 bool mChangedOnDisk = false;
171 bool mIgnoreBrokenLinks = false;
172
173 static QHash<QString, Document*> sDocumentInstances;
174 };
175
176
fileName()177 inline QString Document::fileName() const
178 {
179 return mFileName;
180 }
181
canonicalFilePath()182 inline QString Document::canonicalFilePath() const
183 {
184 return mCanonicalFilePath;
185 }
186
187 /**
188 * Returns the undo stack of this document. Should be used to push any commands
189 * on that modify the document.
190 */
undoStack()191 inline QUndoStack *Document::undoStack() const
192 {
193 return mUndoStack;
194 }
195
196 /**
197 * Sets the current object for this document (displayed in the Properties view).
198 *
199 * This version should only be used with objects owned by this document. See
200 * setCurrentObject(Object*, Document*) for setting it to an object from
201 * another document.
202 */
setCurrentObject(Object * object)203 inline void Document::setCurrentObject(Object *object)
204 {
205 setCurrentObject(object, this);
206 }
207
ignoreBrokenLinks()208 inline bool Document::ignoreBrokenLinks() const
209 {
210 return mIgnoreBrokenLinks;
211 }
212
changedOnDisk()213 inline bool Document::changedOnDisk() const
214 {
215 return mChangedOnDisk;
216 }
217
documentInstances()218 inline const QHash<QString, Document *> &Document::documentInstances()
219 {
220 return sDocumentInstances;
221 }
222
223 using DocumentPtr = QSharedPointer<Document>;
224
225 } // namespace Tiled
226