diff --git a/.github/workflows/build_cmake.yml b/.github/workflows/build_cmake.yml index bbf8b38c24..81e19c91c5 100644 --- a/.github/workflows/build_cmake.yml +++ b/.github/workflows/build_cmake.yml @@ -37,7 +37,7 @@ jobs: } - { name: "Ubuntu AppImage", artifact: "Avogadro2.AppImage", - os: ubuntu-20.04, + os: ubuntu-22.04, cc: "gcc", cxx: "g++", build_type: "Release", cmake_flags: "-G Ninja -DBUILD_MOLEQUEUE=OFF -DINSTALL_BUNDLE_FILES=ON -USE_SYSTEM_ZLIB=ON", diff --git a/.github/workflows/build_qt6.yml b/.github/workflows/build_qt6.yml index feba716410..62b7047feb 100644 --- a/.github/workflows/build_qt6.yml +++ b/.github/workflows/build_qt6.yml @@ -31,7 +31,7 @@ jobs: } - { name: "Ubuntu Qt6 AppImage", artifact: "", - os: ubuntu-20.04, + os: ubuntu-22.04, cc: "gcc", cxx: "g++", build_type: "Release", cmake_flags: "-G Ninja -DINSTALL_BUNDLE_FILES=ON", @@ -135,6 +135,13 @@ jobs: if (NOT result EQUAL 0) message(FATAL_ERROR "Running tests failed!") endif() + + - name: Upload + if: matrix.config.artifact != 0 + uses: actions/upload-artifact@v4 + with: + path: ${{ runner.workspace }}/build/avogadroapp/Avogadro2*.* + name: ${{ matrix.config.artifact }} - name: Setup tmate session if: ${{ failure() }} diff --git a/avogadro/molequeue/CMakeLists.txt b/avogadro/molequeue/CMakeLists.txt index 2f7985fabc..959c2c29d0 100644 --- a/avogadro/molequeue/CMakeLists.txt +++ b/avogadro/molequeue/CMakeLists.txt @@ -1,5 +1,5 @@ if(QT_VERSION EQUAL 6) - find_package(Qt6 COMPONENTS Widgets Network Core5Compat REQUIRED) + find_package(Qt6 COMPONENTS Widgets Network REQUIRED) else() find_package(Qt5 COMPONENTS Widgets Network REQUIRED) endif() @@ -43,6 +43,3 @@ target_sources(MoleQueue PRIVATE ${UI_SOURCES}) avogadro_add_library(MoleQueue ${HEADERS} ${SOURCES}) set_target_properties(MoleQueue PROPERTIES AUTOMOC TRUE) target_link_libraries(MoleQueue PUBLIC Avogadro::QtGui Qt::Widgets Qt::Network) -if(QT_VERSION EQUAL 6) - target_link_libraries(MoleQueue PRIVATE Qt6::Core5Compat) -endif() diff --git a/avogadro/molequeue/client/client.cpp b/avogadro/molequeue/client/client.cpp index 32ce2cc02b..17643d4d8d 100644 --- a/avogadro/molequeue/client/client.cpp +++ b/avogadro/molequeue/client/client.cpp @@ -5,20 +5,16 @@ #include "client.h" -#include "jsonrpcclient.h" #include "jobobject.h" +#include "jsonrpcclient.h" #include namespace Avogadro::MoleQueue { -Client::Client(QObject *parent_) : QObject(parent_), m_jsonRpcClient(nullptr) -{ -} +Client::Client(QObject* parent_) : QObject(parent_), m_jsonRpcClient(nullptr) {} -Client::~Client() -{ -} +Client::~Client() {} bool Client::isConnected() const { @@ -28,7 +24,7 @@ bool Client::isConnected() const return m_jsonRpcClient->isConnected(); } -bool Client::connectToServer(const QString &serverName) +bool Client::connectToServer(const QString& serverName) { if (!m_jsonRpcClient) { m_jsonRpcClient = new JsonRpcClient(this); @@ -60,7 +56,7 @@ int Client::requestQueueList() return localId; } -int Client::submitJob(const JobObject &job) +int Client::submitJob(const JobObject& job) { if (!m_jsonRpcClient) return -1; @@ -112,8 +108,8 @@ int Client::cancelJob(unsigned int moleQueueId) return localId; } -int Client::registerOpenWith(const QString &name, const QString &executable, - const QList &filePatterns) +int Client::registerOpenWith(const QString& name, const QString& executable, + const QList& filePatterns) { if (!m_jsonRpcClient) return -1; @@ -131,9 +127,9 @@ int Client::registerOpenWith(const QString &name, const QString &executable, return localId; } -int Client::registerOpenWith(const QString &name, - const QString &rpcServer, const QString &rpcMethod, - const QList &filePatterns) +int Client::registerOpenWith(const QString& name, const QString& rpcServer, + const QString& rpcMethod, + const QList& filePatterns) { if (!m_jsonRpcClient) return -1; @@ -167,7 +163,7 @@ int Client::listOpenWithNames() return localId; } -int Client::unregisterOpenWith(const QString &handlerName) +int Client::unregisterOpenWith(const QString& handlerName) { if (!m_jsonRpcClient) return -1; @@ -191,60 +187,60 @@ void Client::flush() m_jsonRpcClient->flush(); } -void Client::processResult(const QJsonObject &response) +void Client::processResult(const QJsonObject& response) { - if (response["id"] != QJsonValue::Null - && m_requests.contains(static_cast(response["id"].toDouble()))) { + if (response["id"] != QJsonValue::Null && + m_requests.contains(static_cast(response["id"].toDouble()))) { int localId = static_cast(response["id"].toDouble()); switch (m_requests[localId]) { - case ListQueues: - emit queueListReceived(response["result"].toObject()); - break; - case SubmitJob: - emit submitJobResponse(localId, - static_cast(response["result"] - .toObject()["moleQueueId"].toDouble())); - break; - case LookupJob: - emit lookupJobResponse(localId, response["result"].toObject()); - break; - case CancelJob: - emit cancelJobResponse(static_cast(response["result"] - .toObject()["moleQueueId"].toDouble())); - break; - case RegisterOpenWith: - emit registerOpenWithResponse(localId); - break; - case ListOpenWithNames: - emit listOpenWithNamesResponse(localId, response["result"].toArray()); - break; - case UnregisterOpenWith: - emit unregisterOpenWithResponse(localId); - break; - default: - break; + case ListQueues: + emit queueListReceived(response["result"].toObject()); + break; + case SubmitJob: + emit submitJobResponse( + localId, static_cast( + response["result"].toObject()["moleQueueId"].toDouble())); + break; + case LookupJob: + emit lookupJobResponse(localId, response["result"].toObject()); + break; + case CancelJob: + emit cancelJobResponse(static_cast( + response["result"].toObject()["moleQueueId"].toDouble())); + break; + case RegisterOpenWith: + emit registerOpenWithResponse(localId); + break; + case ListOpenWithNames: + emit listOpenWithNamesResponse(localId, response["result"].toArray()); + break; + case UnregisterOpenWith: + emit unregisterOpenWithResponse(localId); + break; + default: + break; } } } -void Client::processNotification(const QJsonObject ¬ification) +void Client::processNotification(const QJsonObject& notification) { if (notification["method"].toString() == "jobStateChanged") { QJsonObject params = notification["params"].toObject(); emit jobStateChanged( - static_cast(params["moleQueueId"].toDouble()), - params["oldState"].toString(), params["newState"].toString()); + static_cast(params["moleQueueId"].toDouble()), + params["oldState"].toString(), params["newState"].toString()); } } -void Client::processError(const QJsonObject &error) +void Client::processError(const QJsonObject& error) { int localId = static_cast(error["id"].toDouble()); int errorCode = -1; QString errorMessage = tr("No message specified."); QJsonValue errorData; - const QJsonValue &errorValue = error.value(QLatin1String("error")); + const QJsonValue& errorValue = error.value(QLatin1String("error")); if (errorValue.isObject()) { const QJsonObject errorObject = errorValue.toObject(); if (errorObject.value("code").isDouble()) @@ -258,41 +254,28 @@ void Client::processError(const QJsonObject &error) } QJsonObject Client::buildRegisterOpenWithRequest( - const QString &name, const QList &filePatterns, - const QJsonObject &handlerMethod) + const QString& name, const QList& filePatterns, + const QJsonObject& handlerMethod) { - QJsonArray patterns; - foreach (const QRegExp ®ex, filePatterns) { - QJsonObject pattern; - switch (regex.patternSyntax()) { - case QRegExp::RegExp: - case QRegExp::RegExp2: - pattern["regexp"] = regex.pattern(); - break; - case QRegExp::Wildcard: - case QRegExp::WildcardUnix: - pattern["wildcard"] = regex.pattern(); - break; - default: - case QRegExp::FixedString: - case QRegExp::W3CXmlSchema11: - continue; - } - - pattern["caseSensitive"] = regex.caseSensitivity() == Qt::CaseSensitive; - patterns.append(pattern); - } - - QJsonObject params; - params["name"] = name; - params["method"] = handlerMethod; - params["patterns"] = patterns; - - QJsonObject packet = m_jsonRpcClient->emptyRequest(); - packet["method"] = QLatin1String("registerOpenWith"); - packet["params"] = params; - - return packet; + QJsonArray patterns; + foreach (const QRegularExpression& regex, filePatterns) { + QJsonObject pattern; + pattern["regex"] = regex.pattern(); + pattern["caseSensitive"] = regex.patternOptions().testFlag( + QRegularExpression::CaseInsensitiveOption); + patterns.append(pattern); + } + + QJsonObject params; + params["name"] = name; + params["method"] = handlerMethod; + params["patterns"] = patterns; + + QJsonObject packet = m_jsonRpcClient->emptyRequest(); + packet["method"] = QLatin1String("registerOpenWith"); + packet["params"] = params; + + return packet; } -} // End namespace Avogadro +} // namespace Avogadro::MoleQueue diff --git a/avogadro/molequeue/client/client.h b/avogadro/molequeue/client/client.h index 89ddbdf472..f791476d40 100644 --- a/avogadro/molequeue/client/client.h +++ b/avogadro/molequeue/client/client.h @@ -8,11 +8,11 @@ #include "avogadromolequeueexport.h" +#include +#include #include #include #include -#include -#include namespace Avogadro { namespace MoleQueue { @@ -35,7 +35,7 @@ class AVOGADROMOLEQUEUE_EXPORT Client : public QObject Q_OBJECT public: - explicit Client(QObject *parent_ = nullptr); + explicit Client(QObject* parent_ = nullptr); ~Client(); /** @@ -50,7 +50,7 @@ public slots: * @param serverName Name of the socket to connect to, the default of * "MoleQueue" is usually correct when connecting to the running MoleQueue. */ - bool connectToServer(const QString &serverName = "MoleQueue"); + bool connectToServer(const QString& serverName = "MoleQueue"); /** * Request the list of queues and programs from the server. The signal @@ -65,7 +65,7 @@ public slots: * @param job The job specification to be submitted to MoleQueue. * @return The local ID of the job submission request. */ - int submitJob(const JobObject &job); + int submitJob(const JobObject& job); /** * Request information about a job. You should supply the MoleQueue ID that @@ -88,9 +88,9 @@ public slots: * @param executable Executable to call with the filename as the first * argument. If the full path to the exectuble is not specified, it must be * in the user's $PATH. - * @param filePatterns A list of QRegExp objects that the handler can open. - * The QRegExp objects must use RegExp, RegExp2, WildCard, or WildCardUnix - * pattern syntax, else they will be ignored. + * @param filePatterns A list of QRegularExpression objects that the handler + * can open. The QRegularExpression objects may only use the new + * QRegularExpression pattern syntax. * @return The local ID of the request. * @note The executable is expected to use the following calling convention * to open files: @@ -98,17 +98,17 @@ public slots: executable /absolute/path/to/selected/fileName ~~~ */ - int registerOpenWith(const QString &name, const QString &executable, - const QList &filePatterns); + int registerOpenWith(const QString& name, const QString& executable, + const QList& filePatterns); /** * Register a JSON-RPC 2.0 local socket file handler with MoleQueue. * @param name GUI name of the file handler. * @param rpcServer Name of the local socket that the server is listening on. * @param rpcMethod JSON-RPC 2.0 request method to use. - * @param filePatterns A list of QRegExp objects that the handler can open. - * The QRegExp objects must use RegExp, RegExp2, WildCard, or WildCardUnix - * pattern syntax, else they will be ignored. + * @param filePatterns A list of QRegularExpression objects that the handler + * can open. The QRegularExpression objects may only use the new + * QRegularExpression pattern syntax. * @return The local ID of the request. * @note The following JSON-RPC 2.0 request is sent to the server when the * handler is activated: @@ -125,9 +125,9 @@ executable /absolute/path/to/selected/fileName ~~~ * where is replaced by the @a rpcMethod argument. */ - int registerOpenWith(const QString &name, - const QString &rpcServer, const QString &rpcMethod, - const QList &filePatterns); + int registerOpenWith(const QString& name, const QString& rpcServer, + const QString& rpcMethod, + const QList& filePatterns); /** * @brief Request a list of all file handler names. @@ -141,7 +141,7 @@ executable /absolute/path/to/selected/fileName * @return The local ID of the request. * @sa listOpenWithNames */ - int unregisterOpenWith(const QString &handlerName); + int unregisterOpenWith(const QString& handlerName); /** * @brief flush Flush all pending messages to the server. @@ -215,16 +215,17 @@ executable /absolute/path/to/selected/fileName protected slots: /** Parse the response object and emit the appropriate signal(s). */ - void processResult(const QJsonObject &response); + void processResult(const QJsonObject& response); /** Parse a notification object and emit the appropriate signal(s). */ - void processNotification(const QJsonObject ¬ification); + void processNotification(const QJsonObject& notification); /** Parse an error object and emit the appropriate signal(s). */ - void processError(const QJsonObject ¬ification); + void processError(const QJsonObject& notification); protected: - enum MessageType { + enum MessageType + { Invalid = -1, ListQueues, SubmitJob, @@ -235,13 +236,13 @@ protected slots: UnregisterOpenWith }; - JsonRpcClient *m_jsonRpcClient; + JsonRpcClient* m_jsonRpcClient; QHash m_requests; private: - QJsonObject buildRegisterOpenWithRequest(const QString &name, - const QList &filePatterns, - const QJsonObject &handlerMethod); + QJsonObject buildRegisterOpenWithRequest( + const QString& name, const QList& filePatterns, + const QJsonObject& handlerMethod); }; } // End namespace MoleQueue diff --git a/avogadro/molequeue/inputgenerator.cpp b/avogadro/molequeue/inputgenerator.cpp index 8f01f87317..9eb0c71992 100644 --- a/avogadro/molequeue/inputgenerator.cpp +++ b/avogadro/molequeue/inputgenerator.cpp @@ -21,8 +21,8 @@ namespace Avogadro::MoleQueue { -using QtGui::PythonScript; using QtGui::GenericHighlighter; +using QtGui::PythonScript; InputGenerator::InputGenerator(const QString& scriptFilePath_, QObject* parent_) : QObject(parent_), m_interpreter(new PythonScript(scriptFilePath_, this)), @@ -36,9 +36,7 @@ InputGenerator::InputGenerator(QObject* parent_) { } -InputGenerator::~InputGenerator() -{ -} +InputGenerator::~InputGenerator() {} bool InputGenerator::debug() const { @@ -355,7 +353,8 @@ bool InputGenerator::insertMolecule(QJsonObject& json, std::string str; if (!format->writeString(str, mol)) { - m_errors << tr("Error saving molecule representation to string: %1", "%1 = error message") + m_errors << tr("Error saving molecule representation to string: %1", + "%1 = error message") .arg(QString::fromStdString(format->error())); return false; } @@ -409,12 +408,15 @@ void InputGenerator::replaceKeywords(QString& str, // Find each coordinate block keyword in the file, then generate and replace // it with the appropriate values. - QRegExp coordParser(R"(\$\$coords:([^\$]*)\$\$)"); + QRegularExpression coordParser(R"(\$\$coords:([^\$]*)\$\$)"); + QRegularExpressionMatch match; int ind = 0; - while ((ind = coordParser.indexIn(str, ind)) != -1) { + // Not sure while this needs to be a while statement since we replace all in + // one go? We never iterate ind... + while ((match = coordParser.match(str, ind)).hasMatch()) { // Extract spec and prepare the replacement - const QString keyword = coordParser.cap(0); - const QString spec = coordParser.cap(1); + const QString keyword = match.captured(0); + const QString spec = match.captured(1); // Replace all blocks with this signature str.replace(keyword, generateCoordinateBlock(spec, mol)); @@ -522,7 +524,7 @@ bool InputGenerator::parseRules(const QJsonArray& json, GenericHighlighter::Rule& rule = highligher.addRule(); foreach (QJsonValue patternVal, patternsArray) { - QRegExp pattern; + QRegularExpression pattern; if (!parsePattern(patternVal, pattern)) { qDebug() << "Error while parsing pattern:" << '\n' << QString(QJsonDocument(patternVal.toObject()).toJson()); @@ -644,35 +646,49 @@ bool InputGenerator::parseFormat(const QJsonObject& json, } bool InputGenerator::parsePattern(const QJsonValue& json, - QRegExp& pattern) const + QRegularExpression& pattern) const { if (!json.isObject()) return false; QJsonObject patternObj(json.toObject()); - - if (patternObj.contains("regexp") && patternObj.value("regexp").isString()) { - pattern.setPatternSyntax(QRegExp::RegExp2); - pattern.setPattern(patternObj.value("regexp").toString()); - } else if (patternObj.contains("wildcard") && - patternObj.value("wildcard").isString()) { - pattern.setPatternSyntax(QRegExp::WildcardUnix); - pattern.setPattern(patternObj.value("wildcard").toString()); - } else if (patternObj.contains("string") && - patternObj.value("string").isString()) { - pattern.setPatternSyntax(QRegExp::FixedString); - pattern.setPattern(patternObj.value("string").toString()); + QString regexPattern; + QRegularExpression::PatternOptions patternOptions = + QRegularExpression::NoPatternOption; + + if (patternObj.contains(QStringLiteral("regexp")) && + patternObj.value(QStringLiteral("regexp")).isString()) { + // Use the provided regular expression as-is + regexPattern = patternObj.value(QStringLiteral("regexp")).toString(); + } else if (patternObj.contains(QStringLiteral("wildcard")) && + patternObj.value(QStringLiteral("wildcard")).isString()) { + // Convert wildcard pattern (* -> .* and ? -> .) + QString wildcard = patternObj.value(QStringLiteral("wildcard")).toString(); + regexPattern = QRegularExpression::escape(wildcard) + .replace("\\*", ".*") + .replace("\\?", "."); + } else if (patternObj.contains(QStringLiteral("string")) && + patternObj.value(QStringLiteral("string")).isString()) { + // Escape the string so it is treated literally in the regex + regexPattern = QRegularExpression::escape( + patternObj.value(QStringLiteral("string")).toString()); } else { return false; } - if (patternObj.contains("caseSensitive")) { - pattern.setCaseSensitivity(patternObj.value("caseSensitive").toBool(true) - ? Qt::CaseSensitive - : Qt::CaseInsensitive); + // Set case sensitivity if specified + if (patternObj.contains(QStringLiteral("caseSensitive"))) { + bool caseSensitive = + patternObj.value(QStringLiteral("caseSensitive")).toBool(true); + if (!caseSensitive) { + patternOptions |= QRegularExpression::CaseInsensitiveOption; + } } - return true; + // Set the final pattern with options + pattern = QRegularExpression(regexPattern, patternOptions); + + return pattern.isValid(); } -} // namespace Avogadro +} // namespace Avogadro::MoleQueue diff --git a/avogadro/molequeue/inputgenerator.h b/avogadro/molequeue/inputgenerator.h index 94e808c31f..1727097cb0 100644 --- a/avogadro/molequeue/inputgenerator.h +++ b/avogadro/molequeue/inputgenerator.h @@ -15,7 +15,7 @@ #include #include -#include +#include class QJsonDocument; class QProcess; @@ -30,7 +30,7 @@ class Molecule; namespace QtGui { class GenericHighlighter; class PythonScript; -} +} // namespace QtGui namespace MoleQueue { /** @@ -280,13 +280,13 @@ or "Equilibrium Geometry". | ~~~ * * The `patterns` array contains a collection of fixed strings, wildcard - * expressions, and regular expressions (using the QRegExp syntax flavor, see - * the QRegExp documentation) that are used to identify strings that should be - * formatted. + * expressions, and regular expressions (using the QRegularExpression syntax + * flavor, see the QRegularExpression documentation) that are used to identify + * strings that should be formatted. * There must be one of the following members present in each pattern object: - * - `regexp` A QRegExp-style regular expression. If no capture groups ("(...)") - * are defined, the entire match is formatted. If one or more capture groups, - * only the captured texts will be marked. + * - `regexp` A QRegularExpresion-style regular expression. If no capture groups + * ("(...)") are defined, the entire match is formatted. If one or more + * capture groups, only the captured texts will be marked. * - `wildcard` A wildcard expression * - `string` An exact string to match. * @@ -605,7 +605,7 @@ public slots: bool parseRules(const QJsonArray& json, QtGui::GenericHighlighter& highligher) const; bool parseFormat(const QJsonObject& json, QTextCharFormat& format) const; - bool parsePattern(const QJsonValue& json, QRegExp& pattern) const; + bool parsePattern(const QJsonValue& json, QRegularExpression& pattern) const; // File extension of requested molecule format mutable QString m_moleculeExtension; diff --git a/avogadro/qtgui/CMakeLists.txt b/avogadro/qtgui/CMakeLists.txt index c49b733968..ff9ea173d4 100644 --- a/avogadro/qtgui/CMakeLists.txt +++ b/avogadro/qtgui/CMakeLists.txt @@ -1,5 +1,5 @@ if(QT_VERSION EQUAL 6) - find_package(Qt6 COMPONENTS Widgets Core5Compat REQUIRED) + find_package(Qt6 COMPONENTS Widgets REQUIRED) else() find_package(Qt5 COMPONENTS Widgets REQUIRED) endif() @@ -57,6 +57,7 @@ avogadro_headers(QtGui persistentbond.h pluginlayermanager.h pythonscript.h + richtextdelegate.h rwmolecule.h sceneplugin.h scenepluginmodel.h @@ -85,6 +86,7 @@ target_sources(QtGui PRIVATE interfacewidget.cpp jsonwidget.cpp layermodel.cpp + richtextdelegate.cpp rwlayermanager.cpp meshgenerator.cpp molecule.cpp @@ -119,6 +121,3 @@ target_sources(QtGui PRIVATE ${RC_SOURCES}) avogadro_add_library(QtGui) target_link_libraries(QtGui PUBLIC Avogadro::IO Qt::Widgets) -if(QT_VERSION EQUAL 6) - target_link_libraries(QtGui PRIVATE Qt6::Core5Compat) -endif() diff --git a/avogadro/qtgui/filebrowsewidget.cpp b/avogadro/qtgui/filebrowsewidget.cpp index 5042180d7a..ecede6989f 100644 --- a/avogadro/qtgui/filebrowsewidget.cpp +++ b/avogadro/qtgui/filebrowsewidget.cpp @@ -14,7 +14,6 @@ #include #include -#include namespace Avogadro::QtGui { diff --git a/avogadro/qtgui/generichighlighter.cpp b/avogadro/qtgui/generichighlighter.cpp index 571319a814..1827ede17c 100644 --- a/avogadro/qtgui/generichighlighter.cpp +++ b/avogadro/qtgui/generichighlighter.cpp @@ -14,9 +14,7 @@ GenericHighlighter::GenericHighlighter(QObject* parent_) { } -GenericHighlighter::~GenericHighlighter() -{ -} +GenericHighlighter::~GenericHighlighter() {} GenericHighlighter::GenericHighlighter(const GenericHighlighter& other) : QSyntaxHighlighter(static_cast(nullptr)) @@ -67,40 +65,46 @@ QList GenericHighlighter::rules() const void GenericHighlighter::highlightBlock(const QString& text) { - for (auto & m_rule : m_rules) + for (auto& m_rule : m_rules) m_rule.apply(text, *this); } void GenericHighlighter::Rule::apply(const QString& text, GenericHighlighter& highlighter) { - for (auto & m_pattern : m_patterns) { - int index = m_pattern.indexIn(text); - while (index >= 0) { - // If using a regex with capture groups defined, only highlight the - // capture groups. + for (auto& m_pattern : m_patterns) { + // each m_pattern is a QRegularExpression + // We want to highlight every occurrence of m_pattern + QRegularExpressionMatchIterator iterator = m_pattern.globalMatch(text); + while (iterator.hasNext()) { + QRegularExpressionMatch match = iterator.next(); + // If using a regex with capture groups defined, we explicitly don't want + // to highlight the whole expression, only the capture groups if (m_pattern.captureCount() > 0) { - QStringList capturedTexts(m_pattern.capturedTexts()); - QString match(capturedTexts.takeFirst()); - foreach (const QString& capture, capturedTexts) { - int capOffset(match.indexOf(capture)); - while (capOffset > 0) { - int capLength(capture.size()); - highlighter.setFormat(index + capOffset, capLength, m_format); - capOffset = match.indexOf(capture, capOffset + capLength); + // Iterate over capture groups, skipping the implicit group 0 + for (int i = 1; i <= match.lastCapturedIndex(); ++i) { + QString captured = match.captured(i); + if (!captured.isNull()) { + // According to StackOverflow user "peppe", who claims to have + // written the whole QRegularExpression class, the index returned is + // relative to the whole string, not to the current match + // https://stackoverflow.com/questions/28725588/qregularexpression-match-position-in-the-source-string + int index = match.capturedStart(i); + int length = match.capturedLength(i); + highlighter.setFormat(index, length, m_format); } } - index = m_pattern.indexIn(text, index + match.size()); } else { - int length(m_pattern.matchedLength()); + // Straightforward regex with no capture groups, highlight whole match + int index = match.capturedStart(0); + int length = match.capturedLength(0); highlighter.setFormat(index, length, m_format); - index = m_pattern.indexIn(text, index + length); } } } } -void GenericHighlighter::Rule::addPattern(const QRegExp& regexp) +void GenericHighlighter::Rule::addPattern(const QRegularExpression& regexp) { m_patterns.append(regexp); } @@ -110,4 +114,4 @@ void GenericHighlighter::Rule::setFormat(const QTextCharFormat& format) m_format = format; } -} // namespace Avogadro +} // namespace Avogadro::QtGui diff --git a/avogadro/qtgui/generichighlighter.h b/avogadro/qtgui/generichighlighter.h index a11e85d898..ba9067d019 100644 --- a/avogadro/qtgui/generichighlighter.h +++ b/avogadro/qtgui/generichighlighter.h @@ -13,7 +13,7 @@ #include #include -#include +#include namespace Avogadro { namespace QtGui { @@ -27,8 +27,8 @@ class AVOGADROQTGUI_EXPORT GenericHighlighter : public QSyntaxHighlighter Q_OBJECT public: /** - * @brief The Rule class stores a syntax highlighting rule as a set of QRegExp - * patterns and a text format. + * @brief The Rule class stores a syntax highlighting rule as a set of + * QRegularExpression patterns and a text format. */ class AVOGADROQTGUI_EXPORT Rule { @@ -37,7 +37,7 @@ class AVOGADROQTGUI_EXPORT GenericHighlighter : public QSyntaxHighlighter ~Rule() {} /** Add the pattern @a regexp to this Rule. */ - void addPattern(const QRegExp& regexp); + void addPattern(const QRegularExpression& regexp); /** Set this Rule's text format. */ void setFormat(const QTextCharFormat& format); @@ -47,7 +47,7 @@ class AVOGADROQTGUI_EXPORT GenericHighlighter : public QSyntaxHighlighter void apply(const QString& text, GenericHighlighter& highlighter); private: - QList m_patterns; + QList m_patterns; QTextCharFormat m_format; }; @@ -94,7 +94,7 @@ class AVOGADROQTGUI_EXPORT GenericHighlighter : public QSyntaxHighlighter QList m_rules; }; -} // namespace QtPlugins +} // namespace QtGui } // namespace Avogadro #endif // AVOGADRO_QTPLUGINS_GENERICHIGHLIGHTER_H diff --git a/avogadro/qtgui/interfacescript.cpp b/avogadro/qtgui/interfacescript.cpp index dfce9ab7ac..38f555c5bd 100644 --- a/avogadro/qtgui/interfacescript.cpp +++ b/avogadro/qtgui/interfacescript.cpp @@ -601,12 +601,15 @@ void InterfaceScript::replaceKeywords(QString& str, // Find each coordinate block keyword in the file, then generate and replace // it with the appropriate values. - QRegExp coordParser(R"(\$\$coords:([^\$]*)\$\$)"); + QRegularExpression coordParser(R"(\$\$coords:([^\$]*)\$\$)"); + QRegularExpressionMatch match; int ind = 0; - while ((ind = coordParser.indexIn(str, ind)) != -1) { + // Not sure while this needs to be a while statement since we replace all in + // one go? We never iterate ind... + while ((match = coordParser.match(str, ind)).hasMatch()) { // Extract spec and prepare the replacement - const QString keyword = coordParser.cap(0); - const QString spec = coordParser.cap(1); + const QString keyword = match.captured(0); + const QString spec = match.captured(1); // Replace all blocks with this signature str.replace(keyword, generateCoordinateBlock(spec, mol)); @@ -672,7 +675,7 @@ bool InterfaceScript::parseHighlightStyles(const QJsonArray& json) const } bool InterfaceScript::parseRules(const QJsonArray& json, - GenericHighlighter& highligher) const + GenericHighlighter& highlighter) const { bool result(true); foreach (QJsonValue ruleVal, json) { @@ -712,10 +715,10 @@ bool InterfaceScript::parseRules(const QJsonArray& json, } QJsonObject formatObj(ruleObj.value(QStringLiteral("format")).toObject()); - GenericHighlighter::Rule& rule = highligher.addRule(); + GenericHighlighter::Rule& rule = highlighter.addRule(); foreach (QJsonValue patternVal, patternsArray) { - QRegExp pattern; + QRegularExpression pattern; if (!parsePattern(patternVal, pattern)) { qDebug() << "Error while parsing pattern:" << '\n' << QString(QJsonDocument(patternVal.toObject()).toJson()); @@ -844,37 +847,49 @@ bool InterfaceScript::parseFormat(const QJsonObject& json, } bool InterfaceScript::parsePattern(const QJsonValue& json, - QRegExp& pattern) const + QRegularExpression& pattern) const { if (!json.isObject()) return false; QJsonObject patternObj(json.toObject()); + QString regexPattern; + QRegularExpression::PatternOptions patternOptions = + QRegularExpression::NoPatternOption; if (patternObj.contains(QStringLiteral("regexp")) && patternObj.value(QStringLiteral("regexp")).isString()) { - pattern.setPatternSyntax(QRegExp::RegExp2); - pattern.setPattern(patternObj.value(QStringLiteral("regexp")).toString()); + // Use the provided regular expression as-is + regexPattern = patternObj.value(QStringLiteral("regexp")).toString(); } else if (patternObj.contains(QStringLiteral("wildcard")) && patternObj.value(QStringLiteral("wildcard")).isString()) { - pattern.setPatternSyntax(QRegExp::WildcardUnix); - pattern.setPattern(patternObj.value(QStringLiteral("wildcard")).toString()); + // Convert wildcard pattern (* -> .* and ? -> .) + QString wildcard = patternObj.value(QStringLiteral("wildcard")).toString(); + regexPattern = QRegularExpression::escape(wildcard) + .replace("\\*", ".*") + .replace("\\?", "."); } else if (patternObj.contains(QStringLiteral("string")) && patternObj.value(QStringLiteral("string")).isString()) { - pattern.setPatternSyntax(QRegExp::FixedString); - pattern.setPattern(patternObj.value(QStringLiteral("string")).toString()); + // Escape the string so it is treated literally in the regex + regexPattern = QRegularExpression::escape( + patternObj.value(QStringLiteral("string")).toString()); } else { return false; } + // Set case sensitivity if specified if (patternObj.contains(QStringLiteral("caseSensitive"))) { - pattern.setCaseSensitivity( - patternObj.value(QStringLiteral("caseSensitive")).toBool(true) - ? Qt::CaseSensitive - : Qt::CaseInsensitive); + bool caseSensitive = + patternObj.value(QStringLiteral("caseSensitive")).toBool(true); + if (!caseSensitive) { + patternOptions |= QRegularExpression::CaseInsensitiveOption; + } } - return true; + // Set the final pattern with options + pattern = QRegularExpression(regexPattern, patternOptions); + + return pattern.isValid(); } } // namespace Avogadro::QtGui diff --git a/avogadro/qtgui/interfacescript.h b/avogadro/qtgui/interfacescript.h index 63fc384896..d2e0888e33 100644 --- a/avogadro/qtgui/interfacescript.h +++ b/avogadro/qtgui/interfacescript.h @@ -12,10 +12,10 @@ #include +#include #include #include #include -#include class QJsonDocument; class QProcess; @@ -278,13 +278,13 @@ or "Equilibrium Geometry". | ~~~ * * The `patterns` array contains a collection of fixed strings, wildcard - * expressions, and regular expressions (using the QRegExp syntax flavor, see - * the QRegExp documentation) that are used to identify strings that should be - * formatted. + * expressions, and regular expressions (using the QRegularExpression syntax + * flavor, see the QRegularExpression documentation) that are used to identify + * strings that should be formatted. * There must be one of the following members present in each pattern object: - * - `regexp` A QRegExp-style regular expression. If no capture groups ("(...)") - * are defined, the entire match is formatted. If one or more capture groups, - * only the captured texts will be marked. + * - `regexp` A QRegularExpression-style regular expression. If no capture + * groups ("(...)") are defined, the entire match is formatted. If one or more + * capture groups, only the captured texts will be marked. * - `wildcard` A wildcard expression * - `string` An exact string to match. * @@ -638,7 +638,7 @@ public slots: bool parseRules(const QJsonArray& json, QtGui::GenericHighlighter& highligher) const; bool parseFormat(const QJsonObject& json, QTextCharFormat& format) const; - bool parsePattern(const QJsonValue& json, QRegExp& pattern) const; + bool parsePattern(const QJsonValue& json, QRegularExpression& pattern) const; // File extension of requested molecule format mutable QString m_moleculeExtension; diff --git a/avogadro/qtgui/richtextdelegate.cpp b/avogadro/qtgui/richtextdelegate.cpp new file mode 100644 index 0000000000..5f9f2af286 --- /dev/null +++ b/avogadro/qtgui/richtextdelegate.cpp @@ -0,0 +1,89 @@ +/****************************************************************************** + + This source file is part of the Avogadro project. + + Copyright 2015 Marcus Johansson + + This source code is released under the New BSD License, (the "License"). + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +******************************************************************************/ + +#include "richtextdelegate.h" + +namespace Avogadro::QtGui { + +// See for example +// https://gist.github.com/jniemann66/dbc298b35a840bf3f1a2206ea6284c7b +// and https://stackoverflow.com/a/66412883/131896 + +RichTextDelegate::RichTextDelegate(QObject* parent_) + : QStyledItemDelegate(parent_) +{} + +RichTextDelegate::~RichTextDelegate(){}; + +QSize RichTextDelegate::sizeHint(const QStyleOptionViewItem& o, + const QModelIndex& index) const +{ + if (o.text.isEmpty()) { + // This is nothing this function is supposed to handle + return QStyledItemDelegate::sizeHint(o, index); + } + + QStyleOptionViewItem ov = o; + initStyleOption(&ov, index); + + QTextDocument doc; + doc.setHtml(ov.text); + doc.setTextWidth(ov.rect.width()); + doc.setDefaultFont(ov.font); + doc.setDocumentMargin(1); + + return QSize(doc.idealWidth(), doc.size().height()); +} + +void RichTextDelegate::paint(QPainter* p, const QStyleOptionViewItem& o, + const QModelIndex& index) const +{ + if (o.text.isEmpty()) { + // no need to do anything if the text is empty + QStyledItemDelegate::paint(p, o, index); + + return; + } + + QStyleOptionViewItem ov = o; + initStyleOption(&ov, index); + + p->save(); + + QTextDocument doc; + doc.setHtml(ov.text); + + QTextOption textOption; + textOption.setWrapMode(ov.features & QStyleOptionViewItem::WrapText + ? QTextOption::WordWrap + : QTextOption::ManualWrap); + textOption.setTextDirection(ov.direction); + doc.setDefaultTextOption(textOption); + doc.setDefaultFont(ov.font); + doc.setDocumentMargin(1); + doc.setTextWidth(ov.rect.width()); + doc.adjustSize(); + + ov.text = ""; + ov.widget->style()->drawControl(QStyle::CE_ItemViewItem, &ov, p); + + p->translate(ov.rect.left(), ov.rect.top()); + QRect clip(0, 0, ov.rect.width(), ov.rect.height()); + doc.drawContents(p, clip); + p->restore(); +} + +} // namespace Avogadro::QtGui diff --git a/avogadro/qtplugins/symmetry/richtextdelegate.h b/avogadro/qtgui/richtextdelegate.h similarity index 78% rename from avogadro/qtplugins/symmetry/richtextdelegate.h rename to avogadro/qtgui/richtextdelegate.h index 59ecaa54ef..909f4f5cee 100644 --- a/avogadro/qtplugins/symmetry/richtextdelegate.h +++ b/avogadro/qtgui/richtextdelegate.h @@ -21,22 +21,26 @@ #include #include +#include "avogadroqtguiexport.h" + namespace Avogadro { -namespace QtPlugins { +namespace QtGui { -class RichTextDelegate : public QStyledItemDelegate +class AVOGADROQTGUI_EXPORT RichTextDelegate : public QStyledItemDelegate { Q_OBJECT public: - RichTextDelegate(QObject* parent = nullptr) - : QStyledItemDelegate(parent){}; + explicit RichTextDelegate(QObject* parent = 0); + ~RichTextDelegate() override; + QSize sizeHint(const QStyleOptionViewItem& o, const QModelIndex& index) const override; void paint(QPainter* p, const QStyleOptionViewItem& o, const QModelIndex& index) const override; }; -} -} -#endif // AVOGADRO_QTPLUGINS_RICHTEXTDELEGATE_H +} // namespace QtGui +} // namespace Avogadro + +#endif // AVOGADRO_QTGUI_RICHTEXTDELEGATE_H diff --git a/avogadro/qtgui/scriptloader.cpp b/avogadro/qtgui/scriptloader.cpp index f77e918792..47b353b8c8 100644 --- a/avogadro/qtgui/scriptloader.cpp +++ b/avogadro/qtgui/scriptloader.cpp @@ -44,12 +44,12 @@ bool ScriptLoader::queryProgramName(const QString& scriptFilePath, return true; } -QMap ScriptLoader::scriptList(const QString& type) +QMultiMap ScriptLoader::scriptList(const QString& type) { // List of directories to check. /// @todo Custom script locations QStringList dirs; - QMap scriptList; + QMultiMap scriptList; // add the default paths QStringList stdPaths = @@ -136,10 +136,10 @@ QMap ScriptLoader::scriptList(const QString& type) if (scriptList.contains(displayName)) { // check the last-modified-time of the existing case QFileInfo file(filePath); - QFileInfo existingFile(scriptList[displayName]); + QFileInfo existingFile(scriptList.value(displayName)); if (file.lastModified() > existingFile.lastModified()) { // replace existing with this new entry - scriptList.insert(displayName, filePath); + scriptList.replace(displayName, filePath); } } else // new entry scriptList.insert(displayName, filePath); diff --git a/avogadro/qtgui/scriptloader.h b/avogadro/qtgui/scriptloader.h index 1521e35bbe..15b2e40547 100644 --- a/avogadro/qtgui/scriptloader.h +++ b/avogadro/qtgui/scriptloader.h @@ -39,7 +39,7 @@ class AVOGADROQTGUI_EXPORT ScriptLoader : public QObject /** * @return A map of name -> path for all scripts of the requested @arg type */ - static QMap scriptList(const QString& type); + static QMultiMap scriptList(const QString& type); static bool queryProgramName(const QString& scriptFilePath, QString& displayName); diff --git a/avogadro/qtplugins/CMakeLists.txt b/avogadro/qtplugins/CMakeLists.txt index b2c5219a9d..c837fb61df 100644 --- a/avogadro/qtplugins/CMakeLists.txt +++ b/avogadro/qtplugins/CMakeLists.txt @@ -112,11 +112,13 @@ add_subdirectory(focus) add_subdirectory(hydrogens) add_subdirectory(importpqr) add_subdirectory(insertdna) +add_subdirectory(insertfragment) add_subdirectory(label) add_subdirectory(lammpsinput) add_subdirectory(lineformatinput) add_subdirectory(manipulator) add_subdirectory(measuretool) +add_subdirectory(molecularproperties) add_subdirectory(navigator) add_subdirectory(networkdatabases) add_subdirectory(openbabel) @@ -136,18 +138,15 @@ add_subdirectory(templatetool) add_subdirectory(vibrations) add_subdirectory(vrml) -if(QT_VERSION EQUAL 5) - # This will need some work on the QRegExp migration - add_subdirectory(apbs) - add_subdirectory(coordinateeditor) - add_subdirectory(cp2kinput) - add_subdirectory(forcefield) - add_subdirectory(gamessinput) - add_subdirectory(insertfragment) - add_subdirectory(molecularproperties) - # The SVG library is not available in Qt 6 - add_subdirectory(svg) -endif() +# These should work after the QRegExp migration +add_subdirectory(apbs) +add_subdirectory(coordinateeditor) +add_subdirectory(cp2kinput) +add_subdirectory(forcefield) +add_subdirectory(gamessinput) + +# The SVG library changed in Qt6 +add_subdirectory(svg) # Plugins that require VTK if(USE_VTK) @@ -162,12 +161,9 @@ if(USE_VTK) endif() # script plugins (input generators, etc.) -if(QT_VERSION EQUAL 5) - # QRegExp fixes needed in classes these depend on - add_subdirectory(commandscripts) - add_subdirectory(quantuminput) - add_subdirectory(scriptcharges) -endif() +add_subdirectory(commandscripts) +add_subdirectory(quantuminput) +add_subdirectory(scriptcharges) add_subdirectory(scriptfileformats) if(USE_LIBARCHIVE) diff --git a/avogadro/qtplugins/commandscripts/command.h b/avogadro/qtplugins/commandscripts/command.h index 118f5e582f..72d196600c 100644 --- a/avogadro/qtplugins/commandscripts/command.h +++ b/avogadro/qtplugins/commandscripts/command.h @@ -23,7 +23,7 @@ class FileFormat; namespace QtGui { class InterfaceScript; class InterfaceWidget; -} +} // namespace QtGui namespace QtPlugins { @@ -84,12 +84,12 @@ private slots: QProgressDialog* m_progress; // maps program name --> script file path - QMap m_commandScripts; + QMultiMap m_commandScripts; const Io::FileFormat* m_outputFormat; QString m_outputFileName; }; -} -} +} // namespace QtPlugins +} // namespace Avogadro #endif // AVOGADRO_QTPLUGINS_COMMAND_H diff --git a/avogadro/qtplugins/coordinateeditor/coordinateeditordialog.cpp b/avogadro/qtplugins/coordinateeditor/coordinateeditordialog.cpp index 7928ce451a..6f9c21f508 100644 --- a/avogadro/qtplugins/coordinateeditor/coordinateeditordialog.cpp +++ b/avogadro/qtplugins/coordinateeditor/coordinateeditordialog.cpp @@ -19,7 +19,7 @@ #include #include #include -#include +#include #include #include #include @@ -29,7 +29,7 @@ #include #include #include -#include +#include #include #include @@ -77,18 +77,22 @@ enum TokenType }; // Some frequently used regexes: -static const QRegExp TOKEN_SEPARATOR("[\\s,;]+"); -static const QRegExp VALID_TOKEN("[^\\s,;]+"); -static const QRegExp INT_CHECKER("(:?[+-])?\\d+"); -static const QRegExp DOUBLE_CHECKER("(:?[+-])?" // Leading sign - "(:?" // Must match one of the following: - "\\d*\\.\\d*" // Fractional part - "|" // or - "\\d+[Ee](:?[+-])?\\d+" // Exponential part - "|" // or - "\\d*\\.\\d*" // Fractional part and - "[Ee](:?[+-])?\\d+" // Exponential part - ")"); +static const QRegularExpression TOKEN_SEPARATOR("[\\s,;]+"); +static const QRegularExpression VALID_TOKEN("[^\\s,;]+"); +// These two need to be exact +static const QRegularExpression INT_CHECKER( + QRegularExpression::anchoredPattern("(:?[+-])?\\d+")); +static const QRegularExpression DOUBLE_CHECKER( + QRegularExpression::anchoredPattern( + "(:?[+-])?" // Leading sign + "(:?" // Must match one of the following: + "\\d*\\.\\d*" // Fractional part + "|" // or + "\\d+[Ee](:?[+-])?\\d+" // Exponential part + "|" // or + "\\d*\\.\\d*" // Fractional part and + "[Ee](:?[+-])?\\d+" // Exponential part + ")")); struct AtomStruct { @@ -140,8 +144,8 @@ CoordinateEditorDialog::CoordinateEditorDialog(QWidget* parent_) SLOT(textModified(bool))); // Setup spec edit - QRegExp specRegExp("[#ZGSLNabcxyz01_]*"); - auto* specValidator = new QRegExpValidator(specRegExp, this); + QRegularExpression specRegExp("[#ZGSLNabcxyz01_]*"); + auto* specValidator = new QRegularExpressionValidator(specRegExp, this); m_ui->spec->setValidator(specValidator); connect(m_ui->presets, SIGNAL(currentIndexChanged(int)), SLOT(presetChanged(int))); @@ -392,13 +396,14 @@ void CoordinateEditorDialog::validateInputWorker() cleanToken.replace(0, 1, cleanToken[0].toUpper()); // Split the label into symbol and number - QRegExp labelSplitter("([A-Z][a-z]?)(\\d+)"); - if (labelSplitter.indexIn(cleanToken) == -1) { + QRegularExpression labelSplitter("([A-Z][a-z]?)(\\d+)"); + QRegularExpressionMatch match = labelSplitter.match(cleanToken); + if (match.hasMatch()) { m_ui->text->markInvalid(tokenCursor, tr("Invalid atom label.")); break; } // check the symbol - std::string tokenStd(labelSplitter.cap(1).toStdString()); + std::string tokenStd(match.captured(1).toStdString()); atom.atomicNumber = Elements::atomicNumberFromSymbol(tokenStd); if (atom.atomicNumber == Avogadro::InvalidElement) m_ui->text->markInvalid(tokenCursor, tr("Invalid element symbol.")); @@ -682,9 +687,9 @@ QString CoordinateEditorDialog::detectInputFormat() const foreach (const QString& token, tokens) { TokenType tokenType = String; - if (INT_CHECKER.exactMatch(token)) + if (INT_CHECKER.match(token).hasMatch()) tokenType = Integer; - else if (DOUBLE_CHECKER.exactMatch(token)) + else if (DOUBLE_CHECKER.match(token).hasMatch()) tokenType = Double; ++tokenTypeCounts[tokenType]; tokenTypes << tokenType; @@ -797,8 +802,8 @@ QString CoordinateEditorDialog::detectInputFormat() const // Check the current specification -- if a|b|c appears before x|y|z, assume // that the specified coordinates are lattice coords - static QRegExp cartesianSniffer("x|y|z"); - static QRegExp fractionalSniffer("a|b|c"); + static QRegularExpression cartesianSniffer("x|y|z"); + static QRegularExpression fractionalSniffer("a|b|c"); const QString currentSpec(m_ui->spec->text()); int cartesianIndex = currentSpec.indexOf(cartesianSniffer); int fractionalIndex = currentSpec.indexOf(fractionalSniffer); diff --git a/avogadro/qtplugins/coordinateeditor/coordinatetextedit.cpp b/avogadro/qtplugins/coordinateeditor/coordinatetextedit.cpp index fcc83a6f9e..bbddb591a7 100644 --- a/avogadro/qtplugins/coordinateeditor/coordinatetextedit.cpp +++ b/avogadro/qtplugins/coordinateeditor/coordinatetextedit.cpp @@ -20,8 +20,8 @@ CoordinateTextEdit::CoordinateTextEdit(QWidget* p) setMouseTracking(true); m_unmarkedFormat.setUnderlineStyle(QTextCharFormat::NoUnderline); - m_unmarkedFormat.setForeground(qApp->palette().foreground().color()); - m_unmarkedFormat.setBackground(qApp->palette().base().color()); + m_unmarkedFormat.setForeground(qApp->palette().color(QPalette::WindowText)); + m_unmarkedFormat.setBackground(qApp->palette().color(QPalette::Base)); m_invalidFormat.setUnderlineStyle(QTextCharFormat::SpellCheckUnderline); m_invalidFormat.setForeground(Qt::darkRed); diff --git a/avogadro/qtplugins/forcefield/forcefield.cpp b/avogadro/qtplugins/forcefield/forcefield.cpp index 041d8e83aa..f1545b95a8 100644 --- a/avogadro/qtplugins/forcefield/forcefield.cpp +++ b/avogadro/qtplugins/forcefield/forcefield.cpp @@ -485,7 +485,7 @@ void Forcefield::refreshScripts() qDeleteAll(m_scripts); m_scripts.clear(); - QMap scriptPaths = + QMultiMap scriptPaths = QtGui::ScriptLoader::scriptList("energy"); foreach (const QString& filePath, scriptPaths) { auto* model = new ScriptEnergy(filePath); diff --git a/avogadro/qtplugins/gamessinput/gamesshighlighter.cpp b/avogadro/qtplugins/gamessinput/gamesshighlighter.cpp index 7b5e1d3aaf..f76b101300 100644 --- a/avogadro/qtplugins/gamessinput/gamesshighlighter.cpp +++ b/avogadro/qtplugins/gamessinput/gamesshighlighter.cpp @@ -165,27 +165,30 @@ GamessHighlighter::GamessHighlighter(QTextDocument* parent_) << R"(\s\$DATA\b)"; rule.format = m_keywordFormat; foreach (const QString& pattern, m_keywords) { - rule.pattern = QRegExp(pattern); + rule.pattern = QRegularExpression(pattern); m_highlightingRules.append(rule); } - rule.pattern = QRegExp(R"(\s\$END\b)"); + rule.pattern = QRegularExpression(R"(\s\$END\b)"); m_highlightingRules.append(rule); m_singleLineCommentFormat.setForeground(Qt::green); - rule.pattern = QRegExp("![^\n]*"); + rule.pattern = QRegularExpression("![^\n]*"); rule.format = m_singleLineCommentFormat; m_highlightingRules.append(rule); m_numberFormat.setForeground(Qt::blue); - rule.pattern = QRegExp(R"((\b|[\s-])[0-9]+\.([0-9]+\b)?|\.[0-9]+\b)"); + rule.pattern = + QRegularExpression(R"((\b|[\s-])[0-9]+\.([0-9]+\b)?|\.[0-9]+\b)"); rule.format = m_numberFormat; m_highlightingRules.append(rule); m_numberFormat.setForeground(Qt::blue); - rule.pattern = QRegExp(R"((\b|[\s-])[0-9]+\.([0-9]+\b)?|\.[0-9]+\b)"); + rule.pattern = + QRegularExpression(R"((\b|[\s-])[0-9]+\.([0-9]+\b)?|\.[0-9]+\b)"); rule.format = m_numberFormat; m_highlightingRules.append(rule); - rule.pattern = QRegExp(R"((\b|[\s-])[0-9]+([0-9]+\b)?|\.[0-9]+\b)"); + rule.pattern = + QRegularExpression(R"((\b|[\s-])[0-9]+([0-9]+\b)?|\.[0-9]+\b)"); rule.format = m_numberFormat; m_highlightingRules.append(rule); @@ -198,10 +201,11 @@ GamessHighlighter::GamessHighlighter(QTextDocument* parent_) void GamessHighlighter::highlightBlock(const QString& text) { // Single line comments - QRegExp pattern("![^\n]*"); - int commentIndex = pattern.indexIn(text); - if (commentIndex >= 0) - setFormat(commentIndex, pattern.matchedLength(), m_singleLineCommentFormat); + QRegularExpression pattern("![^\n]*"); + QRegularExpressionMatch commentMatch = pattern.match(text); + if (commentMatch.hasMatch()) + setFormat(commentMatch.capturedStart(), commentMatch.capturedLength(), + m_singleLineCommentFormat); setCurrentBlockState(0); @@ -209,11 +213,12 @@ void GamessHighlighter::highlightBlock(const QString& text) int keywordLength = 0; if (previousBlockState() != 1) { foreach (const QString& regexString, m_keywords) { - QRegExp expression(regexString); - expression.setCaseSensitivity(Qt::CaseInsensitive); - startIndex = expression.indexIn(text); - keywordLength = expression.matchedLength(); - if (startIndex >= 0) { + QRegularExpression startExpression( + regexString, QRegularExpression::CaseInsensitiveOption); + QRegularExpressionMatch startMatch = startExpression.match(text); + startIndex = startMatch.capturedStart(); + keywordLength = startMatch.capturedLength(); + if (startMatch.hasMatch()) { setFormat(startIndex, keywordLength, m_keywordFormat); break; } @@ -221,26 +226,29 @@ void GamessHighlighter::highlightBlock(const QString& text) } while (startIndex >= 0) { - QRegExp endExpression(R"(\s\$END\b)"); - endExpression.setCaseSensitivity(Qt::CaseInsensitive); - int endIndex = endExpression.indexIn(text, startIndex); + QRegularExpression endExpression(R"(\s\$END\b)", + QRegularExpression::CaseInsensitiveOption); + QRegularExpressionMatch match = endExpression.match(text, startIndex); + int endIndex = match.capturedStart(); int blockLength; if (endIndex == -1) { setCurrentBlockState(1); blockLength = text.length() - startIndex - keywordLength; } else { - setFormat(endIndex, endExpression.matchedLength(), m_keywordFormat); + setFormat(endIndex, match.capturedLength(), m_keywordFormat); blockLength = endIndex - startIndex - keywordLength; } setFormat(startIndex + keywordLength, blockLength, m_inDataBlockFormat); bool found = false; foreach (const QString& regexString, m_keywords) { - QRegExp expression(regexString); - int index = expression.indexIn(text, startIndex + blockLength); + QRegularExpression newExpression(regexString); + QRegularExpressionMatch newMatch = + newExpression.match(text, startIndex + blockLength); + int index = newMatch.capturedStart(); if (index > startIndex) { found = true; startIndex = index; - keywordLength = expression.matchedLength(); + keywordLength = newMatch.capturedLength(); setFormat(startIndex, keywordLength, m_keywordFormat); break; } @@ -252,13 +260,16 @@ void GamessHighlighter::highlightBlock(const QString& text) if (previousBlockState() == 1) { // Anything outside of data blocks is a comment foreach (const HighlightingRule& rule, m_highlightingRules) { - QRegExp expression(rule.pattern); - expression.setCaseSensitivity(Qt::CaseInsensitive); - int index = text.indexOf(expression); - while (index >= 0) { - int length = expression.matchedLength(); + QRegularExpression otherExpression(rule.pattern); + otherExpression.setPatternOptions( + QRegularExpression::CaseInsensitiveOption); + QRegularExpressionMatchIterator iterator = + otherExpression.globalMatch(text); + while (iterator.hasNext()) { + QRegularExpressionMatch otherMatch = iterator.next(); + int index = otherMatch.capturedStart(); + int length = otherMatch.capturedLength(); setFormat(index, length, rule.format); - index = text.indexOf(expression, index + length); } } } @@ -268,4 +279,4 @@ void GamessHighlighter::highlightBlock(const QString& text) setFormat(80, text.length(), m_errorFormat); } -} // End namespace Avogadro +} // namespace Avogadro::QtPlugins diff --git a/avogadro/qtplugins/gamessinput/gamesshighlighter.h b/avogadro/qtplugins/gamessinput/gamesshighlighter.h index a2e121e978..39e804feee 100644 --- a/avogadro/qtplugins/gamessinput/gamesshighlighter.h +++ b/avogadro/qtplugins/gamessinput/gamesshighlighter.h @@ -19,7 +19,7 @@ #include -#include +#include #include #include @@ -41,15 +41,15 @@ class GamessHighlighter : public QSyntaxHighlighter private: struct HighlightingRule { - QRegExp pattern; + QRegularExpression pattern; QTextCharFormat format; }; QVector m_highlightingRules; QStringList m_keywords; - QRegExp m_commentStartExpression; - QRegExp m_commentEndExpression; + QRegularExpression m_commentStartExpression; + QRegularExpression m_commentEndExpression; QTextCharFormat m_keywordFormat; QTextCharFormat m_numberFormat; diff --git a/avogadro/qtplugins/gamessinput/gamessinput.cpp b/avogadro/qtplugins/gamessinput/gamessinput.cpp index 40ee38f01c..4328bd0188 100644 --- a/avogadro/qtplugins/gamessinput/gamessinput.cpp +++ b/avogadro/qtplugins/gamessinput/gamessinput.cpp @@ -35,9 +35,7 @@ GamessInput::GamessInput(QObject* parent_) connect(m_action, SIGNAL(triggered()), SLOT(menuActivated())); } -GamessInput::~GamessInput() -{ -} +GamessInput::~GamessInput() {} QList GamessInput::actions() const { @@ -101,11 +99,11 @@ void GamessInput::menuActivated() { if (!m_dialog) { m_dialog = new GamessInputDialog(qobject_cast(parent())); - connect(m_dialog, SIGNAL(openJobOutput(Avogadro::MoleQueue::JobObject)), this, - SLOT(openJobOutput(Avogadro::MoleQueue::JobObject))); + connect(m_dialog, SIGNAL(openJobOutput(Avogadro::MoleQueue::JobObject)), + this, SLOT(openJobOutput(Avogadro::MoleQueue::JobObject))); } m_dialog->setMolecule(m_molecule); m_dialog->show(); } -} -} +} // namespace QtPlugins +} // namespace Avogadro diff --git a/avogadro/qtplugins/gamessinput/gamessinput.h b/avogadro/qtplugins/gamessinput/gamessinput.h index 3a4e48df91..8ec948ac38 100644 --- a/avogadro/qtplugins/gamessinput/gamessinput.h +++ b/avogadro/qtplugins/gamessinput/gamessinput.h @@ -62,7 +62,7 @@ private slots: const Io::FileFormat* m_outputFormat; QString m_outputFileName; }; -} -} +} // namespace QtPlugins +} // namespace Avogadro #endif // AVOGADRO_QTPLUGINS_GAMESSINPUT_H diff --git a/avogadro/qtplugins/gamessinput/gamessinputdialog.cpp b/avogadro/qtplugins/gamessinput/gamessinputdialog.cpp index 69b365d7c5..2d2297da42 100644 --- a/avogadro/qtplugins/gamessinput/gamessinputdialog.cpp +++ b/avogadro/qtplugins/gamessinput/gamessinputdialog.cpp @@ -28,9 +28,9 @@ #include #include +using Avogadro::MoleQueue::JobObject; using Avogadro::MoleQueue::MoleQueueDialog; using Avogadro::MoleQueue::MoleQueueManager; -using Avogadro::MoleQueue::JobObject; namespace Avogadro::QtPlugins { @@ -117,9 +117,7 @@ GamessInputDialog::GamessInputDialog(QWidget* parent_, Qt::WindowFlags f) updatePreviewText(); } -GamessInputDialog::~GamessInputDialog() -{ -} +GamessInputDialog::~GamessInputDialog() {} void GamessInputDialog::setMolecule(QtGui::Molecule* mol) { @@ -172,9 +170,7 @@ void GamessInputDialog::connectBasic() SLOT(updatePreviewText())); } -void GamessInputDialog::connectPreview() -{ -} +void GamessInputDialog::connectPreview() {} void GamessInputDialog::connectButtons() { @@ -396,7 +392,7 @@ QString GamessInputDialog::generateJobTitle() const // Merge theory/basis into theory theory += "/" + basis; - theory.replace(QRegExp("\\s+"), ""); + theory.replace(QRegularExpression("\\s+"), ""); return QString("%1 | %2 | %3").arg(formula, calculation, theory); } @@ -435,14 +431,12 @@ void GamessInputDialog::updatePreviewText() auto calculate( static_cast(ui.calculateCombo->currentIndex())); - auto theory( - static_cast(ui.theoryCombo->currentIndex())); + auto theory(static_cast(ui.theoryCombo->currentIndex())); auto basis(static_cast(ui.basisCombo->currentIndex())); auto state(static_cast(ui.stateCombo->currentIndex())); auto multiplicity( static_cast(ui.multiplicityCombo->currentIndex())); - auto charge( - static_cast(ui.chargeCombo->currentIndex())); + auto charge(static_cast(ui.chargeCombo->currentIndex())); // Disable basis selection for semiempirical methods. ui.basisCombo->setEnabled(theory != TheoryAM1 && theory != TheoryPM3); @@ -738,4 +732,4 @@ void GamessInputDialog::updateTitlePlaceholder() ui.titleEdit->setPlaceholderText(generateJobTitle()); } -} // end namespace Avogadro +} // namespace Avogadro::QtPlugins diff --git a/avogadro/qtplugins/gamessinput/gamessinputdialog.h b/avogadro/qtplugins/gamessinput/gamessinputdialog.h index ffc6baef12..15c386ca6b 100644 --- a/avogadro/qtplugins/gamessinput/gamessinputdialog.h +++ b/avogadro/qtplugins/gamessinput/gamessinputdialog.h @@ -32,7 +32,8 @@ class GamessInputDialog : public QDialog Q_OBJECT public: - explicit GamessInputDialog(QWidget* parent_ = nullptr, Qt::WindowFlags f = 0); + explicit GamessInputDialog(QWidget* parent_ = nullptr, + Qt::WindowFlags f = {}); ~GamessInputDialog() override; void setMolecule(QtGui::Molecule* mol); diff --git a/avogadro/qtplugins/molecularproperties/molecularpropertiesdialog.cpp b/avogadro/qtplugins/molecularproperties/molecularpropertiesdialog.cpp index d1510382fa..930020018b 100644 --- a/avogadro/qtplugins/molecularproperties/molecularpropertiesdialog.cpp +++ b/avogadro/qtplugins/molecularproperties/molecularpropertiesdialog.cpp @@ -15,7 +15,7 @@ #include #include #include -#include +#include #include #include #include @@ -98,7 +98,7 @@ void MolecularPropertiesDialog::updateName() std::string smiles; Io::FileFormatManager::instance().writeString(*m_molecule, smiles, "smi"); QString smilesString = QString::fromStdString(smiles); - smilesString.remove(QRegExp("\\s+.*")); + smilesString.remove(QRegularExpression("\\s+.*")); QString requestURL = QString("https://pubchem.ncbi.nlm.nih.gov/rest/pug/compound/smiles/" + QUrl::toPercentEncoding(smilesString) + "/json"); @@ -172,13 +172,17 @@ void MolecularPropertiesDialog::updateMassLabel() void MolecularPropertiesDialog::updateFormulaLabel() { QString formula = QString::fromStdString(m_molecule->formula()); - QRegExp digitParser("(\\d+)"); + QRegularExpression digitParser("(\\d+)"); - int ind = digitParser.indexIn(formula); - while (ind != -1) { - QString digits = digitParser.cap(1); - formula.replace(ind, digits.size(), QString("%1").arg(digits)); - ind = digitParser.indexIn(formula, ind + digits.size() + 11); + QRegularExpressionMatchIterator i = digitParser.globalMatch(formula); + unsigned int offset = 0; + while (i.hasNext()) { + const QRegularExpressionMatch match = i.next(); + QString digits = match.captured(1); + + formula.replace(match.capturedStart(1) + offset, digits.size(), + QString("%1").arg(digits)); + offset += 11; // length of ... } m_ui->formulaLabel->setText(formula); diff --git a/avogadro/qtplugins/openbabel/CMakeLists.txt b/avogadro/qtplugins/openbabel/CMakeLists.txt index 126601023f..1574ac8860 100644 --- a/avogadro/qtplugins/openbabel/CMakeLists.txt +++ b/avogadro/qtplugins/openbabel/CMakeLists.txt @@ -1,7 +1,3 @@ -if(QT_VERSION EQUAL 6) - find_package(Qt6 COMPONENTS Core5Compat REQUIRED) -endif() - set(openbabel_srcs conformersearchdialog.cpp obcharges.cpp @@ -26,6 +22,3 @@ avogadro_plugin(OpenBabel ) target_link_libraries(OpenBabel PRIVATE Avogadro::IO Avogadro::Calc nlohmann_json::nlohmann_json) -if(QT_VERSION EQUAL 6) - target_link_libraries(OpenBabel PRIVATE Qt6::Core5Compat) -endif() diff --git a/avogadro/qtplugins/openbabel/obprocess.cpp b/avogadro/qtplugins/openbabel/obprocess.cpp index 78a1de0793..108828f4e8 100644 --- a/avogadro/qtplugins/openbabel/obprocess.cpp +++ b/avogadro/qtplugins/openbabel/obprocess.cpp @@ -11,7 +11,6 @@ #include #include -#include #include namespace Avogadro::QtPlugins { @@ -148,13 +147,14 @@ void OBProcess::queryReadFormatsPrepare() QString output = QString::fromLatin1(m_process->readAllStandardOutput()); - QRegExp parser(R"(\s*([^\s]+)\s+--\s+([^\n]+)\n)"); + QRegularExpression parser(R"(\s*([^\s]+)\s+--\s+([^\n]+)\n)"); + QRegularExpressionMatch match; int pos = 0; - while ((pos = parser.indexIn(output, pos)) != -1) { - QString extension = parser.cap(1); - QString description = parser.cap(2); + while ((match = parser.match(output, pos)).hasMatch()) { + QString extension = match.captured(1); + QString description = match.captured(2); result.insertMulti(description, extension); - pos += parser.matchedLength(); + pos = match.capturedEnd(0); } releaseProcess(); @@ -173,13 +173,14 @@ void OBProcess::queryWriteFormatsPrepare() QString output = QString::fromLatin1(m_process->readAllStandardOutput()); - QRegExp parser(R"(\s*([^\s]+)\s+--\s+([^\n]+)\n)"); + QRegularExpression parser(R"(\s*([^\s]+)\s+--\s+([^\n]+)\n)"); + QRegularExpressionMatch match; int pos = 0; - while ((pos = parser.indexIn(output, pos)) != -1) { - QString extension = parser.cap(1); - QString description = parser.cap(2); + while ((match = parser.match(output, pos)).hasMatch()) { + QString extension = match.captured(1); + QString description = match.captured(2); result.insertMulti(description, extension); - pos += parser.matchedLength(); + pos = match.capturedEnd(0); } releaseProcess(); @@ -273,13 +274,14 @@ void OBProcess::queryForceFieldsPrepare() QString output = QString::fromLatin1(m_process->readAllStandardOutput()); - QRegExp parser(R"(([^\s]+)\s+(\S[^\n]*[^\n\.]+)\.?\n)"); + QRegularExpression parser(R"(([^\s]+)\s+(\S[^\n]*[^\n\.]+)\.?\n)"); + QRegularExpressionMatch match; int pos = 0; - while ((pos = parser.indexIn(output, pos)) != -1) { - QString key = parser.cap(1); - QString desc = parser.cap(2); + while ((match = parser.match(output, pos)).hasMatch()) { + QString key = match.captured(1); + QString desc = match.captured(2); result.insertMulti(key, desc); - pos += parser.matchedLength(); + pos = match.capturedEnd(0); } releaseProcess(); @@ -312,13 +314,14 @@ void OBProcess::queryChargesPrepare() QString output = QString::fromLatin1(m_process->readAllStandardOutput()); - QRegExp parser(R"(([^\s]+)\s+(\S[^\n]*[^\n\.]+)\.?\n)"); + QRegularExpression parser(R"(([^\s]+)\s+(\S[^\n]*[^\n\.]+)\.?\n)"); + QRegularExpressionMatch match; int pos = 0; - while ((pos = parser.indexIn(output, pos)) != -1) { - QString key = parser.cap(1); - QString desc = parser.cap(2); + while ((match = parser.match(output, pos)).hasMatch()) { + QString key = match.captured(1); + QString desc = match.captured(2); result.insertMulti(key, desc); - pos += parser.matchedLength(); + pos = match.capturedEnd(0); } releaseProcess(); @@ -492,9 +495,10 @@ void OBProcess::optimizeGeometryReadLog() // Search for the maximum number of steps if we haven't found it yet if (m_optimizeGeometryMaxSteps < 0) { - QRegExp maxStepsParser("\nSTEPS = ([0-9]+)\n\n"); - if (maxStepsParser.indexIn(m_optimizeGeometryLog) != -1) { - m_optimizeGeometryMaxSteps = maxStepsParser.cap(1).toInt(); + QRegularExpression maxStepsParser("\nSTEPS = ([0-9]+)\n\n"); + QRegularExpressionMatch match; + if ((match = maxStepsParser.match(m_optimizeGeometryLog)).hasMatch()) { + m_optimizeGeometryMaxSteps = match.captured(1).toInt(); emit optimizeGeometryStatusUpdate(0, m_optimizeGeometryMaxSteps, 0.0, 0.0); } @@ -502,11 +506,18 @@ void OBProcess::optimizeGeometryReadLog() // Emit the last printed step if (m_optimizeGeometryMaxSteps >= 0) { - QRegExp lastStepParser(R"(\n\s*([0-9]+)\s+([-0-9.]+)\s+([-0-9.]+)\n)"); - if (lastStepParser.lastIndexIn(m_optimizeGeometryLog) != -1) { - int step = lastStepParser.cap(1).toInt(); - double energy = lastStepParser.cap(2).toDouble(); - double lastEnergy = lastStepParser.cap(3).toDouble(); + QRegularExpression lastStepParser( + R"(\n\s*([0-9]+)\s+([-0-9.]+)\s+([-0-9.]+)\n)"); + QRegularExpressionMatchIterator matchIterator = + lastStepParser.globalMatch(m_optimizeGeometryLog); + QRegularExpressionMatch lastMatch; + while (matchIterator.hasNext()) { + lastMatch = matchIterator.next(); // Capture the last match + } + if (lastMatch.hasMatch()) { + int step = lastMatch.captured(1).toInt(); + double energy = lastMatch.captured(2).toDouble(); + double lastEnergy = lastMatch.captured(3).toDouble(); emit optimizeGeometryStatusUpdate(step, m_optimizeGeometryMaxSteps, energy, lastEnergy); } @@ -522,9 +533,10 @@ void OBProcess::conformerReadLog() // Search for the maximum number of steps if we haven't found it yet if (m_optimizeGeometryMaxSteps < 0) { - QRegExp maxStepsParser("\nSTEPS = ([0-9]+)\n\n"); - if (maxStepsParser.indexIn(m_optimizeGeometryLog) != -1) { - m_optimizeGeometryMaxSteps = maxStepsParser.cap(1).toInt(); + QRegularExpression maxStepsParser("\nSTEPS = ([0-9]+)\n\n"); + QRegularExpressionMatch match; + if ((match = maxStepsParser.match(m_optimizeGeometryLog)).hasMatch()) { + m_optimizeGeometryMaxSteps = match.captured(1).toInt(); emit optimizeGeometryStatusUpdate(0, m_optimizeGeometryMaxSteps, 0.0, 0.0); } @@ -532,11 +544,13 @@ void OBProcess::conformerReadLog() // Emit the last printed step if (m_optimizeGeometryMaxSteps >= 0) { - QRegExp lastStepParser(R"(\n\s*([0-9]+)\s+([-0-9.]+)\s+([-0-9.]+)\n)"); - if (lastStepParser.lastIndexIn(m_optimizeGeometryLog) != -1) { - int step = lastStepParser.cap(1).toInt(); - double energy = lastStepParser.cap(2).toDouble(); - double lastEnergy = lastStepParser.cap(3).toDouble(); + QRegularExpression lastStepParser( + R"(\n\s*([0-9]+)\s+([-0-9.]+)\s+([-0-9.]+)\n)"); + QRegularExpressionMatch match; + if ((match = lastStepParser.match(m_optimizeGeometryLog)).hasMatch()) { + int step = match.captured(1).toInt(); + double energy = match.captured(2).toDouble(); + double lastEnergy = match.captured(3).toDouble(); emit optimizeGeometryStatusUpdate(step, m_optimizeGeometryMaxSteps, energy, lastEnergy); } diff --git a/avogadro/qtplugins/quantuminput/quantuminput.h b/avogadro/qtplugins/quantuminput/quantuminput.h index bdf9926e52..642a145534 100644 --- a/avogadro/qtplugins/quantuminput/quantuminput.h +++ b/avogadro/qtplugins/quantuminput/quantuminput.h @@ -22,7 +22,7 @@ class FileFormat; namespace MoleQueue { class InputGeneratorDialog; class JobObject; -} +} // namespace MoleQueue namespace QtPlugins { @@ -80,12 +80,12 @@ private slots: QMap m_dialogs; // maps program name --> script file path - QMap m_inputGeneratorScripts; + QMultiMap m_inputGeneratorScripts; const Io::FileFormat* m_outputFormat; QString m_outputFileName; }; -} -} +} // namespace QtPlugins +} // namespace Avogadro #endif // AVOGADRO_QTPLUGINS_QUANTUMINPUT_H diff --git a/avogadro/qtplugins/scriptcharges/scriptchargemodel.cpp b/avogadro/qtplugins/scriptcharges/scriptchargemodel.cpp index 831fe24fe5..e28d239d87 100644 --- a/avogadro/qtplugins/scriptcharges/scriptchargemodel.cpp +++ b/avogadro/qtplugins/scriptcharges/scriptchargemodel.cpp @@ -155,7 +155,7 @@ Core::Array ScriptChargeModel::potentials( QJsonObject json; json[m_formatString] = QString::fromStdString(intermediate); QJsonArray pointsArray; - for (const auto & i : points) { + for (const auto& i : points) { QJsonArray point; point << i.x() << i.y() << i.z(); pointsArray.append(point); @@ -357,7 +357,8 @@ void ScriptChargeModel::processElementString(const QString& str) QString str2(str); str2.replace(',', ' '); // then split on whitespace - QStringList strList = str2.split(QRegExp("\\s+"), Qt::SkipEmptyParts); + QStringList strList = + str2.split(QRegularExpression("\\s+"), Qt::SkipEmptyParts); foreach (QString sstr, strList) { // these should be numbers or ranges (e.g., 1-84) if (sstr.contains('-')) { @@ -398,7 +399,7 @@ bool ScriptChargeModel::parseElements(const QJsonObject& ob) } else if (ob["elements"].isArray()) { QJsonArray arr = ob["elements"].toArray(); - for (auto && i : arr) { + for (auto&& i : arr) { if (i.isString()) { processElementString(i.toString()); } else if (i.isDouble()) { @@ -411,4 +412,4 @@ bool ScriptChargeModel::parseElements(const QJsonObject& ob) return true; } -} // namespace Avogadro +} // namespace Avogadro::QtPlugins diff --git a/avogadro/qtplugins/scriptcharges/scriptcharges.cpp b/avogadro/qtplugins/scriptcharges/scriptcharges.cpp index 381141c771..1a35523756 100644 --- a/avogadro/qtplugins/scriptcharges/scriptcharges.cpp +++ b/avogadro/qtplugins/scriptcharges/scriptcharges.cpp @@ -42,7 +42,7 @@ void ScriptCharges::refreshModels() qDeleteAll(m_models); m_models.clear(); - QMap scriptPaths = + QMultiMap scriptPaths = QtGui::ScriptLoader::scriptList("charges"); foreach (const QString& filePath, scriptPaths) { auto* model = new ScriptChargeModel(filePath); @@ -69,11 +69,11 @@ void ScriptCharges::registerModels() for (QList::const_iterator it = m_models.constBegin(), itEnd = m_models.constEnd(); it != itEnd; ++it) { - if (!Calc::ChargeManager::registerModel((*it)->newInstance()) ) { + if (!Calc::ChargeManager::registerModel((*it)->newInstance())) { qDebug() << "Could not register model" << (*it)->identifier().c_str() << "due to name conflict."; } } } -} // end namespace Avogadro +} // namespace Avogadro::QtPlugins diff --git a/avogadro/qtplugins/scriptfileformats/scriptfileformats.cpp b/avogadro/qtplugins/scriptfileformats/scriptfileformats.cpp index 38c2d28800..0bea6c0337 100644 --- a/avogadro/qtplugins/scriptfileformats/scriptfileformats.cpp +++ b/avogadro/qtplugins/scriptfileformats/scriptfileformats.cpp @@ -20,8 +20,7 @@ namespace Avogadro::QtPlugins { -ScriptFileFormats::ScriptFileFormats(QObject* p) - : ExtensionPlugin(p) +ScriptFileFormats::ScriptFileFormats(QObject* p) : ExtensionPlugin(p) { refreshFileFormats(); } @@ -46,7 +45,7 @@ void ScriptFileFormats::refreshFileFormats() qDeleteAll(m_formats); m_formats.clear(); - QMap scriptPaths = + QMultiMap scriptPaths = QtGui::ScriptLoader::scriptList("formatScripts"); foreach (const QString& filePath, scriptPaths) { auto* format = new FileFormatScript(filePath); @@ -80,4 +79,4 @@ void ScriptFileFormats::registerFileFormats() } } -} // end namespace Avogadro +} // namespace Avogadro::QtPlugins diff --git a/avogadro/qtplugins/symmetry/CMakeLists.txt b/avogadro/qtplugins/symmetry/CMakeLists.txt index ea66c2fad8..f33c721e67 100644 --- a/avogadro/qtplugins/symmetry/CMakeLists.txt +++ b/avogadro/qtplugins/symmetry/CMakeLists.txt @@ -8,7 +8,6 @@ set(symmetry_srcs symmetry.cpp symmetrywidget.cpp operationstablemodel.cpp - richtextdelegate.cpp symmetryutil.cpp ) @@ -35,4 +34,3 @@ avogadro_plugin(SymmetryScene target_link_libraries(Symmetry PRIVATE ${LIBMSYM_LIBRARIES}) target_link_libraries(SymmetryScene PRIVATE Avogadro::Rendering) - diff --git a/avogadro/qtplugins/symmetry/richtextdelegate.cpp b/avogadro/qtplugins/symmetry/richtextdelegate.cpp deleted file mode 100644 index a8fa646b6c..0000000000 --- a/avogadro/qtplugins/symmetry/richtextdelegate.cpp +++ /dev/null @@ -1,51 +0,0 @@ -/****************************************************************************** - - This source file is part of the Avogadro project. - - Copyright 2015 Marcus Johansson - - This source code is released under the New BSD License, (the "License"). - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - -******************************************************************************/ - -#include "richtextdelegate.h" - -namespace Avogadro::QtPlugins { - -QSize RichTextDelegate::sizeHint(const QStyleOptionViewItem& o, - const QModelIndex& index) const -{ - QStyleOptionViewItemV4 ov4 = o; - initStyleOption(&ov4, index); - QTextDocument doc; - doc.setHtml(ov4.text); - doc.setTextWidth(ov4.rect.width()); - return QSize(doc.idealWidth(), doc.size().height()); -} - -void RichTextDelegate::paint(QPainter* p, const QStyleOptionViewItem& o, - const QModelIndex& index) const -{ - QStyleOptionViewItemV4 ov4 = o; - initStyleOption(&ov4, index); - - p->save(); - - QTextDocument doc; - doc.setHtml(ov4.text); - - ov4.text = ""; - ov4.widget->style()->drawControl(QStyle::CE_ItemViewItem, &ov4, p); - - p->translate(ov4.rect.left(), ov4.rect.top()); - QRect clip(0, 0, ov4.rect.width(), ov4.rect.height()); - doc.drawContents(p, clip); - p->restore(); -} -} diff --git a/avogadro/qtplugins/symmetry/symmetrywidget.cpp b/avogadro/qtplugins/symmetry/symmetrywidget.cpp index 15d824cc9c..c3a6500d3a 100644 --- a/avogadro/qtplugins/symmetry/symmetrywidget.cpp +++ b/avogadro/qtplugins/symmetry/symmetrywidget.cpp @@ -4,17 +4,18 @@ ******************************************************************************/ #include "symmetrywidget.h" -#include "richtextdelegate.h" #include "symmetryutil.h" #include "ui_symmetrywidget.h" #include +#include #include #include using Avogadro::QtGui::Molecule; +using Avogadro::QtGui::RichTextDelegate; using namespace msym; using namespace Avogadro::QtPlugins::SymmetryUtil; @@ -62,18 +63,11 @@ msym_thresholds_t sloppy_thresholds = { }; SymmetryWidget::SymmetryWidget(QWidget* parent_) - : QWidget(parent_) - , m_ui(new Ui::SymmetryWidget) - , m_molecule(nullptr) - , m_equivalenceTreeModel(new QStandardItemModel(this)) - , m_operationsTableModel(new OperationsTableModel(this)) - , m_subgroupsTreeModel(new QStandardItemModel(this)) - , m_es(nullptr) - , m_sops(nullptr) - , m_sg(nullptr) - , m_sopsl(0) - , m_sgl(0) - , m_radius(0.0) + : QWidget(parent_), m_ui(new Ui::SymmetryWidget), m_molecule(nullptr), + m_equivalenceTreeModel(new QStandardItemModel(this)), + m_operationsTableModel(new OperationsTableModel(this)), + m_subgroupsTreeModel(new QStandardItemModel(this)), m_es(nullptr), + m_sops(nullptr), m_sg(nullptr), m_sopsl(0), m_sgl(0), m_radius(0.0) { setWindowFlags(Qt::Dialog); m_ui->setupUi(this); @@ -87,10 +81,9 @@ SymmetryWidget::SymmetryWidget(QWidget* parent_) m_ui->subgroupsTree->setModel(m_subgroupsTreeModel); m_ui->subgroupsTree->setItemDelegateForColumn(0, new RichTextDelegate(this)); - connect( - m_ui->detectSymmetryButton, SIGNAL(clicked()), SIGNAL(detectSymmetry())); - connect(m_ui->symmetrizeMoleculeButton, - SIGNAL(clicked()), + connect(m_ui->detectSymmetryButton, SIGNAL(clicked()), + SIGNAL(detectSymmetry())); + connect(m_ui->symmetrizeMoleculeButton, SIGNAL(clicked()), SIGNAL(symmetrizeMolecule())); connect( @@ -138,8 +131,7 @@ void SymmetryWidget::moleculeChanged(unsigned int changes) } void SymmetryWidget::operationsSelectionChanged( - const QItemSelection& selected, - const QItemSelection& deselected) + const QItemSelection& selected, const QItemSelection& deselected) { if (!m_molecule) @@ -240,24 +232,23 @@ void SymmetryWidget::subgroupsSelectionChanged(const QItemSelection& selected, QModelIndex left = m_operationsTableModel->index(row, 0); QModelIndex right = m_operationsTableModel->index( row, m_operationsTableModel->columnCount(left) - 1); - //if (!left.isValid() || !right.isValid()) - // qDebug() << "invalid index " << j; + // if (!left.isValid() || !right.isValid()) + // qDebug() << "invalid index " << j; QItemSelection sel(left, right); selection.merge(sel, QItemSelectionModel::Select); } QModelIndexList tmp = selection.indexes(); - //foreach (QModelIndex j, tmp) { - // qDebug() << "selecting " << j.row() << " " << j.column(); - //} + // foreach (QModelIndex j, tmp) { + // qDebug() << "selecting " << j.row() << " " << j.column(); + // } selectionModel->select(selection, QItemSelectionModel::ClearAndSelect); } void SymmetryWidget::equivalenceSelectionChanged( - const QItemSelection& selected, - const QItemSelection& deselected) + const QItemSelection& selected, const QItemSelection& deselected) { QModelIndex i = m_ui->equivalenceTree->selectionModel()->selectedIndexes().first(); @@ -313,8 +304,7 @@ void SymmetryWidget::setPointGroupSymbol(QString pg) } void SymmetryWidget::setSymmetryOperations( - int sopsl, - const msym::msym_symmetry_operation_t* sops) + int sopsl, const msym::msym_symmetry_operation_t* sops) { m_sops = sops; m_sopsl = sopsl; @@ -373,8 +363,7 @@ void SymmetryWidget::setSubgroups(int sgl, const msym::msym_subgroup_t* sg) auto* const child = new QStandardItem; child->setText(pointGroupSymbol(generator->name)); - child->setData(static_cast(generator - m_sg), - Qt::UserRole); + child->setData(static_cast(generator - m_sg), Qt::UserRole); parent->appendRow(child); } } @@ -400,4 +389,4 @@ msym_thresholds_t* SymmetryWidget::getThresholds() const return thresholds; } -} // namespace Avogadro +} // namespace Avogadro::QtPlugins diff --git a/avogadro/quantumio/gamessukout.cpp b/avogadro/quantumio/gamessukout.cpp index c49eb4e95a..f506a9636e 100644 --- a/avogadro/quantumio/gamessukout.cpp +++ b/avogadro/quantumio/gamessukout.cpp @@ -7,7 +7,7 @@ #include #include -#include +#include #include #include @@ -17,11 +17,11 @@ using std::vector; namespace Avogadro { namespace QuantumIO { -using Quantum::S; -using Quantum::SP; -using Quantum::P; using Quantum::D; using Quantum::F; +using Quantum::P; +using Quantum::S; +using Quantum::SP; using Quantum::UU; using Quantum::orbital; @@ -42,7 +42,7 @@ bool tokenize(std::vector& vcr, const char* buf, QString splitString("["); splitString += QString(delimstr); splitString += QString("]"); - QRegExp splitter(splitString); + QRegularExpression splitter(splitString); foreach (const QString& str, tmp.split(splitter, Qt::SkipEmptyParts)) vcr.push_back(str.toStdString()); @@ -170,9 +170,7 @@ GamessukOut::GamessukOut(const QString& qtfilename, GaussianSet* basis) GamessukOutNoQt(filename, basis); } // end GamessukOut -GamessukOut::~GamessukOut() -{ -} // end ~GamessukOut +GamessukOut::~GamessukOut() {} // end ~GamessukOut void GamessukOut::GamessukOutNoQt(const std::string& filename, GaussianSet* basis) @@ -784,5 +782,5 @@ void GamessukOut::load(GaussianSet* basis) } // end load -} // End Namespace -} +} // namespace QuantumIO +} // namespace Avogadro diff --git a/tests/qtgui/generichighlightertest.cpp b/tests/qtgui/generichighlightertest.cpp index 53b727cca9..8fab84e8ff 100644 --- a/tests/qtgui/generichighlightertest.cpp +++ b/tests/qtgui/generichighlightertest.cpp @@ -109,26 +109,17 @@ TEST(DISABLED_GenericHighlighterTest, exercise) QTextCharFormat format; GenericHighlighter::Rule& regexpRule = highlighter.addRule(); - regexpRule.addPattern( - QRegExp("^.*regexp.*$", Qt::CaseSensitive, QRegExp::RegExp)); + regexpRule.addPattern(QRegularExpression("^.*regexp.*$")); format.setForeground(Qt::blue); regexpRule.setFormat(format); GenericHighlighter::Rule& regexpCapRule = highlighter.addRule(); - regexpCapRule.addPattern( - QRegExp("^.*(this)[^\n]*(that).*$", Qt::CaseSensitive, QRegExp::RegExp)); + regexpCapRule.addPattern(QRegularExpression("^.*(this)[^\n]*(that).*$")); format.setForeground(Qt::yellow); regexpCapRule.setFormat(format); - GenericHighlighter::Rule& wildcardRule = highlighter.addRule(); - wildcardRule.addPattern( - QRegExp("A w*red.", Qt::CaseSensitive, QRegExp::Wildcard)); - format.setForeground(Qt::red); - wildcardRule.setFormat(format); - GenericHighlighter::Rule& stringRule = highlighter.addRule(); - stringRule.addPattern(QRegExp("This string will be green.", Qt::CaseSensitive, - QRegExp::FixedString)); + stringRule.addPattern(QRegularExpression("This string will be green.")); format.setForeground(Qt::green); stringRule.setFormat(format);