1 /*
2  * documentmanager.h
3  * Copyright 2010, Stefan Beller <stefanbeller@googlemail.com>
4  * Copyright 2010, Thorbjørn Lindeijer <thorbjorn@lindeijer.nl>
5  *
6  * This file is part of Tiled.
7  *
8  * This program is free software; you can redistribute it and/or modify it
9  * under the terms of the GNU General Public License as published by the Free
10  * Software Foundation; either version 2 of the License, or (at your option)
11  * any later version.
12  *
13  * This program is distributed in the hope that it will be useful, but WITHOUT
14  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
16  * more details.
17  *
18  * You should have received a copy of the GNU General Public License along with
19  * this program. If not, see <http://www.gnu.org/licenses/>.
20  */
21 
22 #pragma once
23 
24 #include "mapdocument.h"
25 #include "tilesetdocument.h"
26 
27 #include <QHash>
28 #include <QList>
29 #include <QObject>
30 #include <QPointF>
31 #include <QPointer>
32 #include <QVector>
33 
34 class QTabWidget;
35 class QUndoGroup;
36 class QStackedLayout;
37 class QTabBar;
38 
39 namespace Tiled {
40 
41 class FileSystemWatcher;
42 
43 class AbstractTool;
44 class BrokenLinksModel;
45 class BrokenLinksWidget;
46 class Document;
47 class Editor;
48 class FileChangedWarning;
49 class MainWindow;
50 class MapDocument;
51 class MapEditor;
52 class MapView;
53 class TilesetDocument;
54 class TilesetDocumentsModel;
55 class WorldDocument;
56 
57 /**
58  * This class controls the open documents.
59  */
60 class DocumentManager : public QObject
61 {
62     Q_OBJECT
63 
64     Q_PROPERTY(Document *currentDocument READ currentDocument NOTIFY currentDocumentChanged)
65 
66     DocumentManager(QObject *parent = nullptr);
67     ~DocumentManager() override;
68 
69     friend class MainWindow;
70 
71 public:
72     static DocumentManager *instance();
73     static DocumentManager *maybeInstance();
74 
75     QWidget *widget() const;
76 
77     void setEditor(Document::DocumentType documentType, Editor *editor);
78     Editor *editor(Document::DocumentType documentType) const;
79     void deleteEditors();
80     QList<Editor*> editors() const;
81 
82     Editor *currentEditor() const;
83 
84     void saveState();
85     void restoreState();
86 
87     QUndoGroup *undoGroup() const;
88 
89     Document *currentDocument() const;
90 
91     MapView *currentMapView() const;
92     MapView *viewForDocument(MapDocument *mapDocument) const;
93 
94     int findDocument(const QString &fileName) const;
95     int findDocument(Document *document) const;
96 
97     void switchToDocument(int index);
98     bool switchToDocument(const QString &fileName);
99     bool switchToDocument(Document *document);
100     void switchToDocument(MapDocument *mapDocument, QPointF viewCenter, qreal scale);
101     void switchToDocumentAndHandleSimiliarTileset(MapDocument *mapDocument, QPointF viewCenter, qreal scale);
102 
103     void addDocument(const DocumentPtr &document);
104     void insertDocument(int index, const DocumentPtr &document);
105 
106     bool isDocumentModified(Document *document) const;
107 
108     DocumentPtr loadDocument(const QString &fileName,
109                              FileFormat *fileFormat = nullptr,
110                              QString *error = nullptr);
111 
112     bool saveDocument(Document *document, const QString &fileName);
113     bool saveDocumentAs(Document *document);
114 
115     void closeCurrentDocument();
116     void closeAllDocuments();
117 
118     void closeOtherDocuments(int index);
119     void closeDocumentsToRight(int index);
120     void closeDocumentAt(int index);
121 
122     bool reloadCurrentDocument();
123     bool reloadDocumentAt(int index);
124 
125     void checkTilesetColumns(MapDocument *mapDocument);
126     bool checkTilesetColumns(TilesetDocument *tilesetDocument);
127 
128     const QVector<DocumentPtr> &documents() const;
129 
130     TilesetDocumentsModel *tilesetDocumentsModel() const;
131 
132     TilesetDocument *findTilesetDocument(const SharedTileset &tileset) const;
133     TilesetDocument *findTilesetDocument(const QString &fileName) const;
134 
135     void openTileset(const SharedTileset &tileset);
136 
137     void abortMultiDocumentClose();
138 
139     WorldDocument *ensureWorldDocument(const QString &fileName);
140     bool isAnyWorldModified() const;
141     bool isWorldModified(const QString &fileName) const;
142 
143     QString fileDialogStartLocation() const;
144 
145 signals:
146     void documentCreated(Document *document);
147     void documentOpened(Document *document);
148     void documentAboutToBeSaved(Document *document);
149     void documentSaved(Document *document);
150 
151     void fileOpenDialogRequested();
152     void fileOpenRequested(const QString &path);
153     void fileSaveRequested();
154     void templateOpenRequested(const QString &path);
155     void selectCustomPropertyRequested(const QString &name);
156     void templateTilesetReplaced();
157 
158     /**
159      * Emitted when the current displayed map document changed.
160      */
161     void currentDocumentChanged(Document *document);
162 
163     /**
164      * Emitted when the user requested the document at \a index to be closed.
165      */
166     void documentCloseRequested(int index);
167 
168     /**
169      * Emitted when a document is about to be closed.
170      */
171     void documentAboutToClose(Document *document);
172 
173     void currentEditorChanged(Editor *editor);
174 
175     /**
176      * Emitted when an error occurred while reloading the map.
177      */
178     void reloadError(const QString &error);
179 
180     void tilesetDocumentAdded(TilesetDocument *tilesetDocument);
181     void tilesetDocumentRemoved(TilesetDocument *tilesetDocument);
182 
183 public slots:
184     void switchToLeftDocument();
185     void switchToRightDocument();
186 
187     void openFileDialog();
188     void openFile(const QString &path);
189     void saveFile();
190 
191 private:
192     void onWorldUnloaded(const QString &worldFile);
193 
194     void currentIndexChanged();
195     void fileNameChanged(const QString &fileName,
196                          const QString &oldFileName);
197     void updateDocumentTab(Document *document);
198     void onDocumentSaved();
199     void documentTabMoved(int from, int to);
200     void tabContextMenuRequested(const QPoint &pos);
201 
202     void tilesetAdded(int index, Tileset *tileset);
203     void tilesetRemoved(Tileset *tileset);
204 
205     void tilesetNameChanged(Tileset *tileset);
206 
207     void filesChanged(const QStringList &fileNames);
208     void fileChanged(const QString &fileName);
209     void hideChangedWarning();
210 
211     void tilesetImagesChanged(Tileset *tileset);
212 
213     bool askForAdjustment(const Tileset &tileset);
214 
215     void addToTilesetDocument(const SharedTileset &tileset, MapDocument *mapDocument);
216     void removeFromTilesetDocument(const SharedTileset &tileset, MapDocument *mapDocument);
217 
218     void updateSession() const;
219 
220     MapDocument *openMapFile(const QString &path);
221     TilesetDocument *openTilesetFile(const QString &path);
222 
223     QVector<DocumentPtr> mDocuments;
224     QMap<QString, WorldDocument*> mWorldDocuments;
225     TilesetDocumentsModel *mTilesetDocumentsModel;
226 
227     // Pointer becomes null when deleted as part of the UI, to prevent double-deletion
228     QPointer<QWidget> mWidget;
229     QWidget *mNoEditorWidget;
230     QTabBar *mTabBar;
231     FileChangedWarning *mFileChangedWarning;
232     BrokenLinksModel *mBrokenLinksModel;
233     BrokenLinksWidget *mBrokenLinksWidget;
234     QStackedLayout *mEditorStack;
235     MapEditor *mMapEditor;
236 
237     QHash<Document::DocumentType, Editor*> mEditorForType;
238 
239     QUndoGroup *mUndoGroup;
240     FileSystemWatcher *mFileSystemWatcher;
241 
242     static DocumentManager *mInstance;
243 
244     bool mMultiDocumentClose;
245 };
246 
247 /**
248  * Returns the undo group that combines the undo stacks of all opened
249  * documents.
250  *
251  * @see Document::undoStack()
252  */
undoGroup()253 inline QUndoGroup *DocumentManager::undoGroup() const
254 {
255     return mUndoGroup;
256 }
257 
258 /**
259  * Returns all open documents.
260  */
documents()261 inline const QVector<DocumentPtr> &DocumentManager::documents() const
262 {
263     return mDocuments;
264 }
265 
tilesetDocumentsModel()266 inline TilesetDocumentsModel *DocumentManager::tilesetDocumentsModel() const
267 {
268     return mTilesetDocumentsModel;
269 }
270 
271 } // namespace Tiled
272