Audacity 3.2.0
Classes | Public Types | Public Member Functions | Private Member Functions | Private Attributes | List of all members
AccessibleLinksFormatter Class Referencefinal

A class that allows translatable text to have accessible links in it in a way that is friendly to translators. More...

#include <AccessibleLinksFormatter.h>

Collaboration diagram for AccessibleLinksFormatter:
[legend]

Classes

struct  FormatArgument
 
struct  ProcessedArgument
 

Public Types

using LinkClickedHandler = std::function< void()>
 Handler to be called, when the Link is activated. More...
 

Public Member Functions

 AccessibleLinksFormatter (TranslatableString message)
 Create AccessibleLinksFormatter using a TranslatableString. More...
 
AccessibleLinksFormatterFormatLink (wxString placeholder, TranslatableString value, std::string targetURL)
 Replace placeholder with a link, that will open URL in default browser. More...
 
AccessibleLinksFormatterFormatLink (wxString placeholder, TranslatableString value, LinkClickedHandler handler)
 Replace placeholder with a link, that will call a callback provided. More...
 
void Populate (ShuttleGui &S) const
 Generate the UI. More...
 

Private Member Functions

std::vector< ProcessedArgumentProcessArguments (wxString translatedMessage) const
 

Private Attributes

TranslatableString mMessage
 
std::vector< FormatArgumentmFormatArguments
 

Detailed Description

A class that allows translatable text to have accessible links in it in a way that is friendly to translators.

This class allows to replace arbitrary placeholders (like s, url, {} or anything of the choice) with links, that are accessible from the keyboard.

In case there are multiple placeholders with the same name - they will be replaced in order they appear in the message.

Definition at line 29 of file AccessibleLinksFormatter.h.

Member Typedef Documentation

◆ LinkClickedHandler

using AccessibleLinksFormatter::LinkClickedHandler = std::function<void()>

Handler to be called, when the Link is activated.

Definition at line 33 of file AccessibleLinksFormatter.h.

Constructor & Destructor Documentation

◆ AccessibleLinksFormatter()

AccessibleLinksFormatter::AccessibleLinksFormatter ( TranslatableString  message)
explicit

Create AccessibleLinksFormatter using a TranslatableString.

TranslatableString may have the formatting options attached. TranslatableString copy will be stored, so formatting options that are appended after AccessibleLinksFormatter is created won't have any effect on the AccessibleLinksFormatter instance.

Definition at line 38 of file AccessibleLinksFormatter.cpp.

39 : mMessage(std::move(message))
40{
41}

Member Function Documentation

◆ FormatLink() [1/2]

AccessibleLinksFormatter & AccessibleLinksFormatter::FormatLink ( wxString  placeholder,
TranslatableString  value,
LinkClickedHandler  handler 
)

Replace placeholder with a link, that will call a callback provided.

Definition at line 56 of file AccessibleLinksFormatter.cpp.

59{
60 mFormatArguments.push_back({
61 std::move(placeholder),
62 std::move(value),
63 std::move(handler),
64 {}
65 });
66
67 return *this;
68}

References audacity::cloud::audiocom::anonymous_namespace{AuthorizationHandler.cpp}::handler, and mFormatArguments.

◆ FormatLink() [2/2]

AccessibleLinksFormatter & AccessibleLinksFormatter::FormatLink ( wxString  placeholder,
TranslatableString  value,
std::string  targetURL 
)

Replace placeholder with a link, that will open URL in default browser.

Definition at line 43 of file AccessibleLinksFormatter.cpp.

45{
46 mFormatArguments.push_back({
47 std::move(placeholder),
48 std::move(value),
49 {},
50 std::move(targetURL)
51 });
52
53 return *this;
54}

References mFormatArguments.

Referenced by ErrorReportDialog::ErrorReportDialog(), MissingPluginsErrorDialog::MissingPluginsErrorDialog(), NoUpdatesAvailableDialog::NoUpdatesAvailableDialog(), audacity::cloud::audiocom::ShareAudioDialog::InitialStatePanel::PopulateInitialStatePanel(), AboutDialog::PopulateLicensePage(), ApplicationPrefs::PopulateOrExchange(), UnwritableLocationErrorDialog::UnwritableLocationErrorDialog(), and UpdateNoticeDialog::UpdateNoticeDialog().

Here is the caller graph for this function:

◆ Populate()

void AccessibleLinksFormatter::Populate ( ShuttleGui S) const

Generate the UI.

Definition at line 70 of file AccessibleLinksFormatter.cpp.

71{
72 // Just add the text, if there are no links to format
73 if (mFormatArguments.empty())
74 {
75 S.AddFixedText(mMessage);
76 return;
77 }
78
79#ifdef __WXGTK__
80 // Non empty label is required, as wxHyperlinkCtrl would assert otherwise
81 std::unique_ptr<wxHyperlinkCtrl> tempHyperlink
82 = std::make_unique<wxHyperlinkCtrl>(S.GetParent(), wxID_ANY, wxT("temp"), wxString());
83
84 const wxColour hyperlinkColour = tempHyperlink->GetNormalColour();
85
86 tempHyperlink.reset();
87#endif
88
89 wxString translated = mMessage.Translation();
90
91 std::vector<ProcessedArgument> processedArguments =
92 ProcessArguments(translated);
93
94 if (processedArguments.empty())
95 {
96 S.AddFixedText(mMessage);
97 return;
98 }
99
100 const int borderSize = S.GetBorder();
101
102 S.StartHorizontalLay(wxEXPAND);
103 {
104 S.SetBorder(0);
105 S.AddSpace(borderSize);
106
107 S.StartWrapLay(wxEXPAND, 1);
108 {
109 size_t currentPosition = 0;
110
111 for (const ProcessedArgument& processedArgument : processedArguments)
112 {
113 const FormatArgument* argument = processedArgument.Argument;
114
115 // Add everything between currentPosition and PlaceholderPosition
116
117 if (currentPosition != processedArgument.PlaceholderPosition)
118 {
119 const size_t substrLength =
120 processedArgument.PlaceholderPosition - currentPosition;
121
122 S.Prop(0).AddFixedText(
123 Verbatim(translated.substr(currentPosition, substrLength)));
124 }
125
126 // Add hyperlink
127#ifndef __WXGTK__
128 const auto value = argument->Value.Translation();
129 // On macOS wx refuses to create wxHyperlinkCtrl with an empty value
130 if (!value.empty())
131 {
132 wxHyperlinkCtrl* hyperlink = safenew wxHyperlinkCtrl(
133 S.GetParent(), wxID_ANY, argument->Value.Translation(),
134 argument->TargetURL);
135
136 hyperlink->Bind(
137 wxEVT_HYPERLINK,
138 [handler = argument->Handler,
139 url = argument->TargetURL](wxHyperlinkEvent& evt)
140 {
141 if (handler)
142 handler();
143 else if (!url.empty())
144 BasicUI::OpenInDefaultBrowser(url);
145
146 });
147
148
149 S.AddWindow(hyperlink, wxALIGN_TOP | wxALIGN_LEFT);
150 }
151#else
152 wxStaticText* hyperlink = S.AddVariableText(argument->Value);
153
154 hyperlink->SetFont(hyperlink->GetFont().Underlined());
155 hyperlink->SetForegroundColour(hyperlinkColour);
156 hyperlink->SetCursor(wxCURSOR_HAND);
157
158 hyperlink->Bind(wxEVT_LEFT_UP, [handler = argument->Handler, url = argument->TargetURL](wxEvent&) {
159 if (handler)
160 handler();
161 else if (!url.empty())
162 BasicUI::OpenInDefaultBrowser(url);
163 });
164#endif
165 // Update the currentPostion to the first symbol after the
166 // Placeholder
167
169 processedArgument.PlaceholderPosition,
170 argument->Placeholder.Length());
171
172 if (currentPosition >= translated.Length())
173 break;
174 }
175
176 if (currentPosition < translated.Length())
177 S.AddFixedText(Verbatim(translated.substr(currentPosition)));
178 }
179 S.EndWrapLay();
180 }
181 S.EndHorizontalLay();
182
183 S.SetBorder(borderSize);
184}
wxT("CloseDown"))
#define safenew
Definition: MemoryX.h:10
size_t currentPosition
#define S(N)
Definition: ToChars.cpp:64
TranslatableString Verbatim(wxString str)
Require calls to the one-argument constructor to go through this distinct global function name.
wxString Translation() const

References anonymous_namespace{DynamicRangeProcessorEditor.cpp}::borderSize, currentPosition, AccessibleLinksFormatter::FormatArgument::Handler, audacity::cloud::audiocom::anonymous_namespace{AuthorizationHandler.cpp}::handler, mFormatArguments, mMessage, anonymous_namespace{AccessibleLinksFormatter.cpp}::OffsetPosition(), AccessibleLinksFormatter::FormatArgument::Placeholder, ProcessArguments(), S, safenew, AccessibleLinksFormatter::FormatArgument::TargetURL, TranslatableString::Translation(), AccessibleLinksFormatter::FormatArgument::Value, Verbatim(), and wxT().

Referenced by ErrorReportDialog::ErrorReportDialog(), MissingPluginsErrorDialog::MissingPluginsErrorDialog(), NoUpdatesAvailableDialog::NoUpdatesAvailableDialog(), audacity::cloud::audiocom::ShareAudioDialog::InitialStatePanel::PopulateInitialStatePanel(), AboutDialog::PopulateLicensePage(), ApplicationPrefs::PopulateOrExchange(), UnwritableLocationErrorDialog::UnwritableLocationErrorDialog(), and UpdateNoticeDialog::UpdateNoticeDialog().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ ProcessArguments()

std::vector< AccessibleLinksFormatter::ProcessedArgument > AccessibleLinksFormatter::ProcessArguments ( wxString  translatedMessage) const
private

Definition at line 187 of file AccessibleLinksFormatter.cpp.

188{
189 std::vector<ProcessedArgument> result;
190 result.reserve(mFormatArguments.size());
191 // Arguments with the same placeholder are processed left-to-right.
192 // Lets track the last known position of the placeholder
193 std::unordered_map<wxString, size_t> knownPlaceholderPosition;
194
195 for (const FormatArgument& argument : mFormatArguments)
196 {
197 auto it = knownPlaceholderPosition.find(argument.Placeholder);
198
199 const size_t startingPosition =
200 it != knownPlaceholderPosition.end() ?
201 OffsetPosition(it->second, argument.Placeholder.length()) :
202 0;
203
204 const size_t placeholderPosition =
205 startingPosition == wxString::npos ?
207 translatedMessage.find(argument.Placeholder, startingPosition);
208
209 knownPlaceholderPosition[argument.Placeholder] = placeholderPosition;
210
211 if (placeholderPosition != wxString::npos)
212 {
213 result.emplace_back(
214 ProcessedArgument { &argument, placeholderPosition });
215 }
216 }
217
218 std::sort(
219 result.begin(), result.end(),
220 [](const ProcessedArgument& lhs, const ProcessedArgument& rhs) {
221 return lhs.PlaceholderPosition < rhs.PlaceholderPosition;
222 });
223
224 return result;
225}
constexpr size_t npos(-1)

References mFormatArguments, Tuple::detail::npos(), and anonymous_namespace{AccessibleLinksFormatter.cpp}::OffsetPosition().

Referenced by Populate().

Here is the call graph for this function:
Here is the caller graph for this function:

Member Data Documentation

◆ mFormatArguments

std::vector<FormatArgument> AccessibleLinksFormatter::mFormatArguments
private

Definition at line 78 of file AccessibleLinksFormatter.h.

Referenced by FormatLink(), Populate(), and ProcessArguments().

◆ mMessage

TranslatableString AccessibleLinksFormatter::mMessage
private

Definition at line 77 of file AccessibleLinksFormatter.h.

Referenced by Populate().


The documentation for this class was generated from the following files: