Audacity  2.2.2
HelpSystem.cpp
Go to the documentation of this file.
1 /**********************************************************************
2 
3  Audacity: A Digital Audio Editor
4 
5  HelpSystem.cpp
6 
7  Jimmy Johnson
8  Leland Lucius
9  Richard Ash
10 
11 *//********************************************************************/
12 
13 #include "../Audacity.h"
14 
15 #include <wx/button.h>
16 #include <wx/icon.h>
17 #include <wx/dialog.h>
18 #include <wx/intl.h>
19 #include <wx/sizer.h>
20 #include <wx/stattext.h>
21 #include <wx/utils.h>
22 #include <wx/html/htmlwin.h>
23 #include <wx/settings.h>
24 #include <wx/statusbr.h>
25 #include <wx/regex.h>
26 
27 #include "../FileNames.h"
28 #include "LinkingHtmlWindow.h"
29 #include "../Theme.h"
30 #include "../AllThemeResources.h"
31 #include "../ShuttleGui.h"
32 #include "../HelpText.h"
33 #include "../Project.h"
34 #include "../Prefs.h"
35 
36 #include "ErrorDialog.h"
37 #include "HelpSystem.h"
38 
39 #ifdef USE_ALPHA_MANUAL
40 const wxString HelpSystem::HelpHostname = wxT("alphamanual.audacityteam.org");
41 const wxString HelpSystem::HelpServerHomeDir = wxT("/man/");
42 const wxString HelpSystem::HelpServerManDir = wxT("/man/");
43 #else
44 const wxString HelpSystem::HelpHostname = wxT("manual.audacityteam.org");
45 const wxString HelpSystem::HelpServerHomeDir = wxT("/");
46 const wxString HelpSystem::HelpServerManDir = wxT("/man/");
47 #endif
48 const wxString HelpSystem::LocalHelpManDir = wxT("/man/");
49 const wxString HelpSystem::ReleaseSuffix = wxT(".html");
50 
54 void HelpSystem::ShowInfoDialog( wxWindow *parent,
55  const wxString &dlogTitle,
56  const wxString &shortMsg,
57  const wxString &message,
58  const int xSize, const int ySize)
59 {
60  wxDialogWrapper dlog(parent, wxID_ANY,
61  dlogTitle,
62  wxDefaultPosition, wxDefaultSize,
63  wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER | wxMAXIMIZE_BOX /*| wxDEFAULT_FRAME_STYLE */);
64 
65  dlog.SetName(dlog.GetTitle());
66  ShuttleGui S(&dlog, eIsCreating);
67 
68  S.StartVerticalLay(1);
69  {
70  S.AddTitle( shortMsg);
71  S.SetStyle( wxTE_MULTILINE | wxTE_READONLY | wxTE_RICH | wxTE_RICH2 |
72  wxTE_AUTO_URL | wxTE_NOHIDESEL | wxHSCROLL );
73  S.AddTextWindow(message);
74  }
75  S.SetBorder( 0 );
76  S.StartHorizontalLay(wxALIGN_CENTER|wxALIGN_BOTTOM, 0);
78 
79  S.EndHorizontalLay();
80 
81  // Next three lines add a tiny dragger.
82  wxStatusBar * pBar = safenew wxStatusBar( &dlog );
83  pBar->SetSize( 18, 38);
84  S.AddWindow( pBar, wxALIGN_BOTTOM|wxALIGN_RIGHT );
85 
86  S.EndVerticalLay();
87 
88  // Smallest size is half default size. Seems reasonable.
89  dlog.SetMinSize( wxSize(xSize/2, ySize/2) );
90  dlog.SetSize( wxSize(xSize, ySize) );
91  dlog.Center();
92  dlog.ShowModal();
93 }
94 
95 void HelpSystem::ShowHtmlText(wxWindow *pParent,
96  const wxString &Title,
97  const wxString &HtmlText,
98  bool bIsFile,
99  bool bModal)
100 {
101  LinkingHtmlWindow *html;
102 
103  wxASSERT(pParent); // to justify safenew
104  // JKC: ANSWER-ME: Why do we create a fake 'frame' and then put a BrowserDialog
105  // inside it, rather than have a variant of the BrowserDialog that is a
106  // frame??
107  // Bug 1412 seems to be related to the extra frame.
108  auto pFrame = safenew wxFrame {
109  pParent, wxID_ANY, Title, wxDefaultPosition, wxDefaultSize,
110 #if defined(__WXMAC__)
111  // On OSX, the html frame can go behind the help dialog and if the help
112  // html frame is modal, you can't get back to it. Pressing escape gets
113  // you out of this, but it's just easier to add the wxSTAY_ON_TOP flag
114  // to prevent it from falling behind the dialog. Not the perfect solution
115  // but acceptable in this case.
116  wxSTAY_ON_TOP |
117 #endif
118  wxDEFAULT_FRAME_STYLE
119  };
120 
121  BrowserDialog * pWnd;
122  if( bModal )
123  pWnd = safenew HtmlTextHelpDialog{ pFrame, Title };
124  else
125  pWnd = safenew BrowserDialog{ pFrame, Title };
126 
127  // Bug 1412 workaround for 'extra window'. Hide the 'fake' window.
128  pFrame->SetTransparent(0);
129  ShuttleGui S( pWnd, eIsCreating );
130 
131  S.SetStyle( wxNO_BORDER | wxTAB_TRAVERSAL );
132  wxPanel *pPan = S.Prop(true).StartPanel();
133  {
134  S.StartHorizontalLay( wxEXPAND, false );
135  {
136  wxButton * pWndBackwards = S.Id( wxID_BACKWARD ).AddButton( _("<") );
137  wxButton * pWndForwards = S.Id( wxID_FORWARD ).AddButton( _(">") );
138  pWndForwards->Enable( false );
139  pWndBackwards->Enable( false );
140  #if wxUSE_TOOLTIPS
141  pWndForwards->SetToolTip( _("Forwards" ));
142  pWndBackwards->SetToolTip( _("Backwards" ));
143  #endif
144  }
145  S.EndHorizontalLay();
146 
147  html = safenew LinkingHtmlWindow(pPan, wxID_ANY,
148  wxDefaultPosition,
149  bIsFile ? wxSize(500, 400) : wxSize(480, 240),
150  wxHW_SCROLLBAR_AUTO | wxSUNKEN_BORDER);
151 
152  html->SetRelatedFrame( pFrame, wxT("Help: %s") );
153  if( bIsFile )
154  html->LoadFile( HtmlText );
155  else
156  html->SetPage( HtmlText);
157 
158  S.Prop(1).AddWindow( html, wxEXPAND );
159 
160  S.Id( wxID_CANCEL ).AddButton( _("Close") )->SetDefault();
161  }
162  S.EndPanel();
163 
164  // -- START of ICON stuff -----
165  // If this section (providing an icon) causes compilation errors on linux, comment it out for now.
166  // it will just mean that the icon is missing. Works OK on Windows.
167  #ifdef __WXMSW__
168  wxIcon ic{ wxICON(AudacityLogo) };
169  #else
170  wxIcon ic{};
171  ic.CopyFromBitmap(theTheme.Bitmap(bmpAudacityLogo48x48));
172  #endif
173  pFrame->SetIcon( ic );
174  // -- END of ICON stuff -----
175 
176 
177  pWnd->mpHtml = html;
178  pWnd->SetBackgroundColour( wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE));
179 
180  pFrame->CreateStatusBar();
181  pFrame->Centre();
182  pFrame->Layout();
183  pFrame->Fit();
184  pFrame->SetSizeHints(pWnd->GetSize());
185 
186  pFrame->SetName(Title);
187  if (bModal)
188  pWnd->ShowModal();
189  else {
190  pWnd->Show(true);
191  pFrame->Show(true);
192  }
193 
194  html->SetRelatedStatusBar( 0 );
195  html->SetFocus();
196 
197  return;
198 }
199 
200 // Shows help in browser, or possibly in own dialog.
201 void HelpSystem::ShowHelp(wxWindow *parent,
202  const wxString &localFileName,
203  const wxString &remoteURL,
204  bool bModal,
205  bool alwaysDefaultBrowser)
206 {
207  wxASSERT(parent); // to justify safenew
208  AudacityProject * pProj = GetActiveProject();
209  wxString HelpMode = wxT("Local");
210 
211  if( pProj )
212  {
213  HelpMode = pProj->mHelpPref;
214  // these next lines are for legacy cfg files (pre 2.0) where we had different modes
215  if( (HelpMode == wxT("Standard")) || (HelpMode == wxT("InBrowser")) )
216  {
217  HelpMode = wxT("Local");
218  pProj->mHelpPref = HelpMode;
219  gPrefs->Write(wxT("/GUI/Help"), HelpMode);
220  gPrefs->Flush();
221  }
222  }
223 
224  // Anchors (URLs with a '#' in them) are not supported by many OSs for local file names
225  // See, for example, https://groups.google.com/forum/#!topic/wx-users/pC0uOZJalRQ
226  // Problems have been reported on Win, Mac and some versions of Linux.
227  // So we set HelpMode to use the internet if an anchor is found.
228  if (localFileName.Find('#', true) != wxNOT_FOUND)
229  HelpMode = wxT("FromInternet");
230  // Until a solution is found for this, the next few lines are irrelevant.
231 
232  // Obtain the local file system file name, without the anchor if present.
233  wxString localfile;
234  if (localFileName.Find('#', true) != wxNOT_FOUND)
235  localfile = localFileName.BeforeLast('#');
236  else
237  localfile = localFileName;
238 
239  if( (HelpMode == wxT("FromInternet")) && !remoteURL.IsEmpty() )
240  {
241  // Always go to remote URL. Use External browser.
242  OpenInDefaultBrowser( remoteURL );
243  }
244  else if( localfile.IsEmpty() || !wxFileExists( localfile ))
245  {
246  // If you give an empty remote URL, you should have already ensured
247  // that the file exists!
248  wxASSERT( !remoteURL.IsEmpty() );
249  // I can't find it'.
250  // Use Built-in browser to suggest you use the remote url.
251  wxString Text = HelpText( wxT("remotehelp") );
252  Text.Replace( wxT("*URL*"), remoteURL );
253  ShowHtmlText( parent, _("Help on the Internet"), Text, false, bModal );
254  }
255  else if( HelpMode == wxT("Local") || alwaysDefaultBrowser)
256  {
257  // Local file, External browser
258  OpenInDefaultBrowser( wxString(wxT("file:"))+localFileName );
259  }
260  else
261  {
262  // Local file, Built-in browser
263  ShowHtmlText( parent, wxT(""), localFileName, true, bModal );
264  }
265 }
266 
267 void HelpSystem::ShowHelp(wxWindow *parent,
268  const wxString &PageName,
269  bool bModal)
270 {
271  wxString localHelpPage;
272  wxString webHelpPath;
273  wxString webHelpPage;
274  wxString releasePageName;
275  wxString anchor; // optional part of URL after (and including) the '#'
276  if (PageName.Find('#', true) != wxNOT_FOUND)
277  { // need to split anchor off into separate variable
278  releasePageName= PageName.BeforeLast('#');
279  anchor = wxT("#") + PageName.AfterLast('#');
280  }
281  else
282  {
283  releasePageName = PageName;
284  anchor = wxT("");
285  }
286  // The wiki pages are transformed to static HTML by
287  // scripts/mw2html_audacity/mw2html.py
288  // The name is first transformed to lower case, then all
289  // 'special characters' are replaced by underscores. Spaces are
290  // transformed to "+".
291  //
292  // The transformations are handled in mw2html by first applying
293  // 'urllib.parse.quote_plus' (escape chars that are not in "always safe" list)
294  // then replacing escape characters (%xx) with underscores,
295  // and finally removing duplicate / redundant underscores.
296  //
297  // The front page and 'quick_help' are treated as special cases and placed in
298  // the root of the help directory rather than the "/man/" sub-directory.
299  if (releasePageName == wxT("Main_Page"))
300  {
301  releasePageName = wxT("index") + HelpSystem::ReleaseSuffix + anchor;
302  localHelpPage = wxFileName(FileNames::HtmlHelpDir(), releasePageName).GetFullPath();
303  webHelpPath = wxT("https://")+HelpSystem::HelpHostname+HelpSystem::HelpServerHomeDir;
304  }
305  else if (releasePageName == wxT("Quick_Help"))
306  {
307 // DA: No bundled help, by default, and different quick-help URL.
308 #ifdef EXPERIMENTAL_DA
309  releasePageName = wxT("video") + HelpSystem::ReleaseSuffix + anchor;
310  localHelpPage = wxFileName(FileNames::HtmlHelpDir(), releasePageName).GetFullPath();
311  webHelpPath = wxT("https://www.darkaudacity.com/");
312 #else
313  releasePageName = wxT("quick_help") + HelpSystem::ReleaseSuffix + anchor;
314  localHelpPage = wxFileName(FileNames::HtmlHelpDir(), releasePageName).GetFullPath();
315  webHelpPath = wxT("https://")+HelpSystem::HelpHostname+HelpSystem::HelpServerHomeDir;
316 #endif
317  }
318  // not a page name, but rather a full path (e.g. to wiki)
319  // in which case do not do any substitutions.
320  else if (releasePageName.StartsWith( "http" ) )
321  {
322  localHelpPage = "";
323  webHelpPage = releasePageName + anchor;
324  }
325  else
326  {
327  // Handle all other pages.
328  // Change to lower case.
329  releasePageName = releasePageName.Lower();
330  wxRegEx re;
331  // replace 'special characters' with underscores.
332  // RFC 2396 defines the characters a-z, A-Z, 0-9 and ".-_" as "always safe"
333  // mw2html also replaces "-" with "_" so replace that too.
334 
335  // If PageName contains a %xx code, mw2html will transform it:
336  // '%xx' => '%25xx' => '_'
337  re.Compile(wxT("%.."));
338  re.ReplaceAll(&releasePageName, (wxT("_")));
339  // Now replace all other 'not-safe' characters.
340  re.Compile(wxT("[^[:alnum:] . [:space:]]"));
341  re.ReplaceAll(&releasePageName, (wxT("_")));
342  // Replace spaces with "+"
343  releasePageName.Replace(wxT(" "), wxT("+"), true);
344  // Reduce multiple underscores to single underscores
345  re.Compile(wxT("__+"));
346  re.ReplaceAll(&releasePageName, (wxT("_")));
347  // Replace "_." with "."
348  releasePageName.Replace(wxT("_."), wxT("."), true);
349  // Concatenate file name with file extension and anchor.
350  releasePageName = releasePageName + HelpSystem::ReleaseSuffix + anchor;
351  // Other than index and quick_help, all local pages are in subdirectory 'LocalHelpManDir'.
352  localHelpPage = wxFileName(FileNames::HtmlHelpDir() + LocalHelpManDir, releasePageName).GetFullPath();
353  // Other than index and quick_help, all on-line pages are in subdirectory 'HelpServerManDir'.
354  webHelpPath = wxT("https://")+HelpSystem::HelpHostname+HelpSystem::HelpServerManDir;
355  }
356 
357 #ifdef USE_ALPHA_MANUAL
358  webHelpPage = webHelpPath + PageName;
359 #else
360  webHelpPage = webHelpPath + releasePageName;
361 #endif
362 
363  wxLogMessage(wxT("Help button pressed: PageName %s, releasePageName %s"),
364  PageName, releasePageName);
365  wxLogMessage(wxT("webHelpPage %s, localHelpPage %s"),
366  webHelpPage, localHelpPage);
367 
368  wxASSERT(parent); // to justify safenew
369 
371  parent,
372  localHelpPage,
373  webHelpPage,
374  bModal
375  );
376 }
static void ShowInfoDialog(wxWindow *parent, const wxString &dlogTitle, const wxString &shortMsg, const wxString &message, const int xSize, const int ySize)
Displays cutable information in a text ctrl, with an OK button.
Definition: HelpSystem.cpp:54
AUDACITY_DLL_API Theme theTheme
Definition: Theme.cpp:215
Derived from ShuttleGuiBase, an Audacity specific class for shuttling data to and from GUI...
Definition: ShuttleGui.h:366
wxWindow * AddWindow(wxWindow *pWindow, int Flags=wxALIGN_CENTRE|wxALL)
Definition: ShuttleGui.cpp:257
static const wxString LocalHelpManDir
Definition: HelpSystem.h:96
wxPanel * StartPanel(int iStyle=0)
Definition: ShuttleGui.cpp:789
static const wxString HelpServerHomeDir
Definition: HelpSystem.h:86
static const wxString HelpHostname
Definition: HelpSystem.h:81
#define safenew
Definition: Audacity.h:223
void EndHorizontalLay()
Definition: ShuttleGui.cpp:975
static void ShowHtmlText(wxWindow *pParent, const wxString &Title, const wxString &HtmlText, bool bIsFile=false, bool bModal=false)
Definition: HelpSystem.cpp:95
wxBitmap & Bitmap(int iIndex)
Definition: Theme.cpp:1233
AudacityProject provides the main window, with tools and tracks contained within it.
Definition: Project.h:161
void EndVerticalLay()
Definition: ShuttleGui.cpp:991
static wxString HtmlHelpDir()
Definition: FileNames.cpp:173
wxFileConfig * gPrefs
Definition: Prefs.cpp:72
wxString HelpText(const wxString &Key)
Definition: HelpText.cpp:321
void StartHorizontalLay(int PositionFlags=wxALIGN_CENTRE, int iProp=1)
Definition: ShuttleGui.cpp:966
ShuttleGui & Id(int id)
void SetStyle(int Style)
Definition: ShuttleGui.h:252
static void ShowHelp(wxWindow *parent, const wxString &localFileName, const wxString &remoteURL, bool bModal=false, bool alwaysDefaultBrowser=false)
Definition: HelpSystem.cpp:201
void AddTitle(const wxString &Prompt)
Centred text string.
Definition: ShuttleGui.cpp:243
static const wxString ReleaseSuffix
Definition: HelpSystem.h:100
_("Move Track &Down")+wxT("\t")+(GetActiveProject() -> GetCommandManager() ->GetKeyFromName(wxT("TrackMoveDown"))), OnMoveTrack) POPUP_MENU_ITEM(OnMoveTopID, _("Move Track to &Top")+wxT("\t")+(GetActiveProject() ->GetCommandManager() ->GetKeyFromName(wxT("TrackMoveTop"))), OnMoveTrack) POPUP_MENU_ITEM(OnMoveBottomID, _("Move Track to &Bottom")+wxT("\t")+(GetActiveProject() ->GetCommandManager() ->GetKeyFromName(wxT("TrackMoveBottom"))), OnMoveTrack) void TrackMenuTable::OnSetName(wxCommandEvent &)
wxTextCtrl * AddTextWindow(const wxString &Value)
Multiline text box that grows.
Definition: ShuttleGui.cpp:551
AUDACITY_DLL_API AudacityProject * GetActiveProject()
Definition: Project.cpp:302
static const wxString HelpServerManDir
Definition: HelpSystem.h:91
wxString mHelpPref
Definition: Project.h:690
ShuttleGui & Prop(int iProp)
Definition: ShuttleGui.h:374
void AddStandardButtons(long buttons=eOkButton|eCancelButton, wxButton *extra=NULL)
void SetBorder(int Border)
Definition: ShuttleGui.h:251
HtmlWindow * mpHtml
void OpenInDefaultBrowser(const wxHtmlLinkInfo &link)
wxButton * AddButton(const wxString &Text, int PositionFlags=wxALIGN_CENTRE)
Definition: ShuttleGui.cpp:301
void StartVerticalLay(int iProp=1)
Definition: ShuttleGui.cpp:982