Audacity  3.0.3
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 anyting 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(), 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  {
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  {
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 }

References ShuttleGuiBase::AddFixedText(), ShuttleGui::AddSpace(), ShuttleGuiBase::AddVariableText(), ShuttleGuiBase::AddWindow(), currentPosition, ShuttleGuiBase::EndHorizontalLay(), ShuttleGuiBase::EndWrapLay(), ShuttleGuiBase::GetBorder(), ShuttleGuiBase::GetParent(), AccessibleLinksFormatter::FormatArgument::Handler, mFormatArguments, mMessage, anonymous_namespace{AccessibleLinksFormatter.cpp}::OffsetPosition(), AccessibleLinksFormatter::FormatArgument::Placeholder, ProcessArguments(), ShuttleGui::Prop(), safenew, ShuttleGuiBase::SetBorder(), ShuttleGuiBase::StartHorizontalLay(), ShuttleGuiBase::StartWrapLay(), AccessibleLinksFormatter::FormatArgument::TargetURL, TranslatableString::Translation(), AccessibleLinksFormatter::FormatArgument::Value, and Verbatim().

Referenced by ErrorReportDialog::ErrorReportDialog(), 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:
currentPosition
size_t currentPosition
Definition: ScripterCallback.cpp:62
ShuttleGuiBase::EndWrapLay
void EndWrapLay()
Definition: ShuttleGui.cpp:1221
ShuttleGui::AddSpace
wxSizerItem * AddSpace(int width, int height, int prop=0)
Definition: ShuttleGui.cpp:2459
ShuttleGuiBase::GetBorder
int GetBorder() const noexcept
Definition: ShuttleGui.cpp:196
ShuttleGuiBase::EndHorizontalLay
void EndHorizontalLay()
Definition: ShuttleGui.cpp:1177
ShuttleGuiBase::StartHorizontalLay
void StartHorizontalLay(int PositionFlags=wxALIGN_CENTRE, int iProp=1)
Definition: ShuttleGui.cpp:1167
ShuttleGuiBase::AddFixedText
void AddFixedText(const TranslatableString &Str, bool bCenter=false, int wrapWidth=0)
Definition: ShuttleGui.cpp:440
ShuttleGuiBase::GetParent
wxWindow * GetParent()
Definition: ShuttleGui.h:496
ShuttleGuiBase::AddWindow
wxWindow * AddWindow(wxWindow *pWindow, int PositionFlags=wxALIGN_CENTRE)
Definition: ShuttleGui.cpp:299
ShuttleGui::Prop
ShuttleGui & Prop(int iProp)
Definition: ShuttleGui.h:725
Verbatim
TranslatableString Verbatim(wxString str)
Require calls to the one-argument constructor to go through this distinct global function name.
Definition: TranslatableString.h:321
TranslatableString::Translation
wxString Translation() const
Definition: TranslatableString.h:79
ShuttleGuiBase::SetBorder
void SetBorder(int Border)
Definition: ShuttleGui.h:489
ShuttleGuiBase::AddVariableText
wxStaticText * AddVariableText(const TranslatableString &Str, bool bCenter=false, int PositionFlags=0, int wrapWidth=0)
Definition: ShuttleGui.cpp:463
safenew
#define safenew
Definition: MemoryX.h:10
ShuttleGuiBase::StartWrapLay
void StartWrapLay(int PositionFlags=wxEXPAND, int iProp=0)
Definition: ShuttleGui.cpp:1210