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 36 of file AccessibleLinksFormatter.cpp.

37 : mMessage(std::move(message))
38{
39}

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 54 of file AccessibleLinksFormatter.cpp.

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

References 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 41 of file AccessibleLinksFormatter.cpp.

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

References mFormatArguments.

Referenced by ErrorReportDialog::ErrorReportDialog(), NoUpdatesAvailableDialog::NoUpdatesAvailableDialog(), 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 68 of file AccessibleLinksFormatter.cpp.

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

Referenced by ErrorReportDialog::ErrorReportDialog(), NoUpdatesAvailableDialog::NoUpdatesAvailableDialog(), 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 175 of file AccessibleLinksFormatter.cpp.

176{
177 std::vector<ProcessedArgument> result;
178 result.reserve(mFormatArguments.size());
179 // Arguments with the same placeholder are processed left-to-right.
180 // Lets track the last known position of the placeholder
181 std::unordered_map<wxString, size_t> knownPlaceholderPosition;
182
183 for (const FormatArgument& argument : mFormatArguments)
184 {
185 auto it = knownPlaceholderPosition.find(argument.Placeholder);
186
187 const size_t startingPosition =
188 it != knownPlaceholderPosition.end() ?
189 OffsetPosition(it->second, argument.Placeholder.length()) :
190 0;
191
192 const size_t placeholderPosition =
193 startingPosition == wxString::npos ?
194 wxString::npos :
195 translatedMessage.find(argument.Placeholder, startingPosition);
196
197 knownPlaceholderPosition[argument.Placeholder] = placeholderPosition;
198
199 if (placeholderPosition != wxString::npos)
200 {
201 result.emplace_back(
202 ProcessedArgument { &argument, placeholderPosition });
203 }
204 }
205
206 std::sort(
207 result.begin(), result.end(),
208 [](const ProcessedArgument& lhs, const ProcessedArgument& rhs) {
209 return lhs.PlaceholderPosition < rhs.PlaceholderPosition;
210 });
211
212 return result;
213}

References mFormatArguments, 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: