From 108d522dcf6329c5bd0ae0371429931ba1ea688a Mon Sep 17 00:00:00 2001 From: Jonas Kvinge Date: Sun, 25 Aug 2024 03:09:11 +0200 Subject: [PATCH] OrganizeFormat: Move to own classes --- src/CMakeLists.txt | 4 + src/organize/organizedialog.cpp | 3 +- src/organize/organizeformat.cpp | 123 +++------------------ src/organize/organizeformat.h | 37 +------ src/organize/organizeformatvalidator.cpp | 66 +++++++++++ src/organize/organizeformatvalidator.h | 36 ++++++ src/organize/organizesyntaxhighlighter.cpp | 84 ++++++++++++++ src/organize/organizesyntaxhighlighter.h | 49 ++++++++ 8 files changed, 263 insertions(+), 139 deletions(-) create mode 100644 src/organize/organizeformatvalidator.cpp create mode 100644 src/organize/organizeformatvalidator.h create mode 100644 src/organize/organizesyntaxhighlighter.cpp create mode 100644 src/organize/organizesyntaxhighlighter.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 90d65faa4..f201f692c 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -305,6 +305,8 @@ set(SOURCES organize/organize.cpp organize/organizeformat.cpp + organize/organizeformatvalidator.cpp + organize/organizesyntaxhighlighter.cpp organize/organizedialog.cpp organize/organizeerrordialog.cpp @@ -550,6 +552,8 @@ set(HEADERS scrobbler/lastfmimport.h organize/organize.h + organize/organizeformatvalidator.h + organize/organizesyntaxhighlighter.h organize/organizedialog.h organize/organizeerrordialog.h diff --git a/src/organize/organizedialog.cpp b/src/organize/organizedialog.cpp index 78b1f7f68..15ae7a4bc 100644 --- a/src/organize/organizedialog.cpp +++ b/src/organize/organizedialog.cpp @@ -67,6 +67,7 @@ #include "collection/collectionbackend.h" #include "organize.h" #include "organizeformat.h" +#include "organizesyntaxhighlighter.h" #include "organizedialog.h" #include "organizeerrordialog.h" #include "ui_organizedialog.h" @@ -125,7 +126,7 @@ OrganizeDialog::OrganizeDialog(SharedPtr task_manager, SharedPtrnaming); + new OrganizeSyntaxHighlighter(ui_->naming); QObject::connect(ui_->destination, QOverload::of(&QComboBox::currentIndexChanged), this, &OrganizeDialog::UpdatePreviews); QObject::connect(ui_->naming, &LineTextEdit::textChanged, this, &OrganizeDialog::UpdatePreviews); diff --git a/src/organize/organizeformat.cpp b/src/organize/organizeformat.cpp index 6b955e2f9..7d0238a3b 100644 --- a/src/organize/organizeformat.cpp +++ b/src/organize/organizeformat.cpp @@ -21,20 +21,12 @@ #include "config.h" -#include -#include -#include #include +#include #include #include #include -#include -#include -#include #include -#include -#include -#include #include "utilities/filenameconstants.h" #include "utilities/timeconstants.h" @@ -42,11 +34,10 @@ #include "core/song.h" #include "organizeformat.h" +#include "organizeformatvalidator.h" -namespace { -constexpr char kBlockPattern[] = "\\{([^{}]+)\\}"; -constexpr char kTagPattern[] = "\\%([a-zA-Z]*)"; -} +const char OrganizeFormat::kBlockPattern[] = "\\{([^{}]+)\\}"; +const char OrganizeFormat::kTagPattern[] = "\\%([a-zA-Z]*)"; const QStringList OrganizeFormat::kKnownTags = QStringList() << QStringLiteral("title") << QStringLiteral("album") @@ -72,14 +63,6 @@ const QStringList OrganizeFormat::kKnownTags = QStringList() << QStringLiteral(" const QStringList OrganizeFormat::kUniqueTags = QStringList() << QStringLiteral("title") << QStringLiteral("track"); -const QRgb OrganizeFormat::SyntaxHighlighter::kValidTagColorLight = qRgb(64, 64, 255); -const QRgb OrganizeFormat::SyntaxHighlighter::kInvalidTagColorLight = qRgb(255, 64, 64); -const QRgb OrganizeFormat::SyntaxHighlighter::kBlockColorLight = qRgb(230, 230, 230); - -const QRgb OrganizeFormat::SyntaxHighlighter::kValidTagColorDark = qRgb(128, 128, 255); -const QRgb OrganizeFormat::SyntaxHighlighter::kInvalidTagColorDark = qRgb(255, 128, 128); -const QRgb OrganizeFormat::SyntaxHighlighter::kBlockColorDark = qRgb(64, 64, 64); - OrganizeFormat::OrganizeFormat(const QString &format) : format_(format), remove_problematic_(false), @@ -98,7 +81,7 @@ bool OrganizeFormat::IsValid() const { int pos = 0; QString format_copy(format_); - Validator v; + OrganizeFormatValidator v; return v.validate(format_copy, pos) == QValidator::Acceptable; } @@ -133,9 +116,15 @@ OrganizeFormat::GetFilenameForSongResult OrganizeFormat::GetFilenameForSong(cons return GetFilenameForSongResult(); } - if (remove_problematic_) filepath = filepath.remove(QRegularExpression(QLatin1String(kProblematicCharactersRegex), QRegularExpression::PatternOption::CaseInsensitiveOption)); + if (remove_problematic_) { + static const QRegularExpression regex_problematic_characters(QLatin1String(kProblematicCharactersRegex), QRegularExpression::PatternOption::CaseInsensitiveOption); + filepath = filepath.remove(regex_problematic_characters); + } if (remove_non_fat_ || (remove_non_ascii_ && !allow_ascii_ext_)) filepath = Utilities::Transliterate(filepath); - if (remove_non_fat_) filepath = filepath.remove(QRegularExpression(QLatin1String(kInvalidFatCharactersRegex), QRegularExpression::PatternOption::CaseInsensitiveOption)); + if (remove_non_fat_) { + static const QRegularExpression regex_invalid_fat_characters(QLatin1String(kInvalidFatCharactersRegex), QRegularExpression::PatternOption::CaseInsensitiveOption); + filepath = filepath.remove(regex_invalid_fat_characters); + } if (remove_non_ascii_) { int ascii = 128; @@ -209,7 +198,7 @@ QString OrganizeFormat::ParseBlock(QString block, const Song &song, bool *have_t // Find any blocks first qint64 pos = 0; - const QRegularExpression block_regexp(QString::fromLatin1(kBlockPattern)); + static const QRegularExpression block_regexp(QString::fromLatin1(kBlockPattern)); QRegularExpressionMatch re_match; for (re_match = block_regexp.match(block, pos); re_match.hasMatch(); re_match = block_regexp.match(block, pos)) { pos = re_match.capturedStart(); @@ -226,7 +215,7 @@ QString OrganizeFormat::ParseBlock(QString block, const Song &song, bool *have_t // Now look for tags bool empty = false; pos = 0; - const QRegularExpression tag_regexp(QString::fromLatin1(kTagPattern)); + static const QRegularExpression tag_regexp(QString::fromLatin1(kTagPattern)); for (re_match = tag_regexp.match(block, pos); re_match.hasMatch(); re_match = tag_regexp.match(block, pos)) { pos = re_match.capturedStart(); const QString tag = re_match.captured(1); @@ -326,89 +315,11 @@ QString OrganizeFormat::TagValue(const QString &tag, const Song &song) const { if (tag == QLatin1String("track") && value.length() == 1) value.prepend(QLatin1Char('0')); // Replace characters that really shouldn't be in paths - value = value.remove(QRegularExpression(QString::fromLatin1(kInvalidDirCharactersRegex), QRegularExpression::PatternOption::CaseInsensitiveOption)); + static const QRegularExpression regex_invalid_dir_characters(QString::fromLatin1(kInvalidDirCharactersRegex), QRegularExpression::PatternOption::CaseInsensitiveOption); + value = value.remove(regex_invalid_dir_characters); if (remove_problematic_) value = value.remove(QLatin1Char('.')); value = value.trimmed(); return value; } - -OrganizeFormat::Validator::Validator(QObject *parent) : QValidator(parent) {} - -QValidator::State OrganizeFormat::Validator::validate(QString &input, int&) const { - - // Make sure all the blocks match up - int block_level = 0; - for (int i = 0; i < input.length(); ++i) { - if (input[i] == QLatin1Char('{')) { - ++block_level; - } - else if (input[i] == QLatin1Char('}')) { - --block_level; - } - - if (block_level < 0 || block_level > 1) return QValidator::Invalid; - } - - if (block_level != 0) return QValidator::Invalid; - - // Make sure the tags are valid - const QRegularExpression tag_regexp(QString::fromLatin1(kTagPattern)); - QRegularExpressionMatch re_match; - qint64 pos = 0; - for (re_match = tag_regexp.match(input, pos); re_match.hasMatch(); re_match = tag_regexp.match(input, pos)) { - pos = re_match.capturedStart(); - if (!OrganizeFormat::kKnownTags.contains(re_match.captured(1))) { - return QValidator::Invalid; - } - - pos += re_match.capturedLength(); - } - - return QValidator::Acceptable; - -} - -OrganizeFormat::SyntaxHighlighter::SyntaxHighlighter(QObject *parent) : QSyntaxHighlighter(parent) {} - -OrganizeFormat::SyntaxHighlighter::SyntaxHighlighter(QTextEdit *parent) : QSyntaxHighlighter(parent) {} - -OrganizeFormat::SyntaxHighlighter::SyntaxHighlighter(QTextDocument *parent) : QSyntaxHighlighter(parent) {} - -void OrganizeFormat::SyntaxHighlighter::highlightBlock(const QString &text) { - - const bool light = QApplication::palette().color(QPalette::Base).value() > 128; - const QRgb block_color = light ? kBlockColorLight : kBlockColorDark; - const QRgb valid_tag_color = light ? kValidTagColorLight : kValidTagColorDark; - const QRgb invalid_tag_color = light ? kInvalidTagColorLight : kInvalidTagColorDark; - - QTextCharFormat block_format; - block_format.setBackground(QColor(block_color)); - - // Reset formatting - setFormat(0, static_cast(text.length()), QTextCharFormat()); - - // Blocks - const QRegularExpression block_regexp(QString::fromLatin1(kBlockPattern)); - QRegularExpressionMatch re_match; - qint64 pos = 0; - for (re_match = block_regexp.match(text, pos); re_match.hasMatch(); re_match = block_regexp.match(text, pos)) { - pos = re_match.capturedStart(); - setFormat(static_cast(pos), static_cast(re_match.capturedLength()), block_format); - pos += re_match.capturedLength(); - } - - // Tags - const QRegularExpression tag_regexp(QString::fromLatin1(kTagPattern)); - pos = 0; - for (re_match = tag_regexp.match(text, pos); re_match.hasMatch(); re_match = tag_regexp.match(text, pos)) { - pos = re_match.capturedStart(); - QTextCharFormat f = format(static_cast(pos)); - f.setForeground(QColor(OrganizeFormat::kKnownTags.contains(re_match.captured(1)) ? valid_tag_color : invalid_tag_color)); - - setFormat(static_cast(pos), static_cast(re_match.capturedLength()), f); - pos += re_match.capturedLength(); - } - -} diff --git a/src/organize/organizeformat.h b/src/organize/organizeformat.h index d61f60104..34c6d7640 100644 --- a/src/organize/organizeformat.h +++ b/src/organize/organizeformat.h @@ -22,17 +22,9 @@ #ifndef ORGANISEFORMAT_H #define ORGANISEFORMAT_H -#include "config.h" - -#include #include #include -#include -#include -#include -class QTextDocument; -class QTextEdit; class Song; class OrganizeFormat { @@ -40,6 +32,11 @@ class OrganizeFormat { public: explicit OrganizeFormat(const QString &format = QString()); + static const char kBlockPattern[]; + static const char kTagPattern[]; + static const QStringList kKnownTags; + static const QStringList kUniqueTags; + QString format() const { return format_; } bool remove_problematic() const { return remove_problematic_; } bool remove_non_fat() const { return remove_non_fat_; } @@ -63,31 +60,7 @@ class OrganizeFormat { }; GetFilenameForSongResult GetFilenameForSong(const Song& song, QString extension = QString()) const; - class Validator : public QValidator { // clazy:exclude=missing-qobject-macro - public: - explicit Validator(QObject *parent = nullptr); - QValidator::State validate(QString &input, int&) const override; - }; - - class SyntaxHighlighter : public QSyntaxHighlighter { // clazy:exclude=missing-qobject-macro - public: - static const QRgb kValidTagColorLight; - static const QRgb kInvalidTagColorLight; - static const QRgb kBlockColorLight; - static const QRgb kValidTagColorDark; - static const QRgb kInvalidTagColorDark; - static const QRgb kBlockColorDark; - - explicit SyntaxHighlighter(QObject *parent = nullptr); - explicit SyntaxHighlighter(QTextEdit *parent); - explicit SyntaxHighlighter(QTextDocument *parent); - void highlightBlock(const QString &text) override; - }; - private: - static const QStringList kKnownTags; - static const QStringList kUniqueTags; - QString ParseBlock(QString block, const Song &song, bool *have_tagdata = nullptr, bool *any_empty = nullptr) const; QString TagValue(const QString &tag, const Song &song) const; diff --git a/src/organize/organizeformatvalidator.cpp b/src/organize/organizeformatvalidator.cpp new file mode 100644 index 000000000..9b9e276bd --- /dev/null +++ b/src/organize/organizeformatvalidator.cpp @@ -0,0 +1,66 @@ +/* + * Strawberry Music Player + * This file was part of Clementine. + * Copyright 2010, David Sansome + * Copyright 2018-2024, Jonas Kvinge + * + * Strawberry is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Strawberry is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Strawberry. If not, see . + * + */ + +#include +#include + +#include "organizeformat.h" +#include "organizeformatvalidator.h" + +OrganizeFormatValidator::OrganizeFormatValidator(QObject *parent) : QValidator(parent) {} + +QValidator::State OrganizeFormatValidator::validate(QString &input, int &_pos) const { + + Q_UNUSED(_pos) + + // Make sure all the blocks match up + int block_level = 0; + for (int i = 0; i < input.length(); ++i) { + if (input[i] == QLatin1Char('{')) { + ++block_level; + } + else if (input[i] == QLatin1Char('}')) { + --block_level; + } + + if (block_level < 0 || block_level > 1) { + return QValidator::Invalid; + } + } + + if (block_level != 0) return QValidator::Invalid; + + // Make sure the tags are valid + static const QRegularExpression tag_regexp(QString::fromLatin1(OrganizeFormat::kTagPattern)); + QRegularExpressionMatch re_match; + qint64 pos = 0; + for (re_match = tag_regexp.match(input, pos); re_match.hasMatch(); re_match = tag_regexp.match(input, pos)) { + pos = re_match.capturedStart(); + if (!OrganizeFormat::kKnownTags.contains(re_match.captured(1))) { + return QValidator::Invalid; + } + + pos += re_match.capturedLength(); + } + + return QValidator::Acceptable; + +} diff --git a/src/organize/organizeformatvalidator.h b/src/organize/organizeformatvalidator.h new file mode 100644 index 000000000..8992db3ff --- /dev/null +++ b/src/organize/organizeformatvalidator.h @@ -0,0 +1,36 @@ +/* + * Strawberry Music Player + * This file was part of Clementine. + * Copyright 2010, David Sansome + * Copyright 2018-2024, Jonas Kvinge + * + * Strawberry is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Strawberry is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Strawberry. If not, see . + * + */ + +#ifndef ORGANISEFORMATVALIDATOR_H +#define ORGANISEFORMATVALIDATOR_H + +#include +#include + +class OrganizeFormatValidator : public QValidator { + Q_OBJECT + + public: + explicit OrganizeFormatValidator(QObject *parent = nullptr); + QValidator::State validate(QString &input, int &_pos) const override; +}; + +#endif // ORGANISEFORMATVALIDATOR_H diff --git a/src/organize/organizesyntaxhighlighter.cpp b/src/organize/organizesyntaxhighlighter.cpp new file mode 100644 index 000000000..9ca4fecdf --- /dev/null +++ b/src/organize/organizesyntaxhighlighter.cpp @@ -0,0 +1,84 @@ +/* + * Strawberry Music Player + * This file was part of Clementine. + * Copyright 2010, David Sansome + * Copyright 2018-2024, Jonas Kvinge + * + * Strawberry is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Strawberry is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Strawberry. If not, see . + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "organizeformat.h" +#include "organizesyntaxhighlighter.h" + +const QRgb OrganizeSyntaxHighlighter::kValidTagColorLight = qRgb(64, 64, 255); +const QRgb OrganizeSyntaxHighlighter::kInvalidTagColorLight = qRgb(255, 64, 64); +const QRgb OrganizeSyntaxHighlighter::kBlockColorLight = qRgb(230, 230, 230); + +const QRgb OrganizeSyntaxHighlighter::kValidTagColorDark = qRgb(128, 128, 255); +const QRgb OrganizeSyntaxHighlighter::kInvalidTagColorDark = qRgb(255, 128, 128); +const QRgb OrganizeSyntaxHighlighter::kBlockColorDark = qRgb(64, 64, 64); + +OrganizeSyntaxHighlighter::OrganizeSyntaxHighlighter(QObject *parent) : QSyntaxHighlighter(parent) {} + +OrganizeSyntaxHighlighter::OrganizeSyntaxHighlighter(QTextEdit *parent) : QSyntaxHighlighter(parent) {} + +OrganizeSyntaxHighlighter::OrganizeSyntaxHighlighter(QTextDocument *parent) : QSyntaxHighlighter(parent) {} + +void OrganizeSyntaxHighlighter::highlightBlock(const QString &text) { + + const bool light = QApplication::palette().color(QPalette::Base).value() > 128; + const QRgb block_color = light ? kBlockColorLight : kBlockColorDark; + const QRgb valid_tag_color = light ? kValidTagColorLight : kValidTagColorDark; + const QRgb invalid_tag_color = light ? kInvalidTagColorLight : kInvalidTagColorDark; + + QTextCharFormat block_format; + block_format.setBackground(QColor(block_color)); + + // Reset formatting + setFormat(0, static_cast(text.length()), QTextCharFormat()); + + // Blocks + static const QRegularExpression block_regexp(QString::fromLatin1(OrganizeFormat::kBlockPattern)); + QRegularExpressionMatch re_match; + qint64 pos = 0; + for (re_match = block_regexp.match(text, pos); re_match.hasMatch(); re_match = block_regexp.match(text, pos)) { + pos = re_match.capturedStart(); + setFormat(static_cast(pos), static_cast(re_match.capturedLength()), block_format); + pos += re_match.capturedLength(); + } + + // Tags + static const QRegularExpression tag_regexp(QString::fromLatin1(OrganizeFormat::kTagPattern)); + pos = 0; + for (re_match = tag_regexp.match(text, pos); re_match.hasMatch(); re_match = tag_regexp.match(text, pos)) { + pos = re_match.capturedStart(); + QTextCharFormat f = format(static_cast(pos)); + f.setForeground(QColor(OrganizeFormat::kKnownTags.contains(re_match.captured(1)) ? valid_tag_color : invalid_tag_color)); + + setFormat(static_cast(pos), static_cast(re_match.capturedLength()), f); + pos += re_match.capturedLength(); + } + +} diff --git a/src/organize/organizesyntaxhighlighter.h b/src/organize/organizesyntaxhighlighter.h new file mode 100644 index 000000000..8ce0268bf --- /dev/null +++ b/src/organize/organizesyntaxhighlighter.h @@ -0,0 +1,49 @@ +/* + * Strawberry Music Player + * This file was part of Clementine. + * Copyright 2010, David Sansome + * Copyright 2018-2024, Jonas Kvinge + * + * Strawberry is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Strawberry is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Strawberry. If not, see . + * + */ + +#ifndef ORGANISESYNTAXHIGHLIGHTER_H +#define ORGANISESYNTAXHIGHLIGHTER_H + +#include +#include +#include + +class QTextDocument; +class QTextEdit; + +class OrganizeSyntaxHighlighter : public QSyntaxHighlighter { + Q_OBJECT + + public: + static const QRgb kValidTagColorLight; + static const QRgb kInvalidTagColorLight; + static const QRgb kBlockColorLight; + static const QRgb kValidTagColorDark; + static const QRgb kInvalidTagColorDark; + static const QRgb kBlockColorDark; + + explicit OrganizeSyntaxHighlighter(QObject *parent = nullptr); + explicit OrganizeSyntaxHighlighter(QTextEdit *parent); + explicit OrganizeSyntaxHighlighter(QTextDocument *parent); + void highlightBlock(const QString &text) override; +}; + +#endif // ORGANISESYNTAXHIGHLIGHTER_H