From 231cf75bf54e75c6bd4a5bd269b9edac0dcf1f85 Mon Sep 17 00:00:00 2001 From: precondition <57645186+precondition@users.noreply.github.com> Date: Thu, 23 Jan 2025 13:20:44 +0100 Subject: [PATCH] src/anki/ankiclient: add {pitch-categories} marker This marker is a comma-separated list of all the distinct pitch accent categories applicable to the term. Available pitch accent categories: 1. heiban 2. atamadaka 3. nakadaka 4. kifuku 5. odaka Partially solves #250. --- src/anki/ankiclient.cpp | 70 +++++++- src/anki/ankiclient.h | 29 +++- src/gui/widgets/settings/ankisettings.cpp | 1 + src/gui/widgets/settings/ankisettingshelp.ui | 162 +++++++++++-------- 4 files changed, 184 insertions(+), 78 deletions(-) diff --git a/src/anki/ankiclient.cpp b/src/anki/ankiclient.cpp index 99269b7..c3f8a08 100644 --- a/src/anki/ankiclient.cpp +++ b/src/anki/ankiclient.cpp @@ -1124,9 +1124,12 @@ QJsonObject AnkiClient::createAnkiNoteObject( ); QString pitch; + QString pitchCategories; QString pitchGraph; QString pitchPosition; - buildPitchInfo(term.pitches, pitch, pitchGraph, pitchPosition); + const bool canBeKifuku{isKifukuApplicable(term.definitions)}; + buildPitchInfo(term.pitches, canBeKifuku, pitch, pitchCategories, + pitchGraph, pitchPosition); QString tags, tagsBrief; buildTags(term.tags, tags, tagsBrief); @@ -1152,6 +1155,7 @@ QJsonObject AnkiClient::createAnkiNoteObject( value.replace(REPLACE_GLOSSARY_BRIEF, glossaryBrief); value.replace(REPLACE_GLOSSARY_COMPACT, glossaryCompact); value.replace(REPLACE_PITCH, pitch); + value.replace(REPLACE_PITCH_CATEGORIES, pitchCategories); value.replace(REPLACE_PITCH_GRAPHS, pitchGraph); value.replace(REPLACE_PITCH_POSITIONS, pitchPosition); value.replace(REPLACE_READING, reading); @@ -1556,7 +1560,9 @@ void AnkiClient::buildCommonNote( #define PITCH_FORMAT (QString("%2")) void AnkiClient::buildPitchInfo(const QList &pitches, + const bool canBeKifuku, QString &pitch, + QString &pitchCategories, QString &pitchGraph, QString &pitchPosition) { @@ -1569,6 +1575,8 @@ void AnkiClient::buildPitchInfo(const QList &pitches, pitchGraph += ""; pitchPosition += ""; + QSet pitchCategoriesSet{}; + const bool multipleDicts = pitches.size() > 1; if (multipleDicts) @@ -1611,10 +1619,11 @@ void AnkiClient::buildPitchInfo(const QList &pitches, pitchPosition += "
  • "; } - /* Build {pitch} marker */ + /* Build {pitch} and {pitch-categories} markers */ switch (pos) { case 0: + pitchCategoriesSet << "heiban"; pitch += p.mora.first(); if (p.mora.size() > 1) { @@ -1624,6 +1633,7 @@ void AnkiClient::buildPitchInfo(const QList &pitches, } break; case 1: + pitchCategoriesSet << (canBeKifuku ? "kifuku" : "atamadaka"); pitch += PITCH_FORMAT.arg(HL_STYLE).arg(p.mora.first()); if (p.mora.size() > 1) { @@ -1632,6 +1642,18 @@ void AnkiClient::buildPitchInfo(const QList &pitches, break; default: { + if (p.mora.size() == pos) + { + pitchCategoriesSet << "odaka"; + } + else if (canBeKifuku) + { + pitchCategoriesSet << "kifuku"; + } + else + { + pitchCategoriesSet << "nakadaka"; + } QString text = p.mora.first(); pitch += text; @@ -1698,6 +1720,20 @@ void AnkiClient::buildPitchInfo(const QList &pitches, pitch += ""; pitchGraph += ""; pitchPosition += ""; + + bool isFirstPitchCategory{true}; + for (const QString &pitchCategory : pitchCategoriesSet) + { + if (isFirstPitchCategory) + { + pitchCategories += pitchCategory; + isFirstPitchCategory = false; + } + else + { + pitchCategories += "," + pitchCategory; + } + } } #undef HL_STYLE @@ -1905,4 +1941,34 @@ QString AnkiClient::fileToBase64(const QString &path) return file.readAll().toBase64(); } +bool AnkiClient::isKifukuApplicable(const QList &defs) +{ + bool canBeKifuku{false}; + + for (const TermDefinition &def : defs) + { + for (const QString &rule : def.rules) + { + /* See http://www.edrdg.org/jmwsgi/edhelp.py?svc=jmdict&sid=#kw_pos + * for more information on the meaning of JMDict part-of-speech tags + * such as "v1", "adj-i", etc. + */ + if (rule == "v1" || // Ichidan verb + rule == "v5" || // Godan verb + rule == "vk" || // Kuru verb - special class + rule == "vz" || // Ichidan verb - zuru verb (alternative form of -jiru verb) + rule == "adj-i") // I-adjective (keiyoushi) + { + canBeKifuku = true; + } + else if (rule == "vs") // Noun or participle which takes the aux. verb suru + { + return false; + } + } + } + + return canBeKifuku; +} + /* End Note Helpers */ diff --git a/src/anki/ankiclient.h b/src/anki/ankiclient.h index c95df5b..11a3993 100644 --- a/src/anki/ankiclient.h +++ b/src/anki/ankiclient.h @@ -63,6 +63,7 @@ #define REPLACE_GLOSSARY_BRIEF "{glossary-brief}" #define REPLACE_GLOSSARY_COMPACT "{glossary-compact}" #define REPLACE_PITCH "{pitch}" +#define REPLACE_PITCH_CATEGORIES "{pitch-categories}" #define REPLACE_PITCH_GRAPHS "{pitch-graph}" #define REPLACE_PITCH_POSITIONS "{pitch-position}" #define REPLACE_READING "{reading}" @@ -477,17 +478,23 @@ private Q_SLOTS: int getFrequencyAverage(const QList &freq); /** - * Creates the HTML representation of the pitch, pitch graph, and pitch - * position for the given pitches. - * @param pitches The pitches to turn into HTML. - * @param[out] pitch The HTML representation of the {pitch} marker. - * @param[out] pitchGraph The HTML representation of the {pitch-graph} - * marker. - * @param[out] pitchPosition The HTML representation of the {pitch-position} - * marker. + * Creates the HTML representation of the pitch, pitch category, pitch graph, + * and pitch position for the given pitches. + * @param pitches The pitches to turn into HTML. + * @param canBeKifuku Is the term an i-adjective or a verb whose + * pitch accent is either kifuku or heiban. + * @param[out] pitch The HTML representation of the {pitch} marker. + * @param[out] pitchCategories The comma-separated representation of the + * {pitch-categories} marker. + * @param[out] pitchGraph The HTML representation of the {pitch-graph} + * marker. + * @param[out] pitchPosition The HTML representation of the {pitch-position} + * marker. */ void buildPitchInfo(const QList &pitches, + const bool canBeKifuku, QString &pitch, + QString &pitchCategories, QString &pitchGraph, QString &pitchPosition); @@ -530,6 +537,12 @@ private Q_SLOTS: */ static QString fileToBase64(const QString &path); + /** + * Helper method to determine if the kifuku pitch accent pattern + * is potentially applicable to a term, by checking its part-of-speech. + */ + bool isKifukuApplicable(const QList &defs); + /* true if a config exists, false otherwise */ bool m_configExists = false; diff --git a/src/gui/widgets/settings/ankisettings.cpp b/src/gui/widgets/settings/ankisettings.cpp index a753e02..1c36a30 100644 --- a/src/gui/widgets/settings/ankisettings.cpp +++ b/src/gui/widgets/settings/ankisettings.cpp @@ -72,6 +72,7 @@ AnkiSettings::AnkiSettings(QWidget *parent) REPLACE_GLOSSARY_BRIEF, REPLACE_GLOSSARY_COMPACT, REPLACE_PITCH, + REPLACE_PITCH_CATEGORIES, REPLACE_PITCH_GRAPHS, REPLACE_PITCH_POSITIONS, REPLACE_READING, diff --git a/src/gui/widgets/settings/ankisettingshelp.ui b/src/gui/widgets/settings/ankisettingshelp.ui index 7a57f20..9b5c493 100644 --- a/src/gui/widgets/settings/ankisettingshelp.ui +++ b/src/gui/widgets/settings/ankisettingshelp.ui @@ -62,14 +62,14 @@ These will expand to larger expressions in the final card. - + Screenshot of the current frame. - + Title of the video. Filename if no title. @@ -95,14 +95,7 @@ These will expand to larger expressions in the final card. - - - - Pitch graphs for the reading of the term. - - - - + @@ -128,7 +121,7 @@ These will expand to larger expressions in the final card. - + @@ -154,7 +147,7 @@ These will expand to larger expressions in the final card. - + The reading of the word in kana. @@ -202,7 +195,7 @@ These will expand to larger expressions in the final card. - + Screenshot of the current frame without subtitles if visible. @@ -228,7 +221,7 @@ These will expand to larger expressions in the final card. - + The current secondary subtitle. @@ -261,6 +254,63 @@ These will expand to larger expressions in the final card. + + + + + 75 + true + + + + {pitch-categories} + + + Qt::AlignCenter + + + Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse + + + + + + + + 75 + true + + + + {pitch-graph} + + + Qt::AlignCenter + + + Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse + + + + + + + + 75 + true + + + + {pitch-position} + + + Qt::AlignCenter + + + Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse + + + @@ -322,14 +372,7 @@ These will expand to larger expressions in the final card. - - - - Pitch positions for the reading of the term. - - - - + @@ -420,25 +463,6 @@ These will expand to larger expressions in the final card. - - - - - 75 - true - - - - {pitch-graph} - - - Qt::AlignCenter - - - Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse - - - @@ -458,7 +482,7 @@ These will expand to larger expressions in the final card. - + Bulleted list of the term tags. @@ -640,26 +664,7 @@ These will expand to larger expressions in the final card. - - - - - 75 - true - - - - {pitch-position} - - - Qt::AlignCenter - - - Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse - - - - + @@ -698,7 +703,7 @@ These will expand to larger expressions in the final card. - + @@ -724,7 +729,28 @@ These will expand to larger expressions in the final card. - + + + + Comma-separated list of pitch accent categories for the term: heiban, kifuku, atamadaka, nakadaka, odaka + + + + + + + Pitch graphs for the reading of the term. + + + + + + + Pitch positions for the reading of the term. + + + + The current subtitle. @@ -773,7 +799,7 @@ These will expand to larger expressions in the final card. - + @@ -792,7 +818,7 @@ These will expand to larger expressions in the final card. - + @@ -811,14 +837,14 @@ These will expand to larger expressions in the final card. - + Bulleted list of the term tags without description. - +