1
/***************************************************************************
2
* Copyright (c) 2002 Jürgen Riegel <juergen.riegel@web.de> *
4
* This file is part of the FreeCAD CAx development system. *
6
* This program is free software; you can redistribute it and/or modify *
7
* it under the terms of the GNU Library General Public License (LGPL) *
8
* as published by the Free Software Foundation; either version 2 of *
9
* the License, or (at your option) any later version. *
10
* for detail see the LICENCE text file. *
12
* FreeCAD is distributed in the hope that it will be useful, *
13
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
14
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15
* GNU Library General Public License for more details. *
17
* You should have received a copy of the GNU Library General Public *
18
* License along with FreeCAD; if not, write to the Free Software *
19
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
22
***************************************************************************/
24
#include "PreCompiled.h"
27
#if defined(FC_OS_WIN32)
29
#elif defined(FC_OS_LINUX) || defined(FC_OS_MACOSX)
38
#include "PyObjectBase.h"
39
#include <QCoreApplication>
45
//=========================================================================
50
class ConsoleEvent: public QEvent
53
ConsoleSingleton::FreeCAD_ConsoleMsgType msgtype;
54
IntendedRecipient recipient;
59
ConsoleEvent(ConsoleSingleton::FreeCAD_ConsoleMsgType type,
60
IntendedRecipient recipient,
62
const std::string& notifier,
63
const std::string& msg)
64
: QEvent(QEvent::User)
66
, recipient(recipient)
73
class ConsoleOutput: public QObject // clazy:exclude=missing-qobject-macro
76
static ConsoleOutput* getInstance()
79
instance = new ConsoleOutput;
83
static void destruct()
89
void customEvent(QEvent* ev) override
91
if (ev->type() == QEvent::User) {
92
ConsoleEvent* ce = static_cast<ConsoleEvent*>(ev);
93
switch (ce->msgtype) {
94
case ConsoleSingleton::MsgType_Txt:
95
Console().notifyPrivate(LogStyle::Message,
101
case ConsoleSingleton::MsgType_Log:
102
Console().notifyPrivate(LogStyle::Log,
108
case ConsoleSingleton::MsgType_Wrn:
109
Console().notifyPrivate(LogStyle::Warning,
115
case ConsoleSingleton::MsgType_Err:
116
Console().notifyPrivate(LogStyle::Error,
122
case ConsoleSingleton::MsgType_Critical:
123
Console().notifyPrivate(LogStyle::Critical,
129
case ConsoleSingleton::MsgType_Notification:
130
Console().notifyPrivate(LogStyle::Notification,
141
static ConsoleOutput* instance; // NOLINT
144
ConsoleOutput* ConsoleOutput::instance = nullptr; // NOLINT
148
//**************************************************************************
149
// Construction destruction
152
ConsoleSingleton::ConsoleSingleton()
154
: _defaultLogLevel(FC_LOGLEVEL_LOG)
156
: _defaultLogLevel(FC_LOGLEVEL_MSG)
160
ConsoleSingleton::~ConsoleSingleton()
162
ConsoleOutput::destruct();
163
for (ILogger* Iter : _aclObservers) {
169
//**************************************************************************
173
* sets the console in a special mode
175
void ConsoleSingleton::SetConsoleMode(ConsoleMode mode)
177
if (mode & Verbose) {
183
* unsets the console from a special mode
185
void ConsoleSingleton::UnsetConsoleMode(ConsoleMode mode)
187
if (mode & Verbose) {
193
* \a type can be OR'ed with any of the FreeCAD_ConsoleMsgType flags to enable -- if \a b is true --
194
* or to disable -- if \a b is false -- a console observer with name \a sObs.
195
* The return value is an OR'ed value of all message types that have changed their state. For
198
* // switch off warnings and error messages
199
* ConsoleMsgFlags ret = Base::Console().SetEnabledMsgType("myObs",
200
* Base:ConsoleSingleton::MsgType_Wrn|Base::ConsoleSingleton::MsgType_Err,
202
* // do something without notifying observer myObs
204
* // restore the former configuration again
205
* Base::Console().SetEnabledMsgType("myObs", ret, true);
207
* switches off warnings and error messages and restore the state before the modification.
208
* If the observer \a sObs doesn't exist then nothing happens.
210
ConsoleMsgFlags ConsoleSingleton::SetEnabledMsgType(const char* sObs, ConsoleMsgFlags type, bool on)
212
ILogger* pObs = Get(sObs);
214
ConsoleMsgFlags flags = 0;
216
if (type & MsgType_Err) {
217
if (pObs->bErr != on) {
218
flags |= MsgType_Err;
222
if (type & MsgType_Wrn) {
223
if (pObs->bWrn != on) {
224
flags |= MsgType_Wrn;
228
if (type & MsgType_Txt) {
229
if (pObs->bMsg != on) {
230
flags |= MsgType_Txt;
234
if (type & MsgType_Log) {
235
if (pObs->bLog != on) {
236
flags |= MsgType_Log;
240
if (type & MsgType_Critical) {
241
if (pObs->bCritical != on) {
242
flags |= MsgType_Critical;
244
pObs->bCritical = on;
246
if (type & MsgType_Notification) {
247
if (pObs->bNotification != on) {
248
flags |= MsgType_Notification;
250
pObs->bNotification = on;
259
bool ConsoleSingleton::IsMsgTypeEnabled(const char* sObs, FreeCAD_ConsoleMsgType type) const
261
ILogger* pObs = Get(sObs);
272
case MsgType_Critical:
273
return pObs->bCritical;
274
case MsgType_Notification:
275
return pObs->bNotification;
284
void ConsoleSingleton::SetConnectionMode(ConnectionMode mode)
286
connectionMode = mode;
288
// make sure this method gets called from the main thread
289
if (connectionMode == Queued) {
290
ConsoleOutput::getInstance();
294
//**************************************************************************
297
/** Attaches an Observer to Console
298
* Use this method to attach a ILogger derived class to
299
* the Console. After the observer is attached all messages will also
300
* be forwarded to it.
303
void ConsoleSingleton::AttachObserver(ILogger* pcObserver)
306
assert(_aclObservers.find(pcObserver) == _aclObservers.end());
308
_aclObservers.insert(pcObserver);
311
/** Detaches an Observer from Console
312
* Use this method to detach a ILogger derived class.
313
* After detaching you can destruct the Observer or reinsert it later.
316
void ConsoleSingleton::DetachObserver(ILogger* pcObserver)
318
_aclObservers.erase(pcObserver);
321
void Base::ConsoleSingleton::notifyPrivate(LogStyle category,
322
IntendedRecipient recipient,
324
const std::string& notifiername,
325
const std::string& msg)
327
for (ILogger* Iter : _aclObservers) {
328
if (Iter->isActive(category)) {
329
Iter->SendLog(notifiername,
333
content); // send string to the listener
338
void ConsoleSingleton::postEvent(ConsoleSingleton::FreeCAD_ConsoleMsgType type,
339
IntendedRecipient recipient,
341
const std::string& notifiername,
342
const std::string& msg)
344
QCoreApplication::postEvent(ConsoleOutput::getInstance(),
345
new ConsoleEvent(type, recipient, content, notifiername, msg));
348
ILogger* ConsoleSingleton::Get(const char* Name) const
350
const char* OName {};
351
for (ILogger* Iter : _aclObservers) {
352
OName = Iter->Name(); // get the name
353
if (OName && strcmp(OName, Name) == 0) {
360
int* ConsoleSingleton::GetLogLevel(const char* tag, bool create)
365
if (_logLevels.find(tag) != _logLevels.end()) {
366
return &_logLevels[tag];
371
int& ret = _logLevels[tag];
376
void ConsoleSingleton::Refresh()
379
qApp->processEvents(QEventLoop::ExcludeUserInputEvents);
383
void ConsoleSingleton::EnableRefresh(bool enable)
385
_bCanRefresh = enable;
388
//**************************************************************************
391
ConsoleSingleton* ConsoleSingleton::_pcSingleton = nullptr;
393
void ConsoleSingleton::Destruct()
395
// not initialized or double destructed!
396
assert(_pcSingleton);
398
_pcSingleton = nullptr;
401
ConsoleSingleton& ConsoleSingleton::Instance()
405
_pcSingleton = new ConsoleSingleton();
407
return *_pcSingleton;
410
//**************************************************************************
413
// ConsoleSingleton Methods structure
414
PyMethodDef ConsoleSingleton::Methods[] = {
416
ConsoleSingleton::sPyMessage,
418
"PrintMessage(obj) -> None\n\n"
419
"Print a message to the output.\n\n"
420
"obj : object\n The string representation is printed."},
422
ConsoleSingleton::sPyLog,
424
"PrintLog(obj) -> None\n\n"
425
"Print a log message to the output.\n\n"
426
"obj : object\n The string representation is printed."},
428
ConsoleSingleton::sPyError,
430
"PrintError(obj) -> None\n\n"
431
"Print an error message to the output.\n\n"
432
"obj : object\n The string representation is printed."},
433
{"PrintDeveloperError",
434
ConsoleSingleton::sPyDeveloperError,
436
"PrintDeveloperError(obj) -> None\n\n"
437
"Print an error message intended only for Developers to the output.\n\n"
438
"obj : object\n The string representation is printed."},
440
ConsoleSingleton::sPyUserError,
442
"PrintUserError(obj) -> None\n\n"
443
"Print an error message intended only for the User to the output.\n\n"
444
"obj : object\n The string representation is printed."},
445
{"PrintTranslatedUserError",
446
ConsoleSingleton::sPyTranslatedUserError,
448
"PrintTranslatedUserError(obj) -> None\n\n"
449
"Print an already translated error message intended only for the User to the output.\n\n"
450
"obj : object\n The string representation is printed."},
452
ConsoleSingleton::sPyWarning,
454
"PrintWarning(obj) -> None\n\n"
455
"Print a warning message to the output.\n\n"
456
"obj : object\n The string representation is printed."},
457
{"PrintDeveloperWarning",
458
ConsoleSingleton::sPyDeveloperWarning,
460
"PrintDeveloperWarning(obj) -> None\n\n"
461
"Print an warning message intended only for Developers to the output.\n\n"
462
"obj : object\n The string representation is printed."},
464
ConsoleSingleton::sPyUserWarning,
466
"PrintUserWarning(obj) -> None\n\n"
467
"Print a warning message intended only for the User to the output.\n\n"
468
"obj : object\n The string representation is printed."},
469
{"PrintTranslatedUserWarning",
470
ConsoleSingleton::sPyTranslatedUserWarning,
472
"PrintTranslatedUserWarning(obj) -> None\n\n"
473
"Print an already translated warning message intended only for the User to the output.\n\n"
474
"obj : object\n The string representation is printed."},
476
ConsoleSingleton::sPyCritical,
478
"PrintCritical(obj) -> None\n\n"
479
"Print a critical message to the output.\n\n"
480
"obj : object\n The string representation is printed."},
481
{"PrintNotification",
482
ConsoleSingleton::sPyNotification,
484
"PrintNotification(obj) -> None\n\n"
485
"Print a user notification to the output.\n\n"
486
"obj : object\n The string representation is printed."},
487
{"PrintTranslatedNotification",
488
ConsoleSingleton::sPyTranslatedNotification,
490
"PrintTranslatedNotification(obj) -> None\n\n"
491
"Print an already translated notification to the output.\n\n"
492
"obj : object\n The string representation is printed."},
494
ConsoleSingleton::sPySetStatus,
496
"SetStatus(observer, type, status) -> None\n\n"
497
"Set the status for either 'Log', 'Msg', 'Wrn' or 'Error' for an observer.\n\n"
498
"observer : str\n Logging interface name.\n"
499
"type : str\n Message type.\n"
502
ConsoleSingleton::sPyGetStatus,
504
"GetStatus(observer, type) -> bool or None\n\n"
505
"Get the status for either 'Log', 'Msg', 'Wrn' or 'Error' for an observer.\n"
506
"Returns None if the specified observer doesn't exist.\n\n"
507
"observer : str\n Logging interface name.\n"
508
"type : str\n Message type."},
510
ConsoleSingleton::sPyGetObservers,
512
"GetObservers() -> list of str\n\n"
513
"Get the names of the current logging interfaces."},
514
{nullptr, nullptr, 0, nullptr} /* Sentinel */
519
PyObject* FC_PYCONSOLE_MSG(std::function<void(const char*, const char*)> func, PyObject* args)
522
PyObject* notifier {};
524
const char* notifierStr = "";
526
auto retrieveString = [](PyObject* pystr) {
527
PyObject* unicode = nullptr;
529
const char* outstr = nullptr;
531
if (PyUnicode_Check(pystr)) {
532
outstr = PyUnicode_AsUTF8(pystr);
535
unicode = PyObject_Str(pystr);
537
outstr = PyUnicode_AsUTF8(unicode);
547
if (!PyArg_ParseTuple(args, "OO", ¬ifier, &output)) {
549
if (!PyArg_ParseTuple(args, "O", &output)) {
553
else { // retrieve notifier
556
notifierStr = retrieveString(notifier);
563
const char* string = retrieveString(output);
566
func(notifierStr, string); /*process message*/
574
PyObject* ConsoleSingleton::sPyMessage(PyObject* /*self*/, PyObject* args)
576
return FC_PYCONSOLE_MSG(
577
[](const std::string& notifier, const char* msg) {
579
.Send<Base::LogStyle::Message,
580
Base::IntendedRecipient::Developer,
581
Base::ContentType::Untranslatable>(notifier, "%s", msg);
586
PyObject* ConsoleSingleton::sPyWarning(PyObject* /*self*/, PyObject* args)
588
return FC_PYCONSOLE_MSG(
589
[](const std::string& notifier, const char* msg) {
590
Instance().Warning(notifier, "%s", msg);
595
PyObject* ConsoleSingleton::sPyDeveloperWarning(PyObject* /*self*/, PyObject* args)
597
return FC_PYCONSOLE_MSG(
598
[](const std::string& notifier, const char* msg) {
600
.Send<Base::LogStyle::Warning,
601
Base::IntendedRecipient::Developer,
602
Base::ContentType::Untranslatable>(notifier, "%s", msg);
607
PyObject* ConsoleSingleton::sPyUserWarning(PyObject* /*self*/, PyObject* args)
609
return FC_PYCONSOLE_MSG(
610
[](const std::string& notifier, const char* msg) {
612
.Send<Base::LogStyle::Warning,
613
Base::IntendedRecipient::User,
614
Base::ContentType::Untranslated>(notifier, "%s", msg);
619
PyObject* ConsoleSingleton::sPyTranslatedUserWarning(PyObject* /*self*/, PyObject* args)
621
return FC_PYCONSOLE_MSG(
622
[](const std::string& notifier, const char* msg) {
624
.Send<Base::LogStyle::Warning,
625
Base::IntendedRecipient::User,
626
Base::ContentType::Translated>(notifier, "%s", msg);
631
PyObject* ConsoleSingleton::sPyError(PyObject* /*self*/, PyObject* args)
633
return FC_PYCONSOLE_MSG(
634
[](const std::string& notifier, const char* msg) {
636
.Send<Base::LogStyle::Error,
637
Base::IntendedRecipient::All,
638
Base::ContentType::Untranslated>(notifier, "%s", msg);
643
PyObject* ConsoleSingleton::sPyDeveloperError(PyObject* /*self*/, PyObject* args)
645
return FC_PYCONSOLE_MSG(
646
[](const std::string& notifier, const char* msg) {
648
.Send<Base::LogStyle::Error,
649
Base::IntendedRecipient::Developer,
650
Base::ContentType::Untranslatable>(notifier, "%s", msg);
655
PyObject* ConsoleSingleton::sPyUserError(PyObject* /*self*/, PyObject* args)
657
return FC_PYCONSOLE_MSG(
658
[](const std::string& notifier, const char* msg) {
660
.Send<Base::LogStyle::Error,
661
Base::IntendedRecipient::User,
662
Base::ContentType::Untranslated>(notifier, "%s", msg);
667
PyObject* ConsoleSingleton::sPyTranslatedUserError(PyObject* /*self*/, PyObject* args)
669
return FC_PYCONSOLE_MSG(
670
[](const std::string& notifier, const char* msg) {
672
.Send<Base::LogStyle::Error,
673
Base::IntendedRecipient::User,
674
Base::ContentType::Translated>(notifier, "%s", msg);
679
PyObject* ConsoleSingleton::sPyLog(PyObject* /*self*/, PyObject* args)
681
return FC_PYCONSOLE_MSG(
682
[](const std::string& notifier, const char* msg) {
684
.Send<Base::LogStyle::Log,
685
Base::IntendedRecipient::Developer,
686
Base::ContentType::Untranslatable>(notifier, "%s", msg);
691
PyObject* ConsoleSingleton::sPyCritical(PyObject* /*self*/, PyObject* args)
693
return FC_PYCONSOLE_MSG(
694
[](const std::string& notifier, const char* msg) {
696
.Send<Base::LogStyle::Critical,
697
Base::IntendedRecipient::All,
698
Base::ContentType::Untranslated>(notifier, "%s", msg);
703
PyObject* ConsoleSingleton::sPyNotification(PyObject* /*self*/, PyObject* args)
705
return FC_PYCONSOLE_MSG(
706
[](const std::string& notifier, const char* msg) {
708
.Send<Base::LogStyle::Notification,
709
Base::IntendedRecipient::User,
710
Base::ContentType::Untranslated>(notifier, "%s", msg);
715
PyObject* ConsoleSingleton::sPyTranslatedNotification(PyObject* /*self*/, PyObject* args)
717
return FC_PYCONSOLE_MSG(
718
[](const std::string& notifier, const char* msg) {
720
.Send<Base::LogStyle::Notification,
721
Base::IntendedRecipient::User,
722
Base::ContentType::Translated>(notifier, "%s", msg);
727
PyObject* ConsoleSingleton::sPyGetStatus(PyObject* /*self*/, PyObject* args)
731
if (!PyArg_ParseTuple(args, "ss", &pstr1, &pstr2)) {
738
ILogger* pObs = Instance().Get(pstr1);
743
if (strcmp(pstr2, "Log") == 0) {
746
else if (strcmp(pstr2, "Wrn") == 0) {
749
else if (strcmp(pstr2, "Msg") == 0) {
752
else if (strcmp(pstr2, "Err") == 0) {
755
else if (strcmp(pstr2, "Critical") == 0) {
758
else if (strcmp(pstr2, "Notification") == 0) {
759
b = pObs->bNotification;
762
Py_Error(Base::PyExc_FC_GeneralError,
763
"Unknown message type (use 'Log', 'Err', 'Wrn', 'Msg', 'Critical' or "
767
return PyBool_FromLong(b ? 1 : 0);
772
PyObject* ConsoleSingleton::sPySetStatus(PyObject* /*self*/, PyObject* args)
776
PyObject* pyStatus {};
777
if (!PyArg_ParseTuple(args, "ssO!", &pstr1, &pstr2, &PyBool_Type, &pyStatus)) {
783
bool status = asBoolean(pyStatus);
784
ILogger* pObs = Instance().Get(pstr1);
786
if (strcmp(pstr2, "Log") == 0) {
789
else if (strcmp(pstr2, "Wrn") == 0) {
792
else if (strcmp(pstr2, "Msg") == 0) {
795
else if (strcmp(pstr2, "Err") == 0) {
798
else if (strcmp(pstr2, "Critical") == 0) {
799
pObs->bCritical = status;
801
else if (strcmp(pstr2, "Notification") == 0) {
802
pObs->bNotification = status;
805
Py_Error(Base::PyExc_FC_GeneralError,
806
"Unknown message type (use 'Log', 'Err', 'Wrn', 'Msg', 'Critical' or "
813
Py_Error(Base::PyExc_FC_GeneralError, "Unknown logger type");
818
PyObject* ConsoleSingleton::sPyGetObservers(PyObject* /*self*/, PyObject* args)
820
if (!PyArg_ParseTuple(args, "")) {
827
for (auto i : Instance()._aclObservers) {
828
list.append(Py::String(i->Name() ? i->Name() : ""));
831
return Py::new_reference_to(list);
836
Base::ILogger::~ILogger() = default;