1 /*
2  * logginginterface.h
3  * Copyright 2013, Samuli Tuomola <samuli.tuomola@gmail.com>
4  * Copyright 2015, Thorbjørn Lindeijer <bjorn@lindeijer.nl>
5  *
6  * This file is part of libtiled.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions are met:
10  *
11  *    1. Redistributions of source code must retain the above copyright notice,
12  *       this list of conditions and the following disclaimer.
13  *
14  *    2. Redistributions in binary form must reproduce the above copyright
15  *       notice, this list of conditions and the following disclaimer in the
16  *       documentation and/or other materials provided with the distribution.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
19  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
20  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
21  * EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
24  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
26  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
27  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29 
30 #pragma once
31 
32 #include "tiled_global.h"
33 
34 #include <QObject>
35 #include <QPoint>
36 #include <QWeakPointer>
37 
38 #include <functional>
39 
40 class QString;
41 
42 namespace Tiled {
43 
44 class Layer;
45 class Map;
46 class MapObject;
47 class Object;
48 class Tile;
49 class Tileset;
50 
51 class TILEDSHARED_EXPORT Issue
52 {
53 public:
54     enum Severity {
55         Error,
56         Warning
57     };
58 
59     Issue();
60     Issue(Severity severity,
61           const QString &text,
62           const std::function<void()> &callback = std::function<void()>(),
63           const void *context = nullptr);
64 
severity()65     Severity severity() const { return mSeverity; }
text()66     QString text() const { return mText; }
67 
callback()68     std::function<void()> callback() const { return mCallback; }
69     void setCallback(std::function<void()> callback);
70 
setContext(const void * context)71     void setContext(const void *context) { mContext = context; }
context()72     const void *context() const { return mContext; }
73 
id()74     unsigned id() const { return mId; }
75 
76     void addOccurrence(const Issue &issue);
occurrences()77     int occurrences() const { return mOccurrences; }
78 
79     bool operator==(const Issue &o) const
80     {
81         return severity() == o.severity()
82                 && text() == o.text();
83     }
84 
85 private:
86     Issue::Severity mSeverity = Issue::Error;
87     QString mText;
88     std::function<void()> mCallback;
89     const void *mContext = nullptr;
90 
91     int mOccurrences = 1;
92     unsigned mId = 0;
93 
94     static unsigned mNextIssueId;
95 };
96 
97 /**
98  * An interface for reporting issues.
99  *
100  * Normally you'd use the convenience functions in the Tiled namespace.
101  */
102 class TILEDSHARED_EXPORT LoggingInterface : public QObject
103 {
104     Q_OBJECT
105 
106     explicit LoggingInterface(QObject *parent = nullptr);
107 
108 public:
109     static LoggingInterface &instance();
110 
111     enum OutputType {
112         INFO,
113         WARNING,
114         ERROR
115     };
116 
117     void report(const Issue &issue);
118     void log(OutputType type, const QString &message);
119 
120 signals:
121     void issue(const Tiled::Issue &issue);
122 
123     void info(const QString &message);
124     void warning(const QString &message);
125     void error(const QString &message);
126 
127     void removeIssuesWithContext(const void *context);
128 };
129 
REPORT(const Issue & issue)130 inline void REPORT(const Issue &issue)
131 {
132     LoggingInterface::instance().report(issue);
133 }
134 
INFO(const QString & message)135 inline void INFO(const QString &message)
136 {
137     LoggingInterface::instance().log(LoggingInterface::INFO, message);
138 }
139 
140 inline void WARNING(const QString &message, std::function<void()> callback = std::function<void()>(), const void *context = nullptr)
141 {
142     REPORT(Issue { Issue::Warning, message, callback, context });
143 }
144 
145 inline void ERROR(const QString &message, std::function<void()> callback = std::function<void()>(), const void *context = nullptr)
146 {
147     REPORT(Issue { Issue::Error, message, callback, context });
148 }
149 
INFO(QLatin1String message)150 inline void INFO(QLatin1String message)
151 {
152     INFO(QString(message));
153 }
154 
155 inline void WARNING(QLatin1String message, std::function<void()> callback = std::function<void()>(), const void *context = nullptr)
156 {
157     WARNING(QString(message), callback, context);
158 }
159 
160 inline void ERROR(QLatin1String message, std::function<void()> callback = std::function<void()>(), const void *context = nullptr)
161 {
162     ERROR(QString(message), callback, context);
163 }
164 
165 // TODO: Try "static inline" once we switch to C++17
166 #define ACTIVATABLE(Class) \
167     void operator() () const { activated(*this); } \
168     static std::function<void (const Class &)> activated;
169 
170 struct TILEDSHARED_EXPORT OpenFile
171 {
172     QString file;
173 
174     ACTIVATABLE(OpenFile)
175 };
176 
177 struct TILEDSHARED_EXPORT JumpToTile
178 {
179     JumpToTile(const Map *map, QPoint tilePos, const Layer *layer = nullptr);
180 
181     QString mapFile;
182     QPoint tilePos;
183     int layerId = -1;
184 
185     ACTIVATABLE(JumpToTile)
186 };
187 
188 struct TILEDSHARED_EXPORT JumpToObject
189 {
190     JumpToObject(const MapObject *object);
191 
192     QString mapFile;
193     int objectId;
194 
195     ACTIVATABLE(JumpToObject)
196 };
197 
198 struct TILEDSHARED_EXPORT SelectLayer
199 {
200     SelectLayer(const Layer *layer);
201 
202     QString mapFile;
203     int layerId;
204 
205     ACTIVATABLE(SelectLayer)
206 };
207 
208 struct TILEDSHARED_EXPORT SelectCustomProperty
209 {
210     SelectCustomProperty(QString fileName, QString propertyName, const Object *object);
211 
212     QString fileName;
213     QString propertyName;
214     int objectType;         // see Object::TypeId
215     int id = -1;
216 
217     ACTIVATABLE(SelectCustomProperty)
218 };
219 
220 struct TILEDSHARED_EXPORT SelectTile
221 {
222     SelectTile(const Tile *tile);
223 
224     QWeakPointer<Tileset> tileset;
225     QString tilesetFile;
226     int tileId;
227 
228     ACTIVATABLE(SelectTile)
229 };
230 
231 #undef ACTIVATABLE
232 
233 } // namespace Tiled
234 
235 Q_DECLARE_METATYPE(Tiled::Issue)
236