From a08cbf41cf2b3087029c19db49dfca5aa01a4b2d Mon Sep 17 00:00:00 2001 From: Juergen Spitzmueller Date: Tue, 24 Dec 2019 14:31:08 +0100 Subject: [PATCH] Provide way to add (optional) user initials This makes it easier to hook the changes package into LyX's ct markup. --- lib/layouts/changebars.module | 10 +-- src/Author.cpp | 8 +- src/Author.h | 7 +- src/BufferParams.cpp | 4 +- src/Changes.cpp | 48 ++++++++-- src/LaTeXFeatures.cpp | 14 +-- src/LyXRC.cpp | 10 +++ src/LyXRC.h | 3 + src/frontends/qt/GuiPrefs.cpp | 8 +- src/frontends/qt/ui/PrefIdentityUi.ui | 121 +++++++++++++++----------- src/tex2lyx/Preamble.cpp | 6 +- src/tex2lyx/Preamble.h | 2 +- src/tex2lyx/text.cpp | 6 +- 13 files changed, 166 insertions(+), 81 deletions(-) diff --git a/lib/layouts/changebars.module b/lib/layouts/changebars.module index b35c03cbb5..f0c27f3be3 100644 --- a/lib/layouts/changebars.module +++ b/lib/layouts/changebars.module @@ -19,12 +19,12 @@ Format 80 AddToPreamble \usepackage{changebar} - \providecommand{\lyxadded}[3]{} + \providecommand{\lyxadded}[4][]{} \providecommand{\lyxdeleted}{} - \renewcommand{\lyxadded}[3]{ - {\protect\cbstart\color{lyxadded}{}#3\protect\cbend} + \renewcommand{\lyxadded}[4][]{ + {\protect\cbstart\color{lyxadded}{}#4\protect\cbend} } - \renewcommand{\lyxdeleted}[3]{% - {\protect\cbstart\color{lyxdeleted}\sout{#3}\protect\cbend} + \renewcommand{\lyxdeleted}[4][]{% + {\protect\cbstart\color{lyxdeleted}\sout{#4}\protect\cbend} } EndPreamble diff --git a/src/Author.cpp b/src/Author.cpp index 3d03fe7113..b70815c349 100644 --- a/src/Author.cpp +++ b/src/Author.cpp @@ -37,14 +37,14 @@ static int computeHash(docstring const & name, } -Author::Author(docstring const & name, docstring const & email) - : name_(name), email_(email), used_(true), +Author::Author(docstring const & name, docstring const & email, docstring const & initials) + : name_(name), email_(email), initials_(initials), used_(true), buffer_id_(computeHash(name, email)) {} Author::Author(int buffer_id) - : name_(convert(buffer_id)), email_(docstring()), used_(false), + : name_(convert(buffer_id)), email_(docstring()), initials_(docstring()), used_(false), buffer_id_(buffer_id) {} @@ -67,7 +67,7 @@ bool Author::valid() const bool operator==(Author const & l, Author const & r) { - return l.name() == r.name() && l.email() == r.email(); + return l.name() == r.name() && l.email() == r.email() && l.initials() == r.initials(); } diff --git a/src/Author.h b/src/Author.h index 108a701e82..b498655aa0 100644 --- a/src/Author.h +++ b/src/Author.h @@ -24,7 +24,8 @@ public: /// Author() : used_(false), buffer_id_(0) {}; /// - Author(docstring const & name, docstring const & email); + Author(docstring const & name, docstring const & email, + docstring const & initials); /// For when the \author line is missing (#9854) Author(int buffer_id); /// @@ -32,6 +33,8 @@ public: /// docstring email() const { return email_; } /// + docstring initials() const { return initials_; } + /// docstring nameAndEmail() const; /// int bufferId() const { return buffer_id_; } @@ -53,6 +56,8 @@ private: docstring name_; /// The author's email address docstring email_; + /// The author's initials + docstring initials_; /// mutable bool used_; /// The id of the author in the lyx-file diff --git a/src/BufferParams.cpp b/src/BufferParams.cpp index 22793ecb99..3b0b8310b2 100644 --- a/src/BufferParams.cpp +++ b/src/BufferParams.cpp @@ -365,7 +365,9 @@ BufferParams::Impl::Impl() { // set initial author // FIXME UNICODE - authorlist.record(Author(from_utf8(lyxrc.user_name), from_utf8(lyxrc.user_email))); + authorlist.record(Author(from_utf8(lyxrc.user_name), + from_utf8(lyxrc.user_email), + from_utf8(lyxrc.user_initials))); } diff --git a/src/Changes.cpp b/src/Changes.cpp index 8c96338a40..f8f70e1da8 100644 --- a/src/Changes.cpp +++ b/src/Changes.cpp @@ -338,7 +338,7 @@ void Changes::merge() namespace { -docstring getLaTeXMarkup(docstring const & macro, docstring const & author, +docstring getLaTeXMarkup(docstring const & macro, Author const & author, docstring const & chgTime, OutputParams const & runparams) { @@ -348,18 +348,52 @@ docstring getLaTeXMarkup(docstring const & macro, docstring const & author, docstring uncodable_author; odocstringstream ods; + docstring const author_name = author.name(); + docstring const author_initials = author.initials(); + ods << macro; + if (!author_initials.empty()) { + docstring uncodable_initials; + // convert utf8 author initials to something representable + // in the current encoding + pair author_initials_latexed = + runparams.encoding->latexString(author_initials, runparams.dryrun); + if (!author_initials_latexed.second.empty()) { + LYXERR0("Omitting uncodable characters '" + << author_initials_latexed.second + << "' in change author initials!"); + uncodable_initials = author_initials; + } + ods << "[" << author_initials_latexed.first << "]"; + // warn user (once) if we found uncodable glyphs. + if (!uncodable_initials.empty()) { + static std::set warned_author_initials; + static Mutex warned_mutex; + Mutex::Locker locker(&warned_mutex); + if (warned_author_initials.find(uncodable_initials) == warned_author_initials.end()) { + frontend::Alert::warning(_("Uncodable character in author initials"), + support::bformat(_("The author initials '%1$s',\n" + "used for change tracking, contain the following glyphs that\n" + "cannot be represented in the current encoding: %2$s.\n" + "These glyphs will be omitted in the exported LaTeX file.\n\n" + "Choose an appropriate document encoding (such as utf8)\n" + "or change the author initials."), + uncodable_initials, author_initials_latexed.second)); + warned_author_initials.insert(uncodable_author); + } + } + } // convert utf8 author name to something representable // in the current encoding pair author_latexed = - runparams.encoding->latexString(author, runparams.dryrun); + runparams.encoding->latexString(author_name, runparams.dryrun); if (!author_latexed.second.empty()) { LYXERR0("Omitting uncodable characters '" << author_latexed.second << "' in change author name!"); - uncodable_author = author; + uncodable_author = author_name; } - ods << author_latexed.first << "}{" << chgTime << "}{"; + ods << "{" << author_latexed.first << "}{" << chgTime << "}{"; // warn user (once) if we found uncodable glyphs. if (!uncodable_author.empty()) { @@ -414,15 +448,15 @@ int Changes::latexMarkChange(otexstream & os, BufferParams const & bparams, docstring macro_beg; if (change.type == Change::DELETED) { - macro_beg = from_ascii("\\lyxdeleted{"); + macro_beg = from_ascii("\\lyxdeleted"); if (!runparams.inDisplayMath && !dvipost) ++runparams.inulemcmd; } else if (change.type == Change::INSERTED) - macro_beg = from_ascii("\\lyxadded{"); + macro_beg = from_ascii("\\lyxadded"); docstring str = getLaTeXMarkup(macro_beg, - bparams.authors().get(change.author).name(), + bparams.authors().get(change.author), chgTime, runparams); // signature needed by \lyxsout to correctly strike out display math diff --git a/src/LaTeXFeatures.cpp b/src/LaTeXFeatures.cpp index cd04b4c0f2..533f5ad696 100644 --- a/src/LaTeXFeatures.cpp +++ b/src/LaTeXFeatures.cpp @@ -242,20 +242,20 @@ static docstring const changetracking_dvipost_def = from_ascii( "\\dvipost{osend color pop}\n" "\\dvipost{cbstart color push Blue}\n" "\\dvipost{cbend color pop}\n" - "\\DeclareRobustCommand{\\lyxadded}[3]{\\changestart#3\\changeend}\n" - "\\DeclareRobustCommand{\\lyxdeleted}[3]{%\n" - "\\changestart\\overstrikeon#3\\overstrikeoff\\changeend}\n"); + "\\DeclareRobustCommand{\\lyxadded}[4][]{\\changestart#4\\changeend}\n" + "\\DeclareRobustCommand{\\lyxdeleted}[4][]{%\n" + "\\changestart\\overstrikeon#4\\overstrikeoff\\changeend}\n"); static docstring const changetracking_xcolor_ulem_def = from_ascii( "%% Change tracking with ulem\n" - "\\DeclareRobustCommand{\\lyxadded}[3]{{\\color{lyxadded}{}#3}}\n" - "\\DeclareRobustCommand{\\lyxdeleted}[3]{{\\color{lyxdeleted}\\lyxsout{#3}}}\n" + "\\DeclareRobustCommand{\\lyxadded}[4][]{{\\color{lyxadded}{}#4}}\n" + "\\DeclareRobustCommand{\\lyxdeleted}[4][]{{\\color{lyxdeleted}\\lyxsout{#4}}}\n" "\\DeclareRobustCommand{\\lyxsout}[1]{\\ifx\\\\#1\\else\\sout{#1}\\fi}\n"); static docstring const changetracking_xcolor_ulem_hyperref_def = from_ascii( "%% Change tracking with ulem\n" - "\\DeclareRobustCommand{\\lyxadded}[3]{{\\texorpdfstring{\\color{lyxadded}{}}{}#3}}\n" - "\\DeclareRobustCommand{\\lyxdeleted}[3]{{\\texorpdfstring{\\color{lyxdeleted}\\lyxsout{#3}}{}}}\n" + "\\DeclareRobustCommand{\\lyxadded}[4][]{{\\texorpdfstring{\\color{lyxadded}{}}{}#4}}\n" + "\\DeclareRobustCommand{\\lyxdeleted}[4][]{{\\texorpdfstring{\\color{lyxdeleted}\\lyxsout{#4}}{}}}\n" "\\DeclareRobustCommand{\\lyxsout}[1]{\\ifx\\\\#1\\else\\sout{#1}\\fi}\n"); static docstring const changetracking_tikz_math_sout_def = from_ascii( diff --git a/src/LyXRC.cpp b/src/LyXRC.cpp index 83bf82d0f7..19e28a3b58 100644 --- a/src/LyXRC.cpp +++ b/src/LyXRC.cpp @@ -201,6 +201,7 @@ LexerKeyword lyxrcTags[] = { { "\\use_system_theme_icons", LyXRC::RC_USE_SYSTEM_THEME_ICONS }, { "\\use_tooltip", LyXRC::RC_USE_TOOLTIP }, { "\\user_email", LyXRC::RC_USER_EMAIL }, + { "\\user_initials", LyXRC::RC_USER_INITIALS }, { "\\user_name", LyXRC::RC_USER_NAME }, { "\\view_dvi_paper_option", LyXRC::RC_VIEWDVI_PAPEROPTION }, // compatibility with versions older than 1.4.0 only @@ -971,6 +972,9 @@ LyXRC::ReturnValues LyXRC::read(Lexer & lexrc, bool check_format) case RC_USER_EMAIL: lexrc >> user_email; break; + case RC_USER_INITIALS: + lexrc >> user_initials; + break; case RC_PATH_PREFIX: lexrc >> path_prefix; @@ -1446,6 +1450,11 @@ void LyXRC::write(ostream & os, bool ignore_system_lyxrc, string const & name) c if (tag != RC_LAST) break; // fall through + case RC_USER_INITIALS: + os << "\\user_initials \"" << user_initials << "\"\n"; + if (tag != RC_LAST) + break; + // fall through case RC_SHOW_BANNER: if (ignore_system_lyxrc || show_banner != system_lyxrc.show_banner) { @@ -2869,6 +2878,7 @@ void actOnUpdatedPrefs(LyXRC const & lyxrc_orig, LyXRC const & lyxrc_new) case LyXRC::RC_THESAURUSDIRPATH: case LyXRC::RC_UIFILE: case LyXRC::RC_USER_EMAIL: + case LyXRC::RC_USER_INITIALS: case LyXRC::RC_USER_NAME: case LyXRC::RC_USE_CONVERTER_CACHE: case LyXRC::RC_USE_CONVERTER_NEEDAUTH_FORBIDDEN: diff --git a/src/LyXRC.h b/src/LyXRC.h index 10df6361ae..8e47c49120 100644 --- a/src/LyXRC.h +++ b/src/LyXRC.h @@ -169,6 +169,7 @@ public: RC_UIFILE, RC_USELASTFILEPOS, RC_USER_EMAIL, + RC_USER_INITIALS, RC_USER_NAME, RC_USE_CONVERTER_CACHE, RC_USE_CONVERTER_NEEDAUTH_FORBIDDEN, @@ -449,6 +450,8 @@ public: std::string user_name; // set in constructor /// user email std::string user_email; // set in constructor (empty for now) + /// user initials + std::string user_initials; /// icon set name std::string icon_set; /// whether to use the icons from the theme diff --git a/src/frontends/qt/GuiPrefs.cpp b/src/frontends/qt/GuiPrefs.cpp index 02c9234ae3..be6204ba29 100644 --- a/src/frontends/qt/GuiPrefs.cpp +++ b/src/frontends/qt/GuiPrefs.cpp @@ -3409,9 +3409,12 @@ PrefIdentity::PrefIdentity(GuiPreferences * form) this, SIGNAL(changed())); connect(emailED, SIGNAL(textChanged(QString)), this, SIGNAL(changed())); + connect(initialsED, SIGNAL(textChanged(QString)), + this, SIGNAL(changed())); nameED->setValidator(new NoNewLineValidator(nameED)); emailED->setValidator(new NoNewLineValidator(emailED)); + initialsED->setValidator(new NoNewLineValidator(initialsED)); } @@ -3419,6 +3422,7 @@ void PrefIdentity::applyRC(LyXRC & rc) const { rc.user_name = fromqstr(nameED->text()); rc.user_email = fromqstr(emailED->text()); + rc.user_initials = fromqstr(initialsED->text()); } @@ -3426,6 +3430,7 @@ void PrefIdentity::updateRC(LyXRC const & rc) { nameED->setText(toqstr(rc.user_name)); emailED->setText(toqstr(rc.user_email)); + initialsED->setText(toqstr(rc.user_initials)); } @@ -3565,7 +3570,8 @@ void GuiPreferences::dispatchParams() // FIXME: these need lfuns // FIXME UNICODE Author const & author = - Author(from_utf8(rc_.user_name), from_utf8(rc_.user_email)); + Author(from_utf8(rc_.user_name), from_utf8(rc_.user_email), + from_utf8(rc_.user_initials)); theBufferList().recordCurrentAuthor(author); theFormats() = formats_; diff --git a/src/frontends/qt/ui/PrefIdentityUi.ui b/src/frontends/qt/ui/PrefIdentityUi.ui index bd146b31d7..974bdd0c84 100644 --- a/src/frontends/qt/ui/PrefIdentityUi.ui +++ b/src/frontends/qt/ui/PrefIdentityUi.ui @@ -1,77 +1,99 @@ - + + PrefIdentityUi - - + + 0 0 - 388 - 209 + 433 + 135 - + - - - 11 - - - 6 - - - - - 0 - - - 6 - - - - - &E-mail: + + + + + + + &Name: - - emailED + + nameED - - - - Your name - - + + + + + + Your name + + + + + + + &Initials: + + + initialsED + + + + + + + + 0 + 0 + + + + + 50 + 16777215 + + + + Initials of your name + + + + - - - - &Name: + + + + &E-mail: - - nameED + + emailED - - - + + + Your E-mail address - + - + Qt::Vertical - + QSizePolicy::Expanding - + 20 20 @@ -81,14 +103,13 @@ - - - qt_i18n.h - nameED emailED + + qt_i18n.h + diff --git a/src/tex2lyx/Preamble.cpp b/src/tex2lyx/Preamble.cpp index 38139b40ea..b489859068 100644 --- a/src/tex2lyx/Preamble.cpp +++ b/src/tex2lyx/Preamble.cpp @@ -411,9 +411,9 @@ void Preamble::suppressDate(bool suppress) } -void Preamble::registerAuthor(std::string const & name) +void Preamble::registerAuthor(std::string const & name, string const & initials) { - Author author(from_utf8(name), empty_docstring()); + Author author(from_utf8(name), empty_docstring(), from_utf8(initials)); author.setUsed(true); authors_.record(author); h_tracking_changes = "true"; @@ -423,7 +423,7 @@ void Preamble::registerAuthor(std::string const & name) Author const & Preamble::getAuthor(std::string const & name) const { - Author author(from_utf8(name), empty_docstring()); + Author author(from_utf8(name), empty_docstring(), empty_docstring()); for (AuthorList::Authors::const_iterator it = authors_.begin(); it != authors_.end(); ++it) if (*it == author) diff --git a/src/tex2lyx/Preamble.h b/src/tex2lyx/Preamble.h index 6a29c45497..de20b5ede8 100644 --- a/src/tex2lyx/Preamble.h +++ b/src/tex2lyx/Preamble.h @@ -92,7 +92,7 @@ public: /// void titleLayoutFound(bool found) { title_layout_found = found; } /// Register an author named \p name in the author list - void registerAuthor(std::string const & name); + void registerAuthor(std::string const & name, std::string const & initials); /// Get author named \p name (must be registered first) Author const & getAuthor(std::string const & name) const; /// Get number of arguments of special table column type \c or -1 diff --git a/src/tex2lyx/text.cpp b/src/tex2lyx/text.cpp index 9dc589d5e3..626311f17e 100644 --- a/src/tex2lyx/text.cpp +++ b/src/tex2lyx/text.cpp @@ -4053,9 +4053,13 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, if (t.cs() == "lyxadded" || t.cs() == "lyxdeleted") { context.check_layout(os); + string initials; + if (p.hasOpt()) { + initials = p.getArg('[', ']'); + } string name = p.getArg('{', '}'); string localtime = p.getArg('{', '}'); - preamble.registerAuthor(name); + preamble.registerAuthor(name, initials); Author const & author = preamble.getAuthor(name); // from_asctime_utc() will fail if LyX decides to output the // time in the text language. -- 2.39.5