1 /*
2  * brokenlinks.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 "mapdocument.h"
24 #include "tileset.h"
25 
26 #include <QAbstractListModel>
27 #include <QWidget>
28 
29 class QAbstractButton;
30 class QDialogButtonBox;
31 class QItemSelection;
32 class QLabel;
33 class QSortFilterProxyModel;
34 class QTreeView;
35 
36 namespace Tiled {
37 
38 class Tile;
39 class Tileset;
40 class ObjectTemplate;
41 
42 class Document;
43 class TilesetDocument;
44 
45 enum BrokenLinkType {
46     MapTilesetReference,
47     ObjectTemplateTilesetReference,
48     TilesetTileImageSource,
49     TilesetImageSource,
50     ObjectTemplateReference,
51 };
52 
53 struct BrokenLink {
54     BrokenLinkType type;
55 
56     union {
57         Tileset *_tileset;
58         Tile *_tile;
59         const ObjectTemplate *_objectTemplate;
60     };
61 
62     QString filePath() const;
63     Tileset *tileset() const;
64     const ObjectTemplate *objectTemplate() const;
65 };
66 
67 
68 class BrokenLinksModel : public QAbstractListModel
69 {
70     Q_OBJECT
71     Q_PROPERTY(bool hasBrokenLinks READ hasBrokenLinks NOTIFY hasBrokenLinksChanged)
72 
73 public:
74     BrokenLinksModel(QObject *parent = nullptr);
75 
76     void setDocument(Document *document);
77     Document *document() const;
78 
79     void refresh();
80     bool hasBrokenLinks() const;
81 
82     const BrokenLink &brokenLink(int index) const;
83 
84     int rowCount(const QModelIndex &parent = QModelIndex()) const override;
85     int columnCount(const QModelIndex &parent = QModelIndex()) const override;
86     QVariant data(const QModelIndex &index, int role) const override;
87     QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
88 
89 signals:
90     void hasBrokenLinksChanged(bool hasBrokenLinks);
91 
92 private:
93     void tileImageSourceChanged(Tile *tile);
94     void tilesetChanged(Tileset *tileset);
95 
96     void tilesetAdded(int index, Tileset *tileset);
97     void tilesetRemoved(Tileset *tileset);
98 
99     void connectToTileset(const SharedTileset &tileset);
100     void disconnectFromTileset(const SharedTileset &tileset);
101 
102     void removeLink(int index);
103 
104     Document *mDocument;
105     QVector<BrokenLink> mBrokenLinks;
106 };
107 
108 
document()109 inline Document *BrokenLinksModel::document() const
110 {
111     return mDocument;
112 }
113 
hasBrokenLinks()114 inline bool BrokenLinksModel::hasBrokenLinks() const
115 {
116     return !mBrokenLinks.isEmpty();
117 }
118 
brokenLink(int index)119 inline const BrokenLink &BrokenLinksModel::brokenLink(int index) const
120 {
121     return mBrokenLinks.at(index);
122 }
123 
124 
125 class BrokenLinksWidget : public QWidget
126 {
127     Q_OBJECT
128 
129 public:
130     BrokenLinksWidget(BrokenLinksModel *brokenLinksModel, QWidget *parent = nullptr);
131 
132 signals:
133     void ignore();
134 
135 private:
136     void clicked(QAbstractButton *button);
137     void selectionChanged();
138 
139     BrokenLinksModel *mBrokenLinksModel;
140     QSortFilterProxyModel *mProxyModel;
141     QLabel *mTitleLabel;
142     QLabel *mDescriptionLabel;
143     QTreeView *mView;
144     QDialogButtonBox *mButtons;
145     QAbstractButton *mLocateButton;
146 };
147 
148 
149 class LinkFixer
150 {
151 public:
152     LinkFixer(Document *document);
153 
154     void tryFixLinks(const QVector<BrokenLink> &links);
155     void tryFixLink(const BrokenLink &link);
156     bool tryFixLink(const BrokenLink &link, const QString &newFilePath);
157 
158     static QUrl locateImage(const QString &fileName);
159     static QString locateTileset();
160     static QString locateObjectTemplate();
161 
162     void tryFixMapTilesetReference(const SharedTileset &tileset);
163     void tryFixObjectTemplateReference(const ObjectTemplate *objectTemplate);
164 
165 private:
166     bool tryFixMapTilesetReference(const SharedTileset &tileset, const QString &newFilePath);
167     bool tryFixObjectTemplateReference(const ObjectTemplate *objectTemplate, const QString &newFilePath);
168 
169     Document *mDocument;
170 };
171 
172 
173 struct LocateTileset
174 {
175     QWeakPointer<Tileset> mTileset;
176     QWeakPointer<MapDocument> mMapDocument;
177 
178     void operator()() const;
179 };
180 
181 struct LocateObjectTemplate
182 {
183     const ObjectTemplate *mObjectTemplate;
184     QWeakPointer<MapDocument> mMapDocument;
185 
186     void operator()() const;
187 };
188 
189 } // namespace Tiled
190