change dlog -> dutil/log
Change-Id: I5dc77ced2acdd273e048a913409f1cff6e7bc075
Iceyer
8 years ago
0 | 0 | #!/bin/bash |
1 | 1 | |
2 | tr '\n' ' ' < $1 | sed -e "s/#include//g" | sed -e "s/\"//g" | |
2 | public_header=$1 | |
3 | headers=`tr '\n' ' ' < $public_header | sed -e "s/#include//g" | sed -e "s/\"//g"` | |
4 | file_dir=$(dirname "${public_header}") | |
5 | for f in $headers | |
6 | do | |
7 | echo $file_dir/$f | |
8 | done |
0 | // Local | |
1 | #include "AbstractAppender.h" | |
2 | ||
3 | // Qt | |
4 | #include <QMutexLocker> | |
5 | ||
6 | namespace Dtk { | |
7 | namespace Log { | |
8 | ||
9 | /** | |
10 | * \class AbstractAppender | |
11 | * | |
12 | * \brief The AbstractAppender class provides an abstract base class for writing a log entries. | |
13 | * | |
14 | * The AbstractAppender class is the base interface class for all log appenders that could be used with Logger. | |
15 | * | |
16 | * AbstractAppender provides a common implementation for the thread safe, mutex-protected logging of application | |
17 | * messages, such as ConsoleAppender, FileAppender or something else. AbstractAppender is abstract and can not be | |
18 | * instantiated, but you can use any of its subclasses or create a custom log appender at your choice. | |
19 | * | |
20 | * Appenders are the logical devices that is aimed to be attached to Logger object by calling | |
21 | * Logger::registerAppender(). On each log record call from the application Logger object sequentially calls write() | |
22 | * function on all the appenders registered in it. | |
23 | * | |
24 | * You can subclass AbstractAppender to implement a logging target of any kind you like. It may be the external logging | |
25 | * subsystem (for example, syslog in *nix), XML file, SQL database entries, D-Bus messages or anything else you can | |
26 | * imagine. | |
27 | * | |
28 | * For the simple non-structured plain text logging (for example, to a plain text file or to the console output) you may | |
29 | * like to subclass the AbstractStringAppender instead of AbstractAppender, which will give you a more convinient way to | |
30 | * control the format of the log output. | |
31 | * | |
32 | * \sa AbstractStringAppender | |
33 | * \sa Logger::registerAppender() | |
34 | */ | |
35 | ||
36 | ||
37 | //! Constructs a AbstractAppender object. | |
38 | AbstractAppender::AbstractAppender() | |
39 | : m_detailsLevel(Logger::Debug) | |
40 | {} | |
41 | ||
42 | ||
43 | //! Destructs the AbstractAppender object. | |
44 | AbstractAppender::~AbstractAppender() | |
45 | {} | |
46 | ||
47 | ||
48 | //! Returns the current details level of appender. | |
49 | /** | |
50 | * Log records with a log level lower than a current detailsLevel() will be silently ignored by appender and would not | |
51 | * be sent to its append() function. | |
52 | * | |
53 | * It provides additional logging flexibility, allowing you to set the different severity levels for different types | |
54 | * of logs. | |
55 | * | |
56 | * \note This function is thread safe. | |
57 | * | |
58 | * \sa setDetailsLevel() | |
59 | * \sa Logger::LogLevel | |
60 | */ | |
61 | Logger::LogLevel AbstractAppender::detailsLevel() const | |
62 | { | |
63 | QMutexLocker locker(&m_detailsLevelMutex); | |
64 | return m_detailsLevel; | |
65 | } | |
66 | ||
67 | ||
68 | //! Sets the current details level of appender. | |
69 | /** | |
70 | * Default details level is Logger::Debug | |
71 | * | |
72 | * \note This function is thread safe. | |
73 | * | |
74 | * \sa detailsLevel() | |
75 | * \sa Logger::LogLevel | |
76 | */ | |
77 | void AbstractAppender::setDetailsLevel(Logger::LogLevel level) | |
78 | { | |
79 | QMutexLocker locker(&m_detailsLevelMutex); | |
80 | m_detailsLevel = level; | |
81 | } | |
82 | ||
83 | ||
84 | ||
85 | //! Sets the current details level of appender | |
86 | /** | |
87 | * This function is provided for convenience, it behaves like an above function. | |
88 | * | |
89 | * \sa detailsLevel() | |
90 | * \sa Logger::LogLevel | |
91 | */ | |
92 | void AbstractAppender::setDetailsLevel(const QString& level) | |
93 | { | |
94 | setDetailsLevel(Logger::levelFromString(level)); | |
95 | } | |
96 | ||
97 | ||
98 | //! Tries to write the log record to this logger | |
99 | /** | |
100 | * This is the function called by Logger object to write a log message to the appender. | |
101 | * | |
102 | * \note This function is thread safe. | |
103 | * | |
104 | * \sa Logger::write() | |
105 | * \sa detailsLevel() | |
106 | */ | |
107 | void AbstractAppender::write(const QDateTime& timeStamp, Logger::LogLevel logLevel, const char* file, int line, | |
108 | const char* function, const QString& category, const QString& message) | |
109 | { | |
110 | if (logLevel >= detailsLevel()) | |
111 | { | |
112 | QMutexLocker locker(&m_writeMutex); | |
113 | append(timeStamp, logLevel, file, line, function, category, message); | |
114 | } | |
115 | } | |
116 | ||
117 | ||
118 | /** | |
119 | * \fn virtual void AbstractAppender::append(const QDateTime& timeStamp, Logger::LogLevel logLevel, const char* file, | |
120 | * int line, const char* function, const QString& message) | |
121 | * | |
122 | * \brief Writes the log record to the logger instance | |
123 | * | |
124 | * This function is called every time when user tries to write a message to this AbstractAppender instance using | |
125 | * the write() function. Write function works as proxy and transfers only the messages with log level more or equal | |
126 | * to the current logLevel(). | |
127 | * | |
128 | * Overload this function when you are implementing a custom appender. | |
129 | * | |
130 | * \note This function is not needed to be thread safe because it is never called directly by Logger object. The | |
131 | * write() function works as a proxy and protects this function from concurrent access. | |
132 | * | |
133 | * \sa Logger::write() | |
134 | */ | |
135 | ||
136 | } | |
137 | } |
0 | /* | |
1 | Copyright (c) 2010 Boris Moiseev (cyberbobs at gmail dot com) | |
2 | ||
3 | This program is free software: you can redistribute it and/or modify | |
4 | it under the terms of the GNU Lesser General Public License version 2.1 | |
5 | as published by the Free Software Foundation and appearing in the file | |
6 | LICENSE.LGPL included in the packaging of this file. | |
7 | ||
8 | This program is distributed in the hope that it will be useful, | |
9 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
11 | GNU Lesser General Public License for more details. | |
12 | */ | |
13 | #ifndef ABSTRACTAPPENDER_H | |
14 | #define ABSTRACTAPPENDER_H | |
15 | ||
16 | // Local | |
17 | #include "CuteLogger_global.h" | |
18 | #include <Logger.h> | |
19 | ||
20 | // Qt | |
21 | #include <QMutex> | |
22 | ||
23 | namespace Dtk { | |
24 | namespace Log { | |
25 | ||
26 | class CUTELOGGERSHARED_EXPORT AbstractAppender | |
27 | { | |
28 | public: | |
29 | AbstractAppender(); | |
30 | virtual ~AbstractAppender(); | |
31 | ||
32 | Logger::LogLevel detailsLevel() const; | |
33 | void setDetailsLevel(Logger::LogLevel level); | |
34 | void setDetailsLevel(const QString& level); | |
35 | ||
36 | void write(const QDateTime& timeStamp, Logger::LogLevel logLevel, const char* file, int line, const char* function, | |
37 | const QString& category, const QString& message); | |
38 | ||
39 | protected: | |
40 | virtual void append(const QDateTime& timeStamp, Logger::LogLevel logLevel, const char* file, int line, | |
41 | const char* function, const QString& category, const QString& message) = 0; | |
42 | ||
43 | private: | |
44 | QMutex m_writeMutex; | |
45 | ||
46 | Logger::LogLevel m_detailsLevel; | |
47 | mutable QMutex m_detailsLevelMutex; | |
48 | }; | |
49 | ||
50 | }} | |
51 | ||
52 | #endif // ABSTRACTAPPENDER_H |
0 | /* | |
1 | Copyright (c) 2010 Boris Moiseev (cyberbobs at gmail dot com) Nikolay Matyunin (matyunin.n at gmail dot com) | |
2 | ||
3 | Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). | |
4 | ||
5 | This program is free software: you can redistribute it and/or modify | |
6 | it under the terms of the GNU Lesser General Public License version 2.1 | |
7 | as published by the Free Software Foundation and appearing in the file | |
8 | LICENSE.LGPL included in the packaging of this file. | |
9 | ||
10 | This program is distributed in the hope that it will be useful, | |
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
13 | GNU Lesser General Public License for more details. | |
14 | */ | |
15 | // Local | |
16 | #include "AbstractStringAppender.h" | |
17 | ||
18 | // Qt | |
19 | #include <QReadLocker> | |
20 | #include <QWriteLocker> | |
21 | #include <QDateTime> | |
22 | #include <QRegExp> | |
23 | #include <QCoreApplication> | |
24 | #include <QThread> | |
25 | ||
26 | namespace Dtk { | |
27 | namespace Log { | |
28 | ||
29 | /** | |
30 | * \class AbstractStringAppender | |
31 | * | |
32 | * \brief The AbstractStringAppender class provides a convinient base for appenders working with plain text formatted | |
33 | * logs. | |
34 | * | |
35 | * AbstractSringAppender is the simple extension of the AbstractAppender class providing the convinient way to create | |
36 | * custom log appenders working with a plain text formatted log targets. | |
37 | * | |
38 | * It have the formattedString() protected function that formats the logging arguments according to a format set with | |
39 | * setFormat(). | |
40 | * | |
41 | * This class can not be directly instantiated because it contains pure virtual function inherited from AbstractAppender | |
42 | * class. | |
43 | * | |
44 | * For more detailed description of customizing the log output format see the documentation on the setFormat() function. | |
45 | */ | |
46 | ||
47 | ||
48 | const char formattingMarker = '%'; | |
49 | ||
50 | ||
51 | //! Constructs a new string appender object | |
52 | AbstractStringAppender::AbstractStringAppender() | |
53 | : m_format(QLatin1String("%{time}{yyyy-MM-ddTHH:mm:ss.zzz} [%{type:-7}] <%{function}> %{message}\n")) | |
54 | {} | |
55 | ||
56 | ||
57 | //! Returns the current log format string. | |
58 | /** | |
59 | * The default format is set to "%{time}{yyyy-MM-ddTHH:mm:ss.zzz} [%{type:-7}] <%{function}> %{message}\n". You can set a different log record | |
60 | * format using the setFormat() function. | |
61 | * | |
62 | * \sa setFormat(const QString&) | |
63 | */ | |
64 | QString AbstractStringAppender::format() const | |
65 | { | |
66 | QReadLocker locker(&m_formatLock); | |
67 | return m_format; | |
68 | } | |
69 | ||
70 | ||
71 | //! Sets the logging format for writing strings to the log target with this appender. | |
72 | /** | |
73 | * The string format seems to be very common to those developers who have used a standart sprintf function. | |
74 | * | |
75 | * Log output format is a simple QString with the special markers (starting with % sign) which will be replaced with | |
76 | * it's internal meaning when writing a log record. | |
77 | * | |
78 | * Controlling marker begins with the percent sign (%) which is followed by the command inside {} brackets | |
79 | * (the command describes, what will be put to log record instead of marker). | |
80 | * Optional field width argument may be specified right after the command (through the colon symbol before the closing bracket) | |
81 | * Some commands requires an additional formatting argument (in the second {} brackets). | |
82 | * | |
83 | * Field width argument works almost identically to the \c QString::arg() \c fieldWidth argument (and uses it | |
84 | * internally). For example, \c "%{type:-7}" will be replaced with the left padded debug level of the message | |
85 | * (\c "Debug ") or something. For the more detailed description of it you may consider to look to the Qt | |
86 | * Reference Documentation. | |
87 | * | |
88 | * Supported marker commands are: | |
89 | * \arg \c %{time} - timestamp. You may specify your custom timestamp format using the second {} brackets after the marker, | |
90 | * timestamp format here will be similiar to those used in QDateTime::toString() function. For example, | |
91 | * "%{time}{dd-MM-yyyy, HH:mm}" may be replaced with "17-12-2010, 20:17" depending on current date and time. | |
92 | * The default format used here is "HH:mm:ss.zzz". | |
93 | * \arg \c %{type} - Log level. Possible log levels are shown in the Logger::LogLevel enumerator. | |
94 | * \arg \c %{Type} - Uppercased log level. | |
95 | * \arg \c %{typeOne} - One letter log level. | |
96 | * \arg \c %{TypeOne} - One uppercase letter log level. | |
97 | * \arg \c %{File} - Full source file name (with path) of the file that requested log recording. Uses the \c __FILE__ | |
98 | * preprocessor macro. | |
99 | * \arg \c %{file} - Short file name (with stripped path). | |
100 | * \arg \c %{line} - Line number in the source file. Uses the \c __LINE__ preprocessor macro. | |
101 | * \arg \c %{Function} - Name of function that called on of the LOG_* macros. Uses the \c Q_FUNC_INFO macro provided with | |
102 | * Qt. | |
103 | * \arg \c %{function} - Similiar to the %{Function}, but the function name is stripped using stripFunctionName | |
104 | * \arg \c %{message} - The log message sent by the caller. | |
105 | * \arg \c %{category} - The log category. | |
106 | * \arg \c %{appname} - Application name (returned by QCoreApplication::applicationName() function). | |
107 | * \arg \c %{pid} - Application pid (returned by QCoreApplication::applicationPid() function). | |
108 | * \arg \c %{threadid} - ID of current thread. | |
109 | * \arg \c %% - Convinient marker that is replaced with the single \c % mark. | |
110 | * | |
111 | * \note Format doesn't add \c '\\n' to the end of the format line. Please consider adding it manually. | |
112 | * | |
113 | * \sa format() | |
114 | * \sa stripFunctionName() | |
115 | * \sa Logger::LogLevel | |
116 | */ | |
117 | void AbstractStringAppender::setFormat(const QString& format) | |
118 | { | |
119 | QWriteLocker locker(&m_formatLock); | |
120 | m_format = format; | |
121 | } | |
122 | ||
123 | ||
124 | //! Strips the long function signature (as added by Q_FUNC_INFO macro) | |
125 | /** | |
126 | * The string processing drops the returning type, arguments and template parameters of function. It is definitely | |
127 | * useful for enchancing the log output readability. | |
128 | * \return stripped function name | |
129 | */ | |
130 | QString AbstractStringAppender::stripFunctionName(const char* name) | |
131 | { | |
132 | return QString::fromLatin1(qCleanupFuncinfo(name)); | |
133 | } | |
134 | ||
135 | ||
136 | // The function was backported from Qt5 sources (qlogging.h) | |
137 | QByteArray AbstractStringAppender::qCleanupFuncinfo(const char* name) | |
138 | { | |
139 | QByteArray info(name); | |
140 | ||
141 | // Strip the function info down to the base function name | |
142 | // note that this throws away the template definitions, | |
143 | // the parameter types (overloads) and any const/volatile qualifiers. | |
144 | if (info.isEmpty()) | |
145 | return info; | |
146 | ||
147 | int pos; | |
148 | ||
149 | // skip trailing [with XXX] for templates (gcc) | |
150 | pos = info.size() - 1; | |
151 | if (info.endsWith(']')) { | |
152 | while (--pos) { | |
153 | if (info.at(pos) == '[') | |
154 | info.truncate(pos); | |
155 | } | |
156 | } | |
157 | ||
158 | bool hasLambda = false; | |
159 | QRegExp lambdaRegex("::<lambda\\(.*\\)>"); | |
160 | int lambdaIndex = lambdaRegex.indexIn(QString::fromLatin1(info)); | |
161 | if (lambdaIndex != -1) | |
162 | { | |
163 | hasLambda = true; | |
164 | info.remove(lambdaIndex, lambdaRegex.matchedLength()); | |
165 | } | |
166 | ||
167 | // operator names with '(', ')', '<', '>' in it | |
168 | static const char operator_call[] = "operator()"; | |
169 | static const char operator_lessThan[] = "operator<"; | |
170 | static const char operator_greaterThan[] = "operator>"; | |
171 | static const char operator_lessThanEqual[] = "operator<="; | |
172 | static const char operator_greaterThanEqual[] = "operator>="; | |
173 | ||
174 | // canonize operator names | |
175 | info.replace("operator ", "operator"); | |
176 | ||
177 | // remove argument list | |
178 | forever { | |
179 | int parencount = 0; | |
180 | pos = info.lastIndexOf(')'); | |
181 | if (pos == -1) { | |
182 | // Don't know how to parse this function name | |
183 | return info; | |
184 | } | |
185 | ||
186 | // find the beginning of the argument list | |
187 | --pos; | |
188 | ++parencount; | |
189 | while (pos && parencount) { | |
190 | if (info.at(pos) == ')') | |
191 | ++parencount; | |
192 | else if (info.at(pos) == '(') | |
193 | --parencount; | |
194 | --pos; | |
195 | } | |
196 | if (parencount != 0) | |
197 | return info; | |
198 | ||
199 | info.truncate(++pos); | |
200 | ||
201 | if (info.at(pos - 1) == ')') { | |
202 | if (info.indexOf(operator_call) == pos - (int)strlen(operator_call)) | |
203 | break; | |
204 | ||
205 | // this function returns a pointer to a function | |
206 | // and we matched the arguments of the return type's parameter list | |
207 | // try again | |
208 | info.remove(0, info.indexOf('(')); | |
209 | info.chop(1); | |
210 | continue; | |
211 | } else { | |
212 | break; | |
213 | } | |
214 | } | |
215 | ||
216 | if (hasLambda) | |
217 | info.append("::lambda"); | |
218 | ||
219 | // find the beginning of the function name | |
220 | int parencount = 0; | |
221 | int templatecount = 0; | |
222 | --pos; | |
223 | ||
224 | // make sure special characters in operator names are kept | |
225 | if (pos > -1) { | |
226 | switch (info.at(pos)) { | |
227 | case ')': | |
228 | if (info.indexOf(operator_call) == pos - (int)strlen(operator_call) + 1) | |
229 | pos -= 2; | |
230 | break; | |
231 | case '<': | |
232 | if (info.indexOf(operator_lessThan) == pos - (int)strlen(operator_lessThan) + 1) | |
233 | --pos; | |
234 | break; | |
235 | case '>': | |
236 | if (info.indexOf(operator_greaterThan) == pos - (int)strlen(operator_greaterThan) + 1) | |
237 | --pos; | |
238 | break; | |
239 | case '=': { | |
240 | int operatorLength = (int)strlen(operator_lessThanEqual); | |
241 | if (info.indexOf(operator_lessThanEqual) == pos - operatorLength + 1) | |
242 | pos -= 2; | |
243 | else if (info.indexOf(operator_greaterThanEqual) == pos - operatorLength + 1) | |
244 | pos -= 2; | |
245 | break; | |
246 | } | |
247 | default: | |
248 | break; | |
249 | } | |
250 | } | |
251 | ||
252 | while (pos > -1) { | |
253 | if (parencount < 0 || templatecount < 0) | |
254 | return info; | |
255 | ||
256 | char c = info.at(pos); | |
257 | if (c == ')') | |
258 | ++parencount; | |
259 | else if (c == '(') | |
260 | --parencount; | |
261 | else if (c == '>') | |
262 | ++templatecount; | |
263 | else if (c == '<') | |
264 | --templatecount; | |
265 | else if (c == ' ' && templatecount == 0 && parencount == 0) | |
266 | break; | |
267 | ||
268 | --pos; | |
269 | } | |
270 | info = info.mid(pos + 1); | |
271 | ||
272 | // remove trailing '*', '&' that are part of the return argument | |
273 | while ((info.at(0) == '*') | |
274 | || (info.at(0) == '&')) | |
275 | info = info.mid(1); | |
276 | ||
277 | // we have the full function name now. | |
278 | // clean up the templates | |
279 | while ((pos = info.lastIndexOf('>')) != -1) { | |
280 | if (!info.contains('<')) | |
281 | break; | |
282 | ||
283 | // find the matching close | |
284 | int end = pos; | |
285 | templatecount = 1; | |
286 | --pos; | |
287 | while (pos && templatecount) { | |
288 | register char c = info.at(pos); | |
289 | if (c == '>') | |
290 | ++templatecount; | |
291 | else if (c == '<') | |
292 | --templatecount; | |
293 | --pos; | |
294 | } | |
295 | ++pos; | |
296 | info.remove(pos, end - pos + 1); | |
297 | } | |
298 | ||
299 | return info; | |
300 | } | |
301 | ||
302 | ||
303 | //! Returns the string to record to the logging target, formatted according to the format(). | |
304 | /** | |
305 | * \sa format() | |
306 | * \sa setFormat(const QString&) | |
307 | */ | |
308 | QString AbstractStringAppender::formattedString(const QDateTime& timeStamp, Logger::LogLevel logLevel, const char* file, | |
309 | int line, const char* function, const QString& category, const QString& message) const | |
310 | { | |
311 | QString f = format(); | |
312 | const int size = f.size(); | |
313 | ||
314 | QString result; | |
315 | ||
316 | int i = 0; | |
317 | while (i < f.size()) | |
318 | { | |
319 | QChar c = f.at(i); | |
320 | ||
321 | // We will silently ignore the broken % marker at the end of string | |
322 | if (c != QLatin1Char(formattingMarker) || (i + 2) >= size) | |
323 | { | |
324 | result.append(c); | |
325 | } | |
326 | else | |
327 | { | |
328 | i += 2; | |
329 | QChar currentChar = f.at(i); | |
330 | QString command; | |
331 | int fieldWidth = 0; | |
332 | ||
333 | if (currentChar.isLetter()) | |
334 | { | |
335 | command.append(currentChar); | |
336 | int j = 1; | |
337 | while ((i + j) < size && f.at(i + j).isLetter()) | |
338 | { | |
339 | command.append(f.at(i+j)); | |
340 | j++; | |
341 | } | |
342 | ||
343 | i+=j; | |
344 | currentChar = f.at(i); | |
345 | ||
346 | // Check for the padding instruction | |
347 | if (currentChar == QLatin1Char(':')) | |
348 | { | |
349 | currentChar = f.at(++i); | |
350 | if (currentChar.isDigit() || currentChar.category() == QChar::Punctuation_Dash) | |
351 | { | |
352 | int j = 1; | |
353 | while ((i + j) < size && f.at(i + j).isDigit()) | |
354 | j++; | |
355 | fieldWidth = f.mid(i, j).toInt(); | |
356 | ||
357 | i += j; | |
358 | } | |
359 | } | |
360 | } | |
361 | ||
362 | // Log record chunk to insert instead of formatting instruction | |
363 | QString chunk; | |
364 | ||
365 | // Time stamp | |
366 | if (command == QLatin1String("time")) | |
367 | { | |
368 | if (f.at(i + 1) == QLatin1Char('{')) | |
369 | { | |
370 | int j = 1; | |
371 | while ((i + 2 + j) < size && f.at(i + 2 + j) != QLatin1Char('}')) | |
372 | j++; | |
373 | ||
374 | if ((i + 2 + j) < size) | |
375 | { | |
376 | chunk = timeStamp.toString(f.mid(i + 2, j)); | |
377 | ||
378 | i += j; | |
379 | i += 2; | |
380 | } | |
381 | } | |
382 | ||
383 | if (chunk.isNull()) | |
384 | chunk = timeStamp.toString(QLatin1String("HH:mm:ss.zzz")); | |
385 | } | |
386 | ||
387 | // Log level | |
388 | else if (command == QLatin1String("type")) | |
389 | chunk = Logger::levelToString(logLevel); | |
390 | ||
391 | // Uppercased log level | |
392 | else if (command == QLatin1String("Type")) | |
393 | chunk = Logger::levelToString(logLevel).toUpper(); | |
394 | ||
395 | // One letter log level | |
396 | else if (command == QLatin1String("typeOne")) | |
397 | chunk = Logger::levelToString(logLevel).left(1).toLower(); | |
398 | ||
399 | // One uppercase letter log level | |
400 | else if (command == QLatin1String("TypeOne")) | |
401 | chunk = Logger::levelToString(logLevel).left(1).toUpper(); | |
402 | ||
403 | // Filename | |
404 | else if (command == QLatin1String("File")) | |
405 | chunk = QLatin1String(file); | |
406 | ||
407 | // Filename without a path | |
408 | else if (command == QLatin1String("file")) | |
409 | chunk = QString(QLatin1String(file)).section('/', -1); | |
410 | ||
411 | // Source line number | |
412 | else if (command == QLatin1String("line")) | |
413 | chunk = QString::number(line); | |
414 | ||
415 | // Function name, as returned by Q_FUNC_INFO | |
416 | else if (command == QLatin1String("Function")) | |
417 | chunk = QString::fromLatin1(function); | |
418 | ||
419 | // Stripped function name | |
420 | else if (command == QLatin1String("function")) | |
421 | chunk = stripFunctionName(function); | |
422 | ||
423 | // Log message | |
424 | else if (command == QLatin1String("message")) | |
425 | chunk = message; | |
426 | ||
427 | else if (command == QLatin1String("category")) | |
428 | chunk = category; | |
429 | ||
430 | // Application pid | |
431 | else if (command == QLatin1String("pid")) | |
432 | chunk = QString::number(QCoreApplication::applicationPid()); | |
433 | ||
434 | // Appplication name | |
435 | else if (command == QLatin1String("appname")) | |
436 | chunk = QCoreApplication::applicationName(); | |
437 | ||
438 | // Thread ID (duplicates Qt5 threadid debbuging way) | |
439 | else if (command == QLatin1String("threadid")) | |
440 | chunk = QLatin1String("0x") + QString::number(qlonglong(QThread::currentThread()->currentThread()), 16); | |
441 | ||
442 | // We simply replace the double formatting marker (%) with one | |
443 | else if (command == QString(formattingMarker)) | |
444 | chunk = QLatin1Char(formattingMarker); | |
445 | ||
446 | // Do not process any unknown commands | |
447 | else | |
448 | { | |
449 | chunk = QString(formattingMarker); | |
450 | chunk.append(command); | |
451 | } | |
452 | ||
453 | result.append(QString(QLatin1String("%1")).arg(chunk, fieldWidth)); | |
454 | } | |
455 | ||
456 | ++i; | |
457 | } | |
458 | ||
459 | return result; | |
460 | } | |
461 | ||
462 | }} |
0 | /* | |
1 | Copyright (c) 2010 Boris Moiseev (cyberbobs at gmail dot com) | |
2 | ||
3 | This program is free software: you can redistribute it and/or modify | |
4 | it under the terms of the GNU Lesser General Public License version 2.1 | |
5 | as published by the Free Software Foundation and appearing in the file | |
6 | LICENSE.LGPL included in the packaging of this file. | |
7 | ||
8 | This program is distributed in the hope that it will be useful, | |
9 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
11 | GNU Lesser General Public License for more details. | |
12 | */ | |
13 | #ifndef ABSTRACTSTRINGAPPENDER_H | |
14 | #define ABSTRACTSTRINGAPPENDER_H | |
15 | ||
16 | // Local | |
17 | #include "CuteLogger_global.h" | |
18 | #include <AbstractAppender.h> | |
19 | ||
20 | // Qt | |
21 | #include <QReadWriteLock> | |
22 | ||
23 | namespace Dtk { | |
24 | namespace Log { | |
25 | ||
26 | class CUTELOGGERSHARED_EXPORT AbstractStringAppender : public AbstractAppender | |
27 | { | |
28 | public: | |
29 | AbstractStringAppender(); | |
30 | ||
31 | virtual QString format() const; | |
32 | void setFormat(const QString&); | |
33 | ||
34 | static QString stripFunctionName(const char*); | |
35 | ||
36 | protected: | |
37 | QString formattedString(const QDateTime& timeStamp, Logger::LogLevel logLevel, const char* file, int line, | |
38 | const char* function, const QString& category, const QString& message) const; | |
39 | ||
40 | private: | |
41 | static QByteArray qCleanupFuncinfo(const char*); | |
42 | ||
43 | QString m_format; | |
44 | mutable QReadWriteLock m_formatLock; | |
45 | }; | |
46 | ||
47 | }} | |
48 | ||
49 | #endif // ABSTRACTSTRINGAPPENDER_H |
0 | /* | |
1 | Copyright (c) 2010 Boris Moiseev (cyberbobs at gmail dot com) | |
2 | ||
3 | This program is free software: you can redistribute it and/or modify | |
4 | it under the terms of the GNU Lesser General Public License version 2.1 | |
5 | as published by the Free Software Foundation and appearing in the file | |
6 | LICENSE.LGPL included in the packaging of this file. | |
7 | ||
8 | This program is distributed in the hope that it will be useful, | |
9 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
11 | GNU Lesser General Public License for more details. | |
12 | */ | |
13 | // Local | |
14 | #include "ConsoleAppender.h" | |
15 | ||
16 | // STL | |
17 | #include <iostream> | |
18 | ||
19 | namespace Dtk { | |
20 | namespace Log { | |
21 | ||
22 | /** | |
23 | * \class ConsoleAppender | |
24 | * | |
25 | * \brief ConsoleAppender is the simple appender that writes the log records to the std::cerr output stream. | |
26 | * | |
27 | * ConsoleAppender uses "[%{type:-7}] <%{function}> %{message}\n" as a default output format. It is similar to the | |
28 | * AbstractStringAppender but doesn't show a timestamp. | |
29 | * | |
30 | * You can modify ConsoleAppender output format without modifying your code by using \c QT_MESSAGE_PATTERN environment | |
31 | * variable. If you need your application to ignore this environment variable you can call | |
32 | * ConsoleAppender::ignoreEnvironmentPattern(true) | |
33 | */ | |
34 | ||
35 | ||
36 | ConsoleAppender::ConsoleAppender() | |
37 | : AbstractStringAppender(), | |
38 | m_ignoreEnvPattern(false) | |
39 | { | |
40 | setFormat("[%{type:-7}] <%{function}> %{message}\n"); | |
41 | } | |
42 | ||
43 | ||
44 | QString ConsoleAppender::format() const | |
45 | { | |
46 | const QString envPattern = QString::fromLocal8Bit(qgetenv("QT_MESSAGE_PATTERN")); | |
47 | return (m_ignoreEnvPattern || envPattern.isEmpty()) ? AbstractStringAppender::format() : (envPattern + "\n"); | |
48 | } | |
49 | ||
50 | ||
51 | void ConsoleAppender::ignoreEnvironmentPattern(bool ignore) | |
52 | { | |
53 | m_ignoreEnvPattern = ignore; | |
54 | } | |
55 | ||
56 | ||
57 | //! Writes the log record to the std::cerr stream. | |
58 | /** | |
59 | * \sa AbstractStringAppender::format() | |
60 | */ | |
61 | void ConsoleAppender::append(const QDateTime& timeStamp, Logger::LogLevel logLevel, const char* file, int line, | |
62 | const char* function, const QString& category, const QString& message) | |
63 | { | |
64 | std::cerr << qPrintable(formattedString(timeStamp, logLevel, file, line, function, category, message)); | |
65 | } | |
66 | ||
67 | } | |
68 | } |
0 | /* | |
1 | Copyright (c) 2010 Boris Moiseev (cyberbobs at gmail dot com) | |
2 | ||
3 | This program is free software: you can redistribute it and/or modify | |
4 | it under the terms of the GNU Lesser General Public License version 2.1 | |
5 | as published by the Free Software Foundation and appearing in the file | |
6 | LICENSE.LGPL included in the packaging of this file. | |
7 | ||
8 | This program is distributed in the hope that it will be useful, | |
9 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
11 | GNU Lesser General Public License for more details. | |
12 | */ | |
13 | #ifndef CONSOLEAPPENDER_H | |
14 | #define CONSOLEAPPENDER_H | |
15 | ||
16 | #include "CuteLogger_global.h" | |
17 | #include <AbstractStringAppender.h> | |
18 | ||
19 | namespace Dtk { | |
20 | namespace Log { | |
21 | ||
22 | class CUTELOGGERSHARED_EXPORT ConsoleAppender : public AbstractStringAppender | |
23 | { | |
24 | public: | |
25 | ConsoleAppender(); | |
26 | virtual QString format() const; | |
27 | void ignoreEnvironmentPattern(bool ignore); | |
28 | ||
29 | protected: | |
30 | virtual void append(const QDateTime& timeStamp, Logger::LogLevel logLevel, const char* file, int line, | |
31 | const char* function, const QString& category, const QString& message); | |
32 | ||
33 | private: | |
34 | bool m_ignoreEnvPattern; | |
35 | }; | |
36 | ||
37 | }} | |
38 | ||
39 | #endif // CONSOLEAPPENDER_H |
0 | #ifndef CUTELOGGER_GLOBAL_H | |
1 | #define CUTELOGGER_GLOBAL_H | |
2 | ||
3 | #include <QtCore/qglobal.h> | |
4 | ||
5 | // Accept any number of args >= N, but expand to just the Nth one. | |
6 | // Here, N == 6. | |
7 | #define _GET_NTH_ARG(_1, _2, _3, _4, _5, N, ...) N | |
8 | ||
9 | // Define some macros to help us create overrides based on the | |
10 | // arity of a for-each-style macro. | |
11 | #define _fe_0(_call, ...) | |
12 | #define _fe_1(_call, x) _call(x) | |
13 | #define _fe_2(_call, x, ...) _call(x) _fe_1(_call, __VA_ARGS__) | |
14 | #define _fe_3(_call, x, ...) _call(x) _fe_2(_call, __VA_ARGS__) | |
15 | #define _fe_4(_call, x, ...) _call(x) _fe_3(_call, __VA_ARGS__) | |
16 | ||
17 | /** | |
18 | * Provide a for-each construct for variadic macros. Supports up | |
19 | * to 4 args. | |
20 | * | |
21 | * Example usage1: | |
22 | * #define FWD_DECLARE_CLASS(cls) class cls; | |
23 | * CALL_MACRO_X_FOR_EACH(FWD_DECLARE_CLASS, Foo, Bar) | |
24 | * | |
25 | * Example usage 2: | |
26 | * #define START_NS(ns) namespace ns { | |
27 | * #define END_NS(ns) } | |
28 | * #define MY_NAMESPACES System, Net, Http | |
29 | * CALL_MACRO_X_FOR_EACH(START_NS, MY_NAMESPACES) | |
30 | * typedef foo int; | |
31 | * CALL_MACRO_X_FOR_EACH(END_NS, MY_NAMESPACES) | |
32 | */ | |
33 | #define _CALL_MACRO_X_FOR_EACH(x, ...) \ | |
34 | _GET_NTH_ARG("ignored", ##__VA_ARGS__, \ | |
35 | _fe_4, _fe_3, _fe_2, _fe_1, _fe_0)(x, ##__VA_ARGS__) | |
36 | ||
37 | #define _START_NS(ns) namespace ns { | |
38 | #define _END_NS(ns) }/*##ns*/ | |
39 | #define MY_NAMESPACES System, Net, Http | |
40 | #define NS_START(...) _CALL_MACRO_X_FOR_EACH(_START_NS, __VA_ARGS__) | |
41 | #define NS_END(...) _CALL_MACRO_X_FOR_EACH(_END_NS, __VA_ARGS__) | |
42 | ||
43 | #if defined(CUTELOGGER_LIBRARY) | |
44 | # define CUTELOGGERSHARED_EXPORT Q_DECL_EXPORT | |
45 | #else | |
46 | #if defined(Q_OS_WIN32) | |
47 | # define CUTELOGGERSHARED_EXPORT | |
48 | #else | |
49 | # define CUTELOGGERSHARED_EXPORT Q_DECL_IMPORT | |
50 | #endif | |
51 | #endif | |
52 | ||
53 | #endif // CUTELOGGER_GLOBAL_H |
0 | #include "CuteLogger_global.h" | |
1 | #include "RollingFileAppender.h" | |
2 | #include "Logger.h" | |
3 | #include "LogManager.h" | |
4 | #include "FileAppender.h" | |
5 | #include "ConsoleAppender.h" | |
6 | #include "AbstractStringAppender.h" | |
7 | #include "AbstractAppender.h" |
0 | /* | |
1 | Copyright (c) 2010 Boris Moiseev (cyberbobs at gmail dot com) | |
2 | ||
3 | This program is free software: you can redistribute it and/or modify | |
4 | it under the terms of the GNU Lesser General Public License version 2.1 | |
5 | as published by the Free Software Foundation and appearing in the file | |
6 | LICENSE.LGPL included in the packaging of this file. | |
7 | ||
8 | This program is distributed in the hope that it will be useful, | |
9 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
11 | GNU Lesser General Public License for more details. | |
12 | */ | |
13 | // Local | |
14 | #include "FileAppender.h" | |
15 | ||
16 | // STL | |
17 | #include <iostream> | |
18 | ||
19 | namespace Dtk { | |
20 | namespace Log { | |
21 | ||
22 | /** | |
23 | * \class FileAppender | |
24 | * | |
25 | * \brief Simple appender that writes the log records to the plain text file. | |
26 | */ | |
27 | ||
28 | ||
29 | //! Constructs the new file appender assigned to file with the given name. | |
30 | FileAppender::FileAppender(const QString& fileName) | |
31 | { | |
32 | setFileName(fileName); | |
33 | } | |
34 | ||
35 | ||
36 | FileAppender::~FileAppender() | |
37 | { | |
38 | closeFile(); | |
39 | } | |
40 | ||
41 | ||
42 | //! Returns the name set by setFileName() or to the FileAppender constructor. | |
43 | /** | |
44 | * \sa setFileName() | |
45 | */ | |
46 | QString FileAppender::fileName() const | |
47 | { | |
48 | QMutexLocker locker(&m_logFileMutex); | |
49 | return m_logFile.fileName(); | |
50 | } | |
51 | ||
52 | ||
53 | //! Sets the name of the file. The name can have no path, a relative path, or an absolute path. | |
54 | /** | |
55 | * \sa fileName() | |
56 | */ | |
57 | void FileAppender::setFileName(const QString& s) | |
58 | { | |
59 | QMutexLocker locker(&m_logFileMutex); | |
60 | if (m_logFile.isOpen()) | |
61 | m_logFile.close(); | |
62 | ||
63 | m_logFile.setFileName(s); | |
64 | } | |
65 | ||
66 | ||
67 | bool FileAppender::openFile() | |
68 | { | |
69 | bool isOpen = m_logFile.isOpen(); | |
70 | if (!isOpen) | |
71 | { | |
72 | isOpen = m_logFile.open(QIODevice::WriteOnly | QIODevice::Append | QIODevice::Text); | |
73 | if (isOpen) | |
74 | m_logStream.setDevice(&m_logFile); | |
75 | else | |
76 | std::cerr << "<FileAppender::append> Cannot open the log file " << qPrintable(m_logFile.fileName()) << std::endl; | |
77 | } | |
78 | return isOpen; | |
79 | } | |
80 | ||
81 | ||
82 | //! Write the log record to the file. | |
83 | /** | |
84 | * \sa fileName() | |
85 | * \sa AbstractStringAppender::format() | |
86 | */ | |
87 | void FileAppender::append(const QDateTime& timeStamp, Logger::LogLevel logLevel, const char* file, int line, | |
88 | const char* function, const QString& category, const QString& message) | |
89 | { | |
90 | QMutexLocker locker(&m_logFileMutex); | |
91 | ||
92 | if (openFile()) | |
93 | { | |
94 | m_logStream << formattedString(timeStamp, logLevel, file, line, function, category, message); | |
95 | m_logStream.flush(); | |
96 | m_logFile.flush(); | |
97 | } | |
98 | } | |
99 | ||
100 | ||
101 | void FileAppender::closeFile() | |
102 | { | |
103 | QMutexLocker locker(&m_logFileMutex); | |
104 | m_logFile.close(); | |
105 | } | |
106 | ||
107 | }} |
0 | /* | |
1 | Copyright (c) 2010 Boris Moiseev (cyberbobs at gmail dot com) | |
2 | ||
3 | This program is free software: you can redistribute it and/or modify | |
4 | it under the terms of the GNU Lesser General Public License version 2.1 | |
5 | as published by the Free Software Foundation and appearing in the file | |
6 | LICENSE.LGPL included in the packaging of this file. | |
7 | ||
8 | This program is distributed in the hope that it will be useful, | |
9 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
11 | GNU Lesser General Public License for more details. | |
12 | */ | |
13 | #ifndef FILEAPPENDER_H | |
14 | #define FILEAPPENDER_H | |
15 | ||
16 | // Logger | |
17 | #include "CuteLogger_global.h" | |
18 | #include <AbstractStringAppender.h> | |
19 | ||
20 | // Qt | |
21 | #include <QFile> | |
22 | #include <QTextStream> | |
23 | ||
24 | namespace Dtk { | |
25 | namespace Log { | |
26 | ||
27 | class CUTELOGGERSHARED_EXPORT FileAppender : public AbstractStringAppender | |
28 | { | |
29 | public: | |
30 | FileAppender(const QString& fileName = QString()); | |
31 | ~FileAppender(); | |
32 | ||
33 | QString fileName() const; | |
34 | void setFileName(const QString&); | |
35 | ||
36 | protected: | |
37 | virtual void append(const QDateTime& timeStamp, Logger::LogLevel logLevel, const char* file, int line, | |
38 | const char* function, const QString& category, const QString& message); | |
39 | bool openFile(); | |
40 | void closeFile(); | |
41 | ||
42 | private: | |
43 | QFile m_logFile; | |
44 | QTextStream m_logStream; | |
45 | mutable QMutex m_logFileMutex; | |
46 | }; | |
47 | ||
48 | }} | |
49 | ||
50 | #endif // FILEAPPENDER_H |
0 | GNU GENERAL PUBLIC LICENSE | |
1 | Version 3, 29 June 2007 | |
2 | ||
3 | Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/> | |
4 | Everyone is permitted to copy and distribute verbatim copies | |
5 | of this license document, but changing it is not allowed. | |
6 | ||
7 | Preamble | |
8 | ||
9 | The GNU General Public License is a free, copyleft license for | |
10 | software and other kinds of works. | |
11 | ||
12 | The licenses for most software and other practical works are designed | |
13 | to take away your freedom to share and change the works. By contrast, | |
14 | the GNU General Public License is intended to guarantee your freedom to | |
15 | share and change all versions of a program--to make sure it remains free | |
16 | software for all its users. We, the Free Software Foundation, use the | |
17 | GNU General Public License for most of our software; it applies also to | |
18 | any other work released this way by its authors. You can apply it to | |
19 | your programs, too. | |
20 | ||
21 | When we speak of free software, we are referring to freedom, not | |
22 | price. Our General Public Licenses are designed to make sure that you | |
23 | have the freedom to distribute copies of free software (and charge for | |
24 | them if you wish), that you receive source code or can get it if you | |
25 | want it, that you can change the software or use pieces of it in new | |
26 | free programs, and that you know you can do these things. | |
27 | ||
28 | To protect your rights, we need to prevent others from denying you | |
29 | these rights or asking you to surrender the rights. Therefore, you have | |
30 | certain responsibilities if you distribute copies of the software, or if | |
31 | you modify it: responsibilities to respect the freedom of others. | |
32 | ||
33 | For example, if you distribute copies of such a program, whether | |
34 | gratis or for a fee, you must pass on to the recipients the same | |
35 | freedoms that you received. You must make sure that they, too, receive | |
36 | or can get the source code. And you must show them these terms so they | |
37 | know their rights. | |
38 | ||
39 | Developers that use the GNU GPL protect your rights with two steps: | |
40 | (1) assert copyright on the software, and (2) offer you this License | |
41 | giving you legal permission to copy, distribute and/or modify it. | |
42 | ||
43 | For the developers' and authors' protection, the GPL clearly explains | |
44 | that there is no warranty for this free software. For both users' and | |
45 | authors' sake, the GPL requires that modified versions be marked as | |
46 | changed, so that their problems will not be attributed erroneously to | |
47 | authors of previous versions. | |
48 | ||
49 | Some devices are designed to deny users access to install or run | |
50 | modified versions of the software inside them, although the manufacturer | |
51 | can do so. This is fundamentally incompatible with the aim of | |
52 | protecting users' freedom to change the software. The systematic | |
53 | pattern of such abuse occurs in the area of products for individuals to | |
54 | use, which is precisely where it is most unacceptable. Therefore, we | |
55 | have designed this version of the GPL to prohibit the practice for those | |
56 | products. If such problems arise substantially in other domains, we | |
57 | stand ready to extend this provision to those domains in future versions | |
58 | of the GPL, as needed to protect the freedom of users. | |
59 | ||
60 | Finally, every program is threatened constantly by software patents. | |
61 | States should not allow patents to restrict development and use of | |
62 | software on general-purpose computers, but in those that do, we wish to | |
63 | avoid the special danger that patents applied to a free program could | |
64 | make it effectively proprietary. To prevent this, the GPL assures that | |
65 | patents cannot be used to render the program non-free. | |
66 | ||
67 | The precise terms and conditions for copying, distribution and | |
68 | modification follow. | |
69 | ||
70 | TERMS AND CONDITIONS | |
71 | ||
72 | 0. Definitions. | |
73 | ||
74 | "This License" refers to version 3 of the GNU General Public License. | |
75 | ||
76 | "Copyright" also means copyright-like laws that apply to other kinds of | |
77 | works, such as semiconductor masks. | |
78 | ||
79 | "The Program" refers to any copyrightable work licensed under this | |
80 | License. Each licensee is addressed as "you". "Licensees" and | |
81 | "recipients" may be individuals or organizations. | |
82 | ||
83 | To "modify" a work means to copy from or adapt all or part of the work | |
84 | in a fashion requiring copyright permission, other than the making of an | |
85 | exact copy. The resulting work is called a "modified version" of the | |
86 | earlier work or a work "based on" the earlier work. | |
87 | ||
88 | A "covered work" means either the unmodified Program or a work based | |
89 | on the Program. | |
90 | ||
91 | To "propagate" a work means to do anything with it that, without | |
92 | permission, would make you directly or secondarily liable for | |
93 | infringement under applicable copyright law, except executing it on a | |
94 | computer or modifying a private copy. Propagation includes copying, | |
95 | distribution (with or without modification), making available to the | |
96 | public, and in some countries other activities as well. | |
97 | ||
98 | To "convey" a work means any kind of propagation that enables other | |
99 | parties to make or receive copies. Mere interaction with a user through | |
100 | a computer network, with no transfer of a copy, is not conveying. | |
101 | ||
102 | An interactive user interface displays "Appropriate Legal Notices" | |
103 | to the extent that it includes a convenient and prominently visible | |
104 | feature that (1) displays an appropriate copyright notice, and (2) | |
105 | tells the user that there is no warranty for the work (except to the | |
106 | extent that warranties are provided), that licensees may convey the | |
107 | work under this License, and how to view a copy of this License. If | |
108 | the interface presents a list of user commands or options, such as a | |
109 | menu, a prominent item in the list meets this criterion. | |
110 | ||
111 | 1. Source Code. | |
112 | ||
113 | The "source code" for a work means the preferred form of the work | |
114 | for making modifications to it. "Object code" means any non-source | |
115 | form of a work. | |
116 | ||
117 | A "Standard Interface" means an interface that either is an official | |
118 | standard defined by a recognized standards body, or, in the case of | |
119 | interfaces specified for a particular programming language, one that | |
120 | is widely used among developers working in that language. | |
121 | ||
122 | The "System Libraries" of an executable work include anything, other | |
123 | than the work as a whole, that (a) is included in the normal form of | |
124 | packaging a Major Component, but which is not part of that Major | |
125 | Component, and (b) serves only to enable use of the work with that | |
126 | Major Component, or to implement a Standard Interface for which an | |
127 | implementation is available to the public in source code form. A | |
128 | "Major Component", in this context, means a major essential component | |
129 | (kernel, window system, and so on) of the specific operating system | |
130 | (if any) on which the executable work runs, or a compiler used to | |
131 | produce the work, or an object code interpreter used to run it. | |
132 | ||
133 | The "Corresponding Source" for a work in object code form means all | |
134 | the source code needed to generate, install, and (for an executable | |
135 | work) run the object code and to modify the work, including scripts to | |
136 | control those activities. However, it does not include the work's | |
137 | System Libraries, or general-purpose tools or generally available free | |
138 | programs which are used unmodified in performing those activities but | |
139 | which are not part of the work. For example, Corresponding Source | |
140 | includes interface definition files associated with source files for | |
141 | the work, and the source code for shared libraries and dynamically | |
142 | linked subprograms that the work is specifically designed to require, | |
143 | such as by intimate data communication or control flow between those | |
144 | subprograms and other parts of the work. | |
145 | ||
146 | The Corresponding Source need not include anything that users | |
147 | can regenerate automatically from other parts of the Corresponding | |
148 | Source. | |
149 | ||
150 | The Corresponding Source for a work in source code form is that | |
151 | same work. | |
152 | ||
153 | 2. Basic Permissions. | |
154 | ||
155 | All rights granted under this License are granted for the term of | |
156 | copyright on the Program, and are irrevocable provided the stated | |
157 | conditions are met. This License explicitly affirms your unlimited | |
158 | permission to run the unmodified Program. The output from running a | |
159 | covered work is covered by this License only if the output, given its | |
160 | content, constitutes a covered work. This License acknowledges your | |
161 | rights of fair use or other equivalent, as provided by copyright law. | |
162 | ||
163 | You may make, run and propagate covered works that you do not | |
164 | convey, without conditions so long as your license otherwise remains | |
165 | in force. You may convey covered works to others for the sole purpose | |
166 | of having them make modifications exclusively for you, or provide you | |
167 | with facilities for running those works, provided that you comply with | |
168 | the terms of this License in conveying all material for which you do | |
169 | not control copyright. Those thus making or running the covered works | |
170 | for you must do so exclusively on your behalf, under your direction | |
171 | and control, on terms that prohibit them from making any copies of | |
172 | your copyrighted material outside their relationship with you. | |
173 | ||
174 | Conveying under any other circumstances is permitted solely under | |
175 | the conditions stated below. Sublicensing is not allowed; section 10 | |
176 | makes it unnecessary. | |
177 | ||
178 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law. | |
179 | ||
180 | No covered work shall be deemed part of an effective technological | |
181 | measure under any applicable law fulfilling obligations under article | |
182 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or | |
183 | similar laws prohibiting or restricting circumvention of such | |
184 | measures. | |
185 | ||
186 | When you convey a covered work, you waive any legal power to forbid | |
187 | circumvention of technological measures to the extent such circumvention | |
188 | is effected by exercising rights under this License with respect to | |
189 | the covered work, and you disclaim any intention to limit operation or | |
190 | modification of the work as a means of enforcing, against the work's | |
191 | users, your or third parties' legal rights to forbid circumvention of | |
192 | technological measures. | |
193 | ||
194 | 4. Conveying Verbatim Copies. | |
195 | ||
196 | You may convey verbatim copies of the Program's source code as you | |
197 | receive it, in any medium, provided that you conspicuously and | |
198 | appropriately publish on each copy an appropriate copyright notice; | |
199 | keep intact all notices stating that this License and any | |
200 | non-permissive terms added in accord with section 7 apply to the code; | |
201 | keep intact all notices of the absence of any warranty; and give all | |
202 | recipients a copy of this License along with the Program. | |
203 | ||
204 | You may charge any price or no price for each copy that you convey, | |
205 | and you may offer support or warranty protection for a fee. | |
206 | ||
207 | 5. Conveying Modified Source Versions. | |
208 | ||
209 | You may convey a work based on the Program, or the modifications to | |
210 | produce it from the Program, in the form of source code under the | |
211 | terms of section 4, provided that you also meet all of these conditions: | |
212 | ||
213 | a) The work must carry prominent notices stating that you modified | |
214 | it, and giving a relevant date. | |
215 | ||
216 | b) The work must carry prominent notices stating that it is | |
217 | released under this License and any conditions added under section | |
218 | 7. This requirement modifies the requirement in section 4 to | |
219 | "keep intact all notices". | |
220 | ||
221 | c) You must license the entire work, as a whole, under this | |
222 | License to anyone who comes into possession of a copy. This | |
223 | License will therefore apply, along with any applicable section 7 | |
224 | additional terms, to the whole of the work, and all its parts, | |
225 | regardless of how they are packaged. This License gives no | |
226 | permission to license the work in any other way, but it does not | |
227 | invalidate such permission if you have separately received it. | |
228 | ||
229 | d) If the work has interactive user interfaces, each must display | |
230 | Appropriate Legal Notices; however, if the Program has interactive | |
231 | interfaces that do not display Appropriate Legal Notices, your | |
232 | work need not make them do so. | |
233 | ||
234 | A compilation of a covered work with other separate and independent | |
235 | works, which are not by their nature extensions of the covered work, | |
236 | and which are not combined with it such as to form a larger program, | |
237 | in or on a volume of a storage or distribution medium, is called an | |
238 | "aggregate" if the compilation and its resulting copyright are not | |
239 | used to limit the access or legal rights of the compilation's users | |
240 | beyond what the individual works permit. Inclusion of a covered work | |
241 | in an aggregate does not cause this License to apply to the other | |
242 | parts of the aggregate. | |
243 | ||
244 | 6. Conveying Non-Source Forms. | |
245 | ||
246 | You may convey a covered work in object code form under the terms | |
247 | of sections 4 and 5, provided that you also convey the | |
248 | machine-readable Corresponding Source under the terms of this License, | |
249 | in one of these ways: | |
250 | ||
251 | a) Convey the object code in, or embodied in, a physical product | |
252 | (including a physical distribution medium), accompanied by the | |
253 | Corresponding Source fixed on a durable physical medium | |
254 | customarily used for software interchange. | |
255 | ||
256 | b) Convey the object code in, or embodied in, a physical product | |
257 | (including a physical distribution medium), accompanied by a | |
258 | written offer, valid for at least three years and valid for as | |
259 | long as you offer spare parts or customer support for that product | |
260 | model, to give anyone who possesses the object code either (1) a | |
261 | copy of the Corresponding Source for all the software in the | |
262 | product that is covered by this License, on a durable physical | |
263 | medium customarily used for software interchange, for a price no | |
264 | more than your reasonable cost of physically performing this | |
265 | conveying of source, or (2) access to copy the | |
266 | Corresponding Source from a network server at no charge. | |
267 | ||
268 | c) Convey individual copies of the object code with a copy of the | |
269 | written offer to provide the Corresponding Source. This | |
270 | alternative is allowed only occasionally and noncommercially, and | |
271 | only if you received the object code with such an offer, in accord | |
272 | with subsection 6b. | |
273 | ||
274 | d) Convey the object code by offering access from a designated | |
275 | place (gratis or for a charge), and offer equivalent access to the | |
276 | Corresponding Source in the same way through the same place at no | |
277 | further charge. You need not require recipients to copy the | |
278 | Corresponding Source along with the object code. If the place to | |
279 | copy the object code is a network server, the Corresponding Source | |
280 | may be on a different server (operated by you or a third party) | |
281 | that supports equivalent copying facilities, provided you maintain | |
282 | clear directions next to the object code saying where to find the | |
283 | Corresponding Source. Regardless of what server hosts the | |
284 | Corresponding Source, you remain obligated to ensure that it is | |
285 | available for as long as needed to satisfy these requirements. | |
286 | ||
287 | e) Convey the object code using peer-to-peer transmission, provided | |
288 | you inform other peers where the object code and Corresponding | |
289 | Source of the work are being offered to the general public at no | |
290 | charge under subsection 6d. | |
291 | ||
292 | A separable portion of the object code, whose source code is excluded | |
293 | from the Corresponding Source as a System Library, need not be | |
294 | included in conveying the object code work. | |
295 | ||
296 | A "User Product" is either (1) a "consumer product", which means any | |
297 | tangible personal property which is normally used for personal, family, | |
298 | or household purposes, or (2) anything designed or sold for incorporation | |
299 | into a dwelling. In determining whether a product is a consumer product, | |
300 | doubtful cases shall be resolved in favor of coverage. For a particular | |
301 | product received by a particular user, "normally used" refers to a | |
302 | typical or common use of that class of product, regardless of the status | |
303 | of the particular user or of the way in which the particular user | |
304 | actually uses, or expects or is expected to use, the product. A product | |
305 | is a consumer product regardless of whether the product has substantial | |
306 | commercial, industrial or non-consumer uses, unless such uses represent | |
307 | the only significant mode of use of the product. | |
308 | ||
309 | "Installation Information" for a User Product means any methods, | |
310 | procedures, authorization keys, or other information required to install | |
311 | and execute modified versions of a covered work in that User Product from | |
312 | a modified version of its Corresponding Source. The information must | |
313 | suffice to ensure that the continued functioning of the modified object | |
314 | code is in no case prevented or interfered with solely because | |
315 | modification has been made. | |
316 | ||
317 | If you convey an object code work under this section in, or with, or | |
318 | specifically for use in, a User Product, and the conveying occurs as | |
319 | part of a transaction in which the right of possession and use of the | |
320 | User Product is transferred to the recipient in perpetuity or for a | |
321 | fixed term (regardless of how the transaction is characterized), the | |
322 | Corresponding Source conveyed under this section must be accompanied | |
323 | by the Installation Information. But this requirement does not apply | |
324 | if neither you nor any third party retains the ability to install | |
325 | modified object code on the User Product (for example, the work has | |
326 | been installed in ROM). | |
327 | ||
328 | The requirement to provide Installation Information does not include a | |
329 | requirement to continue to provide support service, warranty, or updates | |
330 | for a work that has been modified or installed by the recipient, or for | |
331 | the User Product in which it has been modified or installed. Access to a | |
332 | network may be denied when the modification itself materially and | |
333 | adversely affects the operation of the network or violates the rules and | |
334 | protocols for communication across the network. | |
335 | ||
336 | Corresponding Source conveyed, and Installation Information provided, | |
337 | in accord with this section must be in a format that is publicly | |
338 | documented (and with an implementation available to the public in | |
339 | source code form), and must require no special password or key for | |
340 | unpacking, reading or copying. | |
341 | ||
342 | 7. Additional Terms. | |
343 | ||
344 | "Additional permissions" are terms that supplement the terms of this | |
345 | License by making exceptions from one or more of its conditions. | |
346 | Additional permissions that are applicable to the entire Program shall | |
347 | be treated as though they were included in this License, to the extent | |
348 | that they are valid under applicable law. If additional permissions | |
349 | apply only to part of the Program, that part may be used separately | |
350 | under those permissions, but the entire Program remains governed by | |
351 | this License without regard to the additional permissions. | |
352 | ||
353 | When you convey a copy of a covered work, you may at your option | |
354 | remove any additional permissions from that copy, or from any part of | |
355 | it. (Additional permissions may be written to require their own | |
356 | removal in certain cases when you modify the work.) You may place | |
357 | additional permissions on material, added by you to a covered work, | |
358 | for which you have or can give appropriate copyright permission. | |
359 | ||
360 | Notwithstanding any other provision of this License, for material you | |
361 | add to a covered work, you may (if authorized by the copyright holders of | |
362 | that material) supplement the terms of this License with terms: | |
363 | ||
364 | a) Disclaiming warranty or limiting liability differently from the | |
365 | terms of sections 15 and 16 of this License; or | |
366 | ||
367 | b) Requiring preservation of specified reasonable legal notices or | |
368 | author attributions in that material or in the Appropriate Legal | |
369 | Notices displayed by works containing it; or | |
370 | ||
371 | c) Prohibiting misrepresentation of the origin of that material, or | |
372 | requiring that modified versions of such material be marked in | |
373 | reasonable ways as different from the original version; or | |
374 | ||
375 | d) Limiting the use for publicity purposes of names of licensors or | |
376 | authors of the material; or | |
377 | ||
378 | e) Declining to grant rights under trademark law for use of some | |
379 | trade names, trademarks, or service marks; or | |
380 | ||
381 | f) Requiring indemnification of licensors and authors of that | |
382 | material by anyone who conveys the material (or modified versions of | |
383 | it) with contractual assumptions of liability to the recipient, for | |
384 | any liability that these contractual assumptions directly impose on | |
385 | those licensors and authors. | |
386 | ||
387 | All other non-permissive additional terms are considered "further | |
388 | restrictions" within the meaning of section 10. If the Program as you | |
389 | received it, or any part of it, contains a notice stating that it is | |
390 | governed by this License along with a term that is a further | |
391 | restriction, you may remove that term. If a license document contains | |
392 | a further restriction but permits relicensing or conveying under this | |
393 | License, you may add to a covered work material governed by the terms | |
394 | of that license document, provided that the further restriction does | |
395 | not survive such relicensing or conveying. | |
396 | ||
397 | If you add terms to a covered work in accord with this section, you | |
398 | must place, in the relevant source files, a statement of the | |
399 | additional terms that apply to those files, or a notice indicating | |
400 | where to find the applicable terms. | |
401 | ||
402 | Additional terms, permissive or non-permissive, may be stated in the | |
403 | form of a separately written license, or stated as exceptions; | |
404 | the above requirements apply either way. | |
405 | ||
406 | 8. Termination. | |
407 | ||
408 | You may not propagate or modify a covered work except as expressly | |
409 | provided under this License. Any attempt otherwise to propagate or | |
410 | modify it is void, and will automatically terminate your rights under | |
411 | this License (including any patent licenses granted under the third | |
412 | paragraph of section 11). | |
413 | ||
414 | However, if you cease all violation of this License, then your | |
415 | license from a particular copyright holder is reinstated (a) | |
416 | provisionally, unless and until the copyright holder explicitly and | |
417 | finally terminates your license, and (b) permanently, if the copyright | |
418 | holder fails to notify you of the violation by some reasonable means | |
419 | prior to 60 days after the cessation. | |
420 | ||
421 | Moreover, your license from a particular copyright holder is | |
422 | reinstated permanently if the copyright holder notifies you of the | |
423 | violation by some reasonable means, this is the first time you have | |
424 | received notice of violation of this License (for any work) from that | |
425 | copyright holder, and you cure the violation prior to 30 days after | |
426 | your receipt of the notice. | |
427 | ||
428 | Termination of your rights under this section does not terminate the | |
429 | licenses of parties who have received copies or rights from you under | |
430 | this License. If your rights have been terminated and not permanently | |
431 | reinstated, you do not qualify to receive new licenses for the same | |
432 | material under section 10. | |
433 | ||
434 | 9. Acceptance Not Required for Having Copies. | |
435 | ||
436 | You are not required to accept this License in order to receive or | |
437 | run a copy of the Program. Ancillary propagation of a covered work | |
438 | occurring solely as a consequence of using peer-to-peer transmission | |
439 | to receive a copy likewise does not require acceptance. However, | |
440 | nothing other than this License grants you permission to propagate or | |
441 | modify any covered work. These actions infringe copyright if you do | |
442 | not accept this License. Therefore, by modifying or propagating a | |
443 | covered work, you indicate your acceptance of this License to do so. | |
444 | ||
445 | 10. Automatic Licensing of Downstream Recipients. | |
446 | ||
447 | Each time you convey a covered work, the recipient automatically | |
448 | receives a license from the original licensors, to run, modify and | |
449 | propagate that work, subject to this License. You are not responsible | |
450 | for enforcing compliance by third parties with this License. | |
451 | ||
452 | An "entity transaction" is a transaction transferring control of an | |
453 | organization, or substantially all assets of one, or subdividing an | |
454 | organization, or merging organizations. If propagation of a covered | |
455 | work results from an entity transaction, each party to that | |
456 | transaction who receives a copy of the work also receives whatever | |
457 | licenses to the work the party's predecessor in interest had or could | |
458 | give under the previous paragraph, plus a right to possession of the | |
459 | Corresponding Source of the work from the predecessor in interest, if | |
460 | the predecessor has it or can get it with reasonable efforts. | |
461 | ||
462 | You may not impose any further restrictions on the exercise of the | |
463 | rights granted or affirmed under this License. For example, you may | |
464 | not impose a license fee, royalty, or other charge for exercise of | |
465 | rights granted under this License, and you may not initiate litigation | |
466 | (including a cross-claim or counterclaim in a lawsuit) alleging that | |
467 | any patent claim is infringed by making, using, selling, offering for | |
468 | sale, or importing the Program or any portion of it. | |
469 | ||
470 | 11. Patents. | |
471 | ||
472 | A "contributor" is a copyright holder who authorizes use under this | |
473 | License of the Program or a work on which the Program is based. The | |
474 | work thus licensed is called the contributor's "contributor version". | |
475 | ||
476 | A contributor's "essential patent claims" are all patent claims | |
477 | owned or controlled by the contributor, whether already acquired or | |
478 | hereafter acquired, that would be infringed by some manner, permitted | |
479 | by this License, of making, using, or selling its contributor version, | |
480 | but do not include claims that would be infringed only as a | |
481 | consequence of further modification of the contributor version. For | |
482 | purposes of this definition, "control" includes the right to grant | |
483 | patent sublicenses in a manner consistent with the requirements of | |
484 | this License. | |
485 | ||
486 | Each contributor grants you a non-exclusive, worldwide, royalty-free | |
487 | patent license under the contributor's essential patent claims, to | |
488 | make, use, sell, offer for sale, import and otherwise run, modify and | |
489 | propagate the contents of its contributor version. | |
490 | ||
491 | In the following three paragraphs, a "patent license" is any express | |
492 | agreement or commitment, however denominated, not to enforce a patent | |
493 | (such as an express permission to practice a patent or covenant not to | |
494 | sue for patent infringement). To "grant" such a patent license to a | |
495 | party means to make such an agreement or commitment not to enforce a | |
496 | patent against the party. | |
497 | ||
498 | If you convey a covered work, knowingly relying on a patent license, | |
499 | and the Corresponding Source of the work is not available for anyone | |
500 | to copy, free of charge and under the terms of this License, through a | |
501 | publicly available network server or other readily accessible means, | |
502 | then you must either (1) cause the Corresponding Source to be so | |
503 | available, or (2) arrange to deprive yourself of the benefit of the | |
504 | patent license for this particular work, or (3) arrange, in a manner | |
505 | consistent with the requirements of this License, to extend the patent | |
506 | license to downstream recipients. "Knowingly relying" means you have | |
507 | actual knowledge that, but for the patent license, your conveying the | |
508 | covered work in a country, or your recipient's use of the covered work | |
509 | in a country, would infringe one or more identifiable patents in that | |
510 | country that you have reason to believe are valid. | |
511 | ||
512 | If, pursuant to or in connection with a single transaction or | |
513 | arrangement, you convey, or propagate by procuring conveyance of, a | |
514 | covered work, and grant a patent license to some of the parties | |
515 | receiving the covered work authorizing them to use, propagate, modify | |
516 | or convey a specific copy of the covered work, then the patent license | |
517 | you grant is automatically extended to all recipients of the covered | |
518 | work and works based on it. | |
519 | ||
520 | A patent license is "discriminatory" if it does not include within | |
521 | the scope of its coverage, prohibits the exercise of, or is | |
522 | conditioned on the non-exercise of one or more of the rights that are | |
523 | specifically granted under this License. You may not convey a covered | |
524 | work if you are a party to an arrangement with a third party that is | |
525 | in the business of distributing software, under which you make payment | |
526 | to the third party based on the extent of your activity of conveying | |
527 | the work, and under which the third party grants, to any of the | |
528 | parties who would receive the covered work from you, a discriminatory | |
529 | patent license (a) in connection with copies of the covered work | |
530 | conveyed by you (or copies made from those copies), or (b) primarily | |
531 | for and in connection with specific products or compilations that | |
532 | contain the covered work, unless you entered into that arrangement, | |
533 | or that patent license was granted, prior to 28 March 2007. | |
534 | ||
535 | Nothing in this License shall be construed as excluding or limiting | |
536 | any implied license or other defenses to infringement that may | |
537 | otherwise be available to you under applicable patent law. | |
538 | ||
539 | 12. No Surrender of Others' Freedom. | |
540 | ||
541 | If conditions are imposed on you (whether by court order, agreement or | |
542 | otherwise) that contradict the conditions of this License, they do not | |
543 | excuse you from the conditions of this License. If you cannot convey a | |
544 | covered work so as to satisfy simultaneously your obligations under this | |
545 | License and any other pertinent obligations, then as a consequence you may | |
546 | not convey it at all. For example, if you agree to terms that obligate you | |
547 | to collect a royalty for further conveying from those to whom you convey | |
548 | the Program, the only way you could satisfy both those terms and this | |
549 | License would be to refrain entirely from conveying the Program. | |
550 | ||
551 | 13. Use with the GNU Affero General Public License. | |
552 | ||
553 | Notwithstanding any other provision of this License, you have | |
554 | permission to link or combine any covered work with a work licensed | |
555 | under version 3 of the GNU Affero General Public License into a single | |
556 | combined work, and to convey the resulting work. The terms of this | |
557 | License will continue to apply to the part which is the covered work, | |
558 | but the special requirements of the GNU Affero General Public License, | |
559 | section 13, concerning interaction through a network will apply to the | |
560 | combination as such. | |
561 | ||
562 | 14. Revised Versions of this License. | |
563 | ||
564 | The Free Software Foundation may publish revised and/or new versions of | |
565 | the GNU General Public License from time to time. Such new versions will | |
566 | be similar in spirit to the present version, but may differ in detail to | |
567 | address new problems or concerns. | |
568 | ||
569 | Each version is given a distinguishing version number. If the | |
570 | Program specifies that a certain numbered version of the GNU General | |
571 | Public License "or any later version" applies to it, you have the | |
572 | option of following the terms and conditions either of that numbered | |
573 | version or of any later version published by the Free Software | |
574 | Foundation. If the Program does not specify a version number of the | |
575 | GNU General Public License, you may choose any version ever published | |
576 | by the Free Software Foundation. | |
577 | ||
578 | If the Program specifies that a proxy can decide which future | |
579 | versions of the GNU General Public License can be used, that proxy's | |
580 | public statement of acceptance of a version permanently authorizes you | |
581 | to choose that version for the Program. | |
582 | ||
583 | Later license versions may give you additional or different | |
584 | permissions. However, no additional obligations are imposed on any | |
585 | author or copyright holder as a result of your choosing to follow a | |
586 | later version. | |
587 | ||
588 | 15. Disclaimer of Warranty. | |
589 | ||
590 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY | |
591 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT | |
592 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY | |
593 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, | |
594 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |
595 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM | |
596 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF | |
597 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION. | |
598 | ||
599 | 16. Limitation of Liability. | |
600 | ||
601 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING | |
602 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS | |
603 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY | |
604 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE | |
605 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF | |
606 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD | |
607 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), | |
608 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF | |
609 | SUCH DAMAGES. | |
610 | ||
611 | 17. Interpretation of Sections 15 and 16. | |
612 | ||
613 | If the disclaimer of warranty and limitation of liability provided | |
614 | above cannot be given local legal effect according to their terms, | |
615 | reviewing courts shall apply local law that most closely approximates | |
616 | an absolute waiver of all civil liability in connection with the | |
617 | Program, unless a warranty or assumption of liability accompanies a | |
618 | copy of the Program in return for a fee. | |
619 | ||
620 | END OF TERMS AND CONDITIONS | |
621 | ||
622 | How to Apply These Terms to Your New Programs | |
623 | ||
624 | If you develop a new program, and you want it to be of the greatest | |
625 | possible use to the public, the best way to achieve this is to make it | |
626 | free software which everyone can redistribute and change under these terms. | |
627 | ||
628 | To do so, attach the following notices to the program. It is safest | |
629 | to attach them to the start of each source file to most effectively | |
630 | state the exclusion of warranty; and each file should have at least | |
631 | the "copyright" line and a pointer to where the full notice is found. | |
632 | ||
633 | {one line to give the program's name and a brief idea of what it does.} | |
634 | Copyright (C) {year} {name of author} | |
635 | ||
636 | This program is free software: you can redistribute it and/or modify | |
637 | it under the terms of the GNU General Public License as published by | |
638 | the Free Software Foundation, either version 3 of the License, or | |
639 | (at your option) any later version. | |
640 | ||
641 | This program is distributed in the hope that it will be useful, | |
642 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
643 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
644 | GNU General Public License for more details. | |
645 | ||
646 | You should have received a copy of the GNU General Public License | |
647 | along with this program. If not, see <http://www.gnu.org/licenses/>. | |
648 | ||
649 | Also add information on how to contact you by electronic and paper mail. | |
650 | ||
651 | If the program does terminal interaction, make it output a short | |
652 | notice like this when it starts in an interactive mode: | |
653 | ||
654 | {project} Copyright (C) {year} {fullname} | |
655 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. | |
656 | This is free software, and you are welcome to redistribute it | |
657 | under certain conditions; type `show c' for details. | |
658 | ||
659 | The hypothetical commands `show w' and `show c' should show the appropriate | |
660 | parts of the General Public License. Of course, your program's commands | |
661 | might be different; for a GUI interface, you would use an "about box". | |
662 | ||
663 | You should also get your employer (if you work as a programmer) or school, | |
664 | if any, to sign a "copyright disclaimer" for the program, if necessary. | |
665 | For more information on this, and how to apply and follow the GNU GPL, see | |
666 | <http://www.gnu.org/licenses/>. | |
667 | ||
668 | The GNU General Public License does not permit incorporating your program | |
669 | into proprietary programs. If your program is a subroutine library, you | |
670 | may consider it more useful to permit linking proprietary applications with | |
671 | the library. If this is what you want to do, use the GNU Lesser General | |
672 | Public License instead of this License. But first, please read | |
673 | <http://www.gnu.org/philosophy/why-not-lgpl.html>. |
0 | #include "LogManager.h" | |
1 | #include <Logger.h> | |
2 | #include <ConsoleAppender.h> | |
3 | #include <RollingFileAppender.h> | |
4 | ||
5 | namespace Dtk { | |
6 | namespace Log { | |
7 | ||
8 | /** | |
9 | * \class DLogManager | |
10 | * | |
11 | * \brief DLogManager is the deepin user application log manager | |
12 | */ | |
13 | ||
14 | DLogManager::DLogManager() | |
15 | { | |
16 | QString cachePath = QStandardPaths::standardLocations(QStandardPaths::CacheLocation).at(0); | |
17 | if (!QDir(cachePath).exists()){ | |
18 | QDir(cachePath).mkpath(cachePath); | |
19 | } | |
20 | m_logPath = joinPath(cachePath, QString("%1.log").arg(qApp->applicationName())); | |
21 | m_format = "%{time}{yyyy-MM-dd, HH:mm:ss.zzz} [%{type:-7}] [%{file:-20} %{function:-35} %{line}] %{message}\n"; | |
22 | } | |
23 | ||
24 | void DLogManager::initConsoleAppender(){ | |
25 | m_consoleAppender = new ConsoleAppender; | |
26 | m_consoleAppender->setFormat(m_format); | |
27 | logger->registerAppender(m_consoleAppender); | |
28 | } | |
29 | ||
30 | void DLogManager::initRollingFileAppender(){ | |
31 | m_rollingFileAppender = new RollingFileAppender(m_logPath); | |
32 | m_rollingFileAppender->setFormat(m_format); | |
33 | m_rollingFileAppender->setLogFilesLimit(5); | |
34 | m_rollingFileAppender->setDatePattern(RollingFileAppender::DailyRollover); | |
35 | logger->registerAppender(m_rollingFileAppender); | |
36 | } | |
37 | ||
38 | //! Registers the appender to write the log records to the Console | |
39 | /** | |
40 | * \sa registerFileAppender | |
41 | */ | |
42 | void DLogManager::registerConsoleAppender(){ | |
43 | DLogManager::instance()->initConsoleAppender(); | |
44 | } | |
45 | ||
46 | //! Registers the appender to write the log records to the file | |
47 | /** | |
48 | * \sa getlogFilePath | |
49 | * \sa registerConsoleAppender | |
50 | */ | |
51 | void DLogManager::registerFileAppender() { | |
52 | DLogManager::instance()->initRollingFileAppender(); | |
53 | } | |
54 | ||
55 | //! Return the path file log storage | |
56 | /** | |
57 | * \sa registerFileAppender | |
58 | */ | |
59 | QString DLogManager::getlogFilePath(){ | |
60 | return DLogManager::instance()->m_logPath; | |
61 | } | |
62 | ||
63 | QString DLogManager::joinPath(const QString &path, const QString &fileName){ | |
64 | QString separator(QDir::separator()); | |
65 | return QString("%1%2%3").arg(path, separator, fileName); | |
66 | } | |
67 | ||
68 | DLogManager::~DLogManager() | |
69 | { | |
70 | ||
71 | } | |
72 | ||
73 | }} |
0 | #ifndef LOGMANAGER_H | |
1 | #define LOGMANAGER_H | |
2 | ||
3 | #include <QtCore> | |
4 | ||
5 | namespace Dtk { | |
6 | namespace Log { | |
7 | ||
8 | class ConsoleAppender; | |
9 | class RollingFileAppender; | |
10 | ||
11 | class DLogManager | |
12 | { | |
13 | public: | |
14 | static void registerConsoleAppender(); | |
15 | static void registerFileAppender(); | |
16 | static QString getlogFilePath(); | |
17 | ||
18 | signals: | |
19 | ||
20 | public slots: | |
21 | ||
22 | private: | |
23 | QString m_format; | |
24 | QString m_logPath; | |
25 | ConsoleAppender* m_consoleAppender; | |
26 | RollingFileAppender* m_rollingFileAppender; | |
27 | ||
28 | void initConsoleAppender(); | |
29 | void initRollingFileAppender(); | |
30 | QString joinPath(const QString& path, const QString& fileName); | |
31 | ||
32 | inline static DLogManager* instance(){ | |
33 | static DLogManager instance; | |
34 | return &instance; | |
35 | } | |
36 | explicit DLogManager(); | |
37 | ~DLogManager(); | |
38 | DLogManager(const DLogManager &); | |
39 | DLogManager & operator = (const DLogManager &); | |
40 | }; | |
41 | ||
42 | }} | |
43 | ||
44 | #endif // LOGMANAGER_H |
0 | /* | |
1 | Copyright (c) 2012 Boris Moiseev (cyberbobs at gmail dot com) | |
2 | ||
3 | This program is free software: you can redistribute it and/or modify | |
4 | it under the terms of the GNU Lesser General Public License version 2.1 | |
5 | as published by the Free Software Foundation and appearing in the file | |
6 | LICENSE.LGPL included in the packaging of this file. | |
7 | ||
8 | This program is distributed in the hope that it will be useful, | |
9 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
11 | GNU Lesser General Public License for more details. | |
12 | */ | |
13 | // Local | |
14 | #include "Logger.h" | |
15 | #include "AbstractAppender.h" | |
16 | #include "AbstractStringAppender.h" | |
17 | ||
18 | // Qt | |
19 | #include <QCoreApplication> | |
20 | #include <QReadWriteLock> | |
21 | #include <QSemaphore> | |
22 | #include <QDateTime> | |
23 | #include <QIODevice> | |
24 | #include <QTextCodec> | |
25 | ||
26 | #if defined(Q_OS_ANDROID) | |
27 | # include <android/log.h> | |
28 | # include <AndroidAppender.h> | |
29 | #endif | |
30 | ||
31 | // STL | |
32 | #include <iostream> | |
33 | ||
34 | namespace Dtk { | |
35 | namespace Log { | |
36 | ||
37 | /** | |
38 | * \file Logger.h | |
39 | * \brief A file containing the description of Logger class and and additional useful macros for logging | |
40 | */ | |
41 | ||
42 | ||
43 | /** | |
44 | * \mainpage | |
45 | * | |
46 | * Logger is a simple way to write the history of your application lifecycle to any target logging device (which is | |
47 | * called Appender and may write to any target you will implement with it: console, text file, XML or something - you | |
48 | * choose) and to map logging message to a class, function, source file and line of code which it is called from. | |
49 | * | |
50 | * Some simple appenders (which may be considered an examples) are provided with the Logger itself: see ConsoleAppender | |
51 | * and FileAppender documentation. | |
52 | * | |
53 | * It supports using it in a multithreaded applications, so all of its functions are thread safe. | |
54 | * | |
55 | * Simple usage example: | |
56 | * \code | |
57 | * #include <QCoreApplication> | |
58 | * | |
59 | * #include <DLog> | |
60 | * | |
61 | * using namespace Dtk::Log; | |
62 | * | |
63 | * int main(int argc, char* argv[]) | |
64 | * { | |
65 | * QCoreApplication app(argc, argv); | |
66 | * | |
67 | * // 1 you can use standrd deepin application log format | |
68 | * // 1.1 log to console | |
69 | * DLogManager::registerConsoleAppender(); | |
70 | * | |
71 | * // 1.2 log to standrd deepin user cache path: ~/.cache/{organ}/{appname}/ | |
72 | * // app.setOrganizationName("dtk-test"); // must set | |
73 | * // app.setApplicationName("dlog-example"); // must set | |
74 | * // dInfo()<< "LogFile:" << DLogManager::getlogFilePath(); | |
75 | * // DLogManager::registerFileAppender(); | |
76 | * | |
77 | * // 1.3 log to stdout and file | |
78 | * // DLogManager::registerFileAppender(); | |
79 | * // DLogManager::registerConsoleAppender(); | |
80 | * | |
81 | * // 2 Register your own logger format; | |
82 | * // ConsoleAppender* consoleAppender = new ConsoleAppender; | |
83 | * // consoleAppender->setFormat("[%{type:-7}] <%{Function}> %{message}\n"); | |
84 | * // logger->registerAppender(consoleAppender); | |
85 | * | |
86 | * dInfo("Starting the application"); | |
87 | * int result = 1; | |
88 | * dWarning() << "Something went wrong." << "Result code is" << result; | |
89 | * return result; | |
90 | * } | |
91 | * \endcode | |
92 | * | |
93 | * Logger internally uses the lazy-initialized singleton object and needs no definite initialization, but you may | |
94 | * consider registering a log appender before calling any log recording functions or macros. | |
95 | * | |
96 | * The library design of Logger allows you to simply mass-replace all occurrences of qDebug and similar calls with | |
97 | * similar Logger macros (e.g. dDebug()) | |
98 | * | |
99 | * \note Logger uses a singleton global instance which lives through all the application life cycle and self-destroys | |
100 | * destruction of the QCoreApplication (or QApplication) instance. It needs a QCoreApplication instance to be | |
101 | * created before any of the Logger's functions are called. | |
102 | * | |
103 | * \sa logger | |
104 | * \sa dTrace, dDebug, dInfo, dWarning, dError, dFatal | |
105 | * \sa dCTrace, dCDebug, dCInfo, dCWarning, dCError, dCFatal | |
106 | * \sa dAssert | |
107 | * \sa dTraceTime, dDebugTime, dInfoTime | |
108 | * \sa AbstractAppender | |
109 | */ | |
110 | ||
111 | ||
112 | /** | |
113 | * \def logger | |
114 | * | |
115 | * \brief Macro returning the current instance of Logger object | |
116 | * | |
117 | * If you haven't created a local Logger object it returns the same value as the Logger::globalInstance() functions. | |
118 | * This macro is a recommended way to get an access to the Logger instance used in current class. | |
119 | * | |
120 | * Example: | |
121 | * \code | |
122 | * ConsoleAppender* consoleAppender = new ConsoleAppender; | |
123 | * logger->registerAppender(consoleAppender); | |
124 | * \endcode | |
125 | * | |
126 | * \sa Dtk::Logger::globalInstance() | |
127 | */ | |
128 | ||
129 | ||
130 | /** | |
131 | * \def dTrace | |
132 | * | |
133 | * \brief Writes the trace log record | |
134 | * | |
135 | * This macro is the convinient way to call Logger::write(). It uses the common preprocessor macros \c __FILE__, | |
136 | * \c __LINE__ and the standart Qt \c Q_FUNC_INFO macros to automatically determine the needed parameters to call | |
137 | * Logger::write(). | |
138 | * | |
139 | * \note This and other (dInfo() etc...) macros uses the variadic macro arguments to give convinient usage form for | |
140 | * the different versions of Logger::write() (using the QString or const char* argument or returning the QDebug class | |
141 | * instance). Not all compilers will support this. Please, consider reviewing your compiler documentation to ensure | |
142 | * it support __VA_ARGS__ macro. | |
143 | * | |
144 | * \sa Dtk::Logger::LogLevel | |
145 | * \sa Dtk::Logger::write() | |
146 | */ | |
147 | ||
148 | ||
149 | /** | |
150 | * \def dDebug | |
151 | * | |
152 | * \brief Writes the debug log record | |
153 | * | |
154 | * This macro records the debug log record using the Logger::write() function. It works similar to the dTrace() | |
155 | * macro. | |
156 | * | |
157 | * \sa dTrace() | |
158 | * \sa Dtk::Logger::LogLevel | |
159 | * \sa Dtk::Logger::write() | |
160 | */ | |
161 | ||
162 | ||
163 | /** | |
164 | * \def dInfo | |
165 | * | |
166 | * \brief Writes the info log record | |
167 | * | |
168 | * This macro records the info log record using the Logger::write() function. It works similar to the dTrace() | |
169 | * macro. | |
170 | * | |
171 | * \sa dTrace() | |
172 | * \sa Dtk::Logger::LogLevel | |
173 | * \sa Dtk::Logger::write() | |
174 | */ | |
175 | ||
176 | ||
177 | /** | |
178 | * \def dWarning | |
179 | * | |
180 | * \brief Write the warning log record | |
181 | * | |
182 | * This macro records the warning log record using the Logger::write() function. It works similar to the dTrace() | |
183 | * macro. | |
184 | * | |
185 | * \sa dTrace() | |
186 | * \sa Dtk::Logger::LogLevel | |
187 | * \sa Dtk::Logger::write() | |
188 | */ | |
189 | ||
190 | ||
191 | /** | |
192 | * \def dError | |
193 | * | |
194 | * \brief Write the error log record | |
195 | * This macro records the error log record using the Logger::write() function. It works similar to the dTrace() | |
196 | * macro. | |
197 | * | |
198 | * \sa dTrace() | |
199 | * \sa Dtk::Logger::LogLevel | |
200 | * \sa Dtk::Logger::write() | |
201 | */ | |
202 | ||
203 | ||
204 | /** | |
205 | * \def dFatal | |
206 | * | |
207 | * \brief Write the fatal log record | |
208 | * | |
209 | * This macro records the fatal log record using the Logger::write() function. It works similar to the dTrace() | |
210 | * macro. | |
211 | * | |
212 | * \note Recording of the log record using the Logger::Fatal log level will lead to calling the STL abort() | |
213 | * function, which will interrupt the running of your software and begin the writing of the core dump. | |
214 | * | |
215 | * \sa dTrace() | |
216 | * \sa Dtk::Logger::LogLevel | |
217 | * \sa Dtk::Logger::write() | |
218 | */ | |
219 | ||
220 | ||
221 | /** | |
222 | * \def dCTrace(category) | |
223 | * | |
224 | * \brief Writes the trace log record to the specific category | |
225 | * | |
226 | * This macro is the similar to the dTrace() macro, but has a category parameter | |
227 | * to write only to the category appenders (registered using Logger::registerCategoryAppender() method). | |
228 | * | |
229 | * \param category category name string | |
230 | * | |
231 | * \sa dTrace() | |
232 | * \sa Dtk::Logger::LogLevel | |
233 | * \sa Dtk::Logger::registerCategoryAppender() | |
234 | * \sa Dtk::Logger::write() | |
235 | * \sa dCategory(), dGlobalCategory() | |
236 | */ | |
237 | ||
238 | ||
239 | /** | |
240 | * \def dCDebug | |
241 | * | |
242 | * \brief Writes the debug log record to the specific category | |
243 | * | |
244 | * This macro records the debug log record using the Logger::write() function. It works similar to the dCTrace() | |
245 | * macro. | |
246 | * | |
247 | * \sa dCTrace() | |
248 | */ | |
249 | ||
250 | ||
251 | /** | |
252 | * \def dCInfo | |
253 | * | |
254 | * \brief Writes the info log record to the specific category | |
255 | * | |
256 | * This macro records the info log record using the Logger::write() function. It works similar to the dCTrace() | |
257 | * macro. | |
258 | * | |
259 | * \sa dCTrace() | |
260 | */ | |
261 | ||
262 | ||
263 | /** | |
264 | * \def dCWarning | |
265 | * | |
266 | * \brief Writes the warning log record to the specific category | |
267 | * | |
268 | * This macro records the warning log record using the Logger::write() function. It works similar to the dCTrace() | |
269 | * macro. | |
270 | * | |
271 | * \sa dCTrace() | |
272 | */ | |
273 | ||
274 | ||
275 | /** | |
276 | * \def dCError | |
277 | * | |
278 | * \brief Writes the error log record to the specific category | |
279 | * | |
280 | * This macro records the error log record using the Logger::write() function. It works similar to the dCTrace() | |
281 | * macro. | |
282 | * | |
283 | * \sa dCTrace() | |
284 | */ | |
285 | ||
286 | ||
287 | /** | |
288 | * \def dCFatal | |
289 | * | |
290 | * \brief Write the fatal log record to the specific category | |
291 | * | |
292 | * This macro records the fatal log record using the Logger::write() function. It works similar to the dCTrace() | |
293 | * macro. | |
294 | * | |
295 | * \note Recording of the log record using the Logger::Fatal log level will lead to calling the STL abort() | |
296 | * function, which will interrupt the running of your software and begin the writing of the core dump. | |
297 | * | |
298 | * \sa dCTrace() | |
299 | */ | |
300 | ||
301 | ||
302 | /** | |
303 | * \def dCategory(category) | |
304 | * | |
305 | * \brief Create logger instance inside your custom class to log all messages to the specified category | |
306 | * | |
307 | * This macro is used to pass all log messages inside your custom class to the specific category. | |
308 | * You must include this macro inside your class declaration (similarly to the Q_OBJECT macro). | |
309 | * Internally, this macro redefines loggerInstance() function, creates the local Logger object inside your class and | |
310 | * sets the default category to the specified parameter. | |
311 | * | |
312 | * Thus, any call to loggerInstance() (for example, inside dTrace() macro) will return the local Logger object, | |
313 | * so any logging message will be directed to the default category. | |
314 | * | |
315 | * \note This macro does not register any appender to the newly created logger instance. You should register | |
316 | * logger appenders manually, inside your class. | |
317 | * | |
318 | * Usage example: | |
319 | * \code | |
320 | * class CustomClass : public QObject | |
321 | * { | |
322 | * Q_OBJECT | |
323 | * dCategory("custom_category") | |
324 | * ... | |
325 | * }; | |
326 | * | |
327 | * CustomClass::CustomClass(QObject* parent) : QObject(parent) | |
328 | * { | |
329 | * logger->registerAppender(new FileAppender("custom_category_log")); | |
330 | * dTrace() << "Trace to the custom category log"; | |
331 | * } | |
332 | * \endcode | |
333 | * | |
334 | * \sa Dtk::Logger::write() | |
335 | * \sa dTrace | |
336 | * \sa Dtk::Logger::registerCategoryAppender() | |
337 | * \sa Dtk::Logger::setDefaultCategory() | |
338 | * \sa dGlobalCategory | |
339 | */ | |
340 | ||
341 | ||
342 | /** | |
343 | * \def dGlobalCategory(category) | |
344 | * | |
345 | * \brief Create logger instance inside your custom class to log all messages both to the specified category and to | |
346 | * the global logger instance. | |
347 | * | |
348 | * This macro is similar to dCategory(), but also passes all log messages to the global logger instance appenders. | |
349 | * It is equal to defining the local category logger using dCategory macro and calling: | |
350 | * \code logger->logToGlobalInstance(logger->defaultCategory(), true); \endcode | |
351 | * | |
352 | * \sa dCategory | |
353 | * \sa Dtk::Logger::logToGlobalInstance() | |
354 | * \sa Dtk::Logger::defaultCategory() | |
355 | * \sa Dtk::Logger::registerCategoryAppender() | |
356 | * \sa Dtk::Logger::write() | |
357 | */ | |
358 | ||
359 | ||
360 | ||
361 | /** | |
362 | * \def dAssert | |
363 | * | |
364 | * \brief Check the assertion | |
365 | * | |
366 | * This macro is a convinient and recommended to use way to call Logger::writeAssert() function. It uses the | |
367 | * preprocessor macros (as the dDebug() does) to fill the necessary arguments of the Logger::writeAssert() call. It | |
368 | * also uses undocumented but rather mature and stable \c qt_noop() function (which does nothing) when the assertion | |
369 | * is true. | |
370 | * | |
371 | * Example: | |
372 | * \code | |
373 | * bool b = checkSomething(); | |
374 | * ... | |
375 | * dAssert(b == true); | |
376 | * \endcode | |
377 | * | |
378 | * \sa Dtk::Logger::writeAssert() | |
379 | */ | |
380 | ||
381 | ||
382 | /** | |
383 | * \def dTraceTime | |
384 | * | |
385 | * \brief Logs the processing time of current function / code block | |
386 | * | |
387 | * This macro automagically measures the function or code of block execution time and outputs it as a Logger::Trace | |
388 | * level log record. | |
389 | * | |
390 | * Example: | |
391 | * \code | |
392 | * int foo() | |
393 | * { | |
394 | * dTraceTime(); | |
395 | * ... // Do some long operations | |
396 | * return 0; | |
397 | * } // Outputs: Function foo finished in <time> ms. | |
398 | * \endcode | |
399 | * | |
400 | * If you are measuring a code of block execution time you may also add a name of block to the macro: | |
401 | * \code | |
402 | * int bar(bool doFoo) | |
403 | * { | |
404 | * dTraceTime(); | |
405 | * | |
406 | * if (doFoo) | |
407 | * { | |
408 | * dTraceTime("Foo"); | |
409 | * ... | |
410 | * } | |
411 | * | |
412 | * ... | |
413 | * } | |
414 | * // Outputs: | |
415 | * // "Foo" finished in <time1> ms. | |
416 | * // Function bar finished in <time2> ms. | |
417 | * \endcode | |
418 | * | |
419 | * \note Macro switches to logging the seconds instead of milliseconds when the execution time reaches 10000 ms. | |
420 | * \sa dDebugTime, dInfoTime | |
421 | */ | |
422 | ||
423 | ||
424 | /** | |
425 | * \def dDebugTime | |
426 | * | |
427 | * \brief Logs the processing time of current function / code block | |
428 | * | |
429 | * This macro automagically measures the function or code of block execution time and outputs it as a Logger::Debug | |
430 | * level log record. It works similar to dTraceTime() macro. | |
431 | * | |
432 | * \sa dTraceTime | |
433 | */ | |
434 | ||
435 | ||
436 | /** | |
437 | * \def dInfoTime | |
438 | * | |
439 | * \brief Logs the processing time of current function / code block | |
440 | * | |
441 | * This macro automagically measures the function or code of block execution time and outputs it as a Logger::Info | |
442 | * level log record. It works similar to dTraceTime() macro. | |
443 | * | |
444 | * \sa dTraceTime | |
445 | */ | |
446 | ||
447 | ||
448 | /** | |
449 | * \class Logger | |
450 | * | |
451 | * \brief Very simple but rather powerful component which may be used for logging your application activities. | |
452 | * | |
453 | * Global logger instance created on a first access to it (e.g. registering appenders, calling a dDebug() macro | |
454 | * etc.) registers itself as a Qt default message handler and captures all the qDebug/dWarning/qCritical output. | |
455 | * | |
456 | * \note Qt 4 qDebug set of macro doesn't support capturing source function name, file name or line number so we | |
457 | * recommend to use dDebug() and other Logger macros instead. | |
458 | * | |
459 | * \sa logger | |
460 | * \sa [DLogger Documentation](index.html) | |
461 | */ | |
462 | ||
463 | class LogDevice : public QIODevice | |
464 | { | |
465 | public: | |
466 | LogDevice(Logger* l) | |
467 | : m_logger(l), | |
468 | m_semaphore(1) | |
469 | {} | |
470 | ||
471 | void lock(Logger::LogLevel logLevel, const char* file, int line, const char* function, const char* category) | |
472 | { | |
473 | m_semaphore.acquire(); | |
474 | ||
475 | if (!isOpen()) | |
476 | open(QIODevice::WriteOnly); | |
477 | ||
478 | m_logLevel = logLevel; | |
479 | m_file = file; | |
480 | m_line = line; | |
481 | m_function = function; | |
482 | m_category = category; | |
483 | } | |
484 | ||
485 | protected: | |
486 | qint64 readData(char*, qint64) | |
487 | { | |
488 | return 0; | |
489 | } | |
490 | ||
491 | qint64 writeData(const char* data, qint64 maxSize) | |
492 | { | |
493 | if (maxSize > 0) | |
494 | m_logger->write(m_logLevel, m_file, m_line, m_function, m_category, QString::fromLocal8Bit(QByteArray(data, maxSize))); | |
495 | ||
496 | m_semaphore.release(); | |
497 | return maxSize; | |
498 | } | |
499 | ||
500 | private: | |
501 | Logger* m_logger; | |
502 | QSemaphore m_semaphore; | |
503 | Logger::LogLevel m_logLevel; | |
504 | const char* m_file; | |
505 | int m_line; | |
506 | const char* m_function; | |
507 | const char* m_category; | |
508 | }; | |
509 | ||
510 | ||
511 | // Forward declarations | |
512 | static void cleanupLoggerGlobalInstance(); | |
513 | ||
514 | #if QT_VERSION >= 0x050000 | |
515 | static void qtLoggerMessageHandler(QtMsgType, const QMessageLogContext& context, const QString& msg); | |
516 | #else | |
517 | static void qtLoggerMessageHandler(QtMsgType type, const char* msg); | |
518 | #endif | |
519 | ||
520 | /** | |
521 | * \internal | |
522 | * | |
523 | * LoggerPrivate class implements the Singleton pattern in a thread-safe way. It contains a static pointer to the | |
524 | * global logger instance protected by QReadWriteLock | |
525 | */ | |
526 | class LoggerPrivate | |
527 | { | |
528 | public: | |
529 | static Logger* globalInstance; | |
530 | static QReadWriteLock globalInstanceLock; | |
531 | ||
532 | QList<AbstractAppender*> appenders; | |
533 | QMutex loggerMutex; | |
534 | ||
535 | QMap<QString, bool> categories; | |
536 | QMultiMap<QString, AbstractAppender*> categoryAppenders; | |
537 | QString defaultCategory; | |
538 | ||
539 | LogDevice* logDevice; | |
540 | }; | |
541 | ||
542 | ||
543 | // Static fields initialization | |
544 | Logger* LoggerPrivate::globalInstance = 0; | |
545 | QReadWriteLock LoggerPrivate::globalInstanceLock; | |
546 | ||
547 | ||
548 | static void cleanupLoggerGlobalInstance() | |
549 | { | |
550 | QWriteLocker locker(&LoggerPrivate::globalInstanceLock); | |
551 | ||
552 | delete LoggerPrivate::globalInstance; | |
553 | LoggerPrivate::globalInstance = 0; | |
554 | } | |
555 | ||
556 | ||
557 | #if QT_VERSION >= 0x050000 | |
558 | static void qtLoggerMessageHandler(QtMsgType type, const QMessageLogContext& context, const QString& msg) | |
559 | { | |
560 | Logger::LogLevel level; | |
561 | switch (type) | |
562 | { | |
563 | case QtDebugMsg: | |
564 | level = Logger::Debug; | |
565 | break; | |
566 | case QtInfoMsg: | |
567 | level = Logger::Info; | |
568 | break; | |
569 | case QtWarningMsg: | |
570 | level = Logger::Warning; | |
571 | break; | |
572 | case QtCriticalMsg: | |
573 | level = Logger::Error; | |
574 | break; | |
575 | case QtFatalMsg: | |
576 | level = Logger::Fatal; | |
577 | break; | |
578 | default: | |
579 | level = Logger::Warning; | |
580 | break; | |
581 | } | |
582 | ||
583 | bool isDefaultCategory = QString::fromLatin1(context.category) == "default"; | |
584 | Logger::globalInstance()->write(level, context.file, context.line, context.function, isDefaultCategory ? 0 : context.category, msg); | |
585 | } | |
586 | ||
587 | #else | |
588 | ||
589 | static void qtLoggerMessageHandler(QtMsgType type, const char* msg) | |
590 | { | |
591 | switch (type) | |
592 | { | |
593 | case QtDebugMsg: | |
594 | loggerInstance()->write(Logger::Debug, "", 0, "qDebug", 0, msg); | |
595 | break; | |
596 | case QtWarningMsg: | |
597 | loggerInstance()->write(Logger::Warning, "", 0, "qDebug", 0, msg); | |
598 | break; | |
599 | case QtCriticalMsg: | |
600 | loggerInstance()->write(Logger::Error, "", 0, "qDebug", 0, msg); | |
601 | break; | |
602 | case QtFatalMsg: | |
603 | loggerInstance()->write(Logger::Fatal, "", 0, "qDebug", 0, msg); | |
604 | break; | |
605 | } | |
606 | } | |
607 | #endif | |
608 | ||
609 | ||
610 | //! Construct the instance of Logger | |
611 | /** | |
612 | * If you're only using one global instance of logger you wouldn't probably need to use this constructor manually. | |
613 | * Consider using [logger](@ref logger) macro instead to access the logger instance | |
614 | */ | |
615 | Logger::Logger() | |
616 | : d_ptr(new LoggerPrivate) | |
617 | { | |
618 | Q_D(Logger); | |
619 | ||
620 | d->logDevice = new LogDevice(this); | |
621 | } | |
622 | ||
623 | ||
624 | //! Construct the instance of Logger and set logger default category | |
625 | /** | |
626 | * If you're only using one global instance of logger you wouldn't probably need to use this constructor manually. | |
627 | * Consider using [logger](@ref logger) macro instead to access the logger instance and call | |
628 | * [setDefaultCategory](@ref setDefaultCategory) method. | |
629 | * | |
630 | * \sa Logger() | |
631 | * \sa setDefaultCategory() | |
632 | */ | |
633 | Logger::Logger(const QString& defaultCategory) | |
634 | : d_ptr(new LoggerPrivate) | |
635 | { | |
636 | Q_D(Logger); | |
637 | d->logDevice = new LogDevice(this); | |
638 | ||
639 | setDefaultCategory(defaultCategory); | |
640 | } | |
641 | ||
642 | ||
643 | //! Destroy the instance of Logger | |
644 | /** | |
645 | * You probably wouldn't need to use this function directly. Global instance of logger will be destroyed automatically | |
646 | * at the end of your QCoreApplication execution | |
647 | */ | |
648 | Logger::~Logger() | |
649 | { | |
650 | Q_D(Logger); | |
651 | ||
652 | // Cleanup appenders | |
653 | QMutexLocker appendersLocker(&d->loggerMutex); | |
654 | qDeleteAll(d->appenders); | |
655 | qDeleteAll(d->categoryAppenders); | |
656 | ||
657 | // Cleanup device | |
658 | delete d->logDevice; | |
659 | appendersLocker.unlock(); | |
660 | ||
661 | delete d_ptr; | |
662 | } | |
663 | ||
664 | ||
665 | //! Converts the LogLevel enum value to its string representation | |
666 | /** | |
667 | * \param logLevel Log level to convert | |
668 | * | |
669 | * \sa LogLevel | |
670 | * \sa levelFromString() | |
671 | */ | |
672 | QString Logger::levelToString(Logger::LogLevel logLevel) | |
673 | { | |
674 | switch (logLevel) | |
675 | { | |
676 | case Trace: | |
677 | return QLatin1String("Trace"); | |
678 | case Debug: | |
679 | return QLatin1String("Debug"); | |
680 | case Info: | |
681 | return QLatin1String("Info"); | |
682 | case Warning: | |
683 | return QLatin1String("Warning"); | |
684 | case Error: | |
685 | return QLatin1String("Error"); | |
686 | case Fatal: | |
687 | return QLatin1String("Fatal"); | |
688 | } | |
689 | ||
690 | return QString(); | |
691 | } | |
692 | ||
693 | ||
694 | //! Converts the LogLevel string representation to enum value | |
695 | /** | |
696 | * Comparation of the strings is case independent. If the log level string provided cannot be understood | |
697 | * Logger::Debug is returned. | |
698 | * | |
699 | * \param s String to be decoded | |
700 | * | |
701 | * \sa LogLevel | |
702 | * \sa levelToString() | |
703 | */ | |
704 | Logger::LogLevel Logger::levelFromString(const QString& s) | |
705 | { | |
706 | QString str = s.trimmed().toLower(); | |
707 | ||
708 | LogLevel result = Debug; | |
709 | ||
710 | if (str == QLatin1String("trace")) | |
711 | result = Trace; | |
712 | else if (str == QLatin1String("debug")) | |
713 | result = Debug; | |
714 | else if (str == QLatin1String("info")) | |
715 | result = Info; | |
716 | else if (str == QLatin1String("warning")) | |
717 | result = Warning; | |
718 | else if (str == QLatin1String("error")) | |
719 | result = Error; | |
720 | else if (str == QLatin1String("fatal")) | |
721 | result = Fatal; | |
722 | ||
723 | return result; | |
724 | } | |
725 | ||
726 | ||
727 | //! Returns the global instance of Logger | |
728 | /** | |
729 | * In a most cases you shouldn't use this function directly. Consider using [logger](@ref logger) macro instead. | |
730 | * | |
731 | * \sa logger | |
732 | */ | |
733 | Logger* Logger::globalInstance() | |
734 | { | |
735 | Logger* result = 0; | |
736 | { | |
737 | QReadLocker locker(&LoggerPrivate::globalInstanceLock); | |
738 | result = LoggerPrivate::globalInstance; | |
739 | } | |
740 | ||
741 | if (!result) | |
742 | { | |
743 | QWriteLocker locker(&LoggerPrivate::globalInstanceLock); | |
744 | LoggerPrivate::globalInstance = new Logger; | |
745 | ||
746 | #if QT_VERSION >= 0x050000 | |
747 | qInstallMessageHandler(qtLoggerMessageHandler); | |
748 | #else | |
749 | qInstallMsgHandler(qtLoggerMessageHandler); | |
750 | #endif | |
751 | qAddPostRoutine(cleanupLoggerGlobalInstance); | |
752 | result = LoggerPrivate::globalInstance; | |
753 | } | |
754 | ||
755 | return result; | |
756 | } | |
757 | ||
758 | ||
759 | //! Registers the appender to write the log records to | |
760 | /** | |
761 | * On the log writing call (using one of the macros or the write() function) Logger traverses through the list of | |
762 | * the appenders and writes a log records to the each of them. Please, look through the AbstractAppender | |
763 | * documentation to understand the concept of appenders. | |
764 | * | |
765 | * If no appenders was added to Logger, it falls back to logging into the \c std::cerr STL stream. | |
766 | * | |
767 | * \param appender Appender to register in the Logger | |
768 | * | |
769 | * \note Logger takes ownership on the appender and it will delete it on the application exit. According to this, | |
770 | * appenders must be created on heap to prevent double destruction of the appender. | |
771 | * | |
772 | * \sa registerCategoryAppender | |
773 | * \sa AbstractAppender | |
774 | */ | |
775 | void Logger::registerAppender(AbstractAppender* appender) | |
776 | { | |
777 | Q_D(Logger); | |
778 | ||
779 | QMutexLocker locker(&d->loggerMutex); | |
780 | ||
781 | if (!d->appenders.contains(appender)) | |
782 | d->appenders.append(appender); | |
783 | else | |
784 | std::cerr << "Trying to register appender that was already registered" << std::endl; | |
785 | } | |
786 | ||
787 | //! Registers the appender to write the log records to the specific category | |
788 | /** | |
789 | * Calling this method, you can link some appender with the named category. | |
790 | * On the log writing call to the specific category (calling write() with category parameter directly, | |
791 | * writing to the default category, or using special dCDebug(), dCWarning() etc. macros), | |
792 | * Logger writes the log message only to the list of registered category appenders. | |
793 | * | |
794 | * You can call logToGlobalInstance() to pass all category log messages to the global logger instance appenders | |
795 | * (registered using registerAppender()). | |
796 | * If no category appenders with specific name was registered to the Logger, | |
797 | * it falls back to logging into the \c std::cerr STL stream, both with simple warning message. | |
798 | * | |
799 | * \param category Category name | |
800 | * \param appender Appender to register in the Logger | |
801 | * | |
802 | * \note Logger takes ownership on the appender and it will delete it on the application exit. According to this, | |
803 | * appenders must be created on heap to prevent double destruction of the appender. | |
804 | * | |
805 | * \sa registerAppender | |
806 | * \sa dCTrace(), dCDebug(), dCInfo(), dCWarning(), dCError(), dCFatal() | |
807 | * \sa dCategory(), dGlobalCategory() | |
808 | * \sa logToGlobalInstance | |
809 | * \sa setDefaultCategory | |
810 | */ | |
811 | void Logger::registerCategoryAppender(const QString& category, AbstractAppender* appender) | |
812 | { | |
813 | Q_D(Logger); | |
814 | ||
815 | QMutexLocker locker(&d->loggerMutex); | |
816 | ||
817 | if (!d->categoryAppenders.values().contains(appender)) | |
818 | d->categoryAppenders.insert(category, appender); | |
819 | else | |
820 | std::cerr << "Trying to register appender that was already registered" << std::endl; | |
821 | } | |
822 | ||
823 | //! Sets default logging category | |
824 | /** | |
825 | * All log messages to this category appenders will also be written to general logger instance appenders (registered | |
826 | * using [registerAppender](@ref registerAppender) method), and vice versa. | |
827 | * In particular, any calls to the dDebug() macro will be treated as category logging, | |
828 | * so you needn't to specify category name using dCDebug() macro. | |
829 | * | |
830 | * To unset the default category, pass a null string as a parameter. | |
831 | * | |
832 | * \param category Category name | |
833 | * | |
834 | * \note "category" format marker will be set to the category name for all of these messages | |
835 | * (see [AbstractStringAppender::setFormat](@ref AbstractStringAppender::setFormat)). | |
836 | * | |
837 | * \sa defaultCategory() | |
838 | * \sa registerCategoryAppender() | |
839 | * \sa logToGlobalInstance() | |
840 | */ | |
841 | void Logger::setDefaultCategory(const QString& category) | |
842 | { | |
843 | Q_D(Logger); | |
844 | ||
845 | QMutexLocker locker(&d->loggerMutex); | |
846 | ||
847 | d->defaultCategory = category; | |
848 | } | |
849 | ||
850 | //! Returns default logging category name | |
851 | /** | |
852 | * \sa setDefaultCategory | |
853 | */ | |
854 | QString Logger::defaultCategory() const | |
855 | { | |
856 | Q_D(const Logger); | |
857 | return d->defaultCategory; | |
858 | } | |
859 | ||
860 | //! Links some logging category with the global logger instance appenders. | |
861 | /** | |
862 | * If set to true, all log messages to the specified category appenders will also be written to the global logger instance appenders, | |
863 | * registered using registerAppender(). | |
864 | * | |
865 | * By default, all messages to the specific category are written only to the specific category appenders | |
866 | * (registered using registerCategoryAppender()). | |
867 | * | |
868 | * \param category Category name | |
869 | * \param logToGlobal Link or onlink the category from global logger instance appender | |
870 | * | |
871 | * \sa globalInstance | |
872 | * \sa registerAppender | |
873 | * \sa registerCategoryAppender | |
874 | */ | |
875 | void Logger::logToGlobalInstance(const QString& category, bool logToGlobal) | |
876 | { | |
877 | Q_D(Logger); | |
878 | ||
879 | if (this == globalInstance()) | |
880 | { | |
881 | QMutexLocker locker(&d->loggerMutex); | |
882 | d->categories.insert(category, logToGlobal); | |
883 | } | |
884 | else | |
885 | { | |
886 | globalInstance()->logToGlobalInstance(category, logToGlobal); | |
887 | } | |
888 | } | |
889 | ||
890 | ||
891 | void Logger::write(const QDateTime& timeStamp, LogLevel logLevel, const char* file, int line, const char* function, const char* category, | |
892 | const QString& message, bool fromLocalInstance) | |
893 | { | |
894 | Q_D(Logger); | |
895 | ||
896 | QMutexLocker locker(&d->loggerMutex); | |
897 | ||
898 | QString logCategory = QString::fromLatin1(category); | |
899 | if (logCategory.isNull() && !d->defaultCategory.isNull()) | |
900 | logCategory = d->defaultCategory; | |
901 | ||
902 | bool wasWritten = false; | |
903 | bool isGlobalInstance = this == globalInstance(); | |
904 | bool linkedToGlobal = isGlobalInstance && d->categories.value(logCategory, false); | |
905 | ||
906 | if (!logCategory.isNull()) | |
907 | { | |
908 | QList<AbstractAppender*> appenders = d->categoryAppenders.values(logCategory); | |
909 | if (appenders.length() == 0) | |
910 | { | |
911 | if (logCategory != d->defaultCategory && !linkedToGlobal && !fromLocalInstance) | |
912 | std::cerr << "No appenders assotiated with category " << qPrintable(logCategory) << std::endl; | |
913 | } | |
914 | else | |
915 | { | |
916 | foreach (AbstractAppender* appender, appenders) | |
917 | appender->write(timeStamp, logLevel, file, line, function, logCategory, message); | |
918 | wasWritten = true; | |
919 | } | |
920 | } | |
921 | ||
922 | // the default category is linked to the main logger appenders | |
923 | // global logger instance also writes all linked categories to the main appenders | |
924 | if (logCategory.isNull() || logCategory == d->defaultCategory || linkedToGlobal) | |
925 | { | |
926 | if (!d->appenders.isEmpty()) | |
927 | { | |
928 | foreach (AbstractAppender* appender, d->appenders) | |
929 | appender->write(timeStamp, logLevel, file, line, function, logCategory, message); | |
930 | wasWritten = true; | |
931 | } | |
932 | else | |
933 | { | |
934 | static bool noAppendersWarningShown = false; | |
935 | if (!noAppendersWarningShown) | |
936 | { | |
937 | #if defined(Q_OS_ANDROID) | |
938 | __android_ write(ANDROID_LOG_WARN, "Logger", "No appenders registered with logger"); | |
939 | #else | |
940 | std::cerr << "No appenders registered with logger" << std::endl; | |
941 | #endif | |
942 | noAppendersWarningShown = true; | |
943 | } | |
944 | } | |
945 | } | |
946 | ||
947 | // local logger instances send category messages to the global instance | |
948 | if (!logCategory.isNull() && !isGlobalInstance) | |
949 | globalInstance()->write(timeStamp, logLevel, file, line, function, logCategory.toLatin1(), message, true); | |
950 | ||
951 | if (!wasWritten && !fromLocalInstance) | |
952 | { | |
953 | // Fallback | |
954 | #if defined(Q_OS_ANDROID) | |
955 | QString result = QString(QLatin1String("<%2> %3")).arg(AbstractStringAppender::stripFunctionName(function)).arg(message); | |
956 | __android_log_write(AndroidAppender::androidLogPriority(logLevel), "Logger", qPrintable(result)); | |
957 | #else | |
958 | QString result = QString(QLatin1String("[%1] <%2> %3")).arg(levelToString(logLevel), -7) | |
959 | .arg(AbstractStringAppender::stripFunctionName(function)).arg(message); | |
960 | std::cerr << qPrintable(result) << std::endl; | |
961 | #endif | |
962 | } | |
963 | ||
964 | if (logLevel == Logger::Fatal) | |
965 | abort(); | |
966 | } | |
967 | ||
968 | ||
969 | //! Writes the log record | |
970 | /** | |
971 | * Writes the log records with the supplied arguments to all the registered appenders. | |
972 | * | |
973 | * \note It is not recommended to call this function directly. Instead of this you can just call one of the macros | |
974 | * (dTrace, dTrac, dInfo, dWarning, dError, dFatal) that will supply all the needed | |
975 | * information to this function. | |
976 | * | |
977 | * \param timeStamp - the time stamp of the record | |
978 | * \param logLevel - the log level of the record | |
979 | * \param file - the name of the source file that requested the log record | |
980 | * \param line - the line of the code of source file that requested the log record | |
981 | * \param function - name of the function that requested the log record | |
982 | * \param category - logging category (0 for default category) | |
983 | * \param message - log message | |
984 | * | |
985 | * \note Recording of the log record using the Logger::Fatal log level will lead to calling the STL abort() | |
986 | * function, which will interrupt the running of your software and begin the writing of the core dump. | |
987 | * | |
988 | * \sa LogLevel | |
989 | * \sa dTrace, dDebug, dInfo, dWarning, dError, dFatal | |
990 | * \sa AbstractAppender | |
991 | */ | |
992 | void Logger::write(const QDateTime& timeStamp, LogLevel logLevel, const char* file, int line, const char* function, const char* category, | |
993 | const QString& message) | |
994 | { | |
995 | write(timeStamp, logLevel, file, line, function, category, message, /* fromLocalInstance = */ false); | |
996 | } | |
997 | ||
998 | /** | |
999 | * This is the overloaded function provided for the convinience. It behaves similar to the above function. | |
1000 | * | |
1001 | * This function uses the current timestamp obtained with \c QDateTime::currentDateTime(). | |
1002 | * | |
1003 | * \sa write() | |
1004 | */ | |
1005 | void Logger::write(LogLevel logLevel, const char* file, int line, const char* function, const char* category, | |
1006 | const QString& message) | |
1007 | { | |
1008 | write(QDateTime::currentDateTime(), logLevel, file, line, function, category, message); | |
1009 | } | |
1010 | ||
1011 | ||
1012 | /** | |
1013 | * This is the overloaded function provided for the convinience. It behaves similar to the above function. | |
1014 | * | |
1015 | * This function doesn't accept any log message as argument. It returns the \c QDebug object that can be written | |
1016 | * using the stream functions. For example, you may like to write: | |
1017 | * \code | |
1018 | * dDebug() << "This is the size" << size << "of the element" << elementName; | |
1019 | * \endcode | |
1020 | * instead of writing | |
1021 | * \code | |
1022 | * dDebug(QString(QLatin1String("This is the size %1x%2 of the element %3")) | |
1023 | * .arg(size.x()).arg(size.y()).arg(elementName)); | |
1024 | * \endcode | |
1025 | * | |
1026 | * Please consider reading the Qt Reference Documentation for the description of the QDebug class usage syntax. | |
1027 | * | |
1028 | * \note This overload is definitely more pleasant to use than the first write() overload, but it behaves definitely | |
1029 | * slower than all the above overloads. | |
1030 | * | |
1031 | * \sa write() | |
1032 | */ | |
1033 | QDebug Logger::write(LogLevel logLevel, const char* file, int line, const char* function, const char* category) | |
1034 | { | |
1035 | Q_D(Logger); | |
1036 | ||
1037 | d->logDevice->lock(logLevel, file, line, function, category); | |
1038 | return QDebug(d->logDevice); | |
1039 | } | |
1040 | ||
1041 | ||
1042 | //! Writes the assertion | |
1043 | /** | |
1044 | * This function writes the assertion record using the write() function. | |
1045 | * | |
1046 | * The assertion record is always written using the Logger::Fatal log level which leads to the abortation of the | |
1047 | * program and generation of the core dump (if supported). | |
1048 | * | |
1049 | * The message written to the appenders will be identical to the \c condition argument prefixed with the | |
1050 | * <tt>ASSERT:</tt> notification. | |
1051 | * | |
1052 | * \note It is not recommended to call this function directly. Instead of this you can just call the LOG_ASSERT | |
1053 | * macro that will supply all the needed information to this function. | |
1054 | * | |
1055 | * \sa LOG_ASSERT | |
1056 | * \sa write() | |
1057 | */ | |
1058 | void Logger::writeAssert(const char* file, int line, const char* function, const char* condition) | |
1059 | { | |
1060 | write(Logger::Fatal, file, line, function, 0, QString("ASSERT: \"%1\"").arg(condition)); | |
1061 | } | |
1062 | ||
1063 | ||
1064 | Logger* loggerInstance() | |
1065 | { | |
1066 | return Logger::globalInstance(); | |
1067 | } | |
1068 | ||
1069 | ||
1070 | ||
1071 | void LoggerTimingHelper::start(const char* msg, ...) | |
1072 | { | |
1073 | va_list va; | |
1074 | va_start(va, msg); | |
1075 | m_block = QString().vsprintf(msg, va); | |
1076 | va_end(va); | |
1077 | ||
1078 | m_time.start(); | |
1079 | } | |
1080 | ||
1081 | ||
1082 | void LoggerTimingHelper::start(const QString& block) | |
1083 | { | |
1084 | m_block = block; | |
1085 | m_time.start(); | |
1086 | } | |
1087 | ||
1088 | LoggerTimingHelper::~LoggerTimingHelper() | |
1089 | { | |
1090 | QString message; | |
1091 | if (m_block.isEmpty()) | |
1092 | message = QString(QLatin1String("Function %1 finished in ")).arg(AbstractStringAppender::stripFunctionName(m_function)); | |
1093 | else | |
1094 | message = QString(QLatin1String("\"%1\" finished in ")).arg(m_block); | |
1095 | ||
1096 | int elapsed = m_time.elapsed(); | |
1097 | if (elapsed >= 10000) | |
1098 | message += QString(QLatin1String("%1 s.")).arg(elapsed / 1000); | |
1099 | else | |
1100 | message += QString(QLatin1String("%1 ms.")).arg(elapsed); | |
1101 | ||
1102 | m_logger->write(m_logLevel, m_file, m_line, m_function, 0, message); | |
1103 | } | |
1104 | ||
1105 | ||
1106 | void CuteMessageLogger::write(const char* msg, ...) const | |
1107 | { | |
1108 | va_list va; | |
1109 | va_start(va, msg); | |
1110 | m_l->write(m_level, m_file, m_line, m_function, m_category, QString().vsprintf(msg, va)); | |
1111 | va_end(va); | |
1112 | } | |
1113 | ||
1114 | ||
1115 | void CuteMessageLogger::write(const QString& msg) const | |
1116 | { | |
1117 | m_l->write(m_level, m_file, m_line, m_function, m_category, msg); | |
1118 | } | |
1119 | ||
1120 | ||
1121 | QDebug CuteMessageLogger::write() const | |
1122 | { | |
1123 | return m_l->write(m_level, m_file, m_line, m_function, m_category); | |
1124 | } | |
1125 | ||
1126 | }} |
0 | /* | |
1 | Copyright (c) 2012 Boris Moiseev (cyberbobs at gmail dot com) | |
2 | ||
3 | This program is free software: you can redistribute it and/or modify | |
4 | it under the terms of the GNU Lesser General Public License version 2.1 | |
5 | as published by the Free Software Foundation and appearing in the file | |
6 | LICENSE.LGPL included in the packaging of this file. | |
7 | ||
8 | This program is distributed in the hope that it will be useful, | |
9 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
11 | GNU Lesser General Public License for more details. | |
12 | */ | |
13 | #ifndef LOGGER_H | |
14 | #define LOGGER_H | |
15 | ||
16 | // Qt | |
17 | #include <QString> | |
18 | #include <QDebug> | |
19 | #include <QDateTime> | |
20 | ||
21 | // Local | |
22 | #include "CuteLogger_global.h" | |
23 | ||
24 | namespace Dtk { | |
25 | namespace Log { | |
26 | ||
27 | class AbstractAppender; | |
28 | class Logger; | |
29 | CUTELOGGERSHARED_EXPORT Logger* loggerInstance(); | |
30 | #define logger loggerInstance() | |
31 | ||
32 | ||
33 | #define dTrace CuteMessageLogger(loggerInstance(), Logger::Trace, __FILE__, __LINE__, Q_FUNC_INFO).write | |
34 | #define dDebug CuteMessageLogger(loggerInstance(), Logger::Debug, __FILE__, __LINE__, Q_FUNC_INFO).write | |
35 | #define dInfo CuteMessageLogger(loggerInstance(), Logger::Info, __FILE__, __LINE__, Q_FUNC_INFO).write | |
36 | #define dWarning CuteMessageLogger(loggerInstance(), Logger::Warning, __FILE__, __LINE__, Q_FUNC_INFO).write | |
37 | #define dError CuteMessageLogger(loggerInstance(), Logger::Error, __FILE__, __LINE__, Q_FUNC_INFO).write | |
38 | #define dFatal CuteMessageLogger(loggerInstance(), Logger::Fatal, __FILE__, __LINE__, Q_FUNC_INFO).write | |
39 | ||
40 | #define dCTrace(category) CuteMessageLogger(loggerInstance(), Logger::Trace, __FILE__, __LINE__, Q_FUNC_INFO, category).write() | |
41 | #define dCDebug(category) CuteMessageLogger(loggerInstance(), Logger::Debug, __FILE__, __LINE__, Q_FUNC_INFO, category).write() | |
42 | #define dCInfo(category) CuteMessageLogger(loggerInstance(), Logger::Info, __FILE__, __LINE__, Q_FUNC_INFO, category).write() | |
43 | #define dCWarning(category) CuteMessageLogger(loggerInstance(), Logger::Warning, __FILE__, __LINE__, Q_FUNC_INFO, category).write() | |
44 | #define dCError(category) CuteMessageLogger(loggerInstance(), Logger::Error, __FILE__, __LINE__, Q_FUNC_INFO, category).write() | |
45 | #define dCFatal(category) CuteMessageLogger(loggerInstance(), Logger::Fatal, __FILE__, __LINE__, Q_FUNC_INFO, category).write() | |
46 | ||
47 | #define dTraceTime LoggerTimingHelper loggerTimingHelper(loggerInstance(), Logger::Trace, __FILE__, __LINE__, Q_FUNC_INFO); loggerTimingHelper.start | |
48 | #define dDebugTime LoggerTimingHelper loggerTimingHelper(loggerInstance(), Logger::Debug, __FILE__, __LINE__, Q_FUNC_INFO); loggerTimingHelper.start | |
49 | #define dInfoTime LoggerTimingHelper loggerTimingHelper(loggerInstance(), Logger::Info, __FILE__, __LINE__, Q_FUNC_INFO); loggerTimingHelper.start | |
50 | ||
51 | #define dAssert(cond) ((!(cond)) ? loggerInstance()->writeAssert(__FILE__, __LINE__, Q_FUNC_INFO, #cond) : qt_noop()) | |
52 | #define dAssertX(cond, msg) ((!(cond)) ? loggerInstance()->writeAssert(__FILE__, __LINE__, Q_FUNC_INFO, msg) : qt_noop()) | |
53 | ||
54 | #define dCategory(category) \ | |
55 | private:\ | |
56 | Logger* loggerInstance()\ | |
57 | {\ | |
58 | static Logger customLoggerInstance(category);\ | |
59 | return &customLoggerInstance;\ | |
60 | }\ | |
61 | ||
62 | #define dGlobalCategory(category) \ | |
63 | private:\ | |
64 | Logger* loggerInstance()\ | |
65 | {\ | |
66 | static Logger customLoggerInstance(category);\ | |
67 | customLoggerInstance.logToGlobalInstance(category, true);\ | |
68 | return &customLoggerInstance;\ | |
69 | }\ | |
70 | ||
71 | ||
72 | class LoggerPrivate; | |
73 | class CUTELOGGERSHARED_EXPORT Logger | |
74 | { | |
75 | Q_DISABLE_COPY(Logger) | |
76 | ||
77 | public: | |
78 | Logger(); | |
79 | Logger(const QString& defaultCategory); | |
80 | ~Logger(); | |
81 | ||
82 | //! Describes the possible severity levels of the log records | |
83 | enum LogLevel | |
84 | { | |
85 | Trace, //!< Trace level. Can be used for mostly unneeded records used for internal code tracing. | |
86 | Debug, //!< Debug level. Useful for non-necessary records used for the debugging of the software. | |
87 | Info, //!< Info level. Can be used for informational records, which may be interesting for not only developers. | |
88 | Warning, //!< Warning. May be used to log some non-fatal warnings detected by your application. | |
89 | Error, //!< Error. May be used for a big problems making your application work wrong but not crashing. | |
90 | Fatal //!< Fatal. Used for unrecoverable errors, crashes the application right after the log record is written. | |
91 | }; | |
92 | ||
93 | static QString levelToString(LogLevel logLevel); | |
94 | static LogLevel levelFromString(const QString& s); | |
95 | ||
96 | static Logger* globalInstance(); | |
97 | ||
98 | void registerAppender(AbstractAppender* appender); | |
99 | void registerCategoryAppender(const QString& category, AbstractAppender* appender); | |
100 | ||
101 | void logToGlobalInstance(const QString& category, bool logToGlobal = false); | |
102 | ||
103 | void setDefaultCategory(const QString& category); | |
104 | QString defaultCategory() const; | |
105 | ||
106 | void write(const QDateTime& timeStamp, LogLevel logLevel, const char* file, int line, const char* function, const char* category, | |
107 | const QString& message); | |
108 | void write(LogLevel logLevel, const char* file, int line, const char* function, const char* category, const QString& message); | |
109 | QDebug write(LogLevel logLevel, const char* file, int line, const char* function, const char* category); | |
110 | ||
111 | void writeAssert(const char* file, int line, const char* function, const char* condition); | |
112 | ||
113 | private: | |
114 | void write(const QDateTime& timeStamp, LogLevel logLevel, const char* file, int line, const char* function, const char* category, | |
115 | const QString& message, bool fromLocalInstance); | |
116 | Q_DECLARE_PRIVATE(Logger) | |
117 | LoggerPrivate* d_ptr; | |
118 | }; | |
119 | ||
120 | ||
121 | class CUTELOGGERSHARED_EXPORT CuteMessageLogger | |
122 | { | |
123 | Q_DISABLE_COPY(CuteMessageLogger) | |
124 | ||
125 | public: | |
126 | Q_DECL_CONSTEXPR CuteMessageLogger(Logger* l, Logger::LogLevel level, const char* file, int line, const char* function) | |
127 | : m_l(l), | |
128 | m_level(level), | |
129 | m_file(file), | |
130 | m_line(line), | |
131 | m_function(function), | |
132 | m_category(0) | |
133 | {} | |
134 | ||
135 | Q_DECL_CONSTEXPR CuteMessageLogger(Logger* l, Logger::LogLevel level, const char* file, int line, const char* function, const char* category) | |
136 | : m_l(l), | |
137 | m_level(level), | |
138 | m_file(file), | |
139 | m_line(line), | |
140 | m_function(function), | |
141 | m_category(category) | |
142 | {} | |
143 | ||
144 | void write(const char* msg, ...) const | |
145 | #if defined(Q_CC_GNU) && !defined(__INSURE__) | |
146 | # if defined(Q_CC_MINGW) && !defined(Q_CC_CLANG) | |
147 | __attribute__ ((format (gnu_printf, 2, 3))) | |
148 | # else | |
149 | __attribute__ ((format (printf, 2, 3))) | |
150 | # endif | |
151 | #endif | |
152 | ; | |
153 | ||
154 | void write(const QString& msg) const; | |
155 | ||
156 | QDebug write() const; | |
157 | ||
158 | private: | |
159 | Logger* m_l; | |
160 | Logger::LogLevel m_level; | |
161 | const char* m_file; | |
162 | int m_line; | |
163 | const char* m_function; | |
164 | const char* m_category; | |
165 | }; | |
166 | ||
167 | ||
168 | class CUTELOGGERSHARED_EXPORT LoggerTimingHelper | |
169 | { | |
170 | Q_DISABLE_COPY(LoggerTimingHelper) | |
171 | ||
172 | public: | |
173 | inline explicit LoggerTimingHelper(Logger* l, Logger::LogLevel logLevel, const char* file, int line, | |
174 | const char* function) | |
175 | : m_logger(l), | |
176 | m_logLevel(logLevel), | |
177 | m_file(file), | |
178 | m_line(line), | |
179 | m_function(function) | |
180 | {} | |
181 | ||
182 | void start(const char* msg, ...) | |
183 | #if defined(Q_CC_GNU) && !defined(__INSURE__) | |
184 | # if defined(Q_CC_MINGW) && !defined(Q_CC_CLANG) | |
185 | __attribute__ ((format (gnu_printf, 2, 3))) | |
186 | # else | |
187 | __attribute__ ((format (printf, 2, 3))) | |
188 | # endif | |
189 | #endif | |
190 | ; | |
191 | ||
192 | void start(const QString& msg = QString()); | |
193 | ||
194 | ~LoggerTimingHelper(); | |
195 | ||
196 | private: | |
197 | Logger* m_logger; | |
198 | QTime m_time; | |
199 | Logger::LogLevel m_logLevel; | |
200 | const char* m_file; | |
201 | int m_line; | |
202 | const char* m_function; | |
203 | QString m_block; | |
204 | }; | |
205 | ||
206 | }} | |
207 | ||
208 | #endif // LOGGER_H |
0 | /* | |
1 | Copyright (c) 2010 Karl-Heinz Reichel (khreichel at googlemail dot com) | |
2 | ||
3 | This program is free software: you can redistribute it and/or modify | |
4 | it under the terms of the GNU Lesser General Public License version 2.1 | |
5 | as published by the Free Software Foundation and appearing in the file | |
6 | LICENSE.LGPL included in the packaging of this file. | |
7 | ||
8 | This program is distributed in the hope that it will be useful, | |
9 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
11 | GNU Lesser General Public License for more details. | |
12 | */ | |
13 | // Local | |
14 | #include "OutputDebugAppender.h" | |
15 | ||
16 | // STL | |
17 | #include <windows.h> | |
18 | ||
19 | namespace Dtk { | |
20 | namespace Log { | |
21 | ||
22 | /** | |
23 | * \class OutputDebugAppender | |
24 | * | |
25 | * \brief Appender that writes the log records to the Microsoft Debug Log | |
26 | */ | |
27 | ||
28 | ||
29 | //! Writes the log record to the windows debug log. | |
30 | /** | |
31 | * \sa AbstractStringAppender::format() | |
32 | */ | |
33 | void OutputDebugAppender::append(const QDateTime& timeStamp, | |
34 | Logger::LogLevel logLevel, | |
35 | const char* file, | |
36 | int line, | |
37 | const char* function, | |
38 | const QString& category, | |
39 | const QString& message) | |
40 | { | |
41 | QString s = formattedString(timeStamp, logLevel, file, line, function, category, message); | |
42 | OutputDebugStringW((LPCWSTR) s.utf16()); | |
43 | } | |
44 | ||
45 | }} |
0 | /* | |
1 | Copyright (c) 2010 Karl-Heinz Reichel (khreichel at googlemail dot com) | |
2 | ||
3 | This program is free software: you can redistribute it and/or modify | |
4 | it under the terms of the GNU Lesser General Public License version 2.1 | |
5 | as published by the Free Software Foundation and appearing in the file | |
6 | LICENSE.LGPL included in the packaging of this file. | |
7 | ||
8 | This program is distributed in the hope that it will be useful, | |
9 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
11 | GNU Lesser General Public License for more details. | |
12 | */ | |
13 | ||
14 | #ifndef OUTPUTDEBUGAPPENDER_H | |
15 | #define OUTPUTDEBUGAPPENDER_H | |
16 | ||
17 | #include "CuteLogger_global.h" | |
18 | #include <AbstractStringAppender.h> | |
19 | ||
20 | namespace Dtk { | |
21 | namespace Log { | |
22 | ||
23 | class CUTELOGGERSHARED_EXPORT OutputDebugAppender : public AbstractStringAppender | |
24 | { | |
25 | protected: | |
26 | virtual void append(const QDateTime& timeStamp, Logger::LogLevel logLevel, const char* file, int line, | |
27 | const char* function, const QString& category, const QString& message); | |
28 | }; | |
29 | ||
30 | }} | |
31 | ||
32 | #endif // OUTPUTDEBUGAPPENDER_H |
0 | # Deepin Tool Kit Log | |
1 | ||
2 | DLog is the log module of deepin tool kit for Qt/C++ | |
3 | ||
4 | # Install | |
5 | ||
6 | ```` | |
7 | mkdir build && cd build | |
8 | qmake .. | |
9 | sudo make install | |
10 | ```` | |
11 | ||
12 | # Usage | |
13 | ||
14 | Just add pkgconfig in .pro file | |
15 | ||
16 | ```` | |
17 | unix { | |
18 | CONFIG+=link_pkgconfig | |
19 | PKGCONFIG+=dtklog | |
20 | } | |
21 | ```` | |
22 | ||
23 | # Example | |
24 | ||
25 | ```` | |
26 | #include <QCoreApplication> | |
27 | ||
28 | #include <DLog> | |
29 | ||
30 | using namespace Dtk::Log; | |
31 | ||
32 | int main(int argc, char* argv[]) | |
33 | { | |
34 | QCoreApplication app(argc, argv); | |
35 | ||
36 | /* 1 you can use standrd deepin application log format */ | |
37 | // 1.1 log to console | |
38 | DLogManager::instance()->registerAppender(true); | |
39 | dInfoTime(); | |
40 | /* 1.2 log to standrd deepin user cache path: ~/.cache/{organ}/{appname}/ */ | |
41 | // app.setOrganizationName("dtk-test"); // must set | |
42 | // app.setApplicationName("dlog-example"); // must set | |
43 | // dInfo()<< "LogFile:" << DLogManager::instance()->getlogFilePath(); | |
44 | // DLogManager::instance()->registerAppender(false); | |
45 | ||
46 | /* 2 Register your own logger format;*/ | |
47 | // ConsoleAppender* consoleAppender = new ConsoleAppender; | |
48 | // consoleAppender->setFormat("[%{type:-7}] <%{Function}> %{message}\n"); | |
49 | // logger->registerAppender(consoleAppender); | |
50 | ||
51 | dInfo("Starting the application"); | |
52 | int result = 1; | |
53 | dWarning() << "Something went wrong." << "Result code is" << result; | |
54 | return result; | |
55 | } | |
56 | ```` | |
57 | ||
58 | You can get full example from: | |
59 | ||
60 | [dlog-example](https://github.com/deepin-tool-kit/dtk-example/tree/master/dlog-example) | |
61 | ||
62 | # Document | |
63 | ||
64 | ```` | |
65 | doxygen -g dlog | |
66 | doxygen -w html | |
67 | firefox html/index | |
68 | ```` |
0 | #include <QDateTime> | |
1 | #include <QDir> | |
2 | #include <QFileInfo> | |
3 | ||
4 | #include "RollingFileAppender.h" | |
5 | ||
6 | namespace Dtk { | |
7 | namespace Log { | |
8 | ||
9 | RollingFileAppender::RollingFileAppender(const QString& fileName) | |
10 | : FileAppender(fileName), | |
11 | m_logFilesLimit(0) | |
12 | {} | |
13 | ||
14 | ||
15 | void RollingFileAppender::append(const QDateTime& timeStamp, Logger::LogLevel logLevel, const char* file, int line, | |
16 | const char* function, const QString& category, const QString& message) | |
17 | { | |
18 | if (!m_rollOverTime.isNull() && QDateTime::currentDateTime() > m_rollOverTime) | |
19 | rollOver(); | |
20 | ||
21 | FileAppender::append(timeStamp, logLevel, file, line, function, category, message); | |
22 | } | |
23 | ||
24 | ||
25 | RollingFileAppender::DatePattern RollingFileAppender::datePattern() const | |
26 | { | |
27 | QMutexLocker locker(&m_rollingMutex); | |
28 | return m_frequency; | |
29 | } | |
30 | ||
31 | ||
32 | QString RollingFileAppender::datePatternString() const | |
33 | { | |
34 | QMutexLocker locker(&m_rollingMutex); | |
35 | return m_datePatternString; | |
36 | } | |
37 | ||
38 | ||
39 | void RollingFileAppender::setDatePattern(DatePattern datePattern) | |
40 | { | |
41 | switch (datePattern) | |
42 | { | |
43 | case MinutelyRollover: | |
44 | setDatePatternString(QLatin1String("'.'yyyy-MM-dd-hh-mm")); | |
45 | break; | |
46 | case HourlyRollover: | |
47 | setDatePatternString(QLatin1String("'.'yyyy-MM-dd-hh")); | |
48 | break; | |
49 | case HalfDailyRollover: | |
50 | setDatePatternString(QLatin1String("'.'yyyy-MM-dd-a")); | |
51 | break; | |
52 | case DailyRollover: | |
53 | setDatePatternString(QLatin1String("'.'yyyy-MM-dd")); | |
54 | break; | |
55 | case WeeklyRollover: | |
56 | setDatePatternString(QLatin1String("'.'yyyy-ww")); | |
57 | break; | |
58 | case MonthlyRollover: | |
59 | setDatePatternString(QLatin1String("'.'yyyy-MM")); | |
60 | break; | |
61 | default: | |
62 | Q_ASSERT_X(false, "DailyRollingFileAppender::setDatePattern()", "Invalid datePattern constant"); | |
63 | setDatePattern(DailyRollover); | |
64 | }; | |
65 | ||
66 | QMutexLocker locker(&m_rollingMutex); | |
67 | m_frequency = datePattern; | |
68 | ||
69 | computeRollOverTime(); | |
70 | } | |
71 | ||
72 | ||
73 | void RollingFileAppender::setDatePattern(const QString& datePattern) | |
74 | { | |
75 | setDatePatternString(datePattern); | |
76 | computeFrequency(); | |
77 | ||
78 | computeRollOverTime(); | |
79 | } | |
80 | ||
81 | ||
82 | void RollingFileAppender::setDatePatternString(const QString& datePatternString) | |
83 | { | |
84 | QMutexLocker locker(&m_rollingMutex); | |
85 | m_datePatternString = datePatternString; | |
86 | } | |
87 | ||
88 | ||
89 | void RollingFileAppender::computeFrequency() | |
90 | { | |
91 | QMutexLocker locker(&m_rollingMutex); | |
92 | ||
93 | const QDateTime startTime(QDate(1999, 1, 1), QTime(0, 0)); | |
94 | const QString startString = startTime.toString(m_datePatternString); | |
95 | ||
96 | if (startString != startTime.addSecs(60).toString(m_datePatternString)) | |
97 | m_frequency = MinutelyRollover; | |
98 | else if (startString != startTime.addSecs(60 * 60).toString(m_datePatternString)) | |
99 | m_frequency = HourlyRollover; | |
100 | else if (startString != startTime.addSecs(60 * 60 * 12).toString(m_datePatternString)) | |
101 | m_frequency = HalfDailyRollover; | |
102 | else if (startString != startTime.addDays(1).toString(m_datePatternString)) | |
103 | m_frequency = DailyRollover; | |
104 | else if (startString != startTime.addDays(7).toString(m_datePatternString)) | |
105 | m_frequency = WeeklyRollover; | |
106 | else if (startString != startTime.addMonths(1).toString(m_datePatternString)) | |
107 | m_frequency = MonthlyRollover; | |
108 | else | |
109 | { | |
110 | Q_ASSERT_X(false, "DailyRollingFileAppender::computeFrequency", "The pattern '%1' does not specify a frequency"); | |
111 | return; | |
112 | } | |
113 | } | |
114 | ||
115 | ||
116 | void RollingFileAppender::removeOldFiles() | |
117 | { | |
118 | if (m_logFilesLimit <= 1) | |
119 | return; | |
120 | ||
121 | QFileInfo fileInfo(fileName()); | |
122 | QDir logDirectory(fileInfo.absoluteDir()); | |
123 | logDirectory.setFilter(QDir::Files); | |
124 | logDirectory.setNameFilters(QStringList() << fileInfo.fileName() + "*"); | |
125 | QFileInfoList logFiles = logDirectory.entryInfoList(); | |
126 | ||
127 | QMap<QDateTime, QString> fileDates; | |
128 | for (int i = 0; i < logFiles.length(); ++i) | |
129 | { | |
130 | QString name = logFiles[i].fileName(); | |
131 | QString suffix = name.mid(name.indexOf(fileInfo.fileName()) + fileInfo.fileName().length()); | |
132 | QDateTime fileDateTime = QDateTime::fromString(suffix, datePatternString()); | |
133 | ||
134 | if (fileDateTime.isValid()) | |
135 | fileDates.insert(fileDateTime, logFiles[i].absoluteFilePath()); | |
136 | } | |
137 | ||
138 | QList<QString> fileDateNames = fileDates.values(); | |
139 | for (int i = 0; i < fileDateNames.length() - m_logFilesLimit + 1; ++i) | |
140 | QFile::remove(fileDateNames[i]); | |
141 | } | |
142 | ||
143 | ||
144 | void RollingFileAppender::computeRollOverTime() | |
145 | { | |
146 | Q_ASSERT_X(!m_datePatternString.isEmpty(), "DailyRollingFileAppender::computeRollOverTime()", "No active date pattern"); | |
147 | ||
148 | QDateTime now = QDateTime::currentDateTime(); | |
149 | QDate nowDate = now.date(); | |
150 | QTime nowTime = now.time(); | |
151 | QDateTime start; | |
152 | ||
153 | switch (m_frequency) | |
154 | { | |
155 | case MinutelyRollover: | |
156 | { | |
157 | start = QDateTime(nowDate, QTime(nowTime.hour(), nowTime.minute(), 0, 0)); | |
158 | m_rollOverTime = start.addSecs(60); | |
159 | } | |
160 | break; | |
161 | case HourlyRollover: | |
162 | { | |
163 | start = QDateTime(nowDate, QTime(nowTime.hour(), 0, 0, 0)); | |
164 | m_rollOverTime = start.addSecs(60*60); | |
165 | } | |
166 | break; | |
167 | case HalfDailyRollover: | |
168 | { | |
169 | int hour = nowTime.hour(); | |
170 | if (hour >= 12) | |
171 | hour = 12; | |
172 | else | |
173 | hour = 0; | |
174 | start = QDateTime(nowDate, QTime(hour, 0, 0, 0)); | |
175 | m_rollOverTime = start.addSecs(60*60*12); | |
176 | } | |
177 | break; | |
178 | case DailyRollover: | |
179 | { | |
180 | start = QDateTime(nowDate, QTime(0, 0, 0, 0)); | |
181 | m_rollOverTime = start.addDays(1); | |
182 | } | |
183 | break; | |
184 | case WeeklyRollover: | |
185 | { | |
186 | // Qt numbers the week days 1..7. The week starts on Monday. | |
187 | // Change it to being numbered 0..6, starting with Sunday. | |
188 | int day = nowDate.dayOfWeek(); | |
189 | if (day == Qt::Sunday) | |
190 | day = 0; | |
191 | start = QDateTime(nowDate, QTime(0, 0, 0, 0)).addDays(-1 * day); | |
192 | m_rollOverTime = start.addDays(7); | |
193 | } | |
194 | break; | |
195 | case MonthlyRollover: | |
196 | { | |
197 | start = QDateTime(QDate(nowDate.year(), nowDate.month(), 1), QTime(0, 0, 0, 0)); | |
198 | m_rollOverTime = start.addMonths(1); | |
199 | } | |
200 | break; | |
201 | default: | |
202 | Q_ASSERT_X(false, "DailyRollingFileAppender::computeInterval()", "Invalid datePattern constant"); | |
203 | m_rollOverTime = QDateTime::fromTime_t(0); | |
204 | } | |
205 | ||
206 | m_rollOverSuffix = start.toString(m_datePatternString); | |
207 | Q_ASSERT_X(now.toString(m_datePatternString) == m_rollOverSuffix, | |
208 | "DailyRollingFileAppender::computeRollOverTime()", "File name changes within interval"); | |
209 | Q_ASSERT_X(m_rollOverSuffix != m_rollOverTime.toString(m_datePatternString), | |
210 | "DailyRollingFileAppender::computeRollOverTime()", "File name does not change with rollover"); | |
211 | } | |
212 | ||
213 | ||
214 | void RollingFileAppender::rollOver() | |
215 | { | |
216 | Q_ASSERT_X(!m_datePatternString.isEmpty(), "DailyRollingFileAppender::rollOver()", "No active date pattern"); | |
217 | ||
218 | QString rollOverSuffix = m_rollOverSuffix; | |
219 | computeRollOverTime(); | |
220 | if (rollOverSuffix == m_rollOverSuffix) | |
221 | return; | |
222 | ||
223 | closeFile(); | |
224 | ||
225 | QString targetFileName = fileName() + rollOverSuffix; | |
226 | QFile f(targetFileName); | |
227 | if (f.exists() && !f.remove()) | |
228 | return; | |
229 | f.setFileName(fileName()); | |
230 | if (!f.rename(targetFileName)) | |
231 | return; | |
232 | ||
233 | openFile(); | |
234 | removeOldFiles(); | |
235 | } | |
236 | ||
237 | ||
238 | void RollingFileAppender::setLogFilesLimit(int limit) | |
239 | { | |
240 | QMutexLocker locker(&m_rollingMutex); | |
241 | m_logFilesLimit = limit; | |
242 | } | |
243 | ||
244 | ||
245 | int RollingFileAppender::logFilesLimit() const | |
246 | { | |
247 | QMutexLocker locker(&m_rollingMutex); | |
248 | return m_logFilesLimit; | |
249 | } | |
250 | ||
251 | }} |
0 | #ifndef ROLLINGFILEAPPENDER_H | |
1 | #define ROLLINGFILEAPPENDER_H | |
2 | ||
3 | #include <QDateTime> | |
4 | ||
5 | #include <FileAppender.h> | |
6 | ||
7 | namespace Dtk { | |
8 | namespace Log { | |
9 | ||
10 | /*! | |
11 | * \brief The RollingFileAppender class extends FileAppender so that the underlying file is rolled over at a user chosen frequency. | |
12 | * | |
13 | * The class is based on Log4Qt.DailyRollingFileAppender class (http://log4qt.sourceforge.net/) | |
14 | * and has the same date pattern format. | |
15 | * | |
16 | * For example, if the fileName is set to /foo/bar and the DatePattern set to the daily rollover ('.'yyyy-MM-dd'.log'), on 2014-02-16 at midnight, | |
17 | * the logging file /foo/bar.log will be copied to /foo/bar.2014-02-16.log and logging for 2014-02-17 will continue in /foo/bar | |
18 | * until it rolls over the next day. | |
19 | * | |
20 | * The logFilesLimit parameter is used to automatically delete the oldest log files in the directory during rollover | |
21 | * (so no more than logFilesLimit recent log files exist in the directory at any moment). | |
22 | * \sa setDatePattern(DatePattern), setLogFilesLimit(int) | |
23 | */ | |
24 | class CUTELOGGERSHARED_EXPORT RollingFileAppender : public FileAppender | |
25 | { | |
26 | public: | |
27 | /*! | |
28 | * The enum DatePattern defines constants for date patterns. | |
29 | * \sa setDatePattern(DatePattern) | |
30 | */ | |
31 | enum DatePattern | |
32 | { | |
33 | /*! The minutely date pattern string is "'.'yyyy-MM-dd-hh-mm". */ | |
34 | MinutelyRollover = 0, | |
35 | /*! The hourly date pattern string is "'.'yyyy-MM-dd-hh". */ | |
36 | HourlyRollover, | |
37 | /*! The half-daily date pattern string is "'.'yyyy-MM-dd-a". */ | |
38 | HalfDailyRollover, | |
39 | /*! The daily date pattern string is "'.'yyyy-MM-dd". */ | |
40 | DailyRollover, | |
41 | /*! The weekly date pattern string is "'.'yyyy-ww". */ | |
42 | WeeklyRollover, | |
43 | /*! The monthly date pattern string is "'.'yyyy-MM". */ | |
44 | MonthlyRollover | |
45 | }; | |
46 | Q_ENUMS(DatePattern) | |
47 | ||
48 | RollingFileAppender(const QString& fileName = QString()); | |
49 | ||
50 | DatePattern datePattern() const; | |
51 | void setDatePattern(DatePattern datePattern); | |
52 | void setDatePattern(const QString& datePattern); | |
53 | ||
54 | QString datePatternString() const; | |
55 | ||
56 | void setLogFilesLimit(int limit); | |
57 | int logFilesLimit() const; | |
58 | ||
59 | protected: | |
60 | virtual void append(const QDateTime& timeStamp, Logger::LogLevel logLevel, const char* file, int line, | |
61 | const char* function, const QString& category, const QString& message); | |
62 | ||
63 | private: | |
64 | void rollOver(); | |
65 | void computeRollOverTime(); | |
66 | void computeFrequency(); | |
67 | void removeOldFiles(); | |
68 | void setDatePatternString(const QString& datePatternString); | |
69 | ||
70 | QString m_datePatternString; | |
71 | DatePattern m_frequency; | |
72 | ||
73 | QDateTime m_rollOverTime; | |
74 | QString m_rollOverSuffix; | |
75 | int m_logFilesLimit; | |
76 | mutable QMutex m_rollingMutex; | |
77 | }; | |
78 | ||
79 | }} | |
80 | ||
81 | #endif // ROLLINGFILEAPPENDER_H |
0 | INCLUDEPATH += $$PWD | |
1 | ||
2 | HEADERS += \ | |
3 | $$PWD/RollingFileAppender.h \ | |
4 | $$PWD/Logger.h \ | |
5 | $$PWD/FileAppender.h \ | |
6 | $$PWD/CuteLogger_global.h \ | |
7 | $$PWD/ConsoleAppender.h \ | |
8 | $$PWD/AbstractStringAppender.h \ | |
9 | $$PWD/AbstractAppender.h \ | |
10 | $$PWD/LogManager.h | |
11 | ||
12 | SOURCES += \ | |
13 | $$PWD/RollingFileAppender.cpp \ | |
14 | $$PWD/Logger.cpp \ | |
15 | $$PWD/FileAppender.cpp \ | |
16 | $$PWD/ConsoleAppender.cpp \ | |
17 | $$PWD/AbstractStringAppender.cpp \ | |
18 | $$PWD/AbstractAppender.cpp \ | |
19 | $$PWD/LogManager.cpp | |
20 | ||
21 | win32 { | |
22 | SOURCES += $$PWD/OutputDebugAppender.cpp | |
23 | HEADERS += $$PWD/OutputDebugAppender.h | |
24 | } |
0 | include($$PWD/../common/lib.pri) | |
1 | include(cutelogger.pri) | |
2 | ||
3 | QT -= gui | |
4 | ||
5 | TARGET = dtklog | |
6 | ||
7 | DEFINES += LIBDTKLOG_LIBRARY | |
8 | ||
9 | HEADERS += \ | |
10 | DLog | |
11 | ||
12 | includes.path = $${DTK_INCLUDEPATH}/DLog | |
13 | includes.files += \ | |
14 | DLog \ | |
15 | $$system($$PWD/../common/trheader.sh $$PWD/DLog) | |
16 | ||
17 | QMAKE_PKGCONFIG_NAME = DTK_LOG | |
18 | QMAKE_PKGCONFIG_DESCRIPTION = Deepin Tool Kit Log Module | |
19 | QMAKE_PKGCONFIG_INCDIR = $$includes.path |
0 | // Local | |
1 | #include "AbstractAppender.h" | |
2 | ||
3 | // Qt | |
4 | #include <QMutexLocker> | |
5 | ||
6 | DUTIL_BEGIN_NAMESPACE | |
7 | ||
8 | /** | |
9 | * \class AbstractAppender | |
10 | * | |
11 | * \brief The AbstractAppender class provides an abstract base class for writing a log entries. | |
12 | * | |
13 | * The AbstractAppender class is the base interface class for all log appenders that could be used with Logger. | |
14 | * | |
15 | * AbstractAppender provides a common implementation for the thread safe, mutex-protected logging of application | |
16 | * messages, such as ConsoleAppender, FileAppender or something else. AbstractAppender is abstract and can not be | |
17 | * instantiated, but you can use any of its subclasses or create a custom log appender at your choice. | |
18 | * | |
19 | * Appenders are the logical devices that is aimed to be attached to Logger object by calling | |
20 | * Logger::registerAppender(). On each log record call from the application Logger object sequentially calls write() | |
21 | * function on all the appenders registered in it. | |
22 | * | |
23 | * You can subclass AbstractAppender to implement a logging target of any kind you like. It may be the external logging | |
24 | * subsystem (for example, syslog in *nix), XML file, SQL database entries, D-Bus messages or anything else you can | |
25 | * imagine. | |
26 | * | |
27 | * For the simple non-structured plain text logging (for example, to a plain text file or to the console output) you may | |
28 | * like to subclass the AbstractStringAppender instead of AbstractAppender, which will give you a more convinient way to | |
29 | * control the format of the log output. | |
30 | * | |
31 | * \sa AbstractStringAppender | |
32 | * \sa Logger::registerAppender() | |
33 | */ | |
34 | ||
35 | ||
36 | //! Constructs a AbstractAppender object. | |
37 | AbstractAppender::AbstractAppender() | |
38 | : m_detailsLevel(Logger::Debug) | |
39 | {} | |
40 | ||
41 | ||
42 | //! Destructs the AbstractAppender object. | |
43 | AbstractAppender::~AbstractAppender() | |
44 | {} | |
45 | ||
46 | ||
47 | //! Returns the current details level of appender. | |
48 | /** | |
49 | * Log records with a log level lower than a current detailsLevel() will be silently ignored by appender and would not | |
50 | * be sent to its append() function. | |
51 | * | |
52 | * It provides additional logging flexibility, allowing you to set the different severity levels for different types | |
53 | * of logs. | |
54 | * | |
55 | * \note This function is thread safe. | |
56 | * | |
57 | * \sa setDetailsLevel() | |
58 | * \sa Logger::LogLevel | |
59 | */ | |
60 | Logger::LogLevel AbstractAppender::detailsLevel() const | |
61 | { | |
62 | QMutexLocker locker(&m_detailsLevelMutex); | |
63 | return m_detailsLevel; | |
64 | } | |
65 | ||
66 | ||
67 | //! Sets the current details level of appender. | |
68 | /** | |
69 | * Default details level is Logger::Debug | |
70 | * | |
71 | * \note This function is thread safe. | |
72 | * | |
73 | * \sa detailsLevel() | |
74 | * \sa Logger::LogLevel | |
75 | */ | |
76 | void AbstractAppender::setDetailsLevel(Logger::LogLevel level) | |
77 | { | |
78 | QMutexLocker locker(&m_detailsLevelMutex); | |
79 | m_detailsLevel = level; | |
80 | } | |
81 | ||
82 | ||
83 | ||
84 | //! Sets the current details level of appender | |
85 | /** | |
86 | * This function is provided for convenience, it behaves like an above function. | |
87 | * | |
88 | * \sa detailsLevel() | |
89 | * \sa Logger::LogLevel | |
90 | */ | |
91 | void AbstractAppender::setDetailsLevel(const QString& level) | |
92 | { | |
93 | setDetailsLevel(Logger::levelFromString(level)); | |
94 | } | |
95 | ||
96 | ||
97 | //! Tries to write the log record to this logger | |
98 | /** | |
99 | * This is the function called by Logger object to write a log message to the appender. | |
100 | * | |
101 | * \note This function is thread safe. | |
102 | * | |
103 | * \sa Logger::write() | |
104 | * \sa detailsLevel() | |
105 | */ | |
106 | void AbstractAppender::write(const QDateTime& timeStamp, Logger::LogLevel logLevel, const char* file, int line, | |
107 | const char* function, const QString& category, const QString& message) | |
108 | { | |
109 | if (logLevel >= detailsLevel()) | |
110 | { | |
111 | QMutexLocker locker(&m_writeMutex); | |
112 | append(timeStamp, logLevel, file, line, function, category, message); | |
113 | } | |
114 | } | |
115 | ||
116 | ||
117 | /** | |
118 | * \fn virtual void AbstractAppender::append(const QDateTime& timeStamp, Logger::LogLevel logLevel, const char* file, | |
119 | * int line, const char* function, const QString& message) | |
120 | * | |
121 | * \brief Writes the log record to the logger instance | |
122 | * | |
123 | * This function is called every time when user tries to write a message to this AbstractAppender instance using | |
124 | * the write() function. Write function works as proxy and transfers only the messages with log level more or equal | |
125 | * to the current logLevel(). | |
126 | * | |
127 | * Overload this function when you are implementing a custom appender. | |
128 | * | |
129 | * \note This function is not needed to be thread safe because it is never called directly by Logger object. The | |
130 | * write() function works as a proxy and protects this function from concurrent access. | |
131 | * | |
132 | * \sa Logger::write() | |
133 | */ | |
134 | ||
135 | DUTIL_END_NAMESPACE |
0 | /* | |
1 | Copyright (c) 2010 Boris Moiseev (cyberbobs at gmail dot com) | |
2 | ||
3 | This program is free software: you can redistribute it and/or modify | |
4 | it under the terms of the GNU Lesser General Public License version 2.1 | |
5 | as published by the Free Software Foundation and appearing in the file | |
6 | LICENSE.LGPL included in the packaging of this file. | |
7 | ||
8 | This program is distributed in the hope that it will be useful, | |
9 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
11 | GNU Lesser General Public License for more details. | |
12 | */ | |
13 | #ifndef ABSTRACTAPPENDER_H | |
14 | #define ABSTRACTAPPENDER_H | |
15 | ||
16 | // Local | |
17 | #include "CuteLogger_global.h" | |
18 | #include <Logger.h> | |
19 | ||
20 | // Qt | |
21 | #include <QMutex> | |
22 | ||
23 | DUTIL_BEGIN_NAMESPACE | |
24 | ||
25 | class CUTELOGGERSHARED_EXPORT AbstractAppender | |
26 | { | |
27 | public: | |
28 | AbstractAppender(); | |
29 | virtual ~AbstractAppender(); | |
30 | ||
31 | Logger::LogLevel detailsLevel() const; | |
32 | void setDetailsLevel(Logger::LogLevel level); | |
33 | void setDetailsLevel(const QString& level); | |
34 | ||
35 | void write(const QDateTime& timeStamp, Logger::LogLevel logLevel, const char* file, int line, const char* function, | |
36 | const QString& category, const QString& message); | |
37 | ||
38 | protected: | |
39 | virtual void append(const QDateTime& timeStamp, Logger::LogLevel logLevel, const char* file, int line, | |
40 | const char* function, const QString& category, const QString& message) = 0; | |
41 | ||
42 | private: | |
43 | QMutex m_writeMutex; | |
44 | ||
45 | Logger::LogLevel m_detailsLevel; | |
46 | mutable QMutex m_detailsLevelMutex; | |
47 | }; | |
48 | ||
49 | DUTIL_END_NAMESPACE | |
50 | ||
51 | #endif // ABSTRACTAPPENDER_H |
0 | /* | |
1 | Copyright (c) 2010 Boris Moiseev (cyberbobs at gmail dot com) Nikolay Matyunin (matyunin.n at gmail dot com) | |
2 | ||
3 | Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). | |
4 | ||
5 | This program is free software: you can redistribute it and/or modify | |
6 | it under the terms of the GNU Lesser General Public License version 2.1 | |
7 | as published by the Free Software Foundation and appearing in the file | |
8 | LICENSE.LGPL included in the packaging of this file. | |
9 | ||
10 | This program is distributed in the hope that it will be useful, | |
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
13 | GNU Lesser General Public License for more details. | |
14 | */ | |
15 | // Local | |
16 | #include "AbstractStringAppender.h" | |
17 | ||
18 | // Qt | |
19 | #include <QReadLocker> | |
20 | #include <QWriteLocker> | |
21 | #include <QDateTime> | |
22 | #include <QRegExp> | |
23 | #include <QCoreApplication> | |
24 | #include <QThread> | |
25 | ||
26 | DUTIL_BEGIN_NAMESPACE | |
27 | ||
28 | /** | |
29 | * \class AbstractStringAppender | |
30 | * | |
31 | * \brief The AbstractStringAppender class provides a convinient base for appenders working with plain text formatted | |
32 | * logs. | |
33 | * | |
34 | * AbstractSringAppender is the simple extension of the AbstractAppender class providing the convinient way to create | |
35 | * custom log appenders working with a plain text formatted log targets. | |
36 | * | |
37 | * It have the formattedString() protected function that formats the logging arguments according to a format set with | |
38 | * setFormat(). | |
39 | * | |
40 | * This class can not be directly instantiated because it contains pure virtual function inherited from AbstractAppender | |
41 | * class. | |
42 | * | |
43 | * For more detailed description of customizing the log output format see the documentation on the setFormat() function. | |
44 | */ | |
45 | ||
46 | ||
47 | const char formattingMarker = '%'; | |
48 | ||
49 | ||
50 | //! Constructs a new string appender object | |
51 | AbstractStringAppender::AbstractStringAppender() | |
52 | : m_format(QLatin1String("%{time}{yyyy-MM-ddTHH:mm:ss.zzz} [%{type:-7}] <%{function}> %{message}\n")) | |
53 | {} | |
54 | ||
55 | ||
56 | //! Returns the current log format string. | |
57 | /** | |
58 | * The default format is set to "%{time}{yyyy-MM-ddTHH:mm:ss.zzz} [%{type:-7}] <%{function}> %{message}\n". You can set a different log record | |
59 | * format using the setFormat() function. | |
60 | * | |
61 | * \sa setFormat(const QString&) | |
62 | */ | |
63 | QString AbstractStringAppender::format() const | |
64 | { | |
65 | QReadLocker locker(&m_formatLock); | |
66 | return m_format; | |
67 | } | |
68 | ||
69 | ||
70 | //! Sets the logging format for writing strings to the log target with this appender. | |
71 | /** | |
72 | * The string format seems to be very common to those developers who have used a standart sprintf function. | |
73 | * | |
74 | * Log output format is a simple QString with the special markers (starting with % sign) which will be replaced with | |
75 | * it's internal meaning when writing a log record. | |
76 | * | |
77 | * Controlling marker begins with the percent sign (%) which is followed by the command inside {} brackets | |
78 | * (the command describes, what will be put to log record instead of marker). | |
79 | * Optional field width argument may be specified right after the command (through the colon symbol before the closing bracket) | |
80 | * Some commands requires an additional formatting argument (in the second {} brackets). | |
81 | * | |
82 | * Field width argument works almost identically to the \c QString::arg() \c fieldWidth argument (and uses it | |
83 | * internally). For example, \c "%{type:-7}" will be replaced with the left padded debug level of the message | |
84 | * (\c "Debug ") or something. For the more detailed description of it you may consider to look to the Qt | |
85 | * Reference Documentation. | |
86 | * | |
87 | * Supported marker commands are: | |
88 | * \arg \c %{time} - timestamp. You may specify your custom timestamp format using the second {} brackets after the marker, | |
89 | * timestamp format here will be similiar to those used in QDateTime::toString() function. For example, | |
90 | * "%{time}{dd-MM-yyyy, HH:mm}" may be replaced with "17-12-2010, 20:17" depending on current date and time. | |
91 | * The default format used here is "HH:mm:ss.zzz". | |
92 | * \arg \c %{type} - Log level. Possible log levels are shown in the Logger::LogLevel enumerator. | |
93 | * \arg \c %{Type} - Uppercased log level. | |
94 | * \arg \c %{typeOne} - One letter log level. | |
95 | * \arg \c %{TypeOne} - One uppercase letter log level. | |
96 | * \arg \c %{File} - Full source file name (with path) of the file that requested log recording. Uses the \c __FILE__ | |
97 | * preprocessor macro. | |
98 | * \arg \c %{file} - Short file name (with stripped path). | |
99 | * \arg \c %{line} - Line number in the source file. Uses the \c __LINE__ preprocessor macro. | |
100 | * \arg \c %{Function} - Name of function that called on of the LOG_* macros. Uses the \c Q_FUNC_INFO macro provided with | |
101 | * Qt. | |
102 | * \arg \c %{function} - Similiar to the %{Function}, but the function name is stripped using stripFunctionName | |
103 | * \arg \c %{message} - The log message sent by the caller. | |
104 | * \arg \c %{category} - The log category. | |
105 | * \arg \c %{appname} - Application name (returned by QCoreApplication::applicationName() function). | |
106 | * \arg \c %{pid} - Application pid (returned by QCoreApplication::applicationPid() function). | |
107 | * \arg \c %{threadid} - ID of current thread. | |
108 | * \arg \c %% - Convinient marker that is replaced with the single \c % mark. | |
109 | * | |
110 | * \note Format doesn't add \c '\\n' to the end of the format line. Please consider adding it manually. | |
111 | * | |
112 | * \sa format() | |
113 | * \sa stripFunctionName() | |
114 | * \sa Logger::LogLevel | |
115 | */ | |
116 | void AbstractStringAppender::setFormat(const QString& format) | |
117 | { | |
118 | QWriteLocker locker(&m_formatLock); | |
119 | m_format = format; | |
120 | } | |
121 | ||
122 | ||
123 | //! Strips the long function signature (as added by Q_FUNC_INFO macro) | |
124 | /** | |
125 | * The string processing drops the returning type, arguments and template parameters of function. It is definitely | |
126 | * useful for enchancing the log output readability. | |
127 | * \return stripped function name | |
128 | */ | |
129 | QString AbstractStringAppender::stripFunctionName(const char* name) | |
130 | { | |
131 | return QString::fromLatin1(qCleanupFuncinfo(name)); | |
132 | } | |
133 | ||
134 | ||
135 | // The function was backported from Qt5 sources (qlogging.h) | |
136 | QByteArray AbstractStringAppender::qCleanupFuncinfo(const char* name) | |
137 | { | |
138 | QByteArray info(name); | |
139 | ||
140 | // Strip the function info down to the base function name | |
141 | // note that this throws away the template definitions, | |
142 | // the parameter types (overloads) and any const/volatile qualifiers. | |
143 | if (info.isEmpty()) | |
144 | return info; | |
145 | ||
146 | int pos; | |
147 | ||
148 | // skip trailing [with XXX] for templates (gcc) | |
149 | pos = info.size() - 1; | |
150 | if (info.endsWith(']')) { | |
151 | while (--pos) { | |
152 | if (info.at(pos) == '[') | |
153 | info.truncate(pos); | |
154 | } | |
155 | } | |
156 | ||
157 | bool hasLambda = false; | |
158 | QRegExp lambdaRegex("::<lambda\\(.*\\)>"); | |
159 | int lambdaIndex = lambdaRegex.indexIn(QString::fromLatin1(info)); | |
160 | if (lambdaIndex != -1) | |
161 | { | |
162 | hasLambda = true; | |
163 | info.remove(lambdaIndex, lambdaRegex.matchedLength()); | |
164 | } | |
165 | ||
166 | // operator names with '(', ')', '<', '>' in it | |
167 | static const char operator_call[] = "operator()"; | |
168 | static const char operator_lessThan[] = "operator<"; | |
169 | static const char operator_greaterThan[] = "operator>"; | |
170 | static const char operator_lessThanEqual[] = "operator<="; | |
171 | static const char operator_greaterThanEqual[] = "operator>="; | |
172 | ||
173 | // canonize operator names | |
174 | info.replace("operator ", "operator"); | |
175 | ||
176 | // remove argument list | |
177 | forever { | |
178 | int parencount = 0; | |
179 | pos = info.lastIndexOf(')'); | |
180 | if (pos == -1) { | |
181 | // Don't know how to parse this function name | |
182 | return info; | |
183 | } | |
184 | ||
185 | // find the beginning of the argument list | |
186 | --pos; | |
187 | ++parencount; | |
188 | while (pos && parencount) { | |
189 | if (info.at(pos) == ')') | |
190 | ++parencount; | |
191 | else if (info.at(pos) == '(') | |
192 | --parencount; | |
193 | --pos; | |
194 | } | |
195 | if (parencount != 0) | |
196 | return info; | |
197 | ||
198 | info.truncate(++pos); | |
199 | ||
200 | if (info.at(pos - 1) == ')') { | |
201 | if (info.indexOf(operator_call) == pos - (int)strlen(operator_call)) | |
202 | break; | |
203 | ||
204 | // this function returns a pointer to a function | |
205 | // and we matched the arguments of the return type's parameter list | |
206 | // try again | |
207 | info.remove(0, info.indexOf('(')); | |
208 | info.chop(1); | |
209 | continue; | |
210 | } else { | |
211 | break; | |
212 | } | |
213 | } | |
214 | ||
215 | if (hasLambda) | |
216 | info.append("::lambda"); | |
217 | ||
218 | // find the beginning of the function name | |
219 | int parencount = 0; | |
220 | int templatecount = 0; | |
221 | --pos; | |
222 | ||
223 | // make sure special characters in operator names are kept | |
224 | if (pos > -1) { | |
225 | switch (info.at(pos)) { | |
226 | case ')': | |
227 | if (info.indexOf(operator_call) == pos - (int)strlen(operator_call) + 1) | |
228 | pos -= 2; | |
229 | break; | |
230 | case '<': | |
231 | if (info.indexOf(operator_lessThan) == pos - (int)strlen(operator_lessThan) + 1) | |
232 | --pos; | |
233 | break; | |
234 | case '>': | |
235 | if (info.indexOf(operator_greaterThan) == pos - (int)strlen(operator_greaterThan) + 1) | |
236 | --pos; | |
237 | break; | |
238 | case '=': { | |
239 | int operatorLength = (int)strlen(operator_lessThanEqual); | |
240 | if (info.indexOf(operator_lessThanEqual) == pos - operatorLength + 1) | |
241 | pos -= 2; | |
242 | else if (info.indexOf(operator_greaterThanEqual) == pos - operatorLength + 1) | |
243 | pos -= 2; | |
244 | break; | |
245 | } | |
246 | default: | |
247 | break; | |
248 | } | |
249 | } | |
250 | ||
251 | while (pos > -1) { | |
252 | if (parencount < 0 || templatecount < 0) | |
253 | return info; | |
254 | ||
255 | char c = info.at(pos); | |
256 | if (c == ')') | |
257 | ++parencount; | |
258 | else if (c == '(') | |
259 | --parencount; | |
260 | else if (c == '>') | |
261 | ++templatecount; | |
262 | else if (c == '<') | |
263 | --templatecount; | |
264 | else if (c == ' ' && templatecount == 0 && parencount == 0) | |
265 | break; | |
266 | ||
267 | --pos; | |
268 | } | |
269 | info = info.mid(pos + 1); | |
270 | ||
271 | // remove trailing '*', '&' that are part of the return argument | |
272 | while ((info.at(0) == '*') | |
273 | || (info.at(0) == '&')) | |
274 | info = info.mid(1); | |
275 | ||
276 | // we have the full function name now. | |
277 | // clean up the templates | |
278 | while ((pos = info.lastIndexOf('>')) != -1) { | |
279 | if (!info.contains('<')) | |
280 | break; | |
281 | ||
282 | // find the matching close | |
283 | int end = pos; | |
284 | templatecount = 1; | |
285 | --pos; | |
286 | while (pos && templatecount) { | |
287 | register char c = info.at(pos); | |
288 | if (c == '>') | |
289 | ++templatecount; | |
290 | else if (c == '<') | |
291 | --templatecount; | |
292 | --pos; | |
293 | } | |
294 | ++pos; | |
295 | info.remove(pos, end - pos + 1); | |
296 | } | |
297 | ||
298 | return info; | |
299 | } | |
300 | ||
301 | ||
302 | //! Returns the string to record to the logging target, formatted according to the format(). | |
303 | /** | |
304 | * \sa format() | |
305 | * \sa setFormat(const QString&) | |
306 | */ | |
307 | QString AbstractStringAppender::formattedString(const QDateTime& timeStamp, Logger::LogLevel logLevel, const char* file, | |
308 | int line, const char* function, const QString& category, const QString& message) const | |
309 | { | |
310 | QString f = format(); | |
311 | const int size = f.size(); | |
312 | ||
313 | QString result; | |
314 | ||
315 | int i = 0; | |
316 | while (i < f.size()) | |
317 | { | |
318 | QChar c = f.at(i); | |
319 | ||
320 | // We will silently ignore the broken % marker at the end of string | |
321 | if (c != QLatin1Char(formattingMarker) || (i + 2) >= size) | |
322 | { | |
323 | result.append(c); | |
324 | } | |
325 | else | |
326 | { | |
327 | i += 2; | |
328 | QChar currentChar = f.at(i); | |
329 | QString command; | |
330 | int fieldWidth = 0; | |
331 | ||
332 | if (currentChar.isLetter()) | |
333 | { | |
334 | command.append(currentChar); | |
335 | int j = 1; | |
336 | while ((i + j) < size && f.at(i + j).isLetter()) | |
337 | { | |
338 | command.append(f.at(i+j)); | |
339 | j++; | |
340 | } | |
341 | ||
342 | i+=j; | |
343 | currentChar = f.at(i); | |
344 | ||
345 | // Check for the padding instruction | |
346 | if (currentChar == QLatin1Char(':')) | |
347 | { | |
348 | currentChar = f.at(++i); | |
349 | if (currentChar.isDigit() || currentChar.category() == QChar::Punctuation_Dash) | |
350 | { | |
351 | int j = 1; | |
352 | while ((i + j) < size && f.at(i + j).isDigit()) | |
353 | j++; | |
354 | fieldWidth = f.mid(i, j).toInt(); | |
355 | ||
356 | i += j; | |
357 | } | |
358 | } | |
359 | } | |
360 | ||
361 | // Log record chunk to insert instead of formatting instruction | |
362 | QString chunk; | |
363 | ||
364 | // Time stamp | |
365 | if (command == QLatin1String("time")) | |
366 | { | |
367 | if (f.at(i + 1) == QLatin1Char('{')) | |
368 | { | |
369 | int j = 1; | |
370 | while ((i + 2 + j) < size && f.at(i + 2 + j) != QLatin1Char('}')) | |
371 | j++; | |
372 | ||
373 | if ((i + 2 + j) < size) | |
374 | { | |
375 | chunk = timeStamp.toString(f.mid(i + 2, j)); | |
376 | ||
377 | i += j; | |
378 | i += 2; | |
379 | } | |
380 | } | |
381 | ||
382 | if (chunk.isNull()) | |
383 | chunk = timeStamp.toString(QLatin1String("HH:mm:ss.zzz")); | |
384 | } | |
385 | ||
386 | // Log level | |
387 | else if (command == QLatin1String("type")) | |
388 | chunk = Logger::levelToString(logLevel); | |
389 | ||
390 | // Uppercased log level | |
391 | else if (command == QLatin1String("Type")) | |
392 | chunk = Logger::levelToString(logLevel).toUpper(); | |
393 | ||
394 | // One letter log level | |
395 | else if (command == QLatin1String("typeOne")) | |
396 | chunk = Logger::levelToString(logLevel).left(1).toLower(); | |
397 | ||
398 | // One uppercase letter log level | |
399 | else if (command == QLatin1String("TypeOne")) | |
400 | chunk = Logger::levelToString(logLevel).left(1).toUpper(); | |
401 | ||
402 | // Filename | |
403 | else if (command == QLatin1String("File")) | |
404 | chunk = QLatin1String(file); | |
405 | ||
406 | // Filename without a path | |
407 | else if (command == QLatin1String("file")) | |
408 | chunk = QString(QLatin1String(file)).section('/', -1); | |
409 | ||
410 | // Source line number | |
411 | else if (command == QLatin1String("line")) | |
412 | chunk = QString::number(line); | |
413 | ||
414 | // Function name, as returned by Q_FUNC_INFO | |
415 | else if (command == QLatin1String("Function")) | |
416 | chunk = QString::fromLatin1(function); | |
417 | ||
418 | // Stripped function name | |
419 | else if (command == QLatin1String("function")) | |
420 | chunk = stripFunctionName(function); | |
421 | ||
422 | // Log message | |
423 | else if (command == QLatin1String("message")) | |
424 | chunk = message; | |
425 | ||
426 | else if (command == QLatin1String("category")) | |
427 | chunk = category; | |
428 | ||
429 | // Application pid | |
430 | else if (command == QLatin1String("pid")) | |
431 | chunk = QString::number(QCoreApplication::applicationPid()); | |
432 | ||
433 | // Appplication name | |
434 | else if (command == QLatin1String("appname")) | |
435 | chunk = QCoreApplication::applicationName(); | |
436 | ||
437 | // Thread ID (duplicates Qt5 threadid debbuging way) | |
438 | else if (command == QLatin1String("threadid")) | |
439 | chunk = QLatin1String("0x") + QString::number(qlonglong(QThread::currentThread()->currentThread()), 16); | |
440 | ||
441 | // We simply replace the double formatting marker (%) with one | |
442 | else if (command == QString(formattingMarker)) | |
443 | chunk = QLatin1Char(formattingMarker); | |
444 | ||
445 | // Do not process any unknown commands | |
446 | else | |
447 | { | |
448 | chunk = QString(formattingMarker); | |
449 | chunk.append(command); | |
450 | } | |
451 | ||
452 | result.append(QString(QLatin1String("%1")).arg(chunk, fieldWidth)); | |
453 | } | |
454 | ||
455 | ++i; | |
456 | } | |
457 | ||
458 | return result; | |
459 | } | |
460 | ||
461 | DUTIL_END_NAMESPACE |
0 | /* | |
1 | Copyright (c) 2010 Boris Moiseev (cyberbobs at gmail dot com) | |
2 | ||
3 | This program is free software: you can redistribute it and/or modify | |
4 | it under the terms of the GNU Lesser General Public License version 2.1 | |
5 | as published by the Free Software Foundation and appearing in the file | |
6 | LICENSE.LGPL included in the packaging of this file. | |
7 | ||
8 | This program is distributed in the hope that it will be useful, | |
9 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
11 | GNU Lesser General Public License for more details. | |
12 | */ | |
13 | #ifndef ABSTRACTSTRINGAPPENDER_H | |
14 | #define ABSTRACTSTRINGAPPENDER_H | |
15 | ||
16 | // Local | |
17 | #include "CuteLogger_global.h" | |
18 | #include <AbstractAppender.h> | |
19 | ||
20 | // Qt | |
21 | #include <QReadWriteLock> | |
22 | ||
23 | DUTIL_BEGIN_NAMESPACE | |
24 | ||
25 | class CUTELOGGERSHARED_EXPORT AbstractStringAppender : public AbstractAppender | |
26 | { | |
27 | public: | |
28 | AbstractStringAppender(); | |
29 | ||
30 | virtual QString format() const; | |
31 | void setFormat(const QString&); | |
32 | ||
33 | static QString stripFunctionName(const char*); | |
34 | ||
35 | protected: | |
36 | QString formattedString(const QDateTime& timeStamp, Logger::LogLevel logLevel, const char* file, int line, | |
37 | const char* function, const QString& category, const QString& message) const; | |
38 | ||
39 | private: | |
40 | static QByteArray qCleanupFuncinfo(const char*); | |
41 | ||
42 | QString m_format; | |
43 | mutable QReadWriteLock m_formatLock; | |
44 | }; | |
45 | ||
46 | DUTIL_END_NAMESPACE | |
47 | ||
48 | #endif // ABSTRACTSTRINGAPPENDER_H |
0 | /* | |
1 | Copyright (c) 2010 Boris Moiseev (cyberbobs at gmail dot com) | |
2 | ||
3 | This program is free software: you can redistribute it and/or modify | |
4 | it under the terms of the GNU Lesser General Public License version 2.1 | |
5 | as published by the Free Software Foundation and appearing in the file | |
6 | LICENSE.LGPL included in the packaging of this file. | |
7 | ||
8 | This program is distributed in the hope that it will be useful, | |
9 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
11 | GNU Lesser General Public License for more details. | |
12 | */ | |
13 | // Local | |
14 | #include "ConsoleAppender.h" | |
15 | ||
16 | // STL | |
17 | #include <iostream> | |
18 | ||
19 | DUTIL_BEGIN_NAMESPACE | |
20 | ||
21 | /** | |
22 | * \class ConsoleAppender | |
23 | * | |
24 | * \brief ConsoleAppender is the simple appender that writes the log records to the std::cerr output stream. | |
25 | * | |
26 | * ConsoleAppender uses "[%{type:-7}] <%{function}> %{message}\n" as a default output format. It is similar to the | |
27 | * AbstractStringAppender but doesn't show a timestamp. | |
28 | * | |
29 | * You can modify ConsoleAppender output format without modifying your code by using \c QT_MESSAGE_PATTERN environment | |
30 | * variable. If you need your application to ignore this environment variable you can call | |
31 | * ConsoleAppender::ignoreEnvironmentPattern(true) | |
32 | */ | |
33 | ||
34 | ||
35 | ConsoleAppender::ConsoleAppender() | |
36 | : AbstractStringAppender(), | |
37 | m_ignoreEnvPattern(false) | |
38 | { | |
39 | setFormat("[%{type:-7}] <%{function}> %{message}\n"); | |
40 | } | |
41 | ||
42 | ||
43 | QString ConsoleAppender::format() const | |
44 | { | |
45 | const QString envPattern = QString::fromLocal8Bit(qgetenv("QT_MESSAGE_PATTERN")); | |
46 | return (m_ignoreEnvPattern || envPattern.isEmpty()) ? AbstractStringAppender::format() : (envPattern + "\n"); | |
47 | } | |
48 | ||
49 | ||
50 | void ConsoleAppender::ignoreEnvironmentPattern(bool ignore) | |
51 | { | |
52 | m_ignoreEnvPattern = ignore; | |
53 | } | |
54 | ||
55 | ||
56 | //! Writes the log record to the std::cerr stream. | |
57 | /** | |
58 | * \sa AbstractStringAppender::format() | |
59 | */ | |
60 | void ConsoleAppender::append(const QDateTime& timeStamp, Logger::LogLevel logLevel, const char* file, int line, | |
61 | const char* function, const QString& category, const QString& message) | |
62 | { | |
63 | std::cerr << qPrintable(formattedString(timeStamp, logLevel, file, line, function, category, message)); | |
64 | } | |
65 | ||
66 | DUTIL_END_NAMESPACE |
0 | /* | |
1 | Copyright (c) 2010 Boris Moiseev (cyberbobs at gmail dot com) | |
2 | ||
3 | This program is free software: you can redistribute it and/or modify | |
4 | it under the terms of the GNU Lesser General Public License version 2.1 | |
5 | as published by the Free Software Foundation and appearing in the file | |
6 | LICENSE.LGPL included in the packaging of this file. | |
7 | ||
8 | This program is distributed in the hope that it will be useful, | |
9 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
11 | GNU Lesser General Public License for more details. | |
12 | */ | |
13 | #ifndef CONSOLEAPPENDER_H | |
14 | #define CONSOLEAPPENDER_H | |
15 | ||
16 | #include "CuteLogger_global.h" | |
17 | #include <AbstractStringAppender.h> | |
18 | ||
19 | DUTIL_BEGIN_NAMESPACE | |
20 | ||
21 | class CUTELOGGERSHARED_EXPORT ConsoleAppender : public AbstractStringAppender | |
22 | { | |
23 | public: | |
24 | ConsoleAppender(); | |
25 | virtual QString format() const; | |
26 | void ignoreEnvironmentPattern(bool ignore); | |
27 | ||
28 | protected: | |
29 | virtual void append(const QDateTime& timeStamp, Logger::LogLevel logLevel, const char* file, int line, | |
30 | const char* function, const QString& category, const QString& message); | |
31 | ||
32 | private: | |
33 | bool m_ignoreEnvPattern; | |
34 | }; | |
35 | ||
36 | DUTIL_END_NAMESPACE | |
37 | ||
38 | #endif // CONSOLEAPPENDER_H |
0 | #ifndef CUTELOGGER_GLOBAL_H | |
1 | #define CUTELOGGER_GLOBAL_H | |
2 | ||
3 | #include <QtCore/qglobal.h> | |
4 | ||
5 | #ifndef DTK_NAMESPACE | |
6 | # define DTK_NAMESPACE Dtk | |
7 | #endif | |
8 | ||
9 | #define DUTIL_NAMESPACE Util | |
10 | #define DTK_UTIL_NAMESPACE DTK_NAMESPACE::DUTIL_NAMESPACE | |
11 | ||
12 | #if !defined(DUTIL_NAMESPACE) | |
13 | # define DUTIL_BEGIN_NAMESPACE | |
14 | # define DUTIL_END_NAMESPACE | |
15 | # define DUTIL_USE_NAMESPACE | |
16 | #else | |
17 | # define DUTIL_BEGIN_NAMESPACE namespace DTK_NAMESPACE { namespace DUTIL_NAMESPACE { | |
18 | # define DUTIL_END_NAMESPACE }} | |
19 | # define DUTIL_USE_NAMESPACE using namespace DTK_UTIL_NAMESPACE; | |
20 | #endif | |
21 | ||
22 | #if defined(CUTELOGGER_LIBRARY) | |
23 | # define CUTELOGGERSHARED_EXPORT Q_DECL_EXPORT | |
24 | #else | |
25 | #if defined(Q_OS_WIN32) | |
26 | # define CUTELOGGERSHARED_EXPORT | |
27 | #else | |
28 | # define CUTELOGGERSHARED_EXPORT Q_DECL_IMPORT | |
29 | #endif | |
30 | #endif | |
31 | ||
32 | #endif // CUTELOGGER_GLOBAL_H |
0 | #include "CuteLogger_global.h" | |
1 | #include "RollingFileAppender.h" | |
2 | #include "Logger.h" | |
3 | #include "LogManager.h" | |
4 | #include "FileAppender.h" | |
5 | #include "ConsoleAppender.h" | |
6 | #include "AbstractStringAppender.h" | |
7 | #include "AbstractAppender.h" |
0 | /* | |
1 | Copyright (c) 2010 Boris Moiseev (cyberbobs at gmail dot com) | |
2 | ||
3 | This program is free software: you can redistribute it and/or modify | |
4 | it under the terms of the GNU Lesser General Public License version 2.1 | |
5 | as published by the Free Software Foundation and appearing in the file | |
6 | LICENSE.LGPL included in the packaging of this file. | |
7 | ||
8 | This program is distributed in the hope that it will be useful, | |
9 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
11 | GNU Lesser General Public License for more details. | |
12 | */ | |
13 | // Local | |
14 | #include "FileAppender.h" | |
15 | ||
16 | // STL | |
17 | #include <iostream> | |
18 | ||
19 | DUTIL_BEGIN_NAMESPACE | |
20 | ||
21 | /** | |
22 | * \class FileAppender | |
23 | * | |
24 | * \brief Simple appender that writes the log records to the plain text file. | |
25 | */ | |
26 | ||
27 | ||
28 | //! Constructs the new file appender assigned to file with the given name. | |
29 | FileAppender::FileAppender(const QString& fileName) | |
30 | { | |
31 | setFileName(fileName); | |
32 | } | |
33 | ||
34 | ||
35 | FileAppender::~FileAppender() | |
36 | { | |
37 | closeFile(); | |
38 | } | |
39 | ||
40 | ||
41 | //! Returns the name set by setFileName() or to the FileAppender constructor. | |
42 | /** | |
43 | * \sa setFileName() | |
44 | */ | |
45 | QString FileAppender::fileName() const | |
46 | { | |
47 | QMutexLocker locker(&m_logFileMutex); | |
48 | return m_logFile.fileName(); | |
49 | } | |
50 | ||
51 | ||
52 | //! Sets the name of the file. The name can have no path, a relative path, or an absolute path. | |
53 | /** | |
54 | * \sa fileName() | |
55 | */ | |
56 | void FileAppender::setFileName(const QString& s) | |
57 | { | |
58 | QMutexLocker locker(&m_logFileMutex); | |
59 | if (m_logFile.isOpen()) | |
60 | m_logFile.close(); | |
61 | ||
62 | m_logFile.setFileName(s); | |
63 | } | |
64 | ||
65 | ||
66 | bool FileAppender::openFile() | |
67 | { | |
68 | bool isOpen = m_logFile.isOpen(); | |
69 | if (!isOpen) | |
70 | { | |
71 | isOpen = m_logFile.open(QIODevice::WriteOnly | QIODevice::Append | QIODevice::Text); | |
72 | if (isOpen) | |
73 | m_logStream.setDevice(&m_logFile); | |
74 | else | |
75 | std::cerr << "<FileAppender::append> Cannot open the log file " << qPrintable(m_logFile.fileName()) << std::endl; | |
76 | } | |
77 | return isOpen; | |
78 | } | |
79 | ||
80 | ||
81 | //! Write the log record to the file. | |
82 | /** | |
83 | * \sa fileName() | |
84 | * \sa AbstractStringAppender::format() | |
85 | */ | |
86 | void FileAppender::append(const QDateTime& timeStamp, Logger::LogLevel logLevel, const char* file, int line, | |
87 | const char* function, const QString& category, const QString& message) | |
88 | { | |
89 | QMutexLocker locker(&m_logFileMutex); | |
90 | ||
91 | if (openFile()) | |
92 | { | |
93 | m_logStream << formattedString(timeStamp, logLevel, file, line, function, category, message); | |
94 | m_logStream.flush(); | |
95 | m_logFile.flush(); | |
96 | } | |
97 | } | |
98 | ||
99 | ||
100 | void FileAppender::closeFile() | |
101 | { | |
102 | QMutexLocker locker(&m_logFileMutex); | |
103 | m_logFile.close(); | |
104 | } | |
105 | ||
106 | DUTIL_END_NAMESPACE |
0 | /* | |
1 | Copyright (c) 2010 Boris Moiseev (cyberbobs at gmail dot com) | |
2 | ||
3 | This program is free software: you can redistribute it and/or modify | |
4 | it under the terms of the GNU Lesser General Public License version 2.1 | |
5 | as published by the Free Software Foundation and appearing in the file | |
6 | LICENSE.LGPL included in the packaging of this file. | |
7 | ||
8 | This program is distributed in the hope that it will be useful, | |
9 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
11 | GNU Lesser General Public License for more details. | |
12 | */ | |
13 | #ifndef FILEAPPENDER_H | |
14 | #define FILEAPPENDER_H | |
15 | ||
16 | // Logger | |
17 | #include "CuteLogger_global.h" | |
18 | #include <AbstractStringAppender.h> | |
19 | ||
20 | // Qt | |
21 | #include <QFile> | |
22 | #include <QTextStream> | |
23 | ||
24 | DUTIL_BEGIN_NAMESPACE | |
25 | ||
26 | class CUTELOGGERSHARED_EXPORT FileAppender : public AbstractStringAppender | |
27 | { | |
28 | public: | |
29 | FileAppender(const QString& fileName = QString()); | |
30 | ~FileAppender(); | |
31 | ||
32 | QString fileName() const; | |
33 | void setFileName(const QString&); | |
34 | ||
35 | protected: | |
36 | virtual void append(const QDateTime& timeStamp, Logger::LogLevel logLevel, const char* file, int line, | |
37 | const char* function, const QString& category, const QString& message); | |
38 | bool openFile(); | |
39 | void closeFile(); | |
40 | ||
41 | private: | |
42 | QFile m_logFile; | |
43 | QTextStream m_logStream; | |
44 | mutable QMutex m_logFileMutex; | |
45 | }; | |
46 | ||
47 | DUTIL_END_NAMESPACE | |
48 | ||
49 | #endif // FILEAPPENDER_H |
0 | GNU GENERAL PUBLIC LICENSE | |
1 | Version 3, 29 June 2007 | |
2 | ||
3 | Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/> | |
4 | Everyone is permitted to copy and distribute verbatim copies | |
5 | of this license document, but changing it is not allowed. | |
6 | ||
7 | Preamble | |
8 | ||
9 | The GNU General Public License is a free, copyleft license for | |
10 | software and other kinds of works. | |
11 | ||
12 | The licenses for most software and other practical works are designed | |
13 | to take away your freedom to share and change the works. By contrast, | |
14 | the GNU General Public License is intended to guarantee your freedom to | |
15 | share and change all versions of a program--to make sure it remains free | |
16 | software for all its users. We, the Free Software Foundation, use the | |
17 | GNU General Public License for most of our software; it applies also to | |
18 | any other work released this way by its authors. You can apply it to | |
19 | your programs, too. | |
20 | ||
21 | When we speak of free software, we are referring to freedom, not | |
22 | price. Our General Public Licenses are designed to make sure that you | |
23 | have the freedom to distribute copies of free software (and charge for | |
24 | them if you wish), that you receive source code or can get it if you | |
25 | want it, that you can change the software or use pieces of it in new | |
26 | free programs, and that you know you can do these things. | |
27 | ||
28 | To protect your rights, we need to prevent others from denying you | |
29 | these rights or asking you to surrender the rights. Therefore, you have | |
30 | certain responsibilities if you distribute copies of the software, or if | |
31 | you modify it: responsibilities to respect the freedom of others. | |
32 | ||
33 | For example, if you distribute copies of such a program, whether | |
34 | gratis or for a fee, you must pass on to the recipients the same | |
35 | freedoms that you received. You must make sure that they, too, receive | |
36 | or can get the source code. And you must show them these terms so they | |
37 | know their rights. | |
38 | ||
39 | Developers that use the GNU GPL protect your rights with two steps: | |
40 | (1) assert copyright on the software, and (2) offer you this License | |
41 | giving you legal permission to copy, distribute and/or modify it. | |
42 | ||
43 | For the developers' and authors' protection, the GPL clearly explains | |
44 | that there is no warranty for this free software. For both users' and | |
45 | authors' sake, the GPL requires that modified versions be marked as | |
46 | changed, so that their problems will not be attributed erroneously to | |
47 | authors of previous versions. | |
48 | ||
49 | Some devices are designed to deny users access to install or run | |
50 | modified versions of the software inside them, although the manufacturer | |
51 | can do so. This is fundamentally incompatible with the aim of | |
52 | protecting users' freedom to change the software. The systematic | |
53 | pattern of such abuse occurs in the area of products for individuals to | |
54 | use, which is precisely where it is most unacceptable. Therefore, we | |
55 | have designed this version of the GPL to prohibit the practice for those | |
56 | products. If such problems arise substantially in other domains, we | |
57 | stand ready to extend this provision to those domains in future versions | |
58 | of the GPL, as needed to protect the freedom of users. | |
59 | ||
60 | Finally, every program is threatened constantly by software patents. | |
61 | States should not allow patents to restrict development and use of | |
62 | software on general-purpose computers, but in those that do, we wish to | |
63 | avoid the special danger that patents applied to a free program could | |
64 | make it effectively proprietary. To prevent this, the GPL assures that | |
65 | patents cannot be used to render the program non-free. | |
66 | ||
67 | The precise terms and conditions for copying, distribution and | |
68 | modification follow. | |
69 | ||
70 | TERMS AND CONDITIONS | |
71 | ||
72 | 0. Definitions. | |
73 | ||
74 | "This License" refers to version 3 of the GNU General Public License. | |
75 | ||
76 | "Copyright" also means copyright-like laws that apply to other kinds of | |
77 | works, such as semiconductor masks. | |
78 | ||
79 | "The Program" refers to any copyrightable work licensed under this | |
80 | License. Each licensee is addressed as "you". "Licensees" and | |
81 | "recipients" may be individuals or organizations. | |
82 | ||
83 | To "modify" a work means to copy from or adapt all or part of the work | |
84 | in a fashion requiring copyright permission, other than the making of an | |
85 | exact copy. The resulting work is called a "modified version" of the | |
86 | earlier work or a work "based on" the earlier work. | |
87 | ||
88 | A "covered work" means either the unmodified Program or a work based | |
89 | on the Program. | |
90 | ||
91 | To "propagate" a work means to do anything with it that, without | |
92 | permission, would make you directly or secondarily liable for | |
93 | infringement under applicable copyright law, except executing it on a | |
94 | computer or modifying a private copy. Propagation includes copying, | |
95 | distribution (with or without modification), making available to the | |
96 | public, and in some countries other activities as well. | |
97 | ||
98 | To "convey" a work means any kind of propagation that enables other | |
99 | parties to make or receive copies. Mere interaction with a user through | |
100 | a computer network, with no transfer of a copy, is not conveying. | |
101 | ||
102 | An interactive user interface displays "Appropriate Legal Notices" | |
103 | to the extent that it includes a convenient and prominently visible | |
104 | feature that (1) displays an appropriate copyright notice, and (2) | |
105 | tells the user that there is no warranty for the work (except to the | |
106 | extent that warranties are provided), that licensees may convey the | |
107 | work under this License, and how to view a copy of this License. If | |
108 | the interface presents a list of user commands or options, such as a | |
109 | menu, a prominent item in the list meets this criterion. | |
110 | ||
111 | 1. Source Code. | |
112 | ||
113 | The "source code" for a work means the preferred form of the work | |
114 | for making modifications to it. "Object code" means any non-source | |
115 | form of a work. | |
116 | ||
117 | A "Standard Interface" means an interface that either is an official | |
118 | standard defined by a recognized standards body, or, in the case of | |
119 | interfaces specified for a particular programming language, one that | |
120 | is widely used among developers working in that language. | |
121 | ||
122 | The "System Libraries" of an executable work include anything, other | |
123 | than the work as a whole, that (a) is included in the normal form of | |
124 | packaging a Major Component, but which is not part of that Major | |
125 | Component, and (b) serves only to enable use of the work with that | |
126 | Major Component, or to implement a Standard Interface for which an | |
127 | implementation is available to the public in source code form. A | |
128 | "Major Component", in this context, means a major essential component | |
129 | (kernel, window system, and so on) of the specific operating system | |
130 | (if any) on which the executable work runs, or a compiler used to | |
131 | produce the work, or an object code interpreter used to run it. | |
132 | ||
133 | The "Corresponding Source" for a work in object code form means all | |
134 | the source code needed to generate, install, and (for an executable | |
135 | work) run the object code and to modify the work, including scripts to | |
136 | control those activities. However, it does not include the work's | |
137 | System Libraries, or general-purpose tools or generally available free | |
138 | programs which are used unmodified in performing those activities but | |
139 | which are not part of the work. For example, Corresponding Source | |
140 | includes interface definition files associated with source files for | |
141 | the work, and the source code for shared libraries and dynamically | |
142 | linked subprograms that the work is specifically designed to require, | |
143 | such as by intimate data communication or control flow between those | |
144 | subprograms and other parts of the work. | |
145 | ||
146 | The Corresponding Source need not include anything that users | |
147 | can regenerate automatically from other parts of the Corresponding | |
148 | Source. | |
149 | ||
150 | The Corresponding Source for a work in source code form is that | |
151 | same work. | |
152 | ||
153 | 2. Basic Permissions. | |
154 | ||
155 | All rights granted under this License are granted for the term of | |
156 | copyright on the Program, and are irrevocable provided the stated | |
157 | conditions are met. This License explicitly affirms your unlimited | |
158 | permission to run the unmodified Program. The output from running a | |
159 | covered work is covered by this License only if the output, given its | |
160 | content, constitutes a covered work. This License acknowledges your | |
161 | rights of fair use or other equivalent, as provided by copyright law. | |
162 | ||
163 | You may make, run and propagate covered works that you do not | |
164 | convey, without conditions so long as your license otherwise remains | |
165 | in force. You may convey covered works to others for the sole purpose | |
166 | of having them make modifications exclusively for you, or provide you | |
167 | with facilities for running those works, provided that you comply with | |
168 | the terms of this License in conveying all material for which you do | |
169 | not control copyright. Those thus making or running the covered works | |
170 | for you must do so exclusively on your behalf, under your direction | |
171 | and control, on terms that prohibit them from making any copies of | |
172 | your copyrighted material outside their relationship with you. | |
173 | ||
174 | Conveying under any other circumstances is permitted solely under | |
175 | the conditions stated below. Sublicensing is not allowed; section 10 | |
176 | makes it unnecessary. | |
177 | ||
178 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law. | |
179 | ||
180 | No covered work shall be deemed part of an effective technological | |
181 | measure under any applicable law fulfilling obligations under article | |
182 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or | |
183 | similar laws prohibiting or restricting circumvention of such | |
184 | measures. | |
185 | ||
186 | When you convey a covered work, you waive any legal power to forbid | |
187 | circumvention of technological measures to the extent such circumvention | |
188 | is effected by exercising rights under this License with respect to | |
189 | the covered work, and you disclaim any intention to limit operation or | |
190 | modification of the work as a means of enforcing, against the work's | |
191 | users, your or third parties' legal rights to forbid circumvention of | |
192 | technological measures. | |
193 | ||
194 | 4. Conveying Verbatim Copies. | |
195 | ||
196 | You may convey verbatim copies of the Program's source code as you | |
197 | receive it, in any medium, provided that you conspicuously and | |
198 | appropriately publish on each copy an appropriate copyright notice; | |
199 | keep intact all notices stating that this License and any | |
200 | non-permissive terms added in accord with section 7 apply to the code; | |
201 | keep intact all notices of the absence of any warranty; and give all | |
202 | recipients a copy of this License along with the Program. | |
203 | ||
204 | You may charge any price or no price for each copy that you convey, | |
205 | and you may offer support or warranty protection for a fee. | |
206 | ||
207 | 5. Conveying Modified Source Versions. | |
208 | ||
209 | You may convey a work based on the Program, or the modifications to | |
210 | produce it from the Program, in the form of source code under the | |
211 | terms of section 4, provided that you also meet all of these conditions: | |
212 | ||
213 | a) The work must carry prominent notices stating that you modified | |
214 | it, and giving a relevant date. | |
215 | ||
216 | b) The work must carry prominent notices stating that it is | |
217 | released under this License and any conditions added under section | |
218 | 7. This requirement modifies the requirement in section 4 to | |
219 | "keep intact all notices". | |
220 | ||
221 | c) You must license the entire work, as a whole, under this | |
222 | License to anyone who comes into possession of a copy. This | |
223 | License will therefore apply, along with any applicable section 7 | |
224 | additional terms, to the whole of the work, and all its parts, | |
225 | regardless of how they are packaged. This License gives no | |
226 | permission to license the work in any other way, but it does not | |
227 | invalidate such permission if you have separately received it. | |
228 | ||
229 | d) If the work has interactive user interfaces, each must display | |
230 | Appropriate Legal Notices; however, if the Program has interactive | |
231 | interfaces that do not display Appropriate Legal Notices, your | |
232 | work need not make them do so. | |
233 | ||
234 | A compilation of a covered work with other separate and independent | |
235 | works, which are not by their nature extensions of the covered work, | |
236 | and which are not combined with it such as to form a larger program, | |
237 | in or on a volume of a storage or distribution medium, is called an | |
238 | "aggregate" if the compilation and its resulting copyright are not | |
239 | used to limit the access or legal rights of the compilation's users | |
240 | beyond what the individual works permit. Inclusion of a covered work | |
241 | in an aggregate does not cause this License to apply to the other | |
242 | parts of the aggregate. | |
243 | ||
244 | 6. Conveying Non-Source Forms. | |
245 | ||
246 | You may convey a covered work in object code form under the terms | |
247 | of sections 4 and 5, provided that you also convey the | |
248 | machine-readable Corresponding Source under the terms of this License, | |
249 | in one of these ways: | |
250 | ||
251 | a) Convey the object code in, or embodied in, a physical product | |
252 | (including a physical distribution medium), accompanied by the | |
253 | Corresponding Source fixed on a durable physical medium | |
254 | customarily used for software interchange. | |
255 | ||
256 | b) Convey the object code in, or embodied in, a physical product | |
257 | (including a physical distribution medium), accompanied by a | |
258 | written offer, valid for at least three years and valid for as | |
259 | long as you offer spare parts or customer support for that product | |
260 | model, to give anyone who possesses the object code either (1) a | |
261 | copy of the Corresponding Source for all the software in the | |
262 | product that is covered by this License, on a durable physical | |
263 | medium customarily used for software interchange, for a price no | |
264 | more than your reasonable cost of physically performing this | |
265 | conveying of source, or (2) access to copy the | |
266 | Corresponding Source from a network server at no charge. | |
267 | ||
268 | c) Convey individual copies of the object code with a copy of the | |
269 | written offer to provide the Corresponding Source. This | |
270 | alternative is allowed only occasionally and noncommercially, and | |
271 | only if you received the object code with such an offer, in accord | |
272 | with subsection 6b. | |
273 | ||
274 | d) Convey the object code by offering access from a designated | |
275 | place (gratis or for a charge), and offer equivalent access to the | |
276 | Corresponding Source in the same way through the same place at no | |
277 | further charge. You need not require recipients to copy the | |
278 | Corresponding Source along with the object code. If the place to | |
279 | copy the object code is a network server, the Corresponding Source | |
280 | may be on a different server (operated by you or a third party) | |
281 | that supports equivalent copying facilities, provided you maintain | |
282 | clear directions next to the object code saying where to find the | |
283 | Corresponding Source. Regardless of what server hosts the | |
284 | Corresponding Source, you remain obligated to ensure that it is | |
285 | available for as long as needed to satisfy these requirements. | |
286 | ||
287 | e) Convey the object code using peer-to-peer transmission, provided | |
288 | you inform other peers where the object code and Corresponding | |
289 | Source of the work are being offered to the general public at no | |
290 | charge under subsection 6d. | |
291 | ||
292 | A separable portion of the object code, whose source code is excluded | |
293 | from the Corresponding Source as a System Library, need not be | |
294 | included in conveying the object code work. | |
295 | ||
296 | A "User Product" is either (1) a "consumer product", which means any | |
297 | tangible personal property which is normally used for personal, family, | |
298 | or household purposes, or (2) anything designed or sold for incorporation | |
299 | into a dwelling. In determining whether a product is a consumer product, | |
300 | doubtful cases shall be resolved in favor of coverage. For a particular | |
301 | product received by a particular user, "normally used" refers to a | |
302 | typical or common use of that class of product, regardless of the status | |
303 | of the particular user or of the way in which the particular user | |
304 | actually uses, or expects or is expected to use, the product. A product | |
305 | is a consumer product regardless of whether the product has substantial | |
306 | commercial, industrial or non-consumer uses, unless such uses represent | |
307 | the only significant mode of use of the product. | |
308 | ||
309 | "Installation Information" for a User Product means any methods, | |
310 | procedures, authorization keys, or other information required to install | |
311 | and execute modified versions of a covered work in that User Product from | |
312 | a modified version of its Corresponding Source. The information must | |
313 | suffice to ensure that the continued functioning of the modified object | |
314 | code is in no case prevented or interfered with solely because | |
315 | modification has been made. | |
316 | ||
317 | If you convey an object code work under this section in, or with, or | |
318 | specifically for use in, a User Product, and the conveying occurs as | |
319 | part of a transaction in which the right of possession and use of the | |
320 | User Product is transferred to the recipient in perpetuity or for a | |
321 | fixed term (regardless of how the transaction is characterized), the | |
322 | Corresponding Source conveyed under this section must be accompanied | |
323 | by the Installation Information. But this requirement does not apply | |
324 | if neither you nor any third party retains the ability to install | |
325 | modified object code on the User Product (for example, the work has | |
326 | been installed in ROM). | |
327 | ||
328 | The requirement to provide Installation Information does not include a | |
329 | requirement to continue to provide support service, warranty, or updates | |
330 | for a work that has been modified or installed by the recipient, or for | |
331 | the User Product in which it has been modified or installed. Access to a | |
332 | network may be denied when the modification itself materially and | |
333 | adversely affects the operation of the network or violates the rules and | |
334 | protocols for communication across the network. | |
335 | ||
336 | Corresponding Source conveyed, and Installation Information provided, | |
337 | in accord with this section must be in a format that is publicly | |
338 | documented (and with an implementation available to the public in | |
339 | source code form), and must require no special password or key for | |
340 | unpacking, reading or copying. | |
341 | ||
342 | 7. Additional Terms. | |
343 | ||
344 | "Additional permissions" are terms that supplement the terms of this | |
345 | License by making exceptions from one or more of its conditions. | |
346 | Additional permissions that are applicable to the entire Program shall | |
347 | be treated as though they were included in this License, to the extent | |
348 | that they are valid under applicable law. If additional permissions | |
349 | apply only to part of the Program, that part may be used separately | |
350 | under those permissions, but the entire Program remains governed by | |
351 | this License without regard to the additional permissions. | |
352 | ||
353 | When you convey a copy of a covered work, you may at your option | |
354 | remove any additional permissions from that copy, or from any part of | |
355 | it. (Additional permissions may be written to require their own | |
356 | removal in certain cases when you modify the work.) You may place | |
357 | additional permissions on material, added by you to a covered work, | |
358 | for which you have or can give appropriate copyright permission. | |
359 | ||
360 | Notwithstanding any other provision of this License, for material you | |
361 | add to a covered work, you may (if authorized by the copyright holders of | |
362 | that material) supplement the terms of this License with terms: | |
363 | ||
364 | a) Disclaiming warranty or limiting liability differently from the | |
365 | terms of sections 15 and 16 of this License; or | |
366 | ||
367 | b) Requiring preservation of specified reasonable legal notices or | |
368 | author attributions in that material or in the Appropriate Legal | |
369 | Notices displayed by works containing it; or | |
370 | ||
371 | c) Prohibiting misrepresentation of the origin of that material, or | |
372 | requiring that modified versions of such material be marked in | |
373 | reasonable ways as different from the original version; or | |
374 | ||
375 | d) Limiting the use for publicity purposes of names of licensors or | |
376 | authors of the material; or | |
377 | ||
378 | e) Declining to grant rights under trademark law for use of some | |
379 | trade names, trademarks, or service marks; or | |
380 | ||
381 | f) Requiring indemnification of licensors and authors of that | |
382 | material by anyone who conveys the material (or modified versions of | |
383 | it) with contractual assumptions of liability to the recipient, for | |
384 | any liability that these contractual assumptions directly impose on | |
385 | those licensors and authors. | |
386 | ||
387 | All other non-permissive additional terms are considered "further | |
388 | restrictions" within the meaning of section 10. If the Program as you | |
389 | received it, or any part of it, contains a notice stating that it is | |
390 | governed by this License along with a term that is a further | |
391 | restriction, you may remove that term. If a license document contains | |
392 | a further restriction but permits relicensing or conveying under this | |
393 | License, you may add to a covered work material governed by the terms | |
394 | of that license document, provided that the further restriction does | |
395 | not survive such relicensing or conveying. | |
396 | ||
397 | If you add terms to a covered work in accord with this section, you | |
398 | must place, in the relevant source files, a statement of the | |
399 | additional terms that apply to those files, or a notice indicating | |
400 | where to find the applicable terms. | |
401 | ||
402 | Additional terms, permissive or non-permissive, may be stated in the | |
403 | form of a separately written license, or stated as exceptions; | |
404 | the above requirements apply either way. | |
405 | ||
406 | 8. Termination. | |
407 | ||
408 | You may not propagate or modify a covered work except as expressly | |
409 | provided under this License. Any attempt otherwise to propagate or | |
410 | modify it is void, and will automatically terminate your rights under | |
411 | this License (including any patent licenses granted under the third | |
412 | paragraph of section 11). | |
413 | ||
414 | However, if you cease all violation of this License, then your | |
415 | license from a particular copyright holder is reinstated (a) | |
416 | provisionally, unless and until the copyright holder explicitly and | |
417 | finally terminates your license, and (b) permanently, if the copyright | |
418 | holder fails to notify you of the violation by some reasonable means | |
419 | prior to 60 days after the cessation. | |
420 | ||
421 | Moreover, your license from a particular copyright holder is | |
422 | reinstated permanently if the copyright holder notifies you of the | |
423 | violation by some reasonable means, this is the first time you have | |
424 | received notice of violation of this License (for any work) from that | |
425 | copyright holder, and you cure the violation prior to 30 days after | |
426 | your receipt of the notice. | |
427 | ||
428 | Termination of your rights under this section does not terminate the | |
429 | licenses of parties who have received copies or rights from you under | |
430 | this License. If your rights have been terminated and not permanently | |
431 | reinstated, you do not qualify to receive new licenses for the same | |
432 | material under section 10. | |
433 | ||
434 | 9. Acceptance Not Required for Having Copies. | |
435 | ||
436 | You are not required to accept this License in order to receive or | |
437 | run a copy of the Program. Ancillary propagation of a covered work | |
438 | occurring solely as a consequence of using peer-to-peer transmission | |
439 | to receive a copy likewise does not require acceptance. However, | |
440 | nothing other than this License grants you permission to propagate or | |
441 | modify any covered work. These actions infringe copyright if you do | |
442 | not accept this License. Therefore, by modifying or propagating a | |
443 | covered work, you indicate your acceptance of this License to do so. | |
444 | ||
445 | 10. Automatic Licensing of Downstream Recipients. | |
446 | ||
447 | Each time you convey a covered work, the recipient automatically | |
448 | receives a license from the original licensors, to run, modify and | |
449 | propagate that work, subject to this License. You are not responsible | |
450 | for enforcing compliance by third parties with this License. | |
451 | ||
452 | An "entity transaction" is a transaction transferring control of an | |
453 | organization, or substantially all assets of one, or subdividing an | |
454 | organization, or merging organizations. If propagation of a covered | |
455 | work results from an entity transaction, each party to that | |
456 | transaction who receives a copy of the work also receives whatever | |
457 | licenses to the work the party's predecessor in interest had or could | |
458 | give under the previous paragraph, plus a right to possession of the | |
459 | Corresponding Source of the work from the predecessor in interest, if | |
460 | the predecessor has it or can get it with reasonable efforts. | |
461 | ||
462 | You may not impose any further restrictions on the exercise of the | |
463 | rights granted or affirmed under this License. For example, you may | |
464 | not impose a license fee, royalty, or other charge for exercise of | |
465 | rights granted under this License, and you may not initiate litigation | |
466 | (including a cross-claim or counterclaim in a lawsuit) alleging that | |
467 | any patent claim is infringed by making, using, selling, offering for | |
468 | sale, or importing the Program or any portion of it. | |
469 | ||
470 | 11. Patents. | |
471 | ||
472 | A "contributor" is a copyright holder who authorizes use under this | |
473 | License of the Program or a work on which the Program is based. The | |
474 | work thus licensed is called the contributor's "contributor version". | |
475 | ||
476 | A contributor's "essential patent claims" are all patent claims | |
477 | owned or controlled by the contributor, whether already acquired or | |
478 | hereafter acquired, that would be infringed by some manner, permitted | |
479 | by this License, of making, using, or selling its contributor version, | |
480 | but do not include claims that would be infringed only as a | |
481 | consequence of further modification of the contributor version. For | |
482 | purposes of this definition, "control" includes the right to grant | |
483 | patent sublicenses in a manner consistent with the requirements of | |
484 | this License. | |
485 | ||
486 | Each contributor grants you a non-exclusive, worldwide, royalty-free | |
487 | patent license under the contributor's essential patent claims, to | |
488 | make, use, sell, offer for sale, import and otherwise run, modify and | |
489 | propagate the contents of its contributor version. | |
490 | ||
491 | In the following three paragraphs, a "patent license" is any express | |
492 | agreement or commitment, however denominated, not to enforce a patent | |
493 | (such as an express permission to practice a patent or covenant not to | |
494 | sue for patent infringement). To "grant" such a patent license to a | |
495 | party means to make such an agreement or commitment not to enforce a | |
496 | patent against the party. | |
497 | ||
498 | If you convey a covered work, knowingly relying on a patent license, | |
499 | and the Corresponding Source of the work is not available for anyone | |
500 | to copy, free of charge and under the terms of this License, through a | |
501 | publicly available network server or other readily accessible means, | |
502 | then you must either (1) cause the Corresponding Source to be so | |
503 | available, or (2) arrange to deprive yourself of the benefit of the | |
504 | patent license for this particular work, or (3) arrange, in a manner | |
505 | consistent with the requirements of this License, to extend the patent | |
506 | license to downstream recipients. "Knowingly relying" means you have | |
507 | actual knowledge that, but for the patent license, your conveying the | |
508 | covered work in a country, or your recipient's use of the covered work | |
509 | in a country, would infringe one or more identifiable patents in that | |
510 | country that you have reason to believe are valid. | |
511 | ||
512 | If, pursuant to or in connection with a single transaction or | |
513 | arrangement, you convey, or propagate by procuring conveyance of, a | |
514 | covered work, and grant a patent license to some of the parties | |
515 | receiving the covered work authorizing them to use, propagate, modify | |
516 | or convey a specific copy of the covered work, then the patent license | |
517 | you grant is automatically extended to all recipients of the covered | |
518 | work and works based on it. | |
519 | ||
520 | A patent license is "discriminatory" if it does not include within | |
521 | the scope of its coverage, prohibits the exercise of, or is | |
522 | conditioned on the non-exercise of one or more of the rights that are | |
523 | specifically granted under this License. You may not convey a covered | |
524 | work if you are a party to an arrangement with a third party that is | |
525 | in the business of distributing software, under which you make payment | |
526 | to the third party based on the extent of your activity of conveying | |
527 | the work, and under which the third party grants, to any of the | |
528 | parties who would receive the covered work from you, a discriminatory | |
529 | patent license (a) in connection with copies of the covered work | |
530 | conveyed by you (or copies made from those copies), or (b) primarily | |
531 | for and in connection with specific products or compilations that | |
532 | contain the covered work, unless you entered into that arrangement, | |
533 | or that patent license was granted, prior to 28 March 2007. | |
534 | ||
535 | Nothing in this License shall be construed as excluding or limiting | |
536 | any implied license or other defenses to infringement that may | |
537 | otherwise be available to you under applicable patent law. | |
538 | ||
539 | 12. No Surrender of Others' Freedom. | |
540 | ||
541 | If conditions are imposed on you (whether by court order, agreement or | |
542 | otherwise) that contradict the conditions of this License, they do not | |
543 | excuse you from the conditions of this License. If you cannot convey a | |
544 | covered work so as to satisfy simultaneously your obligations under this | |
545 | License and any other pertinent obligations, then as a consequence you may | |
546 | not convey it at all. For example, if you agree to terms that obligate you | |
547 | to collect a royalty for further conveying from those to whom you convey | |
548 | the Program, the only way you could satisfy both those terms and this | |
549 | License would be to refrain entirely from conveying the Program. | |
550 | ||
551 | 13. Use with the GNU Affero General Public License. | |
552 | ||
553 | Notwithstanding any other provision of this License, you have | |
554 | permission to link or combine any covered work with a work licensed | |
555 | under version 3 of the GNU Affero General Public License into a single | |
556 | combined work, and to convey the resulting work. The terms of this | |
557 | License will continue to apply to the part which is the covered work, | |
558 | but the special requirements of the GNU Affero General Public License, | |
559 | section 13, concerning interaction through a network will apply to the | |
560 | combination as such. | |
561 | ||
562 | 14. Revised Versions of this License. | |
563 | ||
564 | The Free Software Foundation may publish revised and/or new versions of | |
565 | the GNU General Public License from time to time. Such new versions will | |
566 | be similar in spirit to the present version, but may differ in detail to | |
567 | address new problems or concerns. | |
568 | ||
569 | Each version is given a distinguishing version number. If the | |
570 | Program specifies that a certain numbered version of the GNU General | |
571 | Public License "or any later version" applies to it, you have the | |
572 | option of following the terms and conditions either of that numbered | |
573 | version or of any later version published by the Free Software | |
574 | Foundation. If the Program does not specify a version number of the | |
575 | GNU General Public License, you may choose any version ever published | |
576 | by the Free Software Foundation. | |
577 | ||
578 | If the Program specifies that a proxy can decide which future | |
579 | versions of the GNU General Public License can be used, that proxy's | |
580 | public statement of acceptance of a version permanently authorizes you | |
581 | to choose that version for the Program. | |
582 | ||
583 | Later license versions may give you additional or different | |
584 | permissions. However, no additional obligations are imposed on any | |
585 | author or copyright holder as a result of your choosing to follow a | |
586 | later version. | |
587 | ||
588 | 15. Disclaimer of Warranty. | |
589 | ||
590 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY | |
591 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT | |
592 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY | |
593 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, | |
594 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |
595 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM | |
596 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF | |
597 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION. | |
598 | ||
599 | 16. Limitation of Liability. | |
600 | ||
601 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING | |
602 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS | |
603 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY | |
604 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE | |
605 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF | |
606 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD | |
607 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), | |
608 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF | |
609 | SUCH DAMAGES. | |
610 | ||
611 | 17. Interpretation of Sections 15 and 16. | |
612 | ||
613 | If the disclaimer of warranty and limitation of liability provided | |
614 | above cannot be given local legal effect according to their terms, | |
615 | reviewing courts shall apply local law that most closely approximates | |
616 | an absolute waiver of all civil liability in connection with the | |
617 | Program, unless a warranty or assumption of liability accompanies a | |
618 | copy of the Program in return for a fee. | |
619 | ||
620 | END OF TERMS AND CONDITIONS | |
621 | ||
622 | How to Apply These Terms to Your New Programs | |
623 | ||
624 | If you develop a new program, and you want it to be of the greatest | |
625 | possible use to the public, the best way to achieve this is to make it | |
626 | free software which everyone can redistribute and change under these terms. | |
627 | ||
628 | To do so, attach the following notices to the program. It is safest | |
629 | to attach them to the start of each source file to most effectively | |
630 | state the exclusion of warranty; and each file should have at least | |
631 | the "copyright" line and a pointer to where the full notice is found. | |
632 | ||
633 | {one line to give the program's name and a brief idea of what it does.} | |
634 | Copyright (C) {year} {name of author} | |
635 | ||
636 | This program is free software: you can redistribute it and/or modify | |
637 | it under the terms of the GNU General Public License as published by | |
638 | the Free Software Foundation, either version 3 of the License, or | |
639 | (at your option) any later version. | |
640 | ||
641 | This program is distributed in the hope that it will be useful, | |
642 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
643 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
644 | GNU General Public License for more details. | |
645 | ||
646 | You should have received a copy of the GNU General Public License | |
647 | along with this program. If not, see <http://www.gnu.org/licenses/>. | |
648 | ||
649 | Also add information on how to contact you by electronic and paper mail. | |
650 | ||
651 | If the program does terminal interaction, make it output a short | |
652 | notice like this when it starts in an interactive mode: | |
653 | ||
654 | {project} Copyright (C) {year} {fullname} | |
655 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. | |
656 | This is free software, and you are welcome to redistribute it | |
657 | under certain conditions; type `show c' for details. | |
658 | ||
659 | The hypothetical commands `show w' and `show c' should show the appropriate | |
660 | parts of the General Public License. Of course, your program's commands | |
661 | might be different; for a GUI interface, you would use an "about box". | |
662 | ||
663 | You should also get your employer (if you work as a programmer) or school, | |
664 | if any, to sign a "copyright disclaimer" for the program, if necessary. | |
665 | For more information on this, and how to apply and follow the GNU GPL, see | |
666 | <http://www.gnu.org/licenses/>. | |
667 | ||
668 | The GNU General Public License does not permit incorporating your program | |
669 | into proprietary programs. If your program is a subroutine library, you | |
670 | may consider it more useful to permit linking proprietary applications with | |
671 | the library. If this is what you want to do, use the GNU Lesser General | |
672 | Public License instead of this License. But first, please read | |
673 | <http://www.gnu.org/philosophy/why-not-lgpl.html>. |
0 | #include "LogManager.h" | |
1 | #include <Logger.h> | |
2 | #include <ConsoleAppender.h> | |
3 | #include <RollingFileAppender.h> | |
4 | ||
5 | DUTIL_BEGIN_NAMESPACE | |
6 | ||
7 | /** | |
8 | * \class DLogManager | |
9 | * | |
10 | * \brief DLogManager is the deepin user application log manager | |
11 | */ | |
12 | ||
13 | DLogManager::DLogManager() | |
14 | { | |
15 | QString cachePath = QStandardPaths::standardLocations(QStandardPaths::CacheLocation).at(0); | |
16 | if (!QDir(cachePath).exists()){ | |
17 | QDir(cachePath).mkpath(cachePath); | |
18 | } | |
19 | m_logPath = joinPath(cachePath, QString("%1.log").arg(qApp->applicationName())); | |
20 | m_format = "%{time}{yyyy-MM-dd, HH:mm:ss.zzz} [%{type:-7}] [%{file:-20} %{function:-35} %{line}] %{message}\n"; | |
21 | } | |
22 | ||
23 | void DLogManager::initConsoleAppender(){ | |
24 | m_consoleAppender = new ConsoleAppender; | |
25 | m_consoleAppender->setFormat(m_format); | |
26 | logger->registerAppender(m_consoleAppender); | |
27 | } | |
28 | ||
29 | void DLogManager::initRollingFileAppender(){ | |
30 | m_rollingFileAppender = new RollingFileAppender(m_logPath); | |
31 | m_rollingFileAppender->setFormat(m_format); | |
32 | m_rollingFileAppender->setLogFilesLimit(5); | |
33 | m_rollingFileAppender->setDatePattern(RollingFileAppender::DailyRollover); | |
34 | logger->registerAppender(m_rollingFileAppender); | |
35 | } | |
36 | ||
37 | //! Registers the appender to write the log records to the Console | |
38 | /** | |
39 | * \sa registerFileAppender | |
40 | */ | |
41 | void DLogManager::registerConsoleAppender(){ | |
42 | DLogManager::instance()->initConsoleAppender(); | |
43 | } | |
44 | ||
45 | //! Registers the appender to write the log records to the file | |
46 | /** | |
47 | * \sa getlogFilePath | |
48 | * \sa registerConsoleAppender | |
49 | */ | |
50 | void DLogManager::registerFileAppender() { | |
51 | DLogManager::instance()->initRollingFileAppender(); | |
52 | } | |
53 | ||
54 | //! Return the path file log storage | |
55 | /** | |
56 | * \sa registerFileAppender | |
57 | */ | |
58 | QString DLogManager::getlogFilePath(){ | |
59 | return DLogManager::instance()->m_logPath; | |
60 | } | |
61 | ||
62 | QString DLogManager::joinPath(const QString &path, const QString &fileName){ | |
63 | QString separator(QDir::separator()); | |
64 | return QString("%1%2%3").arg(path, separator, fileName); | |
65 | } | |
66 | ||
67 | DLogManager::~DLogManager() | |
68 | { | |
69 | ||
70 | } | |
71 | ||
72 | DUTIL_END_NAMESPACE |
0 | #ifndef LOGMANAGER_H | |
1 | #define LOGMANAGER_H | |
2 | ||
3 | #include <QtCore> | |
4 | ||
5 | #include "CuteLogger_global.h" | |
6 | ||
7 | DUTIL_BEGIN_NAMESPACE | |
8 | ||
9 | class ConsoleAppender; | |
10 | class RollingFileAppender; | |
11 | ||
12 | class DLogManager | |
13 | { | |
14 | public: | |
15 | static void registerConsoleAppender(); | |
16 | static void registerFileAppender(); | |
17 | static QString getlogFilePath(); | |
18 | ||
19 | signals: | |
20 | ||
21 | public slots: | |
22 | ||
23 | private: | |
24 | QString m_format; | |
25 | QString m_logPath; | |
26 | ConsoleAppender* m_consoleAppender; | |
27 | RollingFileAppender* m_rollingFileAppender; | |
28 | ||
29 | void initConsoleAppender(); | |
30 | void initRollingFileAppender(); | |
31 | QString joinPath(const QString& path, const QString& fileName); | |
32 | ||
33 | inline static DLogManager* instance(){ | |
34 | static DLogManager instance; | |
35 | return &instance; | |
36 | } | |
37 | explicit DLogManager(); | |
38 | ~DLogManager(); | |
39 | DLogManager(const DLogManager &); | |
40 | DLogManager & operator = (const DLogManager &); | |
41 | }; | |
42 | ||
43 | DUTIL_END_NAMESPACE | |
44 | ||
45 | #endif // LOGMANAGER_H |
0 | /* | |
1 | Copyright (c) 2012 Boris Moiseev (cyberbobs at gmail dot com) | |
2 | ||
3 | This program is free software: you can redistribute it and/or modify | |
4 | it under the terms of the GNU Lesser General Public License version 2.1 | |
5 | as published by the Free Software Foundation and appearing in the file | |
6 | LICENSE.LGPL included in the packaging of this file. | |
7 | ||
8 | This program is distributed in the hope that it will be useful, | |
9 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
11 | GNU Lesser General Public License for more details. | |
12 | */ | |
13 | // Local | |
14 | #include "Logger.h" | |
15 | #include "AbstractAppender.h" | |
16 | #include "AbstractStringAppender.h" | |
17 | ||
18 | // Qt | |
19 | #include <QCoreApplication> | |
20 | #include <QReadWriteLock> | |
21 | #include <QSemaphore> | |
22 | #include <QDateTime> | |
23 | #include <QIODevice> | |
24 | #include <QTextCodec> | |
25 | ||
26 | #if defined(Q_OS_ANDROID) | |
27 | # include <android/log.h> | |
28 | # include <AndroidAppender.h> | |
29 | #endif | |
30 | ||
31 | // STL | |
32 | #include <iostream> | |
33 | ||
34 | DUTIL_BEGIN_NAMESPACE | |
35 | ||
36 | /** | |
37 | * \file Logger.h | |
38 | * \brief A file containing the description of Logger class and and additional useful macros for logging | |
39 | */ | |
40 | ||
41 | ||
42 | /** | |
43 | * \mainpage | |
44 | * | |
45 | * Logger is a simple way to write the history of your application lifecycle to any target logging device (which is | |
46 | * called Appender and may write to any target you will implement with it: console, text file, XML or something - you | |
47 | * choose) and to map logging message to a class, function, source file and line of code which it is called from. | |
48 | * | |
49 | * Some simple appenders (which may be considered an examples) are provided with the Logger itself: see ConsoleAppender | |
50 | * and FileAppender documentation. | |
51 | * | |
52 | * It supports using it in a multithreaded applications, so all of its functions are thread safe. | |
53 | * | |
54 | * Simple usage example: | |
55 | * \code | |
56 | * #include <QCoreApplication> | |
57 | * | |
58 | * #include <DLog> | |
59 | * | |
60 | * using namespace Dtk::Log; | |
61 | * | |
62 | * int main(int argc, char* argv[]) | |
63 | * { | |
64 | * QCoreApplication app(argc, argv); | |
65 | * | |
66 | * // 1 you can use standrd deepin application log format | |
67 | * // 1.1 log to console | |
68 | * DLogManager::registerConsoleAppender(); | |
69 | * | |
70 | * // 1.2 log to standrd deepin user cache path: ~/.cache/{organ}/{appname}/ | |
71 | * // app.setOrganizationName("dtk-test"); // must set | |
72 | * // app.setApplicationName("dlog-example"); // must set | |
73 | * // dInfo()<< "LogFile:" << DLogManager::getlogFilePath(); | |
74 | * // DLogManager::registerFileAppender(); | |
75 | * | |
76 | * // 1.3 log to stdout and file | |
77 | * // DLogManager::registerFileAppender(); | |
78 | * // DLogManager::registerConsoleAppender(); | |
79 | * | |
80 | * // 2 Register your own logger format; | |
81 | * // ConsoleAppender* consoleAppender = new ConsoleAppender; | |
82 | * // consoleAppender->setFormat("[%{type:-7}] <%{Function}> %{message}\n"); | |
83 | * // logger->registerAppender(consoleAppender); | |
84 | * | |
85 | * dInfo("Starting the application"); | |
86 | * int result = 1; | |
87 | * dWarning() << "Something went wrong." << "Result code is" << result; | |
88 | * return result; | |
89 | * } | |
90 | * \endcode | |
91 | * | |
92 | * Logger internally uses the lazy-initialized singleton object and needs no definite initialization, but you may | |
93 | * consider registering a log appender before calling any log recording functions or macros. | |
94 | * | |
95 | * The library design of Logger allows you to simply mass-replace all occurrences of qDebug and similar calls with | |
96 | * similar Logger macros (e.g. dDebug()) | |
97 | * | |
98 | * \note Logger uses a singleton global instance which lives through all the application life cycle and self-destroys | |
99 | * destruction of the QCoreApplication (or QApplication) instance. It needs a QCoreApplication instance to be | |
100 | * created before any of the Logger's functions are called. | |
101 | * | |
102 | * \sa logger | |
103 | * \sa dTrace, dDebug, dInfo, dWarning, dError, dFatal | |
104 | * \sa dCTrace, dCDebug, dCInfo, dCWarning, dCError, dCFatal | |
105 | * \sa dAssert | |
106 | * \sa dTraceTime, dDebugTime, dInfoTime | |
107 | * \sa AbstractAppender | |
108 | */ | |
109 | ||
110 | ||
111 | /** | |
112 | * \def logger | |
113 | * | |
114 | * \brief Macro returning the current instance of Logger object | |
115 | * | |
116 | * If you haven't created a local Logger object it returns the same value as the Logger::globalInstance() functions. | |
117 | * This macro is a recommended way to get an access to the Logger instance used in current class. | |
118 | * | |
119 | * Example: | |
120 | * \code | |
121 | * ConsoleAppender* consoleAppender = new ConsoleAppender; | |
122 | * logger->registerAppender(consoleAppender); | |
123 | * \endcode | |
124 | * | |
125 | * \sa Dtk::Logger::globalInstance() | |
126 | */ | |
127 | ||
128 | ||
129 | /** | |
130 | * \def dTrace | |
131 | * | |
132 | * \brief Writes the trace log record | |
133 | * | |
134 | * This macro is the convinient way to call Logger::write(). It uses the common preprocessor macros \c __FILE__, | |
135 | * \c __LINE__ and the standart Qt \c Q_FUNC_INFO macros to automatically determine the needed parameters to call | |
136 | * Logger::write(). | |
137 | * | |
138 | * \note This and other (dInfo() etc...) macros uses the variadic macro arguments to give convinient usage form for | |
139 | * the different versions of Logger::write() (using the QString or const char* argument or returning the QDebug class | |
140 | * instance). Not all compilers will support this. Please, consider reviewing your compiler documentation to ensure | |
141 | * it support __VA_ARGS__ macro. | |
142 | * | |
143 | * \sa Dtk::Logger::LogLevel | |
144 | * \sa Dtk::Logger::write() | |
145 | */ | |
146 | ||
147 | ||
148 | /** | |
149 | * \def dDebug | |
150 | * | |
151 | * \brief Writes the debug log record | |
152 | * | |
153 | * This macro records the debug log record using the Logger::write() function. It works similar to the dTrace() | |
154 | * macro. | |
155 | * | |
156 | * \sa dTrace() | |
157 | * \sa Dtk::Logger::LogLevel | |
158 | * \sa Dtk::Logger::write() | |
159 | */ | |
160 | ||
161 | ||
162 | /** | |
163 | * \def dInfo | |
164 | * | |
165 | * \brief Writes the info log record | |
166 | * | |
167 | * This macro records the info log record using the Logger::write() function. It works similar to the dTrace() | |
168 | * macro. | |
169 | * | |
170 | * \sa dTrace() | |
171 | * \sa Dtk::Logger::LogLevel | |
172 | * \sa Dtk::Logger::write() | |
173 | */ | |
174 | ||
175 | ||
176 | /** | |
177 | * \def dWarning | |
178 | * | |
179 | * \brief Write the warning log record | |
180 | * | |
181 | * This macro records the warning log record using the Logger::write() function. It works similar to the dTrace() | |
182 | * macro. | |
183 | * | |
184 | * \sa dTrace() | |
185 | * \sa Dtk::Logger::LogLevel | |
186 | * \sa Dtk::Logger::write() | |
187 | */ | |
188 | ||
189 | ||
190 | /** | |
191 | * \def dError | |
192 | * | |
193 | * \brief Write the error log record | |
194 | * This macro records the error log record using the Logger::write() function. It works similar to the dTrace() | |
195 | * macro. | |
196 | * | |
197 | * \sa dTrace() | |
198 | * \sa Dtk::Logger::LogLevel | |
199 | * \sa Dtk::Logger::write() | |
200 | */ | |
201 | ||
202 | ||
203 | /** | |
204 | * \def dFatal | |
205 | * | |
206 | * \brief Write the fatal log record | |
207 | * | |
208 | * This macro records the fatal log record using the Logger::write() function. It works similar to the dTrace() | |
209 | * macro. | |
210 | * | |
211 | * \note Recording of the log record using the Logger::Fatal log level will lead to calling the STL abort() | |
212 | * function, which will interrupt the running of your software and begin the writing of the core dump. | |
213 | * | |
214 | * \sa dTrace() | |
215 | * \sa Dtk::Logger::LogLevel | |
216 | * \sa Dtk::Logger::write() | |
217 | */ | |
218 | ||
219 | ||
220 | /** | |
221 | * \def dCTrace(category) | |
222 | * | |
223 | * \brief Writes the trace log record to the specific category | |
224 | * | |
225 | * This macro is the similar to the dTrace() macro, but has a category parameter | |
226 | * to write only to the category appenders (registered using Logger::registerCategoryAppender() method). | |
227 | * | |
228 | * \param category category name string | |
229 | * | |
230 | * \sa dTrace() | |
231 | * \sa Dtk::Logger::LogLevel | |
232 | * \sa Dtk::Logger::registerCategoryAppender() | |
233 | * \sa Dtk::Logger::write() | |
234 | * \sa dCategory(), dGlobalCategory() | |
235 | */ | |
236 | ||
237 | ||
238 | /** | |
239 | * \def dCDebug | |
240 | * | |
241 | * \brief Writes the debug log record to the specific category | |
242 | * | |
243 | * This macro records the debug log record using the Logger::write() function. It works similar to the dCTrace() | |
244 | * macro. | |
245 | * | |
246 | * \sa dCTrace() | |
247 | */ | |
248 | ||
249 | ||
250 | /** | |
251 | * \def dCInfo | |
252 | * | |
253 | * \brief Writes the info log record to the specific category | |
254 | * | |
255 | * This macro records the info log record using the Logger::write() function. It works similar to the dCTrace() | |
256 | * macro. | |
257 | * | |
258 | * \sa dCTrace() | |
259 | */ | |
260 | ||
261 | ||
262 | /** | |
263 | * \def dCWarning | |
264 | * | |
265 | * \brief Writes the warning log record to the specific category | |
266 | * | |
267 | * This macro records the warning log record using the Logger::write() function. It works similar to the dCTrace() | |
268 | * macro. | |
269 | * | |
270 | * \sa dCTrace() | |
271 | */ | |
272 | ||
273 | ||
274 | /** | |
275 | * \def dCError | |
276 | * | |
277 | * \brief Writes the error log record to the specific category | |
278 | * | |
279 | * This macro records the error log record using the Logger::write() function. It works similar to the dCTrace() | |
280 | * macro. | |
281 | * | |
282 | * \sa dCTrace() | |
283 | */ | |
284 | ||
285 | ||
286 | /** | |
287 | * \def dCFatal | |
288 | * | |
289 | * \brief Write the fatal log record to the specific category | |
290 | * | |
291 | * This macro records the fatal log record using the Logger::write() function. It works similar to the dCTrace() | |
292 | * macro. | |
293 | * | |
294 | * \note Recording of the log record using the Logger::Fatal log level will lead to calling the STL abort() | |
295 | * function, which will interrupt the running of your software and begin the writing of the core dump. | |
296 | * | |
297 | * \sa dCTrace() | |
298 | */ | |
299 | ||
300 | ||
301 | /** | |
302 | * \def dCategory(category) | |
303 | * | |
304 | * \brief Create logger instance inside your custom class to log all messages to the specified category | |
305 | * | |
306 | * This macro is used to pass all log messages inside your custom class to the specific category. | |
307 | * You must include this macro inside your class declaration (similarly to the Q_OBJECT macro). | |
308 | * Internally, this macro redefines loggerInstance() function, creates the local Logger object inside your class and | |
309 | * sets the default category to the specified parameter. | |
310 | * | |
311 | * Thus, any call to loggerInstance() (for example, inside dTrace() macro) will return the local Logger object, | |
312 | * so any logging message will be directed to the default category. | |
313 | * | |
314 | * \note This macro does not register any appender to the newly created logger instance. You should register | |
315 | * logger appenders manually, inside your class. | |
316 | * | |
317 | * Usage example: | |
318 | * \code | |
319 | * class CustomClass : public QObject | |
320 | * { | |
321 | * Q_OBJECT | |
322 | * dCategory("custom_category") | |
323 | * ... | |
324 | * }; | |
325 | * | |
326 | * CustomClass::CustomClass(QObject* parent) : QObject(parent) | |
327 | * { | |
328 | * logger->registerAppender(new FileAppender("custom_category_log")); | |
329 | * dTrace() << "Trace to the custom category log"; | |
330 | * } | |
331 | * \endcode | |
332 | * | |
333 | * \sa Dtk::Logger::write() | |
334 | * \sa dTrace | |
335 | * \sa Dtk::Logger::registerCategoryAppender() | |
336 | * \sa Dtk::Logger::setDefaultCategory() | |
337 | * \sa dGlobalCategory | |
338 | */ | |
339 | ||
340 | ||
341 | /** | |
342 | * \def dGlobalCategory(category) | |
343 | * | |
344 | * \brief Create logger instance inside your custom class to log all messages both to the specified category and to | |
345 | * the global logger instance. | |
346 | * | |
347 | * This macro is similar to dCategory(), but also passes all log messages to the global logger instance appenders. | |
348 | * It is equal to defining the local category logger using dCategory macro and calling: | |
349 | * \code logger->logToGlobalInstance(logger->defaultCategory(), true); \endcode | |
350 | * | |
351 | * \sa dCategory | |
352 | * \sa Dtk::Logger::logToGlobalInstance() | |
353 | * \sa Dtk::Logger::defaultCategory() | |
354 | * \sa Dtk::Logger::registerCategoryAppender() | |
355 | * \sa Dtk::Logger::write() | |
356 | */ | |
357 | ||
358 | ||
359 | ||
360 | /** | |
361 | * \def dAssert | |
362 | * | |
363 | * \brief Check the assertion | |
364 | * | |
365 | * This macro is a convinient and recommended to use way to call Logger::writeAssert() function. It uses the | |
366 | * preprocessor macros (as the dDebug() does) to fill the necessary arguments of the Logger::writeAssert() call. It | |
367 | * also uses undocumented but rather mature and stable \c qt_noop() function (which does nothing) when the assertion | |
368 | * is true. | |
369 | * | |
370 | * Example: | |
371 | * \code | |
372 | * bool b = checkSomething(); | |
373 | * ... | |
374 | * dAssert(b == true); | |
375 | * \endcode | |
376 | * | |
377 | * \sa Dtk::Logger::writeAssert() | |
378 | */ | |
379 | ||
380 | ||
381 | /** | |
382 | * \def dTraceTime | |
383 | * | |
384 | * \brief Logs the processing time of current function / code block | |
385 | * | |
386 | * This macro automagically measures the function or code of block execution time and outputs it as a Logger::Trace | |
387 | * level log record. | |
388 | * | |
389 | * Example: | |
390 | * \code | |
391 | * int foo() | |
392 | * { | |
393 | * dTraceTime(); | |
394 | * ... // Do some long operations | |
395 | * return 0; | |
396 | * } // Outputs: Function foo finished in <time> ms. | |
397 | * \endcode | |
398 | * | |
399 | * If you are measuring a code of block execution time you may also add a name of block to the macro: | |
400 | * \code | |
401 | * int bar(bool doFoo) | |
402 | * { | |
403 | * dTraceTime(); | |
404 | * | |
405 | * if (doFoo) | |
406 | * { | |
407 | * dTraceTime("Foo"); | |
408 | * ... | |
409 | * } | |
410 | * | |
411 | * ... | |
412 | * } | |
413 | * // Outputs: | |
414 | * // "Foo" finished in <time1> ms. | |
415 | * // Function bar finished in <time2> ms. | |
416 | * \endcode | |
417 | * | |
418 | * \note Macro switches to logging the seconds instead of milliseconds when the execution time reaches 10000 ms. | |
419 | * \sa dDebugTime, dInfoTime | |
420 | */ | |
421 | ||
422 | ||
423 | /** | |
424 | * \def dDebugTime | |
425 | * | |
426 | * \brief Logs the processing time of current function / code block | |
427 | * | |
428 | * This macro automagically measures the function or code of block execution time and outputs it as a Logger::Debug | |
429 | * level log record. It works similar to dTraceTime() macro. | |
430 | * | |
431 | * \sa dTraceTime | |
432 | */ | |
433 | ||
434 | ||
435 | /** | |
436 | * \def dInfoTime | |
437 | * | |
438 | * \brief Logs the processing time of current function / code block | |
439 | * | |
440 | * This macro automagically measures the function or code of block execution time and outputs it as a Logger::Info | |
441 | * level log record. It works similar to dTraceTime() macro. | |
442 | * | |
443 | * \sa dTraceTime | |
444 | */ | |
445 | ||
446 | ||
447 | /** | |
448 | * \class Logger | |
449 | * | |
450 | * \brief Very simple but rather powerful component which may be used for logging your application activities. | |
451 | * | |
452 | * Global logger instance created on a first access to it (e.g. registering appenders, calling a dDebug() macro | |
453 | * etc.) registers itself as a Qt default message handler and captures all the qDebug/dWarning/qCritical output. | |
454 | * | |
455 | * \note Qt 4 qDebug set of macro doesn't support capturing source function name, file name or line number so we | |
456 | * recommend to use dDebug() and other Logger macros instead. | |
457 | * | |
458 | * \sa logger | |
459 | * \sa [DLogger Documentation](index.html) | |
460 | */ | |
461 | ||
462 | class LogDevice : public QIODevice | |
463 | { | |
464 | public: | |
465 | LogDevice(Logger* l) | |
466 | : m_logger(l), | |
467 | m_semaphore(1) | |
468 | {} | |
469 | ||
470 | void lock(Logger::LogLevel logLevel, const char* file, int line, const char* function, const char* category) | |
471 | { | |
472 | m_semaphore.acquire(); | |
473 | ||
474 | if (!isOpen()) | |
475 | open(QIODevice::WriteOnly); | |
476 | ||
477 | m_logLevel = logLevel; | |
478 | m_file = file; | |
479 | m_line = line; | |
480 | m_function = function; | |
481 | m_category = category; | |
482 | } | |
483 | ||
484 | protected: | |
485 | qint64 readData(char*, qint64) | |
486 | { | |
487 | return 0; | |
488 | } | |
489 | ||
490 | qint64 writeData(const char* data, qint64 maxSize) | |
491 | { | |
492 | if (maxSize > 0) | |
493 | m_logger->write(m_logLevel, m_file, m_line, m_function, m_category, QString::fromLocal8Bit(QByteArray(data, maxSize))); | |
494 | ||
495 | m_semaphore.release(); | |
496 | return maxSize; | |
497 | } | |
498 | ||
499 | private: | |
500 | Logger* m_logger; | |
501 | QSemaphore m_semaphore; | |
502 | Logger::LogLevel m_logLevel; | |
503 | const char* m_file; | |
504 | int m_line; | |
505 | const char* m_function; | |
506 | const char* m_category; | |
507 | }; | |
508 | ||
509 | ||
510 | // Forward declarations | |
511 | static void cleanupLoggerGlobalInstance(); | |
512 | ||
513 | #if QT_VERSION >= 0x050000 | |
514 | static void qtLoggerMessageHandler(QtMsgType, const QMessageLogContext& context, const QString& msg); | |
515 | #else | |
516 | static void qtLoggerMessageHandler(QtMsgType type, const char* msg); | |
517 | #endif | |
518 | ||
519 | /** | |
520 | * \internal | |
521 | * | |
522 | * LoggerPrivate class implements the Singleton pattern in a thread-safe way. It contains a static pointer to the | |
523 | * global logger instance protected by QReadWriteLock | |
524 | */ | |
525 | class LoggerPrivate | |
526 | { | |
527 | public: | |
528 | static Logger* globalInstance; | |
529 | static QReadWriteLock globalInstanceLock; | |
530 | ||
531 | QList<AbstractAppender*> appenders; | |
532 | QMutex loggerMutex; | |
533 | ||
534 | QMap<QString, bool> categories; | |
535 | QMultiMap<QString, AbstractAppender*> categoryAppenders; | |
536 | QString defaultCategory; | |
537 | ||
538 | LogDevice* logDevice; | |
539 | }; | |
540 | ||
541 | ||
542 | // Static fields initialization | |
543 | Logger* LoggerPrivate::globalInstance = 0; | |
544 | QReadWriteLock LoggerPrivate::globalInstanceLock; | |
545 | ||
546 | ||
547 | static void cleanupLoggerGlobalInstance() | |
548 | { | |
549 | QWriteLocker locker(&LoggerPrivate::globalInstanceLock); | |
550 | ||
551 | delete LoggerPrivate::globalInstance; | |
552 | LoggerPrivate::globalInstance = 0; | |
553 | } | |
554 | ||
555 | ||
556 | #if QT_VERSION >= 0x050000 | |
557 | static void qtLoggerMessageHandler(QtMsgType type, const QMessageLogContext& context, const QString& msg) | |
558 | { | |
559 | Logger::LogLevel level; | |
560 | switch (type) | |
561 | { | |
562 | case QtDebugMsg: | |
563 | level = Logger::Debug; | |
564 | break; | |
565 | case QtInfoMsg: | |
566 | level = Logger::Info; | |
567 | break; | |
568 | case QtWarningMsg: | |
569 | level = Logger::Warning; | |
570 | break; | |
571 | case QtCriticalMsg: | |
572 | level = Logger::Error; | |
573 | break; | |
574 | case QtFatalMsg: | |
575 | level = Logger::Fatal; | |
576 | break; | |
577 | default: | |
578 | level = Logger::Warning; | |
579 | break; | |
580 | } | |
581 | ||
582 | bool isDefaultCategory = QString::fromLatin1(context.category) == "default"; | |
583 | Logger::globalInstance()->write(level, context.file, context.line, context.function, isDefaultCategory ? 0 : context.category, msg); | |
584 | } | |
585 | ||
586 | #else | |
587 | ||
588 | static void qtLoggerMessageHandler(QtMsgType type, const char* msg) | |
589 | { | |
590 | switch (type) | |
591 | { | |
592 | case QtDebugMsg: | |
593 | loggerInstance()->write(Logger::Debug, "", 0, "qDebug", 0, msg); | |
594 | break; | |
595 | case QtWarningMsg: | |
596 | loggerInstance()->write(Logger::Warning, "", 0, "qDebug", 0, msg); | |
597 | break; | |
598 | case QtCriticalMsg: | |
599 | loggerInstance()->write(Logger::Error, "", 0, "qDebug", 0, msg); | |
600 | break; | |
601 | case QtFatalMsg: | |
602 | loggerInstance()->write(Logger::Fatal, "", 0, "qDebug", 0, msg); | |
603 | break; | |
604 | } | |
605 | } | |
606 | #endif | |
607 | ||
608 | ||
609 | //! Construct the instance of Logger | |
610 | /** | |
611 | * If you're only using one global instance of logger you wouldn't probably need to use this constructor manually. | |
612 | * Consider using [logger](@ref logger) macro instead to access the logger instance | |
613 | */ | |
614 | Logger::Logger() | |
615 | : d_ptr(new LoggerPrivate) | |
616 | { | |
617 | Q_D(Logger); | |
618 | ||
619 | d->logDevice = new LogDevice(this); | |
620 | } | |
621 | ||
622 | ||
623 | //! Construct the instance of Logger and set logger default category | |
624 | /** | |
625 | * If you're only using one global instance of logger you wouldn't probably need to use this constructor manually. | |
626 | * Consider using [logger](@ref logger) macro instead to access the logger instance and call | |
627 | * [setDefaultCategory](@ref setDefaultCategory) method. | |
628 | * | |
629 | * \sa Logger() | |
630 | * \sa setDefaultCategory() | |
631 | */ | |
632 | Logger::Logger(const QString& defaultCategory) | |
633 | : d_ptr(new LoggerPrivate) | |
634 | { | |
635 | Q_D(Logger); | |
636 | d->logDevice = new LogDevice(this); | |
637 | ||
638 | setDefaultCategory(defaultCategory); | |
639 | } | |
640 | ||
641 | ||
642 | //! Destroy the instance of Logger | |
643 | /** | |
644 | * You probably wouldn't need to use this function directly. Global instance of logger will be destroyed automatically | |
645 | * at the end of your QCoreApplication execution | |
646 | */ | |
647 | Logger::~Logger() | |
648 | { | |
649 | Q_D(Logger); | |
650 | ||
651 | // Cleanup appenders | |
652 | QMutexLocker appendersLocker(&d->loggerMutex); | |
653 | qDeleteAll(d->appenders); | |
654 | qDeleteAll(d->categoryAppenders); | |
655 | ||
656 | // Cleanup device | |
657 | delete d->logDevice; | |
658 | appendersLocker.unlock(); | |
659 | ||
660 | delete d_ptr; | |
661 | } | |
662 | ||
663 | ||
664 | //! Converts the LogLevel enum value to its string representation | |
665 | /** | |
666 | * \param logLevel Log level to convert | |
667 | * | |
668 | * \sa LogLevel | |
669 | * \sa levelFromString() | |
670 | */ | |
671 | QString Logger::levelToString(Logger::LogLevel logLevel) | |
672 | { | |
673 | switch (logLevel) | |
674 | { | |
675 | case Trace: | |
676 | return QLatin1String("Trace"); | |
677 | case Debug: | |
678 | return QLatin1String("Debug"); | |
679 | case Info: | |
680 | return QLatin1String("Info"); | |
681 | case Warning: | |
682 | return QLatin1String("Warning"); | |
683 | case Error: | |
684 | return QLatin1String("Error"); | |
685 | case Fatal: | |
686 | return QLatin1String("Fatal"); | |
687 | } | |
688 | ||
689 | return QString(); | |
690 | } | |
691 | ||
692 | ||
693 | //! Converts the LogLevel string representation to enum value | |
694 | /** | |
695 | * Comparation of the strings is case independent. If the log level string provided cannot be understood | |
696 | * Logger::Debug is returned. | |
697 | * | |
698 | * \param s String to be decoded | |
699 | * | |
700 | * \sa LogLevel | |
701 | * \sa levelToString() | |
702 | */ | |
703 | Logger::LogLevel Logger::levelFromString(const QString& s) | |
704 | { | |
705 | QString str = s.trimmed().toLower(); | |
706 | ||
707 | LogLevel result = Debug; | |
708 | ||
709 | if (str == QLatin1String("trace")) | |
710 | result = Trace; | |
711 | else if (str == QLatin1String("debug")) | |
712 | result = Debug; | |
713 | else if (str == QLatin1String("info")) | |
714 | result = Info; | |
715 | else if (str == QLatin1String("warning")) | |
716 | result = Warning; | |
717 | else if (str == QLatin1String("error")) | |
718 | result = Error; | |
719 | else if (str == QLatin1String("fatal")) | |
720 | result = Fatal; | |
721 | ||
722 | return result; | |
723 | } | |
724 | ||
725 | ||
726 | //! Returns the global instance of Logger | |
727 | /** | |
728 | * In a most cases you shouldn't use this function directly. Consider using [logger](@ref logger) macro instead. | |
729 | * | |
730 | * \sa logger | |
731 | */ | |
732 | Logger* Logger::globalInstance() | |
733 | { | |
734 | Logger* result = 0; | |
735 | { | |
736 | QReadLocker locker(&LoggerPrivate::globalInstanceLock); | |
737 | result = LoggerPrivate::globalInstance; | |
738 | } | |
739 | ||
740 | if (!result) | |
741 | { | |
742 | QWriteLocker locker(&LoggerPrivate::globalInstanceLock); | |
743 | LoggerPrivate::globalInstance = new Logger; | |
744 | ||
745 | #if QT_VERSION >= 0x050000 | |
746 | qInstallMessageHandler(qtLoggerMessageHandler); | |
747 | #else | |
748 | qInstallMsgHandler(qtLoggerMessageHandler); | |
749 | #endif | |
750 | qAddPostRoutine(cleanupLoggerGlobalInstance); | |
751 | result = LoggerPrivate::globalInstance; | |
752 | } | |
753 | ||
754 | return result; | |
755 | } | |
756 | ||
757 | ||
758 | //! Registers the appender to write the log records to | |
759 | /** | |
760 | * On the log writing call (using one of the macros or the write() function) Logger traverses through the list of | |
761 | * the appenders and writes a log records to the each of them. Please, look through the AbstractAppender | |
762 | * documentation to understand the concept of appenders. | |
763 | * | |
764 | * If no appenders was added to Logger, it falls back to logging into the \c std::cerr STL stream. | |
765 | * | |
766 | * \param appender Appender to register in the Logger | |
767 | * | |
768 | * \note Logger takes ownership on the appender and it will delete it on the application exit. According to this, | |
769 | * appenders must be created on heap to prevent double destruction of the appender. | |
770 | * | |
771 | * \sa registerCategoryAppender | |
772 | * \sa AbstractAppender | |
773 | */ | |
774 | void Logger::registerAppender(AbstractAppender* appender) | |
775 | { | |
776 | Q_D(Logger); | |
777 | ||
778 | QMutexLocker locker(&d->loggerMutex); | |
779 | ||
780 | if (!d->appenders.contains(appender)) | |
781 | d->appenders.append(appender); | |
782 | else | |
783 | std::cerr << "Trying to register appender that was already registered" << std::endl; | |
784 | } | |
785 | ||
786 | //! Registers the appender to write the log records to the specific category | |
787 | /** | |
788 | * Calling this method, you can link some appender with the named category. | |
789 | * On the log writing call to the specific category (calling write() with category parameter directly, | |
790 | * writing to the default category, or using special dCDebug(), dCWarning() etc. macros), | |
791 | * Logger writes the log message only to the list of registered category appenders. | |
792 | * | |
793 | * You can call logToGlobalInstance() to pass all category log messages to the global logger instance appenders | |
794 | * (registered using registerAppender()). | |
795 | * If no category appenders with specific name was registered to the Logger, | |
796 | * it falls back to logging into the \c std::cerr STL stream, both with simple warning message. | |
797 | * | |
798 | * \param category Category name | |
799 | * \param appender Appender to register in the Logger | |
800 | * | |
801 | * \note Logger takes ownership on the appender and it will delete it on the application exit. According to this, | |
802 | * appenders must be created on heap to prevent double destruction of the appender. | |
803 | * | |
804 | * \sa registerAppender | |
805 | * \sa dCTrace(), dCDebug(), dCInfo(), dCWarning(), dCError(), dCFatal() | |
806 | * \sa dCategory(), dGlobalCategory() | |
807 | * \sa logToGlobalInstance | |
808 | * \sa setDefaultCategory | |
809 | */ | |
810 | void Logger::registerCategoryAppender(const QString& category, AbstractAppender* appender) | |
811 | { | |
812 | Q_D(Logger); | |
813 | ||
814 | QMutexLocker locker(&d->loggerMutex); | |
815 | ||
816 | if (!d->categoryAppenders.values().contains(appender)) | |
817 | d->categoryAppenders.insert(category, appender); | |
818 | else | |
819 | std::cerr << "Trying to register appender that was already registered" << std::endl; | |
820 | } | |
821 | ||
822 | //! Sets default logging category | |
823 | /** | |
824 | * All log messages to this category appenders will also be written to general logger instance appenders (registered | |
825 | * using [registerAppender](@ref registerAppender) method), and vice versa. | |
826 | * In particular, any calls to the dDebug() macro will be treated as category logging, | |
827 | * so you needn't to specify category name using dCDebug() macro. | |
828 | * | |
829 | * To unset the default category, pass a null string as a parameter. | |
830 | * | |
831 | * \param category Category name | |
832 | * | |
833 | * \note "category" format marker will be set to the category name for all of these messages | |
834 | * (see [AbstractStringAppender::setFormat](@ref AbstractStringAppender::setFormat)). | |
835 | * | |
836 | * \sa defaultCategory() | |
837 | * \sa registerCategoryAppender() | |
838 | * \sa logToGlobalInstance() | |
839 | */ | |
840 | void Logger::setDefaultCategory(const QString& category) | |
841 | { | |
842 | Q_D(Logger); | |
843 | ||
844 | QMutexLocker locker(&d->loggerMutex); | |
845 | ||
846 | d->defaultCategory = category; | |
847 | } | |
848 | ||
849 | //! Returns default logging category name | |
850 | /** | |
851 | * \sa setDefaultCategory | |
852 | */ | |
853 | QString Logger::defaultCategory() const | |
854 | { | |
855 | Q_D(const Logger); | |
856 | return d->defaultCategory; | |
857 | } | |
858 | ||
859 | //! Links some logging category with the global logger instance appenders. | |
860 | /** | |
861 | * If set to true, all log messages to the specified category appenders will also be written to the global logger instance appenders, | |
862 | * registered using registerAppender(). | |
863 | * | |
864 | * By default, all messages to the specific category are written only to the specific category appenders | |
865 | * (registered using registerCategoryAppender()). | |
866 | * | |
867 | * \param category Category name | |
868 | * \param logToGlobal Link or onlink the category from global logger instance appender | |
869 | * | |
870 | * \sa globalInstance | |
871 | * \sa registerAppender | |
872 | * \sa registerCategoryAppender | |
873 | */ | |
874 | void Logger::logToGlobalInstance(const QString& category, bool logToGlobal) | |
875 | { | |
876 | Q_D(Logger); | |
877 | ||
878 | if (this == globalInstance()) | |
879 | { | |
880 | QMutexLocker locker(&d->loggerMutex); | |
881 | d->categories.insert(category, logToGlobal); | |
882 | } | |
883 | else | |
884 | { | |
885 | globalInstance()->logToGlobalInstance(category, logToGlobal); | |
886 | } | |
887 | } | |
888 | ||
889 | ||
890 | void Logger::write(const QDateTime& timeStamp, LogLevel logLevel, const char* file, int line, const char* function, const char* category, | |
891 | const QString& message, bool fromLocalInstance) | |
892 | { | |
893 | Q_D(Logger); | |
894 | ||
895 | QMutexLocker locker(&d->loggerMutex); | |
896 | ||
897 | QString logCategory = QString::fromLatin1(category); | |
898 | if (logCategory.isNull() && !d->defaultCategory.isNull()) | |
899 | logCategory = d->defaultCategory; | |
900 | ||
901 | bool wasWritten = false; | |
902 | bool isGlobalInstance = this == globalInstance(); | |
903 | bool linkedToGlobal = isGlobalInstance && d->categories.value(logCategory, false); | |
904 | ||
905 | if (!logCategory.isNull()) | |
906 | { | |
907 | QList<AbstractAppender*> appenders = d->categoryAppenders.values(logCategory); | |
908 | if (appenders.length() == 0) | |
909 | { | |
910 | if (logCategory != d->defaultCategory && !linkedToGlobal && !fromLocalInstance) | |
911 | std::cerr << "No appenders assotiated with category " << qPrintable(logCategory) << std::endl; | |
912 | } | |
913 | else | |
914 | { | |
915 | foreach (AbstractAppender* appender, appenders) | |
916 | appender->write(timeStamp, logLevel, file, line, function, logCategory, message); | |
917 | wasWritten = true; | |
918 | } | |
919 | } | |
920 | ||
921 | // the default category is linked to the main logger appenders | |
922 | // global logger instance also writes all linked categories to the main appenders | |
923 | if (logCategory.isNull() || logCategory == d->defaultCategory || linkedToGlobal) | |
924 | { | |
925 | if (!d->appenders.isEmpty()) | |
926 | { | |
927 | foreach (AbstractAppender* appender, d->appenders) | |
928 | appender->write(timeStamp, logLevel, file, line, function, logCategory, message); | |
929 | wasWritten = true; | |
930 | } | |
931 | else | |
932 | { | |
933 | static bool noAppendersWarningShown = false; | |
934 | if (!noAppendersWarningShown) | |
935 | { | |
936 | #if defined(Q_OS_ANDROID) | |
937 | __android_ write(ANDROID_LOG_WARN, "Logger", "No appenders registered with logger"); | |
938 | #else | |
939 | std::cerr << "No appenders registered with logger" << std::endl; | |
940 | #endif | |
941 | noAppendersWarningShown = true; | |
942 | } | |
943 | } | |
944 | } | |
945 | ||
946 | // local logger instances send category messages to the global instance | |
947 | if (!logCategory.isNull() && !isGlobalInstance) | |
948 | globalInstance()->write(timeStamp, logLevel, file, line, function, logCategory.toLatin1(), message, true); | |
949 | ||
950 | if (!wasWritten && !fromLocalInstance) | |
951 | { | |
952 | // Fallback | |
953 | #if defined(Q_OS_ANDROID) | |
954 | QString result = QString(QLatin1String("<%2> %3")).arg(AbstractStringAppender::stripFunctionName(function)).arg(message); | |
955 | __android_log_write(AndroidAppender::androidLogPriority(logLevel), "Logger", qPrintable(result)); | |
956 | #else | |
957 | QString result = QString(QLatin1String("[%1] <%2> %3")).arg(levelToString(logLevel), -7) | |
958 | .arg(AbstractStringAppender::stripFunctionName(function)).arg(message); | |
959 | std::cerr << qPrintable(result) << std::endl; | |
960 | #endif | |
961 | } | |
962 | ||
963 | if (logLevel == Logger::Fatal) | |
964 | abort(); | |
965 | } | |
966 | ||
967 | ||
968 | //! Writes the log record | |
969 | /** | |
970 | * Writes the log records with the supplied arguments to all the registered appenders. | |
971 | * | |
972 | * \note It is not recommended to call this function directly. Instead of this you can just call one of the macros | |
973 | * (dTrace, dTrac, dInfo, dWarning, dError, dFatal) that will supply all the needed | |
974 | * information to this function. | |
975 | * | |
976 | * \param timeStamp - the time stamp of the record | |
977 | * \param logLevel - the log level of the record | |
978 | * \param file - the name of the source file that requested the log record | |
979 | * \param line - the line of the code of source file that requested the log record | |
980 | * \param function - name of the function that requested the log record | |
981 | * \param category - logging category (0 for default category) | |
982 | * \param message - log message | |
983 | * | |
984 | * \note Recording of the log record using the Logger::Fatal log level will lead to calling the STL abort() | |
985 | * function, which will interrupt the running of your software and begin the writing of the core dump. | |
986 | * | |
987 | * \sa LogLevel | |
988 | * \sa dTrace, dDebug, dInfo, dWarning, dError, dFatal | |
989 | * \sa AbstractAppender | |
990 | */ | |
991 | void Logger::write(const QDateTime& timeStamp, LogLevel logLevel, const char* file, int line, const char* function, const char* category, | |
992 | const QString& message) | |
993 | { | |
994 | write(timeStamp, logLevel, file, line, function, category, message, /* fromLocalInstance = */ false); | |
995 | } | |
996 | ||
997 | /** | |
998 | * This is the overloaded function provided for the convinience. It behaves similar to the above function. | |
999 | * | |
1000 | * This function uses the current timestamp obtained with \c QDateTime::currentDateTime(). | |
1001 | * | |
1002 | * \sa write() | |
1003 | */ | |
1004 | void Logger::write(LogLevel logLevel, const char* file, int line, const char* function, const char* category, | |
1005 | const QString& message) | |
1006 | { | |
1007 | write(QDateTime::currentDateTime(), logLevel, file, line, function, category, message); | |
1008 | } | |
1009 | ||
1010 | ||
1011 | /** | |
1012 | * This is the overloaded function provided for the convinience. It behaves similar to the above function. | |
1013 | * | |
1014 | * This function doesn't accept any log message as argument. It returns the \c QDebug object that can be written | |
1015 | * using the stream functions. For example, you may like to write: | |
1016 | * \code | |
1017 | * dDebug() << "This is the size" << size << "of the element" << elementName; | |
1018 | * \endcode | |
1019 | * instead of writing | |
1020 | * \code | |
1021 | * dDebug(QString(QLatin1String("This is the size %1x%2 of the element %3")) | |
1022 | * .arg(size.x()).arg(size.y()).arg(elementName)); | |
1023 | * \endcode | |
1024 | * | |
1025 | * Please consider reading the Qt Reference Documentation for the description of the QDebug class usage syntax. | |
1026 | * | |
1027 | * \note This overload is definitely more pleasant to use than the first write() overload, but it behaves definitely | |
1028 | * slower than all the above overloads. | |
1029 | * | |
1030 | * \sa write() | |
1031 | */ | |
1032 | QDebug Logger::write(LogLevel logLevel, const char* file, int line, const char* function, const char* category) | |
1033 | { | |
1034 | Q_D(Logger); | |
1035 | ||
1036 | d->logDevice->lock(logLevel, file, line, function, category); | |
1037 | return QDebug(d->logDevice); | |
1038 | } | |
1039 | ||
1040 | ||
1041 | //! Writes the assertion | |
1042 | /** | |
1043 | * This function writes the assertion record using the write() function. | |
1044 | * | |
1045 | * The assertion record is always written using the Logger::Fatal log level which leads to the abortation of the | |
1046 | * program and generation of the core dump (if supported). | |
1047 | * | |
1048 | * The message written to the appenders will be identical to the \c condition argument prefixed with the | |
1049 | * <tt>ASSERT:</tt> notification. | |
1050 | * | |
1051 | * \note It is not recommended to call this function directly. Instead of this you can just call the LOG_ASSERT | |
1052 | * macro that will supply all the needed information to this function. | |
1053 | * | |
1054 | * \sa LOG_ASSERT | |
1055 | * \sa write() | |
1056 | */ | |
1057 | void Logger::writeAssert(const char* file, int line, const char* function, const char* condition) | |
1058 | { | |
1059 | write(Logger::Fatal, file, line, function, 0, QString("ASSERT: \"%1\"").arg(condition)); | |
1060 | } | |
1061 | ||
1062 | ||
1063 | Logger* loggerInstance() | |
1064 | { | |
1065 | return Logger::globalInstance(); | |
1066 | } | |
1067 | ||
1068 | ||
1069 | ||
1070 | void LoggerTimingHelper::start(const char* msg, ...) | |
1071 | { | |
1072 | va_list va; | |
1073 | va_start(va, msg); | |
1074 | m_block = QString().vsprintf(msg, va); | |
1075 | va_end(va); | |
1076 | ||
1077 | m_time.start(); | |
1078 | } | |
1079 | ||
1080 | ||
1081 | void LoggerTimingHelper::start(const QString& block) | |
1082 | { | |
1083 | m_block = block; | |
1084 | m_time.start(); | |
1085 | } | |
1086 | ||
1087 | LoggerTimingHelper::~LoggerTimingHelper() | |
1088 | { | |
1089 | QString message; | |
1090 | if (m_block.isEmpty()) | |
1091 | message = QString(QLatin1String("Function %1 finished in ")).arg(AbstractStringAppender::stripFunctionName(m_function)); | |
1092 | else | |
1093 | message = QString(QLatin1String("\"%1\" finished in ")).arg(m_block); | |
1094 | ||
1095 | int elapsed = m_time.elapsed(); | |
1096 | if (elapsed >= 10000) | |
1097 | message += QString(QLatin1String("%1 s.")).arg(elapsed / 1000); | |
1098 | else | |
1099 | message += QString(QLatin1String("%1 ms.")).arg(elapsed); | |
1100 | ||
1101 | m_logger->write(m_logLevel, m_file, m_line, m_function, 0, message); | |
1102 | } | |
1103 | ||
1104 | ||
1105 | void CuteMessageLogger::write(const char* msg, ...) const | |
1106 | { | |
1107 | va_list va; | |
1108 | va_start(va, msg); | |
1109 | m_l->write(m_level, m_file, m_line, m_function, m_category, QString().vsprintf(msg, va)); | |
1110 | va_end(va); | |
1111 | } | |
1112 | ||
1113 | ||
1114 | void CuteMessageLogger::write(const QString& msg) const | |
1115 | { | |
1116 | m_l->write(m_level, m_file, m_line, m_function, m_category, msg); | |
1117 | } | |
1118 | ||
1119 | ||
1120 | QDebug CuteMessageLogger::write() const | |
1121 | { | |
1122 | return m_l->write(m_level, m_file, m_line, m_function, m_category); | |
1123 | } | |
1124 | ||
1125 | DUTIL_END_NAMESPACE |
0 | /* | |
1 | Copyright (c) 2012 Boris Moiseev (cyberbobs at gmail dot com) | |
2 | ||
3 | This program is free software: you can redistribute it and/or modify | |
4 | it under the terms of the GNU Lesser General Public License version 2.1 | |
5 | as published by the Free Software Foundation and appearing in the file | |
6 | LICENSE.LGPL included in the packaging of this file. | |
7 | ||
8 | This program is distributed in the hope that it will be useful, | |
9 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
11 | GNU Lesser General Public License for more details. | |
12 | */ | |
13 | #ifndef LOGGER_H | |
14 | #define LOGGER_H | |
15 | ||
16 | // Qt | |
17 | #include <QString> | |
18 | #include <QDebug> | |
19 | #include <QDateTime> | |
20 | ||
21 | // Local | |
22 | #include "CuteLogger_global.h" | |
23 | ||
24 | DUTIL_BEGIN_NAMESPACE | |
25 | ||
26 | class AbstractAppender; | |
27 | class Logger; | |
28 | CUTELOGGERSHARED_EXPORT Logger* loggerInstance(); | |
29 | #define logger loggerInstance() | |
30 | ||
31 | ||
32 | #define dTrace CuteMessageLogger(loggerInstance(), Logger::Trace, __FILE__, __LINE__, Q_FUNC_INFO).write | |
33 | #define dDebug CuteMessageLogger(loggerInstance(), Logger::Debug, __FILE__, __LINE__, Q_FUNC_INFO).write | |
34 | #define dInfo CuteMessageLogger(loggerInstance(), Logger::Info, __FILE__, __LINE__, Q_FUNC_INFO).write | |
35 | #define dWarning CuteMessageLogger(loggerInstance(), Logger::Warning, __FILE__, __LINE__, Q_FUNC_INFO).write | |
36 | #define dError CuteMessageLogger(loggerInstance(), Logger::Error, __FILE__, __LINE__, Q_FUNC_INFO).write | |
37 | #define dFatal CuteMessageLogger(loggerInstance(), Logger::Fatal, __FILE__, __LINE__, Q_FUNC_INFO).write | |
38 | ||
39 | #define dCTrace(category) CuteMessageLogger(loggerInstance(), Logger::Trace, __FILE__, __LINE__, Q_FUNC_INFO, category).write() | |
40 | #define dCDebug(category) CuteMessageLogger(loggerInstance(), Logger::Debug, __FILE__, __LINE__, Q_FUNC_INFO, category).write() | |
41 | #define dCInfo(category) CuteMessageLogger(loggerInstance(), Logger::Info, __FILE__, __LINE__, Q_FUNC_INFO, category).write() | |
42 | #define dCWarning(category) CuteMessageLogger(loggerInstance(), Logger::Warning, __FILE__, __LINE__, Q_FUNC_INFO, category).write() | |
43 | #define dCError(category) CuteMessageLogger(loggerInstance(), Logger::Error, __FILE__, __LINE__, Q_FUNC_INFO, category).write() | |
44 | #define dCFatal(category) CuteMessageLogger(loggerInstance(), Logger::Fatal, __FILE__, __LINE__, Q_FUNC_INFO, category).write() | |
45 | ||
46 | #define dTraceTime LoggerTimingHelper loggerTimingHelper(loggerInstance(), Logger::Trace, __FILE__, __LINE__, Q_FUNC_INFO); loggerTimingHelper.start | |
47 | #define dDebugTime LoggerTimingHelper loggerTimingHelper(loggerInstance(), Logger::Debug, __FILE__, __LINE__, Q_FUNC_INFO); loggerTimingHelper.start | |
48 | #define dInfoTime LoggerTimingHelper loggerTimingHelper(loggerInstance(), Logger::Info, __FILE__, __LINE__, Q_FUNC_INFO); loggerTimingHelper.start | |
49 | ||
50 | #define dAssert(cond) ((!(cond)) ? loggerInstance()->writeAssert(__FILE__, __LINE__, Q_FUNC_INFO, #cond) : qt_noop()) | |
51 | #define dAssertX(cond, msg) ((!(cond)) ? loggerInstance()->writeAssert(__FILE__, __LINE__, Q_FUNC_INFO, msg) : qt_noop()) | |
52 | ||
53 | #define dCategory(category) \ | |
54 | private:\ | |
55 | Logger* loggerInstance()\ | |
56 | {\ | |
57 | static Logger customLoggerInstance(category);\ | |
58 | return &customLoggerInstance;\ | |
59 | }\ | |
60 | ||
61 | #define dGlobalCategory(category) \ | |
62 | private:\ | |
63 | Logger* loggerInstance()\ | |
64 | {\ | |
65 | static Logger customLoggerInstance(category);\ | |
66 | customLoggerInstance.logToGlobalInstance(category, true);\ | |
67 | return &customLoggerInstance;\ | |
68 | }\ | |
69 | ||
70 | ||
71 | class LoggerPrivate; | |
72 | class CUTELOGGERSHARED_EXPORT Logger | |
73 | { | |
74 | Q_DISABLE_COPY(Logger) | |
75 | ||
76 | public: | |
77 | Logger(); | |
78 | Logger(const QString& defaultCategory); | |
79 | ~Logger(); | |
80 | ||
81 | //! Describes the possible severity levels of the log records | |
82 | enum LogLevel | |
83 | { | |
84 | Trace, //!< Trace level. Can be used for mostly unneeded records used for internal code tracing. | |
85 | Debug, //!< Debug level. Useful for non-necessary records used for the debugging of the software. | |
86 | Info, //!< Info level. Can be used for informational records, which may be interesting for not only developers. | |
87 | Warning, //!< Warning. May be used to log some non-fatal warnings detected by your application. | |
88 | Error, //!< Error. May be used for a big problems making your application work wrong but not crashing. | |
89 | Fatal //!< Fatal. Used for unrecoverable errors, crashes the application right after the log record is written. | |
90 | }; | |
91 | ||
92 | static QString levelToString(LogLevel logLevel); | |
93 | static LogLevel levelFromString(const QString& s); | |
94 | ||
95 | static Logger* globalInstance(); | |
96 | ||
97 | void registerAppender(AbstractAppender* appender); | |
98 | void registerCategoryAppender(const QString& category, AbstractAppender* appender); | |
99 | ||
100 | void logToGlobalInstance(const QString& category, bool logToGlobal = false); | |
101 | ||
102 | void setDefaultCategory(const QString& category); | |
103 | QString defaultCategory() const; | |
104 | ||
105 | void write(const QDateTime& timeStamp, LogLevel logLevel, const char* file, int line, const char* function, const char* category, | |
106 | const QString& message); | |
107 | void write(LogLevel logLevel, const char* file, int line, const char* function, const char* category, const QString& message); | |
108 | QDebug write(LogLevel logLevel, const char* file, int line, const char* function, const char* category); | |
109 | ||
110 | void writeAssert(const char* file, int line, const char* function, const char* condition); | |
111 | ||
112 | private: | |
113 | void write(const QDateTime& timeStamp, LogLevel logLevel, const char* file, int line, const char* function, const char* category, | |
114 | const QString& message, bool fromLocalInstance); | |
115 | Q_DECLARE_PRIVATE(Logger) | |
116 | LoggerPrivate* d_ptr; | |
117 | }; | |
118 | ||
119 | ||
120 | class CUTELOGGERSHARED_EXPORT CuteMessageLogger | |
121 | { | |
122 | Q_DISABLE_COPY(CuteMessageLogger) | |
123 | ||
124 | public: | |
125 | Q_DECL_CONSTEXPR CuteMessageLogger(Logger* l, Logger::LogLevel level, const char* file, int line, const char* function) | |
126 | : m_l(l), | |
127 | m_level(level), | |
128 | m_file(file), | |
129 | m_line(line), | |
130 | m_function(function), | |
131 | m_category(0) | |
132 | {} | |
133 | ||
134 | Q_DECL_CONSTEXPR CuteMessageLogger(Logger* l, Logger::LogLevel level, const char* file, int line, const char* function, const char* category) | |
135 | : m_l(l), | |
136 | m_level(level), | |
137 | m_file(file), | |
138 | m_line(line), | |
139 | m_function(function), | |
140 | m_category(category) | |
141 | {} | |
142 | ||
143 | void write(const char* msg, ...) const | |
144 | #if defined(Q_CC_GNU) && !defined(__INSURE__) | |
145 | # if defined(Q_CC_MINGW) && !defined(Q_CC_CLANG) | |
146 | __attribute__ ((format (gnu_printf, 2, 3))) | |
147 | # else | |
148 | __attribute__ ((format (printf, 2, 3))) | |
149 | # endif | |
150 | #endif | |
151 | ; | |
152 | ||
153 | void write(const QString& msg) const; | |
154 | ||
155 | QDebug write() const; | |
156 | ||
157 | private: | |
158 | Logger* m_l; | |
159 | Logger::LogLevel m_level; | |
160 | const char* m_file; | |
161 | int m_line; | |
162 | const char* m_function; | |
163 | const char* m_category; | |
164 | }; | |
165 | ||
166 | ||
167 | class CUTELOGGERSHARED_EXPORT LoggerTimingHelper | |
168 | { | |
169 | Q_DISABLE_COPY(LoggerTimingHelper) | |
170 | ||
171 | public: | |
172 | inline explicit LoggerTimingHelper(Logger* l, Logger::LogLevel logLevel, const char* file, int line, | |
173 | const char* function) | |
174 | : m_logger(l), | |
175 | m_logLevel(logLevel), | |
176 | m_file(file), | |
177 | m_line(line), | |
178 | m_function(function) | |
179 | {} | |
180 | ||
181 | void start(const char* msg, ...) | |
182 | #if defined(Q_CC_GNU) && !defined(__INSURE__) | |
183 | # if defined(Q_CC_MINGW) && !defined(Q_CC_CLANG) | |
184 | __attribute__ ((format (gnu_printf, 2, 3))) | |
185 | # else | |
186 | __attribute__ ((format (printf, 2, 3))) | |
187 | # endif | |
188 | #endif | |
189 | ; | |
190 | ||
191 | void start(const QString& msg = QString()); | |
192 | ||
193 | ~LoggerTimingHelper(); | |
194 | ||
195 | private: | |
196 | Logger* m_logger; | |
197 | QTime m_time; | |
198 | Logger::LogLevel m_logLevel; | |
199 | const char* m_file; | |
200 | int m_line; | |
201 | const char* m_function; | |
202 | QString m_block; | |
203 | }; | |
204 | ||
205 | DUTIL_END_NAMESPACE | |
206 | ||
207 | #endif // LOGGER_H |
0 | /* | |
1 | Copyright (c) 2010 Karl-Heinz Reichel (khreichel at googlemail dot com) | |
2 | ||
3 | This program is free software: you can redistribute it and/or modify | |
4 | it under the terms of the GNU Lesser General Public License version 2.1 | |
5 | as published by the Free Software Foundation and appearing in the file | |
6 | LICENSE.LGPL included in the packaging of this file. | |
7 | ||
8 | This program is distributed in the hope that it will be useful, | |
9 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
11 | GNU Lesser General Public License for more details. | |
12 | */ | |
13 | // Local | |
14 | #include "OutputDebugAppender.h" | |
15 | ||
16 | // STL | |
17 | #include <windows.h> | |
18 | ||
19 | DUTIL_BEGIN_NAMESPACE | |
20 | ||
21 | /** | |
22 | * \class OutputDebugAppender | |
23 | * | |
24 | * \brief Appender that writes the log records to the Microsoft Debug Log | |
25 | */ | |
26 | ||
27 | ||
28 | //! Writes the log record to the windows debug log. | |
29 | /** | |
30 | * \sa AbstractStringAppender::format() | |
31 | */ | |
32 | void OutputDebugAppender::append(const QDateTime& timeStamp, | |
33 | Logger::LogLevel logLevel, | |
34 | const char* file, | |
35 | int line, | |
36 | const char* function, | |
37 | const QString& category, | |
38 | const QString& message) | |
39 | { | |
40 | QString s = formattedString(timeStamp, logLevel, file, line, function, category, message); | |
41 | OutputDebugStringW((LPCWSTR) s.utf16()); | |
42 | } | |
43 | ||
44 | DUTIL_END_NAMESPACE |
0 | /* | |
1 | Copyright (c) 2010 Karl-Heinz Reichel (khreichel at googlemail dot com) | |
2 | ||
3 | This program is free software: you can redistribute it and/or modify | |
4 | it under the terms of the GNU Lesser General Public License version 2.1 | |
5 | as published by the Free Software Foundation and appearing in the file | |
6 | LICENSE.LGPL included in the packaging of this file. | |
7 | ||
8 | This program is distributed in the hope that it will be useful, | |
9 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
11 | GNU Lesser General Public License for more details. | |
12 | */ | |
13 | ||
14 | #ifndef OUTPUTDEBUGAPPENDER_H | |
15 | #define OUTPUTDEBUGAPPENDER_H | |
16 | ||
17 | #include "CuteLogger_global.h" | |
18 | #include <AbstractStringAppender.h> | |
19 | ||
20 | DUTIL_BEGIN_NAMESPACE | |
21 | ||
22 | class CUTELOGGERSHARED_EXPORT OutputDebugAppender : public AbstractStringAppender | |
23 | { | |
24 | protected: | |
25 | virtual void append(const QDateTime& timeStamp, Logger::LogLevel logLevel, const char* file, int line, | |
26 | const char* function, const QString& category, const QString& message); | |
27 | }; | |
28 | ||
29 | DUTIL_END_NAMESPACE | |
30 | ||
31 | #endif // OUTPUTDEBUGAPPENDER_H |
0 | # Deepin Tool Kit Log | |
1 | ||
2 | DLog is the log module of deepin tool kit for Qt/C++ | |
3 | ||
4 | # Install | |
5 | ||
6 | ```` | |
7 | mkdir build && cd build | |
8 | qmake .. | |
9 | sudo make install | |
10 | ```` | |
11 | ||
12 | # Usage | |
13 | ||
14 | Just add pkgconfig in .pro file | |
15 | ||
16 | ```` | |
17 | unix { | |
18 | CONFIG+=link_pkgconfig | |
19 | PKGCONFIG+=dtklog | |
20 | } | |
21 | ```` | |
22 | ||
23 | # Example | |
24 | ||
25 | ```` | |
26 | #include <QCoreApplication> | |
27 | ||
28 | #include <DLog> | |
29 | ||
30 | using namespace Dtk::Log; | |
31 | ||
32 | int main(int argc, char* argv[]) | |
33 | { | |
34 | QCoreApplication app(argc, argv); | |
35 | ||
36 | /* 1 you can use standrd deepin application log format */ | |
37 | // 1.1 log to console | |
38 | DLogManager::instance()->registerAppender(true); | |
39 | dInfoTime(); | |
40 | /* 1.2 log to standrd deepin user cache path: ~/.cache/{organ}/{appname}/ */ | |
41 | // app.setOrganizationName("dtk-test"); // must set | |
42 | // app.setApplicationName("dlog-example"); // must set | |
43 | // dInfo()<< "LogFile:" << DLogManager::instance()->getlogFilePath(); | |
44 | // DLogManager::instance()->registerAppender(false); | |
45 | ||
46 | /* 2 Register your own logger format;*/ | |
47 | // ConsoleAppender* consoleAppender = new ConsoleAppender; | |
48 | // consoleAppender->setFormat("[%{type:-7}] <%{Function}> %{message}\n"); | |
49 | // logger->registerAppender(consoleAppender); | |
50 | ||
51 | dInfo("Starting the application"); | |
52 | int result = 1; | |
53 | dWarning() << "Something went wrong." << "Result code is" << result; | |
54 | return result; | |
55 | } | |
56 | ```` | |
57 | ||
58 | You can get full example from: | |
59 | ||
60 | [dlog-example](https://github.com/deepin-tool-kit/dtk-example/tree/master/dlog-example) | |
61 | ||
62 | # Document | |
63 | ||
64 | ```` | |
65 | doxygen -g dlog | |
66 | doxygen -w html | |
67 | firefox html/index | |
68 | ```` |
0 | #include <QDateTime> | |
1 | #include <QDir> | |
2 | #include <QFileInfo> | |
3 | ||
4 | #include "RollingFileAppender.h" | |
5 | ||
6 | DUTIL_BEGIN_NAMESPACE | |
7 | ||
8 | RollingFileAppender::RollingFileAppender(const QString& fileName) | |
9 | : FileAppender(fileName), | |
10 | m_logFilesLimit(0) | |
11 | {} | |
12 | ||
13 | ||
14 | void RollingFileAppender::append(const QDateTime& timeStamp, Logger::LogLevel logLevel, const char* file, int line, | |
15 | const char* function, const QString& category, const QString& message) | |
16 | { | |
17 | if (!m_rollOverTime.isNull() && QDateTime::currentDateTime() > m_rollOverTime) | |
18 | rollOver(); | |
19 | ||
20 | FileAppender::append(timeStamp, logLevel, file, line, function, category, message); | |
21 | } | |
22 | ||
23 | ||
24 | RollingFileAppender::DatePattern RollingFileAppender::datePattern() const | |
25 | { | |
26 | QMutexLocker locker(&m_rollingMutex); | |
27 | return m_frequency; | |
28 | } | |
29 | ||
30 | ||
31 | QString RollingFileAppender::datePatternString() const | |
32 | { | |
33 | QMutexLocker locker(&m_rollingMutex); | |
34 | return m_datePatternString; | |
35 | } | |
36 | ||
37 | ||
38 | void RollingFileAppender::setDatePattern(DatePattern datePattern) | |
39 | { | |
40 | switch (datePattern) | |
41 | { | |
42 | case MinutelyRollover: | |
43 | setDatePatternString(QLatin1String("'.'yyyy-MM-dd-hh-mm")); | |
44 | break; | |
45 | case HourlyRollover: | |
46 | setDatePatternString(QLatin1String("'.'yyyy-MM-dd-hh")); | |
47 | break; | |
48 | case HalfDailyRollover: | |
49 | setDatePatternString(QLatin1String("'.'yyyy-MM-dd-a")); | |
50 | break; | |
51 | case DailyRollover: | |
52 | setDatePatternString(QLatin1String("'.'yyyy-MM-dd")); | |
53 | break; | |
54 | case WeeklyRollover: | |
55 | setDatePatternString(QLatin1String("'.'yyyy-ww")); | |
56 | break; | |
57 | case MonthlyRollover: | |
58 | setDatePatternString(QLatin1String("'.'yyyy-MM")); | |
59 | break; | |
60 | default: | |
61 | Q_ASSERT_X(false, "DailyRollingFileAppender::setDatePattern()", "Invalid datePattern constant"); | |
62 | setDatePattern(DailyRollover); | |
63 | }; | |
64 | ||
65 | QMutexLocker locker(&m_rollingMutex); | |
66 | m_frequency = datePattern; | |
67 | ||
68 | computeRollOverTime(); | |
69 | } | |
70 | ||
71 | ||
72 | void RollingFileAppender::setDatePattern(const QString& datePattern) | |
73 | { | |
74 | setDatePatternString(datePattern); | |
75 | computeFrequency(); | |
76 | ||
77 | computeRollOverTime(); | |
78 | } | |
79 | ||
80 | ||
81 | void RollingFileAppender::setDatePatternString(const QString& datePatternString) | |
82 | { | |
83 | QMutexLocker locker(&m_rollingMutex); | |
84 | m_datePatternString = datePatternString; | |
85 | } | |
86 | ||
87 | ||
88 | void RollingFileAppender::computeFrequency() | |
89 | { | |
90 | QMutexLocker locker(&m_rollingMutex); | |
91 | ||
92 | const QDateTime startTime(QDate(1999, 1, 1), QTime(0, 0)); | |
93 | const QString startString = startTime.toString(m_datePatternString); | |
94 | ||
95 | if (startString != startTime.addSecs(60).toString(m_datePatternString)) | |
96 | m_frequency = MinutelyRollover; | |
97 | else if (startString != startTime.addSecs(60 * 60).toString(m_datePatternString)) | |
98 | m_frequency = HourlyRollover; | |
99 | else if (startString != startTime.addSecs(60 * 60 * 12).toString(m_datePatternString)) | |
100 | m_frequency = HalfDailyRollover; | |
101 | else if (startString != startTime.addDays(1).toString(m_datePatternString)) | |
102 | m_frequency = DailyRollover; | |
103 | else if (startString != startTime.addDays(7).toString(m_datePatternString)) | |
104 | m_frequency = WeeklyRollover; | |
105 | else if (startString != startTime.addMonths(1).toString(m_datePatternString)) | |
106 | m_frequency = MonthlyRollover; | |
107 | else | |
108 | { | |
109 | Q_ASSERT_X(false, "DailyRollingFileAppender::computeFrequency", "The pattern '%1' does not specify a frequency"); | |
110 | return; | |
111 | } | |
112 | } | |
113 | ||
114 | ||
115 | void RollingFileAppender::removeOldFiles() | |
116 | { | |
117 | if (m_logFilesLimit <= 1) | |
118 | return; | |
119 | ||
120 | QFileInfo fileInfo(fileName()); | |
121 | QDir logDirectory(fileInfo.absoluteDir()); | |
122 | logDirectory.setFilter(QDir::Files); | |
123 | logDirectory.setNameFilters(QStringList() << fileInfo.fileName() + "*"); | |
124 | QFileInfoList logFiles = logDirectory.entryInfoList(); | |
125 | ||
126 | QMap<QDateTime, QString> fileDates; | |
127 | for (int i = 0; i < logFiles.length(); ++i) | |
128 | { | |
129 | QString name = logFiles[i].fileName(); | |
130 | QString suffix = name.mid(name.indexOf(fileInfo.fileName()) + fileInfo.fileName().length()); | |
131 | QDateTime fileDateTime = QDateTime::fromString(suffix, datePatternString()); | |
132 | ||
133 | if (fileDateTime.isValid()) | |
134 | fileDates.insert(fileDateTime, logFiles[i].absoluteFilePath()); | |
135 | } | |
136 | ||
137 | QList<QString> fileDateNames = fileDates.values(); | |
138 | for (int i = 0; i < fileDateNames.length() - m_logFilesLimit + 1; ++i) | |
139 | QFile::remove(fileDateNames[i]); | |
140 | } | |
141 | ||
142 | ||
143 | void RollingFileAppender::computeRollOverTime() | |
144 | { | |
145 | Q_ASSERT_X(!m_datePatternString.isEmpty(), "DailyRollingFileAppender::computeRollOverTime()", "No active date pattern"); | |
146 | ||
147 | QDateTime now = QDateTime::currentDateTime(); | |
148 | QDate nowDate = now.date(); | |
149 | QTime nowTime = now.time(); | |
150 | QDateTime start; | |
151 | ||
152 | switch (m_frequency) | |
153 | { | |
154 | case MinutelyRollover: | |
155 | { | |
156 | start = QDateTime(nowDate, QTime(nowTime.hour(), nowTime.minute(), 0, 0)); | |
157 | m_rollOverTime = start.addSecs(60); | |
158 | } | |
159 | break; | |
160 | case HourlyRollover: | |
161 | { | |
162 | start = QDateTime(nowDate, QTime(nowTime.hour(), 0, 0, 0)); | |
163 | m_rollOverTime = start.addSecs(60*60); | |
164 | } | |
165 | break; | |
166 | case HalfDailyRollover: | |
167 | { | |
168 | int hour = nowTime.hour(); | |
169 | if (hour >= 12) | |
170 | hour = 12; | |
171 | else | |
172 | hour = 0; | |
173 | start = QDateTime(nowDate, QTime(hour, 0, 0, 0)); | |
174 | m_rollOverTime = start.addSecs(60*60*12); | |
175 | } | |
176 | break; | |
177 | case DailyRollover: | |
178 | { | |
179 | start = QDateTime(nowDate, QTime(0, 0, 0, 0)); | |
180 | m_rollOverTime = start.addDays(1); | |
181 | } | |
182 | break; | |
183 | case WeeklyRollover: | |
184 | { | |
185 | // Qt numbers the week days 1..7. The week starts on Monday. | |
186 | // Change it to being numbered 0..6, starting with Sunday. | |
187 | int day = nowDate.dayOfWeek(); | |
188 | if (day == Qt::Sunday) | |
189 | day = 0; | |
190 | start = QDateTime(nowDate, QTime(0, 0, 0, 0)).addDays(-1 * day); | |
191 | m_rollOverTime = start.addDays(7); | |
192 | } | |
193 | break; | |
194 | case MonthlyRollover: | |
195 | { | |
196 | start = QDateTime(QDate(nowDate.year(), nowDate.month(), 1), QTime(0, 0, 0, 0)); | |
197 | m_rollOverTime = start.addMonths(1); | |
198 | } | |
199 | break; | |
200 | default: | |
201 | Q_ASSERT_X(false, "DailyRollingFileAppender::computeInterval()", "Invalid datePattern constant"); | |
202 | m_rollOverTime = QDateTime::fromTime_t(0); | |
203 | } | |
204 | ||
205 | m_rollOverSuffix = start.toString(m_datePatternString); | |
206 | Q_ASSERT_X(now.toString(m_datePatternString) == m_rollOverSuffix, | |
207 | "DailyRollingFileAppender::computeRollOverTime()", "File name changes within interval"); | |
208 | Q_ASSERT_X(m_rollOverSuffix != m_rollOverTime.toString(m_datePatternString), | |
209 | "DailyRollingFileAppender::computeRollOverTime()", "File name does not change with rollover"); | |
210 | } | |
211 | ||
212 | ||
213 | void RollingFileAppender::rollOver() | |
214 | { | |
215 | Q_ASSERT_X(!m_datePatternString.isEmpty(), "DailyRollingFileAppender::rollOver()", "No active date pattern"); | |
216 | ||
217 | QString rollOverSuffix = m_rollOverSuffix; | |
218 | computeRollOverTime(); | |
219 | if (rollOverSuffix == m_rollOverSuffix) | |
220 | return; | |
221 | ||
222 | closeFile(); | |
223 | ||
224 | QString targetFileName = fileName() + rollOverSuffix; | |
225 | QFile f(targetFileName); | |
226 | if (f.exists() && !f.remove()) | |
227 | return; | |
228 | f.setFileName(fileName()); | |
229 | if (!f.rename(targetFileName)) | |
230 | return; | |
231 | ||
232 | openFile(); | |
233 | removeOldFiles(); | |
234 | } | |
235 | ||
236 | ||
237 | void RollingFileAppender::setLogFilesLimit(int limit) | |
238 | { | |
239 | QMutexLocker locker(&m_rollingMutex); | |
240 | m_logFilesLimit = limit; | |
241 | } | |
242 | ||
243 | ||
244 | int RollingFileAppender::logFilesLimit() const | |
245 | { | |
246 | QMutexLocker locker(&m_rollingMutex); | |
247 | return m_logFilesLimit; | |
248 | } | |
249 | ||
250 | DUTIL_END_NAMESPACE |
0 | #ifndef ROLLINGFILEAPPENDER_H | |
1 | #define ROLLINGFILEAPPENDER_H | |
2 | ||
3 | #include <QDateTime> | |
4 | ||
5 | #include <FileAppender.h> | |
6 | ||
7 | DUTIL_BEGIN_NAMESPACE | |
8 | ||
9 | /*! | |
10 | * \brief The RollingFileAppender class extends FileAppender so that the underlying file is rolled over at a user chosen frequency. | |
11 | * | |
12 | * The class is based on Log4Qt.DailyRollingFileAppender class (http://log4qt.sourceforge.net/) | |
13 | * and has the same date pattern format. | |
14 | * | |
15 | * For example, if the fileName is set to /foo/bar and the DatePattern set to the daily rollover ('.'yyyy-MM-dd'.log'), on 2014-02-16 at midnight, | |
16 | * the logging file /foo/bar.log will be copied to /foo/bar.2014-02-16.log and logging for 2014-02-17 will continue in /foo/bar | |
17 | * until it rolls over the next day. | |
18 | * | |
19 | * The logFilesLimit parameter is used to automatically delete the oldest log files in the directory during rollover | |
20 | * (so no more than logFilesLimit recent log files exist in the directory at any moment). | |
21 | * \sa setDatePattern(DatePattern), setLogFilesLimit(int) | |
22 | */ | |
23 | class CUTELOGGERSHARED_EXPORT RollingFileAppender : public FileAppender | |
24 | { | |
25 | public: | |
26 | /*! | |
27 | * The enum DatePattern defines constants for date patterns. | |
28 | * \sa setDatePattern(DatePattern) | |
29 | */ | |
30 | enum DatePattern | |
31 | { | |
32 | /*! The minutely date pattern string is "'.'yyyy-MM-dd-hh-mm". */ | |
33 | MinutelyRollover = 0, | |
34 | /*! The hourly date pattern string is "'.'yyyy-MM-dd-hh". */ | |
35 | HourlyRollover, | |
36 | /*! The half-daily date pattern string is "'.'yyyy-MM-dd-a". */ | |
37 | HalfDailyRollover, | |
38 | /*! The daily date pattern string is "'.'yyyy-MM-dd". */ | |
39 | DailyRollover, | |
40 | /*! The weekly date pattern string is "'.'yyyy-ww". */ | |
41 | WeeklyRollover, | |
42 | /*! The monthly date pattern string is "'.'yyyy-MM". */ | |
43 | MonthlyRollover | |
44 | }; | |
45 | Q_ENUMS(DatePattern) | |
46 | ||
47 | RollingFileAppender(const QString& fileName = QString()); | |
48 | ||
49 | DatePattern datePattern() const; | |
50 | void setDatePattern(DatePattern datePattern); | |
51 | void setDatePattern(const QString& datePattern); | |
52 | ||
53 | QString datePatternString() const; | |
54 | ||
55 | void setLogFilesLimit(int limit); | |
56 | int logFilesLimit() const; | |
57 | ||
58 | protected: | |
59 | virtual void append(const QDateTime& timeStamp, Logger::LogLevel logLevel, const char* file, int line, | |
60 | const char* function, const QString& category, const QString& message); | |
61 | ||
62 | private: | |
63 | void rollOver(); | |
64 | void computeRollOverTime(); | |
65 | void computeFrequency(); | |
66 | void removeOldFiles(); | |
67 | void setDatePatternString(const QString& datePatternString); | |
68 | ||
69 | QString m_datePatternString; | |
70 | DatePattern m_frequency; | |
71 | ||
72 | QDateTime m_rollOverTime; | |
73 | QString m_rollOverSuffix; | |
74 | int m_logFilesLimit; | |
75 | mutable QMutex m_rollingMutex; | |
76 | }; | |
77 | ||
78 | DUTIL_END_NAMESPACE | |
79 | ||
80 | #endif // ROLLINGFILEAPPENDER_H |
0 | INCLUDEPATH += $$PWD | |
1 | ||
2 | HEADERS += \ | |
3 | $$PWD/RollingFileAppender.h \ | |
4 | $$PWD/Logger.h \ | |
5 | $$PWD/FileAppender.h \ | |
6 | $$PWD/CuteLogger_global.h \ | |
7 | $$PWD/ConsoleAppender.h \ | |
8 | $$PWD/AbstractStringAppender.h \ | |
9 | $$PWD/AbstractAppender.h \ | |
10 | $$PWD/LogManager.h | |
11 | ||
12 | SOURCES += \ | |
13 | $$PWD/RollingFileAppender.cpp \ | |
14 | $$PWD/Logger.cpp \ | |
15 | $$PWD/FileAppender.cpp \ | |
16 | $$PWD/ConsoleAppender.cpp \ | |
17 | $$PWD/AbstractStringAppender.cpp \ | |
18 | $$PWD/AbstractAppender.cpp \ | |
19 | $$PWD/LogManager.cpp | |
20 | ||
21 | win32 { | |
22 | SOURCES += $$PWD/OutputDebugAppender.cpp | |
23 | HEADERS += $$PWD/OutputDebugAppender.h | |
24 | } |
0 | DCOMMON_DIR = $$PWD/../common | |
1 | include($$DCOMMON_DIR/lib.pri) | |
2 | include(dlog/dlog.pri) | |
3 | ||
4 | QT -= gui | |
5 | ||
6 | TARGET = dtkutil | |
7 | ||
8 | DEFINES += LIBDTKUTIL_LIBRARY | |
9 | ||
10 | HEADERS += \ | |
11 | DLog | |
12 | ||
13 | includes.path = $${DTK_INCLUDEPATH}/DUtil | |
14 | includes.files += \ | |
15 | $$system($$DCOMMON_DIR/trheader.sh $$PWD/dlog/DLog) \ | |
16 | $$PWD/dlog/DLog | |
17 | ||
18 | QMAKE_PKGCONFIG_NAME = DTK_UTIL | |
19 | QMAKE_PKGCONFIG_DESCRIPTION = Deepin Tool Kit Util Module | |
20 | QMAKE_PKGCONFIG_INCDIR = $$includes.path |
20 | 20 | |
21 | 21 | #define DUI_DECL_DEPRECATED Q_DECL_DEPRECATED |
22 | 22 | |
23 | #ifndef DTK_NAMESPACE | |
23 | 24 | #define DTK_NAMESPACE Dtk |
25 | #endif | |
26 | ||
24 | 27 | #define DWIDGET_NAMESPACE Widget |
28 | #define DTK_WIDGET_NAMESPACE DTK_NAMESPACE::Widget | |
25 | 29 | |
26 | 30 | #if !defined(DWIDGET_NAMESPACE) |
27 | # define DWIDGET_NAMESPACE_BEGIN | |
28 | # define DWIDGET_NAMESPACE_END | |
29 | # define USE_NAMESPACE_DWIDGET | |
31 | # define DWIDGET_BEGIN_NAMESPACE | |
32 | # define DWIDGET_END_NAMESPACE | |
33 | # define DWIDGET_USE_NAMESPACE | |
30 | 34 | #else |
31 | # define DWIDGET_NAMESPACE_BEGIN namespace DTK_NAMESPACE { namespace DWIDGET_NAMESPACE { | |
32 | # define DWIDGET_NAMESPACE_END }} | |
33 | # define USE_NAMESPACE_DWIDGET using namespace DTK_NAMESPACE::DWIDGET_NAMESPACE; | |
35 | # define DWIDGET_BEGIN_NAMESPACE namespace DTK_NAMESPACE { namespace DWIDGET_NAMESPACE { | |
36 | # define DWIDGET_END_NAMESPACE }} | |
37 | # define DWIDGET_USE_NAMESPACE using namespace DTK_WIDGET_NAMESPACE; | |
34 | 38 | #endif |
35 | 39 | |
36 | 40 | #define D_THEME_INIT_WIDGET(className, propertys...) \ |
11 | 11 | #include "anchors.h" |
12 | 12 | #include "denhancedwidget.h" |
13 | 13 | |
14 | DWIDGET_NAMESPACE_BEGIN | |
14 | DWIDGET_BEGIN_NAMESPACE | |
15 | 15 | |
16 | 16 | class AnchorsBasePrivate |
17 | 17 | { |
1084 | 1084 | QRect::setRight(arg); |
1085 | 1085 | } |
1086 | 1086 | |
1087 | DWIDGET_NAMESPACE_END | |
1087 | DWIDGET_END_NAMESPACE |
18 | 18 | |
19 | 19 | #include "libdui_global.h" |
20 | 20 | |
21 | DWIDGET_NAMESPACE_BEGIN | |
21 | DWIDGET_BEGIN_NAMESPACE | |
22 | 22 | |
23 | 23 | class AnchorsBase; |
24 | 24 | struct AnchorInfo { |
285 | 285 | T *m_widget; |
286 | 286 | }; |
287 | 287 | |
288 | DWIDGET_NAMESPACE_END | |
288 | DWIDGET_END_NAMESPACE | |
289 | 289 | |
290 | 290 | #endif // ANCHORS_H |
8 | 8 | |
9 | 9 | #include "dabstractcomboboxdelegate.h" |
10 | 10 | |
11 | DWIDGET_NAMESPACE_BEGIN | |
11 | DWIDGET_BEGIN_NAMESPACE | |
12 | 12 | |
13 | 13 | DAbstractComboBoxDelegate::DAbstractComboBoxDelegate(QObject *parent) : QStyledItemDelegate(parent) |
14 | 14 | { |
41 | 41 | editor->setGeometry(option.rect); |
42 | 42 | } |
43 | 43 | |
44 | DWIDGET_NAMESPACE_END | |
44 | DWIDGET_END_NAMESPACE |
15 | 15 | |
16 | 16 | #include "dcombobox.h" |
17 | 17 | |
18 | DWIDGET_NAMESPACE_BEGIN | |
18 | DWIDGET_BEGIN_NAMESPACE | |
19 | 19 | |
20 | 20 | class DAbstractComboBoxDelegate : public QStyledItemDelegate |
21 | 21 | { |
28 | 28 | |
29 | 29 | }; |
30 | 30 | |
31 | DWIDGET_NAMESPACE_END | |
31 | DWIDGET_END_NAMESPACE | |
32 | 32 | |
33 | 33 | #endif // DABSTRACTCOMBOBOXDELEGATE_H |
19 | 19 | #include "dabstractdialog.h" |
20 | 20 | #include "private/dabstractdialogprivate_p.h" |
21 | 21 | |
22 | DWIDGET_NAMESPACE_BEGIN | |
22 | DWIDGET_BEGIN_NAMESPACE | |
23 | 23 | |
24 | 24 | DAbstractDialogPrivate::DAbstractDialogPrivate(DAbstractDialog *qq): |
25 | 25 | DObjectPrivate(qq) |
215 | 215 | dd.init(); |
216 | 216 | } |
217 | 217 | |
218 | DWIDGET_NAMESPACE_END | |
218 | DWIDGET_END_NAMESPACE |
19 | 19 | class QPushButton; |
20 | 20 | class QResizeEvent; |
21 | 21 | |
22 | DWIDGET_NAMESPACE_BEGIN | |
22 | DWIDGET_BEGIN_NAMESPACE | |
23 | 23 | |
24 | 24 | class DAbstractDialogPrivate; |
25 | 25 | class DAbstractDialog : public QDialog, public DObject |
71 | 71 | D_DECLARE_PRIVATE(DAbstractDialog) |
72 | 72 | }; |
73 | 73 | |
74 | DWIDGET_NAMESPACE_END | |
74 | DWIDGET_END_NAMESPACE | |
75 | 75 | |
76 | 76 | #endif // DABSTRACTDIALOG_H |
12 | 12 | #include "dthememanager.h" |
13 | 13 | #include "private/dthemehelper.h" |
14 | 14 | |
15 | DWIDGET_NAMESPACE_BEGIN | |
15 | DWIDGET_BEGIN_NAMESPACE | |
16 | 16 | |
17 | 17 | DApplication::DApplication(int &argc, char **argv) : |
18 | 18 | QApplication(argc, argv) |
31 | 31 | themeManager->setTheme(theme); |
32 | 32 | } |
33 | 33 | |
34 | DWIDGET_NAMESPACE_END | |
34 | DWIDGET_END_NAMESPACE |
13 | 13 | |
14 | 14 | #include "libdui_global.h" |
15 | 15 | |
16 | DWIDGET_NAMESPACE_BEGIN | |
16 | DWIDGET_BEGIN_NAMESPACE | |
17 | 17 | |
18 | 18 | class LIBDUISHARED_EXPORT DApplication : public QApplication |
19 | 19 | { |
25 | 25 | void setTheme(const QString & theme); |
26 | 26 | }; |
27 | 27 | |
28 | DWIDGET_NAMESPACE_END | |
28 | DWIDGET_END_NAMESPACE | |
29 | 29 | |
30 | 30 | #endif // DAPPLICATION_H |
9 | 9 | #include "darrowbutton.h" |
10 | 10 | #include "dthememanager.h" |
11 | 11 | |
12 | DWIDGET_NAMESPACE_BEGIN | |
12 | DWIDGET_BEGIN_NAMESPACE | |
13 | 13 | |
14 | 14 | ArrowButtonIcon::ArrowButtonIcon(QWidget *parent) : |
15 | 15 | QLabel(parent) |
172 | 172 | m_pressLabel->setButtonState(state); |
173 | 173 | } |
174 | 174 | |
175 | DWIDGET_NAMESPACE_END | |
175 | DWIDGET_END_NAMESPACE |
19 | 19 | #include "libdui_global.h" |
20 | 20 | #include "dconstants.h" |
21 | 21 | |
22 | DWIDGET_NAMESPACE_BEGIN | |
22 | DWIDGET_BEGIN_NAMESPACE | |
23 | 23 | |
24 | 24 | class ArrowButtonIcon : public QLabel |
25 | 25 | { |
87 | 87 | ArrowButtonState m_buttonState = ArrowStateNormal; |
88 | 88 | }; |
89 | 89 | |
90 | DWIDGET_NAMESPACE_END | |
90 | DWIDGET_END_NAMESPACE | |
91 | 91 | |
92 | 92 | #endif // DARROWBUTTON_H |
11 | 11 | |
12 | 12 | #include <QResizeEvent> |
13 | 13 | |
14 | DWIDGET_NAMESPACE_BEGIN | |
14 | DWIDGET_BEGIN_NAMESPACE | |
15 | 15 | |
16 | 16 | ArrowHeaderLine::ArrowHeaderLine(QWidget *parent) : |
17 | 17 | DHeaderLine(parent) |
82 | 82 | DBaseExpand::resizeEvent(e); |
83 | 83 | } |
84 | 84 | |
85 | DWIDGET_NAMESPACE_END | |
85 | DWIDGET_END_NAMESPACE |
17 | 17 | #include "dbaseline.h" |
18 | 18 | #include "dheaderline.h" |
19 | 19 | |
20 | DWIDGET_NAMESPACE_BEGIN | |
20 | DWIDGET_BEGIN_NAMESPACE | |
21 | 21 | |
22 | 22 | class ArrowHeaderLine : public DHeaderLine |
23 | 23 | { |
54 | 54 | ArrowHeaderLine *m_headerLine = NULL; |
55 | 55 | }; |
56 | 56 | |
57 | DWIDGET_NAMESPACE_END | |
57 | DWIDGET_END_NAMESPACE | |
58 | 58 | |
59 | 59 | #endif // DARROWLINEEXPAND_H |
14 | 14 | #endif |
15 | 15 | #include <QApplication> |
16 | 16 | |
17 | USE_NAMESPACE_DWIDGET | |
17 | DWIDGET_USE_NAMESPACE | |
18 | 18 | |
19 | 19 | DArrowRectangle::DArrowRectangle(ArrowDirection direction, QWidget * parent) : |
20 | 20 | QWidget(parent),m_arrowDirection(direction) |
23 | 23 | #include "dthememanager.h" |
24 | 24 | #include "dgraphicsgloweffect.h" |
25 | 25 | |
26 | DWIDGET_NAMESPACE_BEGIN | |
26 | DWIDGET_BEGIN_NAMESPACE | |
27 | 27 | |
28 | 28 | class LIBDUISHARED_EXPORT DArrowRectangle : public QWidget |
29 | 29 | { |
122 | 122 | QWidget *m_content = NULL; |
123 | 123 | }; |
124 | 124 | |
125 | DWIDGET_NAMESPACE_END | |
125 | DWIDGET_END_NAMESPACE | |
126 | 126 | |
127 | 127 | #endif // DARROWRECTANGLE_H |
9 | 9 | #include "dbasebutton.h" |
10 | 10 | #include "dthememanager.h" |
11 | 11 | |
12 | USE_NAMESPACE_DWIDGET | |
12 | DWIDGET_USE_NAMESPACE | |
13 | 13 | |
14 | 14 | DBaseButton::DBaseButton(QWidget *parent) : |
15 | 15 | QPushButton(parent) |
14 | 14 | #include <QPushButton> |
15 | 15 | #include "libdui_global.h" |
16 | 16 | |
17 | DWIDGET_NAMESPACE_BEGIN | |
17 | DWIDGET_BEGIN_NAMESPACE | |
18 | 18 | |
19 | 19 | class LIBDUISHARED_EXPORT DBaseButton : public QPushButton |
20 | 20 | { |
28 | 28 | void initInsideFrame(); |
29 | 29 | }; |
30 | 30 | |
31 | DWIDGET_NAMESPACE_END | |
31 | DWIDGET_END_NAMESPACE | |
32 | 32 | |
33 | 33 | #endif // DBASEBUTTON_H |
12 | 12 | |
13 | 13 | #include <QResizeEvent> |
14 | 14 | |
15 | DWIDGET_NAMESPACE_BEGIN | |
15 | DWIDGET_BEGIN_NAMESPACE | |
16 | 16 | |
17 | 17 | DBaseExpand::DBaseExpand(QWidget *parent) : QWidget(parent) |
18 | 18 | { |
174 | 174 | } |
175 | 175 | |
176 | 176 | |
177 | DWIDGET_NAMESPACE_END | |
177 | DWIDGET_END_NAMESPACE |
18 | 18 | #include "dseparatorhorizontal.h" |
19 | 19 | #include "dconstants.h" |
20 | 20 | |
21 | DWIDGET_NAMESPACE_BEGIN | |
21 | DWIDGET_BEGIN_NAMESPACE | |
22 | 22 | |
23 | 23 | class ContentLoader : public QFrame |
24 | 24 | { |
65 | 65 | bool m_expand = false; |
66 | 66 | }; |
67 | 67 | |
68 | DWIDGET_NAMESPACE_END | |
68 | DWIDGET_END_NAMESPACE | |
69 | 69 | |
70 | 70 | #endif // DBASEEXPAND_H |
9 | 9 | #include "dbaseline.h" |
10 | 10 | #include "dthememanager.h" |
11 | 11 | |
12 | DWIDGET_NAMESPACE_BEGIN | |
12 | DWIDGET_BEGIN_NAMESPACE | |
13 | 13 | |
14 | 14 | DBaseLine::DBaseLine(QWidget *parent) : QLabel(parent) |
15 | 15 | { |
84 | 84 | return m_rightMargin; |
85 | 85 | } |
86 | 86 | |
87 | DWIDGET_NAMESPACE_END | |
87 | DWIDGET_END_NAMESPACE |
16 | 16 | #include "libdui_global.h" |
17 | 17 | #include "dconstants.h" |
18 | 18 | |
19 | DWIDGET_NAMESPACE_BEGIN | |
19 | DWIDGET_BEGIN_NAMESPACE | |
20 | 20 | |
21 | 21 | class LIBDUISHARED_EXPORT DBaseLine : public QLabel |
22 | 22 | { |
44 | 44 | int m_rightMargin = HEADER_RIGHT_MARGIN; |
45 | 45 | }; |
46 | 46 | |
47 | DWIDGET_NAMESPACE_END | |
47 | DWIDGET_END_NAMESPACE | |
48 | 48 | |
49 | 49 | #endif // DBASELINE_H |
23 | 23 | #include "dboxwidget.h" |
24 | 24 | #include "private/dboxwidget_p.h" |
25 | 25 | |
26 | DWIDGET_NAMESPACE_BEGIN | |
26 | DWIDGET_BEGIN_NAMESPACE | |
27 | 27 | |
28 | 28 | DBoxWidgetPrivate::DBoxWidgetPrivate(DBoxWidget *qq): |
29 | 29 | DObjectPrivate(qq), |
139 | 139 | |
140 | 140 | } |
141 | 141 | |
142 | DWIDGET_NAMESPACE_END | |
142 | DWIDGET_END_NAMESPACE |
14 | 14 | |
15 | 15 | #include "dobject.h" |
16 | 16 | |
17 | DWIDGET_NAMESPACE_BEGIN | |
17 | DWIDGET_BEGIN_NAMESPACE | |
18 | 18 | |
19 | 19 | class DBoxWidgetPrivate; |
20 | 20 | class DBoxWidget : public QFrame, public DObject |
61 | 61 | explicit DVBoxWidget(QWidget *parent = 0); |
62 | 62 | }; |
63 | 63 | |
64 | DWIDGET_NAMESPACE_END | |
64 | DWIDGET_END_NAMESPACE | |
65 | 65 | |
66 | 66 | #endif // DBOXWIDGET_H |
18 | 18 | #include <QLabel> |
19 | 19 | #include <QDebug> |
20 | 20 | |
21 | DWIDGET_NAMESPACE_BEGIN | |
21 | DWIDGET_BEGIN_NAMESPACE | |
22 | 22 | |
23 | 23 | #include "dwindowclosebutton.h" |
24 | 24 | |
432 | 432 | |
433 | 433 | } |
434 | 434 | |
435 | DWIDGET_NAMESPACE_END | |
435 | DWIDGET_END_NAMESPACE |
21 | 21 | class QLabel; |
22 | 22 | |
23 | 23 | |
24 | DWIDGET_NAMESPACE_BEGIN | |
24 | DWIDGET_BEGIN_NAMESPACE | |
25 | 25 | |
26 | 26 | |
27 | 27 | class ImageButton: public QPushButton |
138 | 138 | void clearData(); |
139 | 139 | }; |
140 | 140 | |
141 | DWIDGET_NAMESPACE_END | |
141 | DWIDGET_END_NAMESPACE | |
142 | 142 | |
143 | 143 | #endif // DBUTTONGRID_H |
81 | 81 | } |
82 | 82 | |
83 | 83 | |
84 | DWIDGET_NAMESPACE_BEGIN | |
84 | DWIDGET_BEGIN_NAMESPACE | |
85 | 85 | |
86 | 86 | DButtonList::DButtonList(QWidget *parent) : QListWidget(parent) |
87 | 87 | { |
217 | 217 | } |
218 | 218 | |
219 | 219 | |
220 | DWIDGET_NAMESPACE_END | |
220 | DWIDGET_END_NAMESPACE |
47 | 47 | }; |
48 | 48 | |
49 | 49 | |
50 | DWIDGET_NAMESPACE_BEGIN | |
50 | DWIDGET_BEGIN_NAMESPACE | |
51 | 51 | |
52 | 52 | class LIBDUISHARED_EXPORT DButtonList : public QListWidget |
53 | 53 | { |
90 | 90 | }; |
91 | 91 | |
92 | 92 | |
93 | DWIDGET_NAMESPACE_END | |
93 | DWIDGET_END_NAMESPACE | |
94 | 94 | |
95 | 95 | #endif // DBUTTONLIST_H |
16 | 16 | #include <QResizeEvent> |
17 | 17 | #include <QDebug> |
18 | 18 | |
19 | DWIDGET_NAMESPACE_BEGIN | |
19 | DWIDGET_BEGIN_NAMESPACE | |
20 | 20 | |
21 | 21 | DCalendar::DCalendar(QWidget *parent) : QWidget(parent) |
22 | 22 | { |
272 | 272 | m_viewCurrent = m_viewRight; |
273 | 273 | } |
274 | 274 | |
275 | DWIDGET_NAMESPACE_END | |
275 | DWIDGET_END_NAMESPACE |
23 | 23 | class CaLunarDayInfo; |
24 | 24 | class CalendarView; |
25 | 25 | |
26 | DWIDGET_NAMESPACE_BEGIN | |
26 | DWIDGET_BEGIN_NAMESPACE | |
27 | 27 | |
28 | 28 | class LIBDUISHARED_EXPORT DCalendar : public QWidget |
29 | 29 | { |
94 | 94 | QDate m_showDate; |
95 | 95 | }; |
96 | 96 | |
97 | DWIDGET_NAMESPACE_END | |
97 | DWIDGET_END_NAMESPACE | |
98 | 98 | |
99 | 99 | #endif // CALENDARWIDGET_H |
9 | 9 | #include "dcheckbox.h" |
10 | 10 | #include "dthememanager.h" |
11 | 11 | |
12 | DWIDGET_NAMESPACE_BEGIN | |
12 | DWIDGET_BEGIN_NAMESPACE | |
13 | 13 | |
14 | 14 | DCheckBox::DCheckBox(QWidget *parent) : |
15 | 15 | QCheckBox(parent) |
23 | 23 | D_THEME_INIT_WIDGET(DCheckBox) |
24 | 24 | } |
25 | 25 | |
26 | DWIDGET_NAMESPACE_END | |
26 | DWIDGET_END_NAMESPACE |
13 | 13 | |
14 | 14 | #include "libdui_global.h" |
15 | 15 | |
16 | DWIDGET_NAMESPACE_BEGIN | |
16 | DWIDGET_BEGIN_NAMESPACE | |
17 | 17 | |
18 | 18 | class DCheckBox : public QCheckBox |
19 | 19 | { |
23 | 23 | explicit DCheckBox(const QString &text, QWidget *parent=0); |
24 | 24 | }; |
25 | 25 | |
26 | DWIDGET_NAMESPACE_END | |
26 | DWIDGET_END_NAMESPACE | |
27 | 27 | |
28 | 28 | #endif // DCHECKBOX_H |
14 | 14 | #include <QDebug> |
15 | 15 | #include <QVBoxLayout> |
16 | 16 | |
17 | USE_NAMESPACE_DWIDGET | |
17 | DWIDGET_USE_NAMESPACE | |
18 | 18 | |
19 | 19 | DCircleProgressPrivate::DCircleProgressPrivate(DCircleProgress *q) |
20 | 20 | : DObjectPrivate(q) |
17 | 17 | #include <QLabel> |
18 | 18 | #include <QPixmap> |
19 | 19 | |
20 | DWIDGET_NAMESPACE_BEGIN | |
20 | DWIDGET_BEGIN_NAMESPACE | |
21 | 21 | |
22 | 22 | class DCircleProgressPrivate; |
23 | 23 | class LIBDUISHARED_EXPORT DCircleProgress : public QWidget, public DObject |
66 | 66 | D_DECLARE_PRIVATE(DCircleProgress) |
67 | 67 | }; |
68 | 68 | |
69 | DWIDGET_NAMESPACE_END | |
69 | DWIDGET_END_NAMESPACE | |
70 | 70 | |
71 | 71 | #endif // DCIRCLEPROGRESS_H |
9 | 9 | #include "dcolorcombobox.h" |
10 | 10 | #include "private/dcombobox_p.h" |
11 | 11 | |
12 | DWIDGET_NAMESPACE_BEGIN | |
12 | DWIDGET_BEGIN_NAMESPACE | |
13 | 13 | |
14 | 14 | class ColorDelegateItem : public DComboBoxItem |
15 | 15 | { |
173 | 173 | emit currentColorChange(QColor(colorObj["itemColor"].toString())); |
174 | 174 | } |
175 | 175 | |
176 | DWIDGET_NAMESPACE_END | |
176 | DWIDGET_END_NAMESPACE | |
177 | 177 | |
178 | 178 | #include "dcolorcombobox.moc" |
25 | 25 | #include "dcombobox.h" |
26 | 26 | #include "dabstractcomboboxdelegate.h" |
27 | 27 | |
28 | DWIDGET_NAMESPACE_BEGIN | |
28 | DWIDGET_BEGIN_NAMESPACE | |
29 | 29 | |
30 | 30 | class DColorComboBoxPrivate; |
31 | 31 | class LIBDUISHARED_EXPORT DColorComboBox : public DComboBox |
46 | 46 | D_DECLARE_PRIVATE(DColorComboBox) |
47 | 47 | }; |
48 | 48 | |
49 | DWIDGET_NAMESPACE_END | |
49 | DWIDGET_END_NAMESPACE | |
50 | 50 | |
51 | 51 | #endif // DCOLORCOMBOBOX_H |
13 | 13 | #include <QPainter> |
14 | 14 | #include <QMouseEvent> |
15 | 15 | |
16 | DWIDGET_NAMESPACE_BEGIN | |
16 | DWIDGET_BEGIN_NAMESPACE | |
17 | 17 | |
18 | 18 | DColorPicker::DColorPicker(int row, int column, int cellSize, |
19 | 19 | int spacing, int margin, |
295 | 295 | (m_row-1)*(m_cellSize+m_spacing)+m_cellSize+m_margin*2); |
296 | 296 | } |
297 | 297 | |
298 | DWIDGET_NAMESPACE_END | |
298 | DWIDGET_END_NAMESPACE |
14 | 14 | #include <QColor> |
15 | 15 | #include "libdui_global.h" |
16 | 16 | |
17 | DWIDGET_NAMESPACE_BEGIN | |
17 | DWIDGET_BEGIN_NAMESPACE | |
18 | 18 | |
19 | 19 | class DColorPicker : public QFrame |
20 | 20 | { |
97 | 97 | QColor m_selectedBorderColor; |
98 | 98 | }; |
99 | 99 | |
100 | DWIDGET_NAMESPACE_END | |
100 | DWIDGET_END_NAMESPACE | |
101 | 101 | |
102 | 102 | #endif // DCOLORPICKER_H |
16 | 16 | #include "dcombobox.h" |
17 | 17 | #include "dthememanager.h" |
18 | 18 | |
19 | DWIDGET_NAMESPACE_BEGIN | |
19 | DWIDGET_BEGIN_NAMESPACE | |
20 | 20 | |
21 | 21 | DComboBoxPrivate::DComboBoxPrivate(DComboBox *parent) : |
22 | 22 | DObjectPrivate(parent) |
364 | 364 | emit focusChanged(false); |
365 | 365 | } |
366 | 366 | |
367 | DWIDGET_NAMESPACE_END | |
367 | DWIDGET_END_NAMESPACE | |
368 | 368 | |
369 | 369 | #include "moc_dcombobox.cpp" |
22 | 22 | #include "dconstants.h" |
23 | 23 | #include "dcomboboxmodel.h" |
24 | 24 | |
25 | DWIDGET_NAMESPACE_BEGIN | |
25 | DWIDGET_BEGIN_NAMESPACE | |
26 | 26 | |
27 | 27 | class DComboBoxPrivate; |
28 | 28 | |
72 | 72 | Q_PRIVATE_SLOT(d_func(), void _q_slotCurrentIndexChange(int index)) |
73 | 73 | }; |
74 | 74 | |
75 | DWIDGET_NAMESPACE_END | |
75 | DWIDGET_END_NAMESPACE | |
76 | 76 | |
77 | 77 | #endif // DCOMBOBOX_H |
8 | 8 | |
9 | 9 | #include "dcomboboxmodel.h" |
10 | 10 | |
11 | USE_NAMESPACE_DWIDGET | |
11 | DWIDGET_USE_NAMESPACE | |
12 | 12 | |
13 | 13 | DComboBoxModel::DComboBoxModel(QObject *parent) : QAbstractItemModel(parent) |
14 | 14 | { |
18 | 18 | |
19 | 19 | #include "libdui_global.h" |
20 | 20 | |
21 | DWIDGET_NAMESPACE_BEGIN | |
21 | DWIDGET_BEGIN_NAMESPACE | |
22 | 22 | |
23 | 23 | class LIBDUISHARED_EXPORT DComboBoxModel : public QAbstractItemModel |
24 | 24 | { |
48 | 48 | QJsonArray m_dataArray; |
49 | 49 | }; |
50 | 50 | |
51 | DWIDGET_NAMESPACE_END | |
51 | DWIDGET_END_NAMESPACE | |
52 | 52 | |
53 | 53 | #endif // DCOMBOBOXSIMPLEMODEL_H |
19 | 19 | |
20 | 20 | #include "libdui_global.h" |
21 | 21 | |
22 | DWIDGET_NAMESPACE_BEGIN | |
22 | DWIDGET_BEGIN_NAMESPACE | |
23 | 23 | //basis width and height |
24 | 24 | const int BUTTON_HEIGHT = 22; |
25 | 25 | const int EXPAND_HEADER_HEIGHT = 30; |
36 | 36 | const int IMAGE_BUTTON_WIDTH = 24; |
37 | 37 | const int FONT_SIZE = 12; |
38 | 38 | const int NORMAL_RADIUS = 3; |
39 | DWIDGET_NAMESPACE_END | |
39 | DWIDGET_END_NAMESPACE | |
40 | 40 | |
41 | 41 | #endif //DCONSTANTS_H |
24 | 24 | #include "dthememanager.h" |
25 | 25 | #include "dboxwidget.h" |
26 | 26 | |
27 | DWIDGET_NAMESPACE_BEGIN | |
27 | DWIDGET_BEGIN_NAMESPACE | |
28 | 28 | |
29 | 29 | DDialogPrivate::DDialogPrivate(DDialog *qq) : |
30 | 30 | DAbstractDialogPrivate(qq) |
642 | 642 | emit closed(); |
643 | 643 | } |
644 | 644 | |
645 | DWIDGET_NAMESPACE_END | |
645 | DWIDGET_END_NAMESPACE | |
646 | 646 | |
647 | 647 | #include "moc_ddialog.cpp" |
19 | 19 | class QCloseEvent; |
20 | 20 | class QVBoxLayout; |
21 | 21 | |
22 | DWIDGET_NAMESPACE_BEGIN | |
22 | DWIDGET_BEGIN_NAMESPACE | |
23 | 23 | |
24 | 24 | class DDialogPrivate; |
25 | 25 | class DDialog : public DAbstractDialog |
107 | 107 | Q_PRIVATE_SLOT(d_func(), void _q_defaultButtonTriggered()) |
108 | 108 | }; |
109 | 109 | |
110 | DWIDGET_NAMESPACE_END | |
110 | DWIDGET_END_NAMESPACE | |
111 | 111 | |
112 | 112 | #endif // DDIALOG_H |
11 | 11 | |
12 | 12 | #include "denhancedwidget.h" |
13 | 13 | |
14 | DWIDGET_NAMESPACE_BEGIN | |
14 | DWIDGET_BEGIN_NAMESPACE | |
15 | 15 | |
16 | 16 | class DEnhancedWidgetPrivate |
17 | 17 | { |
155 | 155 | } |
156 | 156 | } |
157 | 157 | |
158 | DWIDGET_NAMESPACE_END | |
158 | DWIDGET_END_NAMESPACE |
13 | 13 | |
14 | 14 | #include "libdui_global.h" |
15 | 15 | |
16 | DWIDGET_NAMESPACE_BEGIN | |
16 | DWIDGET_BEGIN_NAMESPACE | |
17 | 17 | |
18 | 18 | class DEnhancedWidgetPrivate; |
19 | 19 | class DEnhancedWidget: public QObject |
55 | 55 | Q_DECLARE_PRIVATE(DEnhancedWidget) |
56 | 56 | }; |
57 | 57 | |
58 | DWIDGET_NAMESPACE_END | |
58 | DWIDGET_END_NAMESPACE | |
59 | 59 | |
60 | 60 | #endif // DENHANCEDWIDGET_H |
8 | 8 | |
9 | 9 | #include "dexpandgroup.h" |
10 | 10 | |
11 | USE_NAMESPACE_DWIDGET | |
11 | DWIDGET_USE_NAMESPACE | |
12 | 12 | |
13 | 13 | DExpandGroup::DExpandGroup(QObject *parent) : QObject(parent) |
14 | 14 | { |
16 | 16 | #include "libdui_global.h" |
17 | 17 | #include "dbaseexpand.h" |
18 | 18 | |
19 | DWIDGET_NAMESPACE_BEGIN | |
19 | DWIDGET_BEGIN_NAMESPACE | |
20 | 20 | |
21 | 21 | class LIBDUISHARED_EXPORT DExpandGroup : public QObject |
22 | 22 | { |
41 | 41 | QMap<int, DBaseExpand *> m_checkedMap; |
42 | 42 | }; |
43 | 43 | |
44 | DWIDGET_NAMESPACE_END | |
44 | DWIDGET_END_NAMESPACE | |
45 | 45 | |
46 | 46 | #endif // EXPANDGROUP_H |
15 | 15 | #include <QScreen> |
16 | 16 | #include <QGuiApplication> |
17 | 17 | |
18 | DWIDGET_NAMESPACE_BEGIN | |
18 | DWIDGET_BEGIN_NAMESPACE | |
19 | 19 | |
20 | 20 | DFileChooserEdit::DFileChooserEdit(QWidget *parent) |
21 | 21 | : DLineEdit(*new DFileChooserEditPrivate(this), parent) |
91 | 91 | q->dialogClosed(code); |
92 | 92 | } |
93 | 93 | |
94 | DWIDGET_NAMESPACE_END | |
94 | DWIDGET_END_NAMESPACE | |
95 | 95 | |
96 | 96 | #include "moc_dfilechooseredit.cpp" |
11 | 11 | |
12 | 12 | #include "dlineedit.h" |
13 | 13 | |
14 | DWIDGET_NAMESPACE_BEGIN | |
14 | DWIDGET_BEGIN_NAMESPACE | |
15 | 15 | |
16 | 16 | class DFileChooserEditPrivate; |
17 | 17 | class LIBDUISHARED_EXPORT DFileChooserEdit : public DLineEdit |
46 | 46 | Q_PRIVATE_SLOT(d_func(), void _q_showFileChooserDialog()) |
47 | 47 | }; |
48 | 48 | |
49 | DWIDGET_NAMESPACE_END | |
49 | DWIDGET_END_NAMESPACE | |
50 | 50 | |
51 | 51 | #endif // DFILECHOOSEREDIT_H |
12 | 12 | #include "dflowlayout.h" |
13 | 13 | #include "private/dflowlayout_p.h" |
14 | 14 | |
15 | DWIDGET_NAMESPACE_BEGIN | |
15 | DWIDGET_BEGIN_NAMESPACE | |
16 | 16 | |
17 | 17 | DFlowLayoutPrivate::DFlowLayoutPrivate(DFlowLayout *qq) : |
18 | 18 | DObjectPrivate(qq) |
384 | 384 | invalidate(); |
385 | 385 | } |
386 | 386 | |
387 | DWIDGET_NAMESPACE_END | |
387 | DWIDGET_END_NAMESPACE |
15 | 15 | |
16 | 16 | #include "dobject.h" |
17 | 17 | |
18 | DWIDGET_NAMESPACE_BEGIN | |
18 | DWIDGET_BEGIN_NAMESPACE | |
19 | 19 | |
20 | 20 | class DFlowLayoutPrivate; |
21 | 21 | class DFlowLayout : public QLayout, public DObject |
78 | 78 | D_DECLARE_PRIVATE(DFlowLayout) |
79 | 79 | }; |
80 | 80 | |
81 | DWIDGET_NAMESPACE_END | |
81 | DWIDGET_END_NAMESPACE | |
82 | 82 | |
83 | 83 | #endif // DFLOWLAYOUT_H |
11 | 11 | #include "dfontcombobox.h" |
12 | 12 | #include "private/dcombobox_p.h" |
13 | 13 | |
14 | DWIDGET_NAMESPACE_BEGIN | |
14 | DWIDGET_BEGIN_NAMESPACE | |
15 | 15 | |
16 | 16 | class FontDelegateItem : public DComboBoxItem |
17 | 17 | { |
110 | 110 | emit currentFontNameChange(nameObj["itemFont"].toString()); |
111 | 111 | } |
112 | 112 | |
113 | DWIDGET_NAMESPACE_END | |
113 | DWIDGET_END_NAMESPACE | |
114 | 114 | |
115 | 115 | #include "dfontcombobox.moc" |
24 | 24 | #include "dcomboboxmodel.h" |
25 | 25 | #include "dabstractcomboboxdelegate.h" |
26 | 26 | |
27 | DWIDGET_NAMESPACE_BEGIN | |
27 | DWIDGET_BEGIN_NAMESPACE | |
28 | 28 | |
29 | 29 | class LIBDUISHARED_EXPORT DFontComboBox : public DComboBox |
30 | 30 | { |
40 | 40 | void onCurrentIndexChange(int index); |
41 | 41 | }; |
42 | 42 | |
43 | DWIDGET_NAMESPACE_END | |
43 | DWIDGET_END_NAMESPACE | |
44 | 44 | |
45 | 45 | #endif // DFONTCOMBOBOX_H |
8 | 8 | |
9 | 9 | #include "dgraphicsgloweffect.h" |
10 | 10 | |
11 | USE_NAMESPACE_DWIDGET | |
11 | DWIDGET_USE_NAMESPACE | |
12 | 12 | |
13 | 13 | DGraphicsGlowEffect::DGraphicsGlowEffect(QObject *parent) : |
14 | 14 | QGraphicsEffect(parent), |
15 | 15 | |
16 | 16 | #include "libdui_global.h" |
17 | 17 | |
18 | DWIDGET_NAMESPACE_BEGIN | |
18 | DWIDGET_BEGIN_NAMESPACE | |
19 | 19 | |
20 | 20 | class LIBDUISHARED_EXPORT DGraphicsGlowEffect : public QGraphicsEffect |
21 | 21 | { |
49 | 49 | QColor m_color; |
50 | 50 | }; |
51 | 51 | |
52 | DWIDGET_NAMESPACE_END | |
52 | DWIDGET_END_NAMESPACE | |
53 | 53 | |
54 | 54 | #endif // DGRAPHICSGLOWEFFECT_H |
9 | 9 | #include "dheaderline.h" |
10 | 10 | #include "dthememanager.h" |
11 | 11 | |
12 | DWIDGET_NAMESPACE_BEGIN | |
12 | DWIDGET_BEGIN_NAMESPACE | |
13 | 13 | |
14 | 14 | DHeaderLine::DHeaderLine(QWidget *parent) : DBaseLine(parent) |
15 | 15 | { |
33 | 33 | setFixedHeight(CONTENT_HEADER_HEIGHT); |
34 | 34 | } |
35 | 35 | |
36 | DWIDGET_NAMESPACE_END | |
36 | DWIDGET_END_NAMESPACE |
15 | 15 | #include "libdui_global.h" |
16 | 16 | #include "dbaseline.h" |
17 | 17 | |
18 | DWIDGET_NAMESPACE_BEGIN | |
18 | DWIDGET_BEGIN_NAMESPACE | |
19 | 19 | |
20 | 20 | class LIBDUISHARED_EXPORT DHeaderLine : public DBaseLine |
21 | 21 | { |
33 | 33 | QLabel *m_titleLabel = NULL; |
34 | 34 | }; |
35 | 35 | |
36 | DWIDGET_NAMESPACE_END | |
36 | DWIDGET_END_NAMESPACE | |
37 | 37 | |
38 | 38 | #endif // DHEADERLINE_H |
11 | 11 | |
12 | 12 | #include "libdui_global.h" |
13 | 13 | |
14 | DWIDGET_NAMESPACE_BEGIN | |
14 | DWIDGET_BEGIN_NAMESPACE | |
15 | 15 | |
16 | 16 | namespace DIALOG { |
17 | 17 | const int DEFAULT_WIDTH = 380; |
31 | 31 | const int BUTTON_LAYOUT_RIGHT_MARGIN = 2; |
32 | 32 | } |
33 | 33 | |
34 | DWIDGET_NAMESPACE_END | |
34 | DWIDGET_END_NAMESPACE | |
35 | 35 | |
36 | 36 | #endif // BUTTON_CONSTANTS_H |
37 | 37 |
13 | 13 | #include <QMouseEvent> |
14 | 14 | #include <QEvent> |
15 | 15 | |
16 | DWIDGET_NAMESPACE_BEGIN | |
16 | DWIDGET_BEGIN_NAMESPACE | |
17 | 17 | |
18 | 18 | DImageButton::DImageButton(QWidget *parent) |
19 | 19 | : QLabel(parent) |
193 | 193 | return m_state; |
194 | 194 | } |
195 | 195 | |
196 | DWIDGET_NAMESPACE_END | |
196 | DWIDGET_END_NAMESPACE |
16 | 16 | |
17 | 17 | #include "libdui_global.h" |
18 | 18 | |
19 | DWIDGET_NAMESPACE_BEGIN | |
19 | DWIDGET_BEGIN_NAMESPACE | |
20 | 20 | |
21 | 21 | class LIBDUISHARED_EXPORT DImageButton : public QLabel |
22 | 22 | { |
81 | 81 | QString m_checkedPic; |
82 | 82 | }; |
83 | 83 | |
84 | DWIDGET_NAMESPACE_END | |
84 | DWIDGET_END_NAMESPACE | |
85 | 85 | |
86 | 86 | #endif // DIMAGEBUTTON_H |
16 | 16 | #include "dlabel.h" |
17 | 17 | #include "dpasswordedit.h" |
18 | 18 | |
19 | DWIDGET_NAMESPACE_BEGIN | |
19 | DWIDGET_BEGIN_NAMESPACE | |
20 | 20 | |
21 | 21 | DInputDialogPrivate::DInputDialogPrivate(DInputDialog *qq) : |
22 | 22 | DDialogPrivate(qq) |
472 | 472 | return dialog.doubleValue(); |
473 | 473 | } |
474 | 474 | |
475 | DWIDGET_NAMESPACE_END | |
475 | DWIDGET_END_NAMESPACE |
15 | 15 | #include "dlineedit.h" |
16 | 16 | #include "dobject.h" |
17 | 17 | |
18 | DWIDGET_NAMESPACE_BEGIN | |
18 | DWIDGET_BEGIN_NAMESPACE | |
19 | 19 | |
20 | 20 | class DInputDialogPrivate; |
21 | 21 | class DInputDialog : public DDialog |
148 | 148 | D_DECLARE_PRIVATE(DInputDialog) |
149 | 149 | }; |
150 | 150 | |
151 | DWIDGET_NAMESPACE_END | |
151 | DWIDGET_END_NAMESPACE | |
152 | 152 | |
153 | 153 | #endif // DINPUTDIALOG_H |
17 | 17 | #include "dipv4lineedit.h" |
18 | 18 | #include "private/dipv4lineedit_p.h" |
19 | 19 | |
20 | DWIDGET_NAMESPACE_BEGIN | |
20 | DWIDGET_BEGIN_NAMESPACE | |
21 | 21 | |
22 | 22 | #define RX_PATTERN_IP "^(2[0-4]\\d|25[0-5]|[01]?\\d\\d?)?$" |
23 | 23 | |
407 | 407 | |
408 | 408 | #include "moc_dipv4lineedit.cpp" |
409 | 409 | |
410 | DWIDGET_NAMESPACE_END | |
410 | DWIDGET_END_NAMESPACE |
11 | 11 | |
12 | 12 | #include "dlineedit.h" |
13 | 13 | |
14 | DWIDGET_NAMESPACE_BEGIN | |
14 | DWIDGET_BEGIN_NAMESPACE | |
15 | 15 | |
16 | 16 | class DIpv4LineEditPrivate; |
17 | 17 | class DIpv4LineEdit : public DLineEdit |
55 | 55 | Q_PRIVATE_SLOT(d_func(), void _q_setIpLineEditText(const QString &)) |
56 | 56 | }; |
57 | 57 | |
58 | DWIDGET_NAMESPACE_END | |
58 | DWIDGET_END_NAMESPACE | |
59 | 59 | |
60 | 60 | #endif // DIPV4LINEEDIT_H |
9 | 9 | #include "dlabel.h" |
10 | 10 | #include "dthememanager.h" |
11 | 11 | |
12 | USE_NAMESPACE_DWIDGET | |
12 | DWIDGET_USE_NAMESPACE | |
13 | 13 | |
14 | 14 | DLabel::DLabel(QWidget *parent, Qt::WindowFlags f) |
15 | 15 | : QLabel(parent, f) |
14 | 14 | |
15 | 15 | #include "libdui_global.h" |
16 | 16 | |
17 | DWIDGET_NAMESPACE_BEGIN | |
17 | DWIDGET_BEGIN_NAMESPACE | |
18 | 18 | |
19 | 19 | class LIBDUISHARED_EXPORT DLabel : public QLabel |
20 | 20 | { |
25 | 25 | DLabel(const QString & text, QWidget * parent = 0, Qt::WindowFlags f = 0); |
26 | 26 | }; |
27 | 27 | |
28 | DWIDGET_NAMESPACE_END | |
28 | DWIDGET_END_NAMESPACE | |
29 | 29 | |
30 | 30 | #endif // DLABEL_H |
14 | 14 | #include <QDebug> |
15 | 15 | #include <QResizeEvent> |
16 | 16 | |
17 | DWIDGET_NAMESPACE_BEGIN | |
17 | DWIDGET_BEGIN_NAMESPACE | |
18 | 18 | |
19 | 19 | DLineEdit::DLineEdit(QWidget *parent) |
20 | 20 | : QLineEdit(parent), |
164 | 164 | m_insideFrame->setFixedWidth(size.width()); |
165 | 165 | } |
166 | 166 | |
167 | DWIDGET_NAMESPACE_END | |
167 | DWIDGET_END_NAMESPACE | |
168 | 168 | |
169 | 169 | #include "moc_dlineedit.cpp" |
14 | 14 | #include "libdui_global.h" |
15 | 15 | #include "dobject.h" |
16 | 16 | |
17 | DWIDGET_NAMESPACE_BEGIN | |
17 | DWIDGET_BEGIN_NAMESPACE | |
18 | 18 | |
19 | 19 | class DLineEditPrivate; |
20 | 20 | class LIBDUISHARED_EXPORT DLineEdit : public QLineEdit, public DObject |
61 | 61 | Q_PRIVATE_SLOT(d_func(), void _q_resizeInsideFrame(const QSize &)) |
62 | 62 | }; |
63 | 63 | |
64 | DWIDGET_NAMESPACE_END | |
64 | DWIDGET_END_NAMESPACE | |
65 | 65 | |
66 | 66 | #endif // DLINEEDIT_H |
9 | 9 | #include "dlinkbutton.h" |
10 | 10 | #include "dthememanager.h" |
11 | 11 | |
12 | DWIDGET_NAMESPACE_BEGIN | |
12 | DWIDGET_BEGIN_NAMESPACE | |
13 | 13 | |
14 | 14 | DLinkButton::DLinkButton(const QString &text, QWidget *parent) : |
15 | 15 | QPushButton(text, parent) |
17 | 17 | D_THEME_INIT_WIDGET(DLinkButton); |
18 | 18 | } |
19 | 19 | |
20 | DWIDGET_NAMESPACE_END | |
20 | DWIDGET_END_NAMESPACE |
13 | 13 | |
14 | 14 | #include "libdui_global.h" |
15 | 15 | |
16 | DWIDGET_NAMESPACE_BEGIN | |
16 | DWIDGET_BEGIN_NAMESPACE | |
17 | 17 | |
18 | 18 | class LIBDUISHARED_EXPORT DLinkButton : public QPushButton |
19 | 19 | { |
23 | 23 | DLinkButton(const QString & text = QString(), QWidget * parent = 0); |
24 | 24 | }; |
25 | 25 | |
26 | DWIDGET_NAMESPACE_END | |
26 | DWIDGET_END_NAMESPACE | |
27 | 27 | |
28 | 28 | #endif // DLINKBUTTON_H |
15 | 15 | #include "private/dlistview_p.h" |
16 | 16 | #include "dflowlayout.h" |
17 | 17 | |
18 | DWIDGET_NAMESPACE_BEGIN | |
18 | DWIDGET_BEGIN_NAMESPACE | |
19 | 19 | |
20 | 20 | class DListItemCreator |
21 | 21 | { |
833 | 833 | |
834 | 834 | #include "moc_dlistview.cpp" |
835 | 835 | |
836 | DWIDGET_NAMESPACE_END | |
836 | DWIDGET_END_NAMESPACE |
14 | 14 | |
15 | 15 | #include "dobject.h" |
16 | 16 | |
17 | DWIDGET_NAMESPACE_BEGIN | |
17 | DWIDGET_BEGIN_NAMESPACE | |
18 | 18 | |
19 | 19 | class DVariantListModel : public QAbstractListModel |
20 | 20 | { |
146 | 146 | Q_PRIVATE_SLOT(d_func(), void _q_onItemPaint(const QStyleOptionViewItem&, const QModelIndex&)) |
147 | 147 | }; |
148 | 148 | |
149 | DWIDGET_NAMESPACE_END | |
149 | DWIDGET_END_NAMESPACE | |
150 | 150 | |
151 | 151 | #endif // DLISTVIEW_H |
16 | 16 | #include "dlistwidget.h" |
17 | 17 | #include "private/dlistwidget_p.h" |
18 | 18 | |
19 | DWIDGET_NAMESPACE_BEGIN | |
19 | DWIDGET_BEGIN_NAMESPACE | |
20 | 20 | |
21 | 21 | DListWidgetPrivate::DListWidgetPrivate(DListWidget *qq): |
22 | 22 | DScrollAreaPrivate(qq), |
540 | 540 | d_func()->init(); |
541 | 541 | } |
542 | 542 | |
543 | DWIDGET_NAMESPACE_END | |
543 | DWIDGET_END_NAMESPACE |
15 | 15 | #include "dscrollarea.h" |
16 | 16 | #include "libdui_global.h" |
17 | 17 | |
18 | DWIDGET_NAMESPACE_BEGIN | |
18 | DWIDGET_BEGIN_NAMESPACE | |
19 | 19 | |
20 | 20 | class DListWidgetPrivate; |
21 | 21 | class DListWidget : public DScrollArea |
112 | 112 | D_DECLARE_PRIVATE(DListWidget) |
113 | 113 | }; |
114 | 114 | |
115 | DWIDGET_NAMESPACE_END | |
115 | DWIDGET_END_NAMESPACE | |
116 | 116 | |
117 | 117 | #endif // DLISTWIDGET_H |
13 | 13 | #include "private/dloadingindicator_p.h" |
14 | 14 | #include "dthememanager.h" |
15 | 15 | |
16 | DWIDGET_NAMESPACE_BEGIN | |
16 | DWIDGET_BEGIN_NAMESPACE | |
17 | 17 | |
18 | 18 | DLoadingIndicatorPrivate::DLoadingIndicatorPrivate(DLoadingIndicator *qq) : |
19 | 19 | DObjectPrivate(qq) |
280 | 280 | } |
281 | 281 | |
282 | 282 | |
283 | DWIDGET_NAMESPACE_END | |
283 | DWIDGET_END_NAMESPACE |
24 | 24 | #include "libdui_global.h" |
25 | 25 | #include "dobject.h" |
26 | 26 | |
27 | DWIDGET_NAMESPACE_BEGIN | |
27 | DWIDGET_BEGIN_NAMESPACE | |
28 | 28 | |
29 | 29 | class DLoadingIndicatorPrivate; |
30 | 30 | class LIBDUISHARED_EXPORT DLoadingIndicator : public QGraphicsView, public DObject |
88 | 88 | D_DECLARE_PRIVATE(DLoadingIndicator) |
89 | 89 | }; |
90 | 90 | |
91 | DWIDGET_NAMESPACE_END | |
91 | DWIDGET_END_NAMESPACE | |
92 | 92 | |
93 | 93 | #endif // DLOADINGINDICATOR_H |
9 | 9 | #include "dobject.h" |
10 | 10 | #include "private/dobject_p.h" |
11 | 11 | |
12 | DWIDGET_NAMESPACE_BEGIN | |
12 | DWIDGET_BEGIN_NAMESPACE | |
13 | 13 | |
14 | 14 | DObjectPrivate::DObjectPrivate(DObject *qq) |
15 | 15 | : q_ptr(qq) |
33 | 33 | |
34 | 34 | } |
35 | 35 | |
36 | DWIDGET_NAMESPACE_END | |
36 | DWIDGET_END_NAMESPACE |
13 | 13 | |
14 | 14 | #include "libdui_global.h" |
15 | 15 | |
16 | DWIDGET_NAMESPACE_BEGIN | |
16 | DWIDGET_BEGIN_NAMESPACE | |
17 | 17 | |
18 | 18 | #define D_DECLARE_PRIVATE(Class) Q_DECLARE_PRIVATE_D(qGetPtrHelper(d_d_ptr),Class) |
19 | 19 | #define D_DECLARE_PUBLIC(Class) Q_DECLARE_PUBLIC(Class) |
36 | 36 | D_DECLARE_PRIVATE(DObject) |
37 | 37 | }; |
38 | 38 | |
39 | DWIDGET_NAMESPACE_END | |
39 | DWIDGET_END_NAMESPACE | |
40 | 40 | |
41 | 41 | #endif // DOBJECT_H |
14 | 14 | #include <QDebug> |
15 | 15 | #include <QResizeEvent> |
16 | 16 | |
17 | DWIDGET_NAMESPACE_BEGIN | |
17 | DWIDGET_BEGIN_NAMESPACE | |
18 | 18 | |
19 | 19 | DOptionPrivate::DOptionPrivate(DOption *q) : |
20 | 20 | DObjectPrivate(q) |
202 | 202 | d->sizeChanged(e); |
203 | 203 | } |
204 | 204 | |
205 | DWIDGET_NAMESPACE_END | |
205 | DWIDGET_END_NAMESPACE | |
206 | 206 | |
207 | 207 | #include "moc_doption.cpp" |
15 | 15 | #include <QFrame> |
16 | 16 | #include <QHBoxLayout> |
17 | 17 | |
18 | DWIDGET_NAMESPACE_BEGIN | |
18 | DWIDGET_BEGIN_NAMESPACE | |
19 | 19 | |
20 | 20 | class DOptionPrivate; |
21 | 21 | class LIBDUISHARED_EXPORT DOption : public QFrame, public DObject |
52 | 52 | void checkedIconChanged(const QString checkedIcon) const; |
53 | 53 | }; |
54 | 54 | |
55 | DWIDGET_NAMESPACE_END | |
55 | DWIDGET_END_NAMESPACE | |
56 | 56 | |
57 | 57 | #endif // DOPTION_H |
14 | 14 | |
15 | 15 | #include <QDebug> |
16 | 16 | |
17 | DWIDGET_NAMESPACE_BEGIN | |
17 | DWIDGET_BEGIN_NAMESPACE | |
18 | 18 | |
19 | 19 | DOptionListPrivate::DOptionListPrivate(DOptionList *q) : |
20 | 20 | DObjectPrivate(q) |
132 | 132 | d->setCurrentSelected(value); |
133 | 133 | } |
134 | 134 | |
135 | DWIDGET_NAMESPACE_END | |
135 | DWIDGET_END_NAMESPACE | |
136 | 136 | |
137 | 137 | #include "moc_doptionlist.cpp" |
15 | 15 | |
16 | 16 | #include <QListWidget> |
17 | 17 | |
18 | DWIDGET_NAMESPACE_BEGIN | |
18 | DWIDGET_BEGIN_NAMESPACE | |
19 | 19 | |
20 | 20 | class DOptionListPrivate; |
21 | 21 | class LIBDUISHARED_EXPORT DOptionList : public QListWidget, public DObject |
37 | 37 | D_PRIVATE_SLOT(void _q_currentItemChanged(QListWidgetItem*,QListWidgetItem*)) |
38 | 38 | }; |
39 | 39 | |
40 | DWIDGET_NAMESPACE_END | |
40 | DWIDGET_END_NAMESPACE | |
41 | 41 | |
42 | 42 | #endif // DOPTIONLIST_H |
12 | 12 | |
13 | 13 | #include <QDebug> |
14 | 14 | |
15 | DWIDGET_NAMESPACE_BEGIN | |
15 | DWIDGET_BEGIN_NAMESPACE | |
16 | 16 | |
17 | 17 | DPasswordEdit::DPasswordEdit(QWidget *parent) |
18 | 18 | : DLineEdit(*new DPasswordEditPrivate(this), parent) |
62 | 62 | q->setEchoMode(q->Normal); |
63 | 63 | } |
64 | 64 | |
65 | DWIDGET_NAMESPACE_END | |
65 | DWIDGET_END_NAMESPACE | |
66 | 66 | |
67 | 67 | #include "moc_dpasswordedit.cpp" |
68 | 68 |
11 | 11 | |
12 | 12 | #include "dlineedit.h" |
13 | 13 | |
14 | DWIDGET_NAMESPACE_BEGIN | |
14 | DWIDGET_BEGIN_NAMESPACE | |
15 | 15 | |
16 | 16 | class DPasswordEditPrivate; |
17 | 17 | class LIBDUISHARED_EXPORT DPasswordEdit : public DLineEdit |
31 | 31 | Q_PRIVATE_SLOT(d_func(), void _q_toggleEchoMode()) |
32 | 32 | }; |
33 | 33 | |
34 | DWIDGET_NAMESPACE_END | |
34 | DWIDGET_END_NAMESPACE | |
35 | 35 | |
36 | 36 | #endif // DPASSWORDEDIT_H |
11 | 11 | |
12 | 12 | #include <QGraphicsPixmapItem> |
13 | 13 | |
14 | DWIDGET_NAMESPACE_BEGIN | |
14 | DWIDGET_BEGIN_NAMESPACE | |
15 | 15 | |
16 | 16 | DPictureSequenceViewPrivate::DPictureSequenceViewPrivate(DPictureSequenceView *q) : |
17 | 17 | DObjectPrivate(q) |
145 | 145 | d->setSingleShot(singleShot); |
146 | 146 | } |
147 | 147 | |
148 | DWIDGET_NAMESPACE_END | |
148 | DWIDGET_END_NAMESPACE | |
149 | 149 | |
150 | 150 | #include "moc_dpicturesequenceview.cpp" |
14 | 14 | |
15 | 15 | #include <QGraphicsView> |
16 | 16 | |
17 | DWIDGET_NAMESPACE_BEGIN | |
17 | DWIDGET_BEGIN_NAMESPACE | |
18 | 18 | |
19 | 19 | class DPictureSequenceViewPrivate; |
20 | 20 | class DPictureSequenceView : public QGraphicsView, public DObject |
42 | 42 | void playEnd() const; |
43 | 43 | }; |
44 | 44 | |
45 | DWIDGET_NAMESPACE_END | |
45 | DWIDGET_END_NAMESPACE | |
46 | 46 | |
47 | 47 | #endif // DPICTURESEQUENCEVIEW_H |
17 | 17 | #include "dscrollbar.h" |
18 | 18 | #include "private/dscrollarea_p.h" |
19 | 19 | |
20 | DWIDGET_NAMESPACE_BEGIN | |
20 | DWIDGET_BEGIN_NAMESPACE | |
21 | 21 | |
22 | 22 | DScrollAreaPrivate::DScrollAreaPrivate(DScrollArea *qq): |
23 | 23 | DObjectPrivate(qq), |
162 | 162 | d_func()->init(); |
163 | 163 | } |
164 | 164 | |
165 | DWIDGET_NAMESPACE_END | |
165 | DWIDGET_END_NAMESPACE |
14 | 14 | #include "libdui_global.h" |
15 | 15 | #include "dobject.h" |
16 | 16 | |
17 | DWIDGET_NAMESPACE_BEGIN | |
17 | DWIDGET_BEGIN_NAMESPACE | |
18 | 18 | |
19 | 19 | class DScrollBar; |
20 | 20 | class DScrollAreaPrivate; |
46 | 46 | D_DECLARE_PRIVATE(DScrollArea) |
47 | 47 | }; |
48 | 48 | |
49 | DWIDGET_NAMESPACE_END | |
49 | DWIDGET_END_NAMESPACE | |
50 | 50 | |
51 | 51 | #endif // DSCROLLAREA_H |
9 | 9 | #include "dscrollbar.h" |
10 | 10 | #include "dthememanager.h" |
11 | 11 | |
12 | DWIDGET_NAMESPACE_BEGIN | |
12 | DWIDGET_BEGIN_NAMESPACE | |
13 | 13 | |
14 | 14 | DScrollBar::DScrollBar(QWidget *parent) : QScrollBar(parent) |
15 | 15 | { |
17 | 17 | } |
18 | 18 | |
19 | 19 | |
20 | DWIDGET_NAMESPACE_END | |
20 | DWIDGET_END_NAMESPACE |
13 | 13 | |
14 | 14 | #include "libdui_global.h" |
15 | 15 | |
16 | DWIDGET_NAMESPACE_BEGIN | |
16 | DWIDGET_BEGIN_NAMESPACE | |
17 | 17 | |
18 | 18 | class LIBDUISHARED_EXPORT DScrollBar : public QScrollBar |
19 | 19 | { |
26 | 26 | public slots: |
27 | 27 | }; |
28 | 28 | |
29 | DWIDGET_NAMESPACE_END | |
29 | DWIDGET_END_NAMESPACE | |
30 | 30 | |
31 | 31 | #endif // DSCROLLBAR_H |
17 | 17 | #include <QResizeEvent> |
18 | 18 | #include <QTimer> |
19 | 19 | |
20 | USE_NAMESPACE_DWIDGET | |
20 | DWIDGET_USE_NAMESPACE | |
21 | 21 | |
22 | 22 | DSearchEdit::DSearchEdit(QWidget *parent) |
23 | 23 | : QFrame(parent) |
17 | 17 | #include "libdui_global.h" |
18 | 18 | #include "dimagebutton.h" |
19 | 19 | |
20 | DWIDGET_NAMESPACE_BEGIN | |
20 | DWIDGET_BEGIN_NAMESPACE | |
21 | 21 | |
22 | 22 | class LIBDUISHARED_EXPORT DSearchEdit : public QFrame |
23 | 23 | { |
66 | 66 | QEasingCurve m_hideCurve = QEasingCurve::InCubic; |
67 | 67 | }; |
68 | 68 | |
69 | DWIDGET_NAMESPACE_END | |
69 | DWIDGET_END_NAMESPACE | |
70 | 70 | |
71 | 71 | #endif // DSEARCHEDIT_H |
13 | 13 | #include <QApplication> |
14 | 14 | #include "dthememanager.h" |
15 | 15 | |
16 | DWIDGET_NAMESPACE_BEGIN | |
16 | DWIDGET_BEGIN_NAMESPACE | |
17 | 17 | |
18 | 18 | DSegmentedHighlight::DSegmentedHighlight(QWidget *parent) : |
19 | 19 | QToolButton(parent) |
289 | 289 | } |
290 | 290 | } |
291 | 291 | |
292 | DWIDGET_NAMESPACE_END | |
292 | DWIDGET_END_NAMESPACE |
17 | 17 | #include <QEasingCurve> |
18 | 18 | #include "libdui_global.h" |
19 | 19 | |
20 | DWIDGET_NAMESPACE_BEGIN | |
20 | DWIDGET_BEGIN_NAMESPACE | |
21 | 21 | |
22 | 22 | class DSegmentedHighlight : public QToolButton |
23 | 23 | { |
85 | 85 | void animationDurationChanged(int animationDuration); |
86 | 86 | }; |
87 | 87 | |
88 | DWIDGET_NAMESPACE_END | |
88 | DWIDGET_END_NAMESPACE | |
89 | 89 | #endif // DSEGMENTEDCONTROL_H |
9 | 9 | #include "dseparatorhorizontal.h" |
10 | 10 | #include "dthememanager.h" |
11 | 11 | |
12 | DWIDGET_NAMESPACE_BEGIN | |
12 | DWIDGET_BEGIN_NAMESPACE | |
13 | 13 | |
14 | 14 | DSeparatorHorizontal::DSeparatorHorizontal(QWidget *parent) : QWidget(parent) |
15 | 15 | { |
35 | 35 | this->setLayout(mainLayout); |
36 | 36 | } |
37 | 37 | |
38 | DWIDGET_NAMESPACE_END | |
38 | DWIDGET_END_NAMESPACE |
14 | 14 | |
15 | 15 | #include "libdui_global.h" |
16 | 16 | |
17 | DWIDGET_NAMESPACE_BEGIN | |
17 | DWIDGET_BEGIN_NAMESPACE | |
18 | 18 | |
19 | 19 | class LIBDUISHARED_EXPORT DSeparatorHorizontal : public QWidget |
20 | 20 | { |
27 | 27 | QWidget *m_bottomRec = NULL; |
28 | 28 | }; |
29 | 29 | |
30 | DWIDGET_NAMESPACE_END | |
30 | DWIDGET_END_NAMESPACE | |
31 | 31 | |
32 | 32 | #endif // DSEPARATORHORIZONTAL_H |
9 | 9 | #include "dseparatorvertical.h" |
10 | 10 | #include "dthememanager.h" |
11 | 11 | |
12 | DWIDGET_NAMESPACE_BEGIN | |
12 | DWIDGET_BEGIN_NAMESPACE | |
13 | 13 | |
14 | 14 | DSeparatorVertical::DSeparatorVertical(QWidget *parent) : QWidget(parent) |
15 | 15 | { |
35 | 35 | this->setLayout(mainLayout); |
36 | 36 | } |
37 | 37 | |
38 | DWIDGET_NAMESPACE_END | |
38 | DWIDGET_END_NAMESPACE |
14 | 14 | |
15 | 15 | #include "libdui_global.h" |
16 | 16 | |
17 | DWIDGET_NAMESPACE_BEGIN | |
17 | DWIDGET_BEGIN_NAMESPACE | |
18 | 18 | |
19 | 19 | class LIBDUISHARED_EXPORT DSeparatorVertical : public QWidget |
20 | 20 | { |
27 | 27 | QWidget *m_rightRec = NULL; |
28 | 28 | }; |
29 | 29 | |
30 | DWIDGET_NAMESPACE_END | |
30 | DWIDGET_END_NAMESPACE | |
31 | 31 | |
32 | 32 | #endif // DSEPARATORVERTICAL_H |
16 | 16 | |
17 | 17 | #include <cctype> |
18 | 18 | |
19 | USE_NAMESPACE_DWIDGET | |
19 | DWIDGET_USE_NAMESPACE | |
20 | 20 | |
21 | 21 | // static const varibles |
22 | 22 | const QString DShortcutEdit::DefaultTips = tr("请输入新的快捷键"); |
18 | 18 | |
19 | 19 | #include "libdui_global.h" |
20 | 20 | |
21 | DWIDGET_NAMESPACE_BEGIN | |
21 | DWIDGET_BEGIN_NAMESPACE | |
22 | 22 | |
23 | 23 | class DShortcutEditLabel; |
24 | 24 | class LIBDUISHARED_EXPORT DShortcutEdit : public QFrame |
96 | 96 | EchoState m_state = Normal; |
97 | 97 | }; |
98 | 98 | |
99 | DWIDGET_NAMESPACE_END | |
99 | DWIDGET_END_NAMESPACE | |
100 | 100 | |
101 | 101 | #endif // DSHORTCUTEDIT_H |
9 | 9 | #include "dsimplecombobox.h" |
10 | 10 | #include "private/dcombobox_p.h" |
11 | 11 | |
12 | DWIDGET_NAMESPACE_BEGIN | |
12 | DWIDGET_BEGIN_NAMESPACE | |
13 | 13 | |
14 | 14 | class SimpleDelegateItem : public DComboBoxItem |
15 | 15 | { |
102 | 102 | emit currentTextChanged(nameObj["itemText"].toString()); |
103 | 103 | } |
104 | 104 | |
105 | DWIDGET_NAMESPACE_END | |
105 | DWIDGET_END_NAMESPACE | |
106 | 106 | |
107 | 107 | #include "dsimplecombobox.moc" |
16 | 16 | #include "dabstractcomboboxdelegate.h" |
17 | 17 | #include "dcombobox.h" |
18 | 18 | |
19 | DWIDGET_NAMESPACE_BEGIN | |
19 | DWIDGET_BEGIN_NAMESPACE | |
20 | 20 | |
21 | 21 | class LIBDUISHARED_EXPORT DSimpleComboBox : public DComboBox |
22 | 22 | { |
34 | 34 | Q_SLOT void onCurrentIndexChange(int index); |
35 | 35 | }; |
36 | 36 | |
37 | DWIDGET_NAMESPACE_END | |
37 | DWIDGET_END_NAMESPACE | |
38 | 38 | |
39 | 39 | #endif // DSIMPLECOMBOBOX_H |
16 | 16 | #include "dslider.h" |
17 | 17 | #include "dthememanager.h" |
18 | 18 | |
19 | DWIDGET_NAMESPACE_BEGIN | |
19 | DWIDGET_BEGIN_NAMESPACE | |
20 | 20 | |
21 | 21 | static const int CustomDrawingLeftPadding = 10; |
22 | 22 | static const int CustomDrawingRightPadding = 10; |
453 | 453 | sliderMax - sliderMin, opt.upsideDown); |
454 | 454 | } |
455 | 455 | |
456 | DWIDGET_NAMESPACE_END | |
456 | DWIDGET_END_NAMESPACE |
13 | 13 | |
14 | 14 | #include "libdui_global.h" |
15 | 15 | |
16 | DWIDGET_NAMESPACE_BEGIN | |
16 | DWIDGET_BEGIN_NAMESPACE | |
17 | 17 | |
18 | 18 | class DSliderPrivate; |
19 | 19 | class LIBDUISHARED_EXPORT DSlider : public QSlider |
83 | 83 | Q_DISABLE_COPY(DSlider) |
84 | 84 | }; |
85 | 85 | |
86 | DWIDGET_NAMESPACE_END | |
86 | DWIDGET_END_NAMESPACE | |
87 | 87 | |
88 | 88 | #endif // DSLIDER_H |
16 | 16 | #include "private/dspinbox_p.h" |
17 | 17 | #include "dimagebutton.h" |
18 | 18 | |
19 | DWIDGET_NAMESPACE_BEGIN | |
19 | DWIDGET_BEGIN_NAMESPACE | |
20 | 20 | |
21 | 21 | DImageButton* DSpinBox_getButton(const QString &image_name) |
22 | 22 | { |
222 | 222 | d_func()->_q_resizeInsideFrame(e->size()); |
223 | 223 | } |
224 | 224 | |
225 | DWIDGET_NAMESPACE_END | |
225 | DWIDGET_END_NAMESPACE |
14 | 14 | #include "libdui_global.h" |
15 | 15 | #include "dobject.h" |
16 | 16 | |
17 | DWIDGET_NAMESPACE_BEGIN | |
17 | DWIDGET_BEGIN_NAMESPACE | |
18 | 18 | |
19 | 19 | class DSpinBoxPrivate; |
20 | 20 | class DSpinBox : public QSpinBox, public DObject |
77 | 77 | double m_defaultValue; |
78 | 78 | }; |
79 | 79 | |
80 | DWIDGET_NAMESPACE_END | |
80 | DWIDGET_END_NAMESPACE | |
81 | 81 | |
82 | 82 | #endif // DSPINBOX_H |
12 | 12 | #include "dstackwidget.h" |
13 | 13 | #include "private/dstackwidget_p.h" |
14 | 14 | |
15 | DWIDGET_NAMESPACE_BEGIN | |
15 | DWIDGET_BEGIN_NAMESPACE | |
16 | 16 | |
17 | 17 | DAbstractStackWidgetTransitionPrivate::DAbstractStackWidgetTransitionPrivate(DAbstractStackWidgetTransition *qq): |
18 | 18 | DObjectPrivate(qq), |
367 | 367 | d_func()->init(); |
368 | 368 | } |
369 | 369 | |
370 | DWIDGET_NAMESPACE_END | |
370 | DWIDGET_END_NAMESPACE |
15 | 15 | #include "dobject.h" |
16 | 16 | #include "libdui_global.h" |
17 | 17 | |
18 | DWIDGET_NAMESPACE_BEGIN | |
18 | DWIDGET_BEGIN_NAMESPACE | |
19 | 19 | |
20 | 20 | class DStackWidget; |
21 | 21 | class DAbstractStackWidgetTransitionPrivate; |
136 | 136 | D_DECLARE_PRIVATE(DStackWidget) |
137 | 137 | }; |
138 | 138 | |
139 | DWIDGET_NAMESPACE_END | |
139 | DWIDGET_END_NAMESPACE | |
140 | 140 | |
141 | 141 | #endif // DSTACKWIDGET_H |
13 | 13 | #include <QDebug> |
14 | 14 | #include "dthememanager.h" |
15 | 15 | |
16 | DWIDGET_NAMESPACE_BEGIN | |
16 | DWIDGET_BEGIN_NAMESPACE | |
17 | 17 | |
18 | 18 | DSwitchButton::DSwitchButton(QWidget *parent) : |
19 | 19 | QFrame(parent), |
192 | 192 | } |
193 | 193 | } |
194 | 194 | |
195 | DWIDGET_NAMESPACE_END | |
195 | DWIDGET_END_NAMESPACE |
15 | 15 | #include <QUrl> |
16 | 16 | #include "libdui_global.h" |
17 | 17 | |
18 | DWIDGET_NAMESPACE_BEGIN | |
18 | DWIDGET_BEGIN_NAMESPACE | |
19 | 19 | |
20 | 20 | class DSwitchButton : public QFrame |
21 | 21 | { |
74 | 74 | QString m_enabledImageSource; |
75 | 75 | }; |
76 | 76 | |
77 | DWIDGET_NAMESPACE_END | |
77 | DWIDGET_END_NAMESPACE | |
78 | 78 | #endif // DSWITCHBUTTON_H |
79 | 79 |
11 | 11 | |
12 | 12 | #include <QResizeEvent> |
13 | 13 | |
14 | DWIDGET_NAMESPACE_BEGIN | |
14 | DWIDGET_BEGIN_NAMESPACE | |
15 | 15 | |
16 | 16 | SwitchHeaderLine::SwitchHeaderLine(QWidget *parent) : |
17 | 17 | DHeaderLine(parent) |
71 | 71 | DBaseExpand::resizeEvent(e); |
72 | 72 | } |
73 | 73 | |
74 | DWIDGET_NAMESPACE_END | |
74 | DWIDGET_END_NAMESPACE |
16 | 16 | #include "dswitchbutton.h" |
17 | 17 | #include "dheaderline.h" |
18 | 18 | |
19 | DWIDGET_NAMESPACE_BEGIN | |
19 | DWIDGET_BEGIN_NAMESPACE | |
20 | 20 | |
21 | 21 | class SwitchHeaderLine : public DHeaderLine |
22 | 22 | { |
55 | 55 | SwitchHeaderLine *m_headerLine = NULL; |
56 | 56 | }; |
57 | 57 | |
58 | DWIDGET_NAMESPACE_END | |
58 | DWIDGET_END_NAMESPACE | |
59 | 59 | |
60 | 60 | #endif // DSWITCHLINEEXPAND_H |
9 | 9 | #include "dtextbutton.h" |
10 | 10 | #include "dthememanager.h" |
11 | 11 | |
12 | DWIDGET_NAMESPACE_BEGIN | |
12 | DWIDGET_BEGIN_NAMESPACE | |
13 | 13 | |
14 | 14 | DTextButton::DTextButton(const QString & text, QWidget * parent) : |
15 | 15 | QPushButton(text, parent) |
22 | 22 | |
23 | 23 | } |
24 | 24 | |
25 | DWIDGET_NAMESPACE_END | |
25 | DWIDGET_END_NAMESPACE |
14 | 14 | |
15 | 15 | #include "libdui_global.h" |
16 | 16 | |
17 | DWIDGET_NAMESPACE_BEGIN | |
17 | DWIDGET_BEGIN_NAMESPACE | |
18 | 18 | |
19 | 19 | class LIBDUISHARED_EXPORT DTextButton : public QPushButton |
20 | 20 | { |
24 | 24 | ~DTextButton(); |
25 | 25 | }; |
26 | 26 | |
27 | DWIDGET_NAMESPACE_END | |
27 | DWIDGET_END_NAMESPACE | |
28 | 28 | |
29 | 29 | #endif // DTEXTBUTTON_H |
13 | 13 | #include "dapplication.h" |
14 | 14 | #include "private/dthemehelper.h" |
15 | 15 | |
16 | DWIDGET_NAMESPACE_BEGIN | |
16 | DWIDGET_BEGIN_NAMESPACE | |
17 | 17 | |
18 | 18 | class DThemeManagerPrivate : public DThemeManager |
19 | 19 | { |
71 | 71 | } |
72 | 72 | |
73 | 73 | |
74 | DWIDGET_NAMESPACE_END | |
74 | DWIDGET_END_NAMESPACE |
15 | 15 | |
16 | 16 | #include "libdui_global.h" |
17 | 17 | |
18 | DWIDGET_NAMESPACE_BEGIN | |
18 | DWIDGET_BEGIN_NAMESPACE | |
19 | 19 | |
20 | 20 | class DThemeManager : public QObject |
21 | 21 | { |
41 | 41 | QString m_theme; |
42 | 42 | }; |
43 | 43 | |
44 | DWIDGET_NAMESPACE_END | |
44 | DWIDGET_END_NAMESPACE | |
45 | 45 | |
46 | 46 | #endif // DTHEMEMANAGER_H |
12 | 12 | |
13 | 13 | #include "dwindowclosebutton.h" |
14 | 14 | |
15 | DWIDGET_NAMESPACE_BEGIN | |
15 | DWIDGET_BEGIN_NAMESPACE | |
16 | 16 | |
17 | 17 | DWindowCloseButton::DWindowCloseButton(QWidget * parent) : |
18 | 18 | DImageButton(parent) |
56 | 56 | this->setPressPic(m_pressedImage); |
57 | 57 | } |
58 | 58 | |
59 | DWIDGET_NAMESPACE_END | |
59 | DWIDGET_END_NAMESPACE | |
60 | 60 | |
61 | 61 |
14 | 14 | |
15 | 15 | #include "dimagebutton.h" |
16 | 16 | |
17 | DWIDGET_NAMESPACE_BEGIN | |
17 | DWIDGET_BEGIN_NAMESPACE | |
18 | 18 | |
19 | 19 | class LIBDUISHARED_EXPORT DWindowCloseButton : public DImageButton |
20 | 20 | { |
41 | 41 | QString m_pressedImage; |
42 | 42 | }; |
43 | 43 | |
44 | DWIDGET_NAMESPACE_END | |
44 | DWIDGET_END_NAMESPACE | |
45 | 45 | |
46 | 46 | #endif // DWINDOWCLOSEBUTTON_H |
12 | 12 | |
13 | 13 | #include "dwindowmaxbutton.h" |
14 | 14 | |
15 | DWIDGET_NAMESPACE_BEGIN | |
15 | DWIDGET_BEGIN_NAMESPACE | |
16 | 16 | |
17 | 17 | DWindowMaxButton::DWindowMaxButton(QWidget * parent) : |
18 | 18 | DImageButton(parent) |
56 | 56 | this->setPressPic(m_pressedImage); |
57 | 57 | } |
58 | 58 | |
59 | DWIDGET_NAMESPACE_END | |
59 | DWIDGET_END_NAMESPACE | |
60 | 60 | |
61 | 61 |
14 | 14 | |
15 | 15 | #include "dimagebutton.h" |
16 | 16 | |
17 | DWIDGET_NAMESPACE_BEGIN | |
17 | DWIDGET_BEGIN_NAMESPACE | |
18 | 18 | |
19 | 19 | class LIBDUISHARED_EXPORT DWindowMaxButton : public DImageButton |
20 | 20 | { |
41 | 41 | QString m_pressedImage; |
42 | 42 | }; |
43 | 43 | |
44 | DWIDGET_NAMESPACE_END | |
44 | DWIDGET_END_NAMESPACE | |
45 | 45 | |
46 | 46 | #endif // DWINDOWMAXBUTTON_H |
14 | 14 | |
15 | 15 | #include "dwindowminbutton.h" |
16 | 16 | |
17 | DWIDGET_NAMESPACE_BEGIN | |
17 | DWIDGET_BEGIN_NAMESPACE | |
18 | 18 | |
19 | 19 | DWindowMinButton::DWindowMinButton(QWidget * parent) : |
20 | 20 | DImageButton(parent) |
58 | 58 | this->setPressPic(m_pressedImage); |
59 | 59 | } |
60 | 60 | |
61 | DWIDGET_NAMESPACE_END | |
61 | DWIDGET_END_NAMESPACE |
11 | 11 | |
12 | 12 | #include "dimagebutton.h" |
13 | 13 | |
14 | DWIDGET_NAMESPACE_BEGIN | |
14 | DWIDGET_BEGIN_NAMESPACE | |
15 | 15 | |
16 | 16 | class LIBDUISHARED_EXPORT DWindowMinButton : public DImageButton |
17 | 17 | { |
38 | 38 | QString m_pressedImage; |
39 | 39 | }; |
40 | 40 | |
41 | DWIDGET_NAMESPACE_END | |
41 | DWIDGET_END_NAMESPACE | |
42 | 42 | |
43 | 43 | #endif // DWINDOWMINBUTTON_H |
12 | 12 | |
13 | 13 | #include "dwindowoptionbutton.h" |
14 | 14 | |
15 | DWIDGET_NAMESPACE_BEGIN | |
15 | DWIDGET_BEGIN_NAMESPACE | |
16 | 16 | |
17 | 17 | DWindowOptionButton::DWindowOptionButton(QWidget * parent) : |
18 | 18 | DImageButton(parent) |
56 | 56 | this->setPressPic(m_pressedImage); |
57 | 57 | } |
58 | 58 | |
59 | DWIDGET_NAMESPACE_END | |
59 | DWIDGET_END_NAMESPACE | |
60 | 60 | |
61 | 61 |
14 | 14 | |
15 | 15 | #include "dimagebutton.h" |
16 | 16 | |
17 | DWIDGET_NAMESPACE_BEGIN | |
17 | DWIDGET_BEGIN_NAMESPACE | |
18 | 18 | |
19 | 19 | class LIBDUISHARED_EXPORT DWindowOptionButton : public DImageButton |
20 | 20 | { |
41 | 41 | QString m_pressedImage; |
42 | 42 | }; |
43 | 43 | |
44 | DWIDGET_NAMESPACE_END | |
44 | DWIDGET_END_NAMESPACE | |
45 | 45 | |
46 | 46 | #endif // DWINDOWOPTIONBUTTON_H |
12 | 12 | |
13 | 13 | #include "dwindowrestorebutton.h" |
14 | 14 | |
15 | DWIDGET_NAMESPACE_BEGIN | |
15 | DWIDGET_BEGIN_NAMESPACE | |
16 | 16 | |
17 | 17 | DWindowRestoreButton::DWindowRestoreButton(QWidget * parent) : |
18 | 18 | DImageButton(parent) |
56 | 56 | this->setPressPic(m_pressedImage); |
57 | 57 | } |
58 | 58 | |
59 | DWIDGET_NAMESPACE_END | |
59 | DWIDGET_END_NAMESPACE | |
60 | 60 | |
61 | 61 |
14 | 14 | |
15 | 15 | #include "dimagebutton.h" |
16 | 16 | |
17 | DWIDGET_NAMESPACE_BEGIN | |
17 | DWIDGET_BEGIN_NAMESPACE | |
18 | 18 | |
19 | 19 | class LIBDUISHARED_EXPORT DWindowRestoreButton : public DImageButton |
20 | 20 | { |
41 | 41 | QString m_pressedImage; |
42 | 42 | }; |
43 | 43 | |
44 | DWIDGET_NAMESPACE_END | |
44 | DWIDGET_END_NAMESPACE | |
45 | 45 | |
46 | 46 | #endif // DWINDOWRESTOREBUTTON_H |
14 | 14 | |
15 | 15 | class QBoxLayout; |
16 | 16 | |
17 | DWIDGET_NAMESPACE_BEGIN | |
17 | DWIDGET_BEGIN_NAMESPACE | |
18 | 18 | |
19 | 19 | class DAbstractDialogPrivate : public DObjectPrivate |
20 | 20 | { |
38 | 38 | Q_DECLARE_PUBLIC(DAbstractDialog) |
39 | 39 | }; |
40 | 40 | |
41 | DWIDGET_NAMESPACE_END | |
41 | DWIDGET_END_NAMESPACE | |
42 | 42 | |
43 | 43 | #endif // DABSTRACTDIALOG_P_H |
44 | 44 |
14 | 14 | |
15 | 15 | class QBoxLayout; |
16 | 16 | |
17 | DWIDGET_NAMESPACE_BEGIN | |
17 | DWIDGET_BEGIN_NAMESPACE | |
18 | 18 | |
19 | 19 | class DBoxWidgetPrivate : public DObjectPrivate |
20 | 20 | { |
27 | 27 | Q_DECLARE_PUBLIC(DBoxWidget) |
28 | 28 | }; |
29 | 29 | |
30 | DWIDGET_NAMESPACE_END | |
30 | DWIDGET_END_NAMESPACE | |
31 | 31 | |
32 | 32 | #endif // DBOXWIDGET_P_H |
33 | 33 |
16 | 16 | |
17 | 17 | #include <QPainter> |
18 | 18 | |
19 | DWIDGET_NAMESPACE_BEGIN | |
19 | DWIDGET_BEGIN_NAMESPACE | |
20 | 20 | |
21 | 21 | class DCircleProgressPrivate : public DObjectPrivate |
22 | 22 | { |
41 | 41 | QColor m_backgroundColor = Qt::darkCyan; |
42 | 42 | }; |
43 | 43 | |
44 | DWIDGET_NAMESPACE_END | |
44 | DWIDGET_END_NAMESPACE | |
45 | 45 | |
46 | 46 | #endif // DCIRCLEPROGRESS_P_H |
12 | 12 | #include "dobject_p.h" |
13 | 13 | #include "dcombobox.h" |
14 | 14 | |
15 | DWIDGET_NAMESPACE_BEGIN | |
15 | DWIDGET_BEGIN_NAMESPACE | |
16 | 16 | |
17 | 17 | class DComboBoxItem; |
18 | 18 | |
75 | 75 | bool m_hovered = false; |
76 | 76 | }; |
77 | 77 | |
78 | DWIDGET_NAMESPACE_END | |
78 | DWIDGET_END_NAMESPACE | |
79 | 79 | |
80 | 80 | #endif // DCOMBOBOX_P_H |
81 | 81 |
16 | 16 | |
17 | 17 | class QHBoxLayout; |
18 | 18 | |
19 | DWIDGET_NAMESPACE_BEGIN | |
19 | DWIDGET_BEGIN_NAMESPACE | |
20 | 20 | |
21 | 21 | class DVBoxWidget; |
22 | 22 | class DHBoxWidget; |
59 | 59 | Q_DECLARE_PUBLIC(DDialog) |
60 | 60 | }; |
61 | 61 | |
62 | DWIDGET_NAMESPACE_END | |
62 | DWIDGET_END_NAMESPACE | |
63 | 63 | |
64 | 64 | #endif // DDIALOG_P_H |
65 | 65 |
15 | 15 | #include "dfilechooseredit.h" |
16 | 16 | #include "dimagebutton.h" |
17 | 17 | |
18 | DWIDGET_NAMESPACE_BEGIN | |
18 | DWIDGET_BEGIN_NAMESPACE | |
19 | 19 | |
20 | 20 | class DFileChooserEditPrivate : DLineEditPrivate |
21 | 21 | { |
32 | 32 | DFileChooserEdit::DialogDisplayPosition dialogDisplayPosition = DFileChooserEdit::FoloowParentWindow; |
33 | 33 | }; |
34 | 34 | |
35 | DWIDGET_NAMESPACE_END | |
35 | DWIDGET_END_NAMESPACE | |
36 | 36 | |
37 | 37 | #endif // DFILECHOOSEREDIT_P_H |
38 | 38 |
14 | 14 | |
15 | 15 | class QLayoutItem; |
16 | 16 | |
17 | DWIDGET_NAMESPACE_BEGIN | |
17 | DWIDGET_BEGIN_NAMESPACE | |
18 | 18 | |
19 | 19 | class DFlowLayoutPrivate : public DObjectPrivate |
20 | 20 | { |
31 | 31 | D_DECLARE_PUBLIC(DFlowLayout) |
32 | 32 | }; |
33 | 33 | |
34 | DWIDGET_NAMESPACE_END | |
34 | DWIDGET_END_NAMESPACE | |
35 | 35 | |
36 | 36 | #endif // DFLOWLAYOUT_P_H |
37 | 37 |
12 | 12 | #include "dinputdialog.h" |
13 | 13 | #include "ddialog_p.h" |
14 | 14 | |
15 | DWIDGET_NAMESPACE_BEGIN | |
15 | DWIDGET_BEGIN_NAMESPACE | |
16 | 16 | |
17 | 17 | class DLabel; |
18 | 18 | class DLineEdit; |
37 | 37 | D_DECLARE_PUBLIC(DInputDialog) |
38 | 38 | }; |
39 | 39 | |
40 | DWIDGET_NAMESPACE_END | |
40 | DWIDGET_END_NAMESPACE | |
41 | 41 | |
42 | 42 | #endif // DINPUTDIALOG_P_H |
43 | 43 |
12 | 12 | #include "dlineedit_p.h" |
13 | 13 | #include "dipv4lineedit.h" |
14 | 14 | |
15 | DWIDGET_NAMESPACE_BEGIN | |
15 | DWIDGET_BEGIN_NAMESPACE | |
16 | 16 | |
17 | 17 | class DIpv4LineEditPrivate : public DLineEditPrivate |
18 | 18 | { |
36 | 36 | D_DECLARE_PUBLIC(DIpv4LineEdit) |
37 | 37 | }; |
38 | 38 | |
39 | DWIDGET_NAMESPACE_END | |
39 | DWIDGET_END_NAMESPACE | |
40 | 40 | |
41 | 41 | #endif // DIPV4LINEEDIT_P_H |
42 | 42 |
15 | 15 | |
16 | 16 | #include <QHBoxLayout> |
17 | 17 | |
18 | DWIDGET_NAMESPACE_BEGIN | |
18 | DWIDGET_BEGIN_NAMESPACE | |
19 | 19 | |
20 | 20 | class DLineEditPrivate : public DObjectPrivate |
21 | 21 | { |
38 | 38 | QHBoxLayout *m_centeralHLayout; |
39 | 39 | }; |
40 | 40 | |
41 | DWIDGET_NAMESPACE_END | |
41 | DWIDGET_END_NAMESPACE | |
42 | 42 | |
43 | 43 | #endif // DLINEEDIT_P_H |
44 | 44 |
12 | 12 | #include "dobject_p.h" |
13 | 13 | #include "dlistview.h" |
14 | 14 | |
15 | DWIDGET_NAMESPACE_BEGIN | |
15 | DWIDGET_BEGIN_NAMESPACE | |
16 | 16 | |
17 | 17 | class DListItemCreator; |
18 | 18 | class DBoxWidget; |
58 | 58 | D_DECLARE_PUBLIC(DListView) |
59 | 59 | }; |
60 | 60 | |
61 | DWIDGET_NAMESPACE_END | |
61 | DWIDGET_END_NAMESPACE | |
62 | 62 | |
63 | 63 | #endif // DLISTVIEW_P_H |
64 | 64 |
15 | 15 | |
16 | 16 | class QVBoxLayout; |
17 | 17 | |
18 | DWIDGET_NAMESPACE_BEGIN | |
18 | DWIDGET_BEGIN_NAMESPACE | |
19 | 19 | |
20 | 20 | class DListWidgetPrivate : public DScrollAreaPrivate |
21 | 21 | { |
42 | 42 | D_DECLARE_PUBLIC(DListWidget) |
43 | 43 | }; |
44 | 44 | |
45 | DWIDGET_NAMESPACE_END | |
45 | DWIDGET_END_NAMESPACE | |
46 | 46 | |
47 | 47 | #endif // DLISTWIDGET_P_H |
48 | 48 |
12 | 12 | #include "dloadingindicator.h" |
13 | 13 | #include "dobject_p.h" |
14 | 14 | |
15 | DWIDGET_NAMESPACE_BEGIN | |
15 | DWIDGET_BEGIN_NAMESPACE | |
16 | 16 | |
17 | 17 | class DLoadingIndicatorPrivate : public DObjectPrivate |
18 | 18 | { |
30 | 30 | D_DECLARE_PUBLIC(DLoadingIndicator) |
31 | 31 | }; |
32 | 32 | |
33 | DWIDGET_NAMESPACE_END | |
33 | DWIDGET_END_NAMESPACE | |
34 | 34 | |
35 | 35 | #endif // DLOADINGINDICATOR_P |
36 | 36 |
12 | 12 | #include "libdui_global.h" |
13 | 13 | #include "dobject.h" |
14 | 14 | |
15 | DWIDGET_NAMESPACE_BEGIN | |
15 | DWIDGET_BEGIN_NAMESPACE | |
16 | 16 | |
17 | 17 | class DObjectPrivate |
18 | 18 | { |
27 | 27 | Q_DECLARE_PUBLIC(DObject) |
28 | 28 | }; |
29 | 29 | |
30 | DWIDGET_NAMESPACE_END | |
30 | DWIDGET_END_NAMESPACE | |
31 | 31 | |
32 | 32 | #endif // DOBJECT_P_H |
33 | 33 |
16 | 16 | #include <QHBoxLayout> |
17 | 17 | #include <QListWidgetItem> |
18 | 18 | |
19 | DWIDGET_NAMESPACE_BEGIN | |
19 | DWIDGET_BEGIN_NAMESPACE | |
20 | 20 | |
21 | 21 | class DOptionPrivate : public DObjectPrivate |
22 | 22 | { |
56 | 56 | QHBoxLayout *m_layout; |
57 | 57 | }; |
58 | 58 | |
59 | DWIDGET_NAMESPACE_END | |
59 | DWIDGET_END_NAMESPACE | |
60 | 60 | |
61 | 61 | #endif // DOPTION_P_H |
62 | 62 |
16 | 16 | #include <QList> |
17 | 17 | #include <QListWidgetItem> |
18 | 18 | |
19 | DWIDGET_NAMESPACE_BEGIN | |
19 | DWIDGET_BEGIN_NAMESPACE | |
20 | 20 | |
21 | 21 | class DOptionListPrivate : public DObjectPrivate |
22 | 22 | { |
38 | 38 | QMap<QListWidgetItem *, DOption *> m_optionList; |
39 | 39 | }; |
40 | 40 | |
41 | DWIDGET_NAMESPACE_END | |
41 | DWIDGET_END_NAMESPACE | |
42 | 42 | |
43 | 43 | #endif // DOPTIONLIST_P_H |
12 | 12 | #include "dlineedit_p.h" |
13 | 13 | #include "dpasswordedit.h" |
14 | 14 | |
15 | DWIDGET_NAMESPACE_BEGIN | |
15 | DWIDGET_BEGIN_NAMESPACE | |
16 | 16 | |
17 | 17 | class DPasswordEditPrivate : DLineEditPrivate |
18 | 18 | { |
27 | 27 | Q_DECLARE_PUBLIC(DPasswordEdit) |
28 | 28 | }; |
29 | 29 | |
30 | DWIDGET_NAMESPACE_END | |
30 | DWIDGET_END_NAMESPACE | |
31 | 31 | |
32 | 32 | #endif // DPASSWORDEDIT_P_H |
33 | 33 |
16 | 16 | #include <QGraphicsScene> |
17 | 17 | #include <QTimer> |
18 | 18 | |
19 | DWIDGET_NAMESPACE_BEGIN | |
19 | DWIDGET_BEGIN_NAMESPACE | |
20 | 20 | |
21 | 21 | class DPictureSequenceViewPrivate : public DObjectPrivate |
22 | 22 | { |
52 | 52 | QList<QGraphicsPixmapItem *> m_pictureList; |
53 | 53 | }; |
54 | 54 | |
55 | DWIDGET_NAMESPACE_END | |
55 | DWIDGET_END_NAMESPACE | |
56 | 56 | |
57 | 57 | #endif // DPICTURESEQUENCEVIEW_P_H |
58 | 58 |
15 | 15 | |
16 | 16 | class QPropertyAnimation; |
17 | 17 | |
18 | DWIDGET_NAMESPACE_BEGIN | |
18 | DWIDGET_BEGIN_NAMESPACE | |
19 | 19 | |
20 | 20 | class DScrollAreaPrivate : public DObjectPrivate |
21 | 21 | { |
35 | 35 | D_DECLARE_PUBLIC(DScrollArea) |
36 | 36 | }; |
37 | 37 | |
38 | DWIDGET_NAMESPACE_END | |
38 | DWIDGET_END_NAMESPACE | |
39 | 39 | |
40 | 40 | #endif // DSCROLLAREA_P_H |
15 | 15 | class QFrame; |
16 | 16 | class QLabel; |
17 | 17 | |
18 | DWIDGET_NAMESPACE_BEGIN | |
18 | DWIDGET_BEGIN_NAMESPACE | |
19 | 19 | |
20 | 20 | class DImageButton; |
21 | 21 | class DSpinBoxPrivate : public DObjectPrivate |
48 | 48 | D_DECLARE_PUBLIC(DDoubleSpinBox) |
49 | 49 | }; |
50 | 50 | |
51 | DWIDGET_NAMESPACE_END | |
51 | DWIDGET_END_NAMESPACE | |
52 | 52 | |
53 | 53 | #endif // DSPINBOX_P_H |
54 | 54 |
15 | 15 | |
16 | 16 | class QStackedLayout; |
17 | 17 | |
18 | DWIDGET_NAMESPACE_BEGIN | |
18 | DWIDGET_BEGIN_NAMESPACE | |
19 | 19 | |
20 | 20 | class DAbstractStackWidgetTransitionPrivate : public DObjectPrivate |
21 | 21 | { |
47 | 47 | D_DECLARE_PUBLIC(DStackWidget) |
48 | 48 | }; |
49 | 49 | |
50 | DWIDGET_NAMESPACE_END | |
50 | DWIDGET_END_NAMESPACE | |
51 | 51 | |
52 | 52 | #endif // DSTACKWIDGET_P |
53 | 53 |