This is an automated email from the ASF dual-hosted git repository.

swebb2066 pushed a commit to branch improve_qt_support
in repository https://gitbox.apache.org/repos/asf/logging-log4cxx.git

commit 51594c6cd94191bb585e67b67034562c283e6f6d
Author: Stephen Webb <[email protected]>
AuthorDate: Fri Dec 26 12:39:09 2025 +1100

    Simplify using the Qt event loop to watch for configuration file change
---
 src/main/cpp-qt/configuration.cpp           | 140 ++++++++++++----------------
 src/main/include/log4cxx-qt/configuration.h |  41 ++++----
 src/site/markdown/qt-support.md             |   4 +-
 3 files changed, 88 insertions(+), 97 deletions(-)

diff --git a/src/main/cpp-qt/configuration.cpp 
b/src/main/cpp-qt/configuration.cpp
index 29ab7fe9..52b3c39a 100644
--- a/src/main/cpp-qt/configuration.cpp
+++ b/src/main/cpp-qt/configuration.cpp
@@ -17,115 +17,98 @@
 #include <log4cxx-qt/configuration.h>
 #include <log4cxx-qt/transcoder.h>
 #include <log4cxx/helpers/loglog.h>
+#include <log4cxx/helpers/stringhelper.h>
 #include <log4cxx/xml/domconfigurator.h>
 #include <log4cxx/propertyconfigurator.h>
-
 #include <QFileSystemWatcher>
 #include <QDir>
 #include <QFile>
 #include <memory>
 #include <QDebug>
 
-namespace LOG4CXX_NS
-{
-namespace qt
+namespace
 {
-using helpers::LogLog;
-
-static std::unique_ptr<QFileSystemWatcher> watcher;
-static QString configFilename;
-
-static void loadXMLFile(const QString& path){
-       QFileInfo fi(configFilename);
-       if(!fi.exists()){
-               return;
-       }
-       LOG4CXX_DECODE_QSTRING(lsPath, path);
-       xml::DOMConfigurator::configure(lsPath);
-}
+using namespace LOG4CXX_NS;
 
-static void loadPropertiesFile(const QString& path){
-       QFileInfo fi(configFilename);
-       if(!fi.exists()){
-               return;
-       }
-       LOG4CXX_DECODE_QSTRING(lsPath, path);
-       PropertyConfigurator::configure(lsPath);
+spi::ConfigurationStatus tryLoadFile(const LogString& lsFilename)
+{
+       return helpers::StringHelper::endsWith(lsFilename, LOG4CXX_STR(".xml"))
+               ? xml::DOMConfigurator::configure(lsFilename)
+               : PropertyConfigurator::configure(lsFilename);
 }
 
-static void dirChanged(const QString&){
-       QFileInfo fi(configFilename);
-       if(fi.exists()){
-               // From the Qt docs:
-               // Note that QFileSystemWatcher stops monitoring files once 
they have been renamed
-               // or removed from disk, and directories once they have been 
removed from disk.
-               //
-               // Some text editing programs will replace the file with a new 
one, which deletes
-               // the old file(thus causing Qt to remove the watch), so we 
need to add in the
-               // file whenever the directory changes.
-               // See also: 
https://stackoverflow.com/questions/18300376/qt-qfilesystemwatcher-signal-filechanged-gets-emited-only-once
-               watcher->addPath(configFilename);
-       }
+spi::ConfigurationStatus tryLoadFile(const QString& filename)
+{
+       LOG4CXX_DECODE_QSTRING(lsFilename, filename);
+       return tryLoadFile(lsFilename);
 }
 
-Configuration::Configuration(){}
-
-spi::ConfigurationStatus Configuration::tryLoadFile(const QString& filename){
-       auto stat = spi:: ConfigurationStatus::NotConfigured;
-       auto isXML = false;
+} // namespace
 
-       LOG4CXX_DECODE_QSTRING(lsFilename, filename);
-       if(filename.endsWith(".xml")){
-               stat = xml::DOMConfigurator::configure(lsFilename);
-               isXML = true;
-       }else if(filename.endsWith(".properties")){
-               stat = PropertyConfigurator::configure(lsFilename);
-       }
-
-       if( stat == spi::ConfigurationStatus::Configured ){
-               watcher = std::make_unique<QFileSystemWatcher>();
-               configFilename = filename;
-               QFileInfo fi(filename);
-               watcher->addPath(fi.dir().absolutePath());
-               watcher->addPath(filename);
+namespace LOG4CXX_NS::qt
+{
 
-               QObject::connect(watcher.get(), 
&QFileSystemWatcher::directoryChanged,
-                                                &dirChanged);
-               if(isXML){
-                       QObject::connect(watcher.get(), 
&QFileSystemWatcher::fileChanged,
-                                                        &loadXMLFile);
-               }else{
-                       QObject::connect(watcher.get(), 
&QFileSystemWatcher::fileChanged,
-                                                        &loadPropertiesFile);
-               }
-       }
+void Configuration::reconfigureWhenModified(const QString& filename)
+{
+       static auto watcher = std::make_unique<QFileSystemWatcher>();
+       QFileInfo fi(filename);
+       // From the Qt docs:
+       // Note that QFileSystemWatcher stops monitoring files once they have 
been renamed
+       // or removed from disk, and directories once they have been removed 
from disk.
+       //
+       // Some text editing programs will replace the file with a new one, 
which deletes
+       // the old file(thus causing Qt to remove the watch), so we need to add 
in the
+       // file whenever the directory changes.
+       // See also: 
https://stackoverflow.com/questions/18300376/qt-qfilesystemwatcher-signal-filechanged-gets-emited-only-once
+       watcher->addPath(fi.dir().absolutePath());
+       watcher->addPath(filename);
+       QObject::connect(watcher.get(), &QFileSystemWatcher::directoryChanged
+               , [filename](const QString&){
+                       if (QFileInfo(filename).exists())
+                               watcher->addPath(filename);
+               });
+       QObject::connect(watcher.get(), &QFileSystemWatcher::fileChanged
+               , [](const QString& fullPath){
+                       tryLoadFile(fullPath);
+               });
+}
 
-       return stat;
+void Configuration::reconfigureWhenModified(const LogString& lsFilename)
+{
+       LOG4CXX_ENCODE_QSTRING(filename, lsFilename);
+       reconfigureWhenModified(filename);
 }
 
-std::tuple<spi::ConfigurationStatus,QString>
-Configuration::configureFromFileAndWatch(const QVector<QString>& directories,
-                                                                               
 const QVector<QString>& filenames){
-       for( QString dir : directories ){
-               for( QString fname : filenames ){
+       std::tuple<spi::ConfigurationStatus,QString>
+Configuration::configureFromFileAndWatch
+       ( const QVector<QString>& directories
+       , const QVector<QString>& filenames
+       )
+{
+       for( QString dir : directories )
+       {
+               for( QString fname : filenames )
+               {
                        QString candidate_str = dir + "/" + fname;
                        QFile candidate(candidate_str);
 
-                       if (LogLog::isDebugEnabled())
+                       if (helpers::LogLog::isDebugEnabled())
                        {
                                LOG4CXX_DECODE_QSTRING(msg, "Checking file " + 
candidate_str);
-                               LogLog::debug(msg);
+                               helpers::LogLog::debug(msg);
                        }
                        if (candidate.exists())
                        {
                                auto configStatus = tryLoadFile(candidate_str);
-                               if( configStatus == 
spi::ConfigurationStatus::Configured ){
+                               if( configStatus == 
spi::ConfigurationStatus::Configured )
+                               {
+                                       reconfigureWhenModified(candidate_str);
                                        return {configStatus, candidate_str};
                                }
-                               if (LogLog::isDebugEnabled())
+                               if (helpers::LogLog::isDebugEnabled())
                                {
                                        LOG4CXX_DECODE_QSTRING(failmsg, "Unable 
to load  " + candidate_str + ": trying next");
-                                       LogLog::debug(failmsg);
+                                       helpers::LogLog::debug(failmsg);
                                }
                        }
                }
@@ -134,5 +117,4 @@ Configuration::configureFromFileAndWatch(const 
QVector<QString>& directories,
        return {spi::ConfigurationStatus::NotConfigured, QString()};
 }
 
-} //namespace helpers
-} //namespace log4cxx
+} // namespace LOG4CXX_NS::qt
diff --git a/src/main/include/log4cxx-qt/configuration.h 
b/src/main/include/log4cxx-qt/configuration.h
index ea8c393a..2496d0ea 100644
--- a/src/main/include/log4cxx-qt/configuration.h
+++ b/src/main/include/log4cxx-qt/configuration.h
@@ -22,28 +22,37 @@
 #include <log4cxx/log4cxx.h>
 #include <log4cxx/defaultconfigurator.h>
 
-namespace LOG4CXX_NS {
-namespace qt {
-
-class LOG4CXX_EXPORT Configuration {
-private:
-       Configuration();
-
-       static LOG4CXX_NS::spi::ConfigurationStatus tryLoadFile(const QString& 
filename);
+namespace LOG4CXX_NS::qt
+{
 
+/// Configuration support methods that use the Qt event loop
+/// to reload the configuration file when it is modified.
+class LOG4CXX_EXPORT Configuration
+{
 public:
        /**
-        * Configure Log4cxx and watch the file for changes.  See also 
DefaultConfigurator::configureFromFile.
+        * Select the file to configure Log4cxx and watch the file for changes. 
 See also DefaultConfigurator::configureFromFile.
         *
-        * @param directories
-        * @param filenames
-        * @return
+        * @param directories Each directory is checked for each entry in \c 
filenames
+        * @param filenames Each file name is checked in each entry in \c 
directories
+        * @return the selected file path if Log4cxx was successfully configured
+        */
+       static std::tuple<spi::ConfigurationStatus, QString> 
configureFromFileAndWatch
+               ( const QVector<QString>& directories
+               , const QVector<QString>& filenames
+               );
+
+       /**
+        * Set up a QFileSystemWatcher that will reconfigure Log4cxx when \c 
fullPath is modified.
+        */
+       static void reconfigureWhenModified(const QString& fullPath);
+
+       /**
+        * Set up a QFileSystemWatcher that will reconfigure Log4cxx when \c 
fullPath is modified.
         */
-       static std::tuple<LOG4CXX_NS::spi::ConfigurationStatus,QString> 
configureFromFileAndWatch(const QVector<QString>& directories,
-                                                                               
                                                                                
                   const QVector<QString>& filenames);
+       static void reconfigureWhenModified(const LogString& fullPath);
 };
 
-} /* namespace qt */
-} /* namespace log4cxx */
+} // namespace LOG4CXX_NS::qt
 
 #endif /* LOG4CXX_QT_CONFIGURATION_H */
diff --git a/src/site/markdown/qt-support.md b/src/site/markdown/qt-support.md
index 7e0bb13e..06d7b944 100644
--- a/src/site/markdown/qt-support.md
+++ b/src/site/markdown/qt-support.md
@@ -28,8 +28,8 @@ routed to Log4cxx, a message handler for Qt must be installed.
 
 Log4cxx provides a cmake build option `LOG4CXX_QT_SUPPORT=ON`
 which adds the log4cxx::qt namespace methods
-for directing Qt messages to Log4cxx and
-using the Qt event loop to process a configuration file change.
+for [directing Qt messages to Log4cxx](@ref log4cxx::qt::messageHandler) and
+[using the Qt event loop](@ref log4cxx::qt::Configuration) to process a 
configuration file change.
 Use the target `log4cxx-qt` instead of `log4cxx`
 in your `target_link_libraries` cmake directive.
 Also, including `log4cxx-qt/logger.h` allows you to use QString values

Reply via email to