Documentation.cpp 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327
  1. // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved.
  2. #include "Documentation.h"
  3. #include "Misc/Paths.h"
  4. #include "Styling/CoreStyle.h"
  5. #include "Widgets/SToolTip.h"
  6. #include "Misc/MessageDialog.h"
  7. #include "HAL/FileManager.h"
  8. #include "Misc/CommandLine.h"
  9. #include "Dialogs/Dialogs.h"
  10. #include "SDocumentationAnchor.h"
  11. #include "UDNParser.h"
  12. #include "DocumentationPage.h"
  13. #include "DocumentationLink.h"
  14. #include "SExtDocumentationToolTip.h"
  15. #include "Interfaces/IAnalyticsProvider.h"
  16. #include "EngineAnalytics.h"
  17. #include "DocumentationLink.h"
  18. using namespace EXT_DOC_NAMESPACE;
  19. #define LOCTEXT_NAMESPACE "DocumentationActor"
  20. TSharedRef< IDocumentation > FExtDocumentation::Create()
  21. {
  22. return MakeShareable( new FExtDocumentation() );
  23. }
  24. FExtDocumentation::FExtDocumentation()
  25. {
  26. }
  27. FExtDocumentation::~FExtDocumentation()
  28. {
  29. }
  30. bool FExtDocumentation::OpenHome(FDocumentationSourceInfo Source, const FString& BaseUrlId) const
  31. {
  32. return Open(TEXT("%ROOT%"), Source, BaseUrlId);
  33. }
  34. bool FExtDocumentation::OpenHome(const FCultureRef& Culture, FDocumentationSourceInfo Source, const FString& BaseUrlId) const
  35. {
  36. return Open(TEXT("%ROOT%"), Culture, Source, BaseUrlId);
  37. }
  38. bool FExtDocumentation::OpenAPIHome(FDocumentationSourceInfo Source) const
  39. {
  40. FString Url;
  41. FUnrealEdMisc::Get().GetURL(TEXT("APIDocsURL"), Url, true);
  42. if (!Url.IsEmpty())
  43. {
  44. FUnrealEdMisc::Get().ReplaceDocumentationURLWildcards(Url, FInternationalization::Get().GetCurrentCulture());
  45. FPlatformProcess::LaunchURL(*Url, nullptr, nullptr);
  46. return true;
  47. }
  48. return false;
  49. }
  50. bool FExtDocumentation::Open(const FString& Link, FDocumentationSourceInfo Source, const FString& BaseUrlId) const
  51. {
  52. FString DocumentationUrl;
  53. // Warn the user if they are opening a URL
  54. if (Link.StartsWith(TEXT("http")) || Link.StartsWith(TEXT("https")))
  55. {
  56. FText Message = LOCTEXT("OpeningURLMessage", "You are about to open an external URL. This will open your web browser. Do you want to proceed?");
  57. FText URLDialog = LOCTEXT("OpeningURLTitle", "Open external link");
  58. FSuppressableWarningDialog::FSetupInfo Info(Message, URLDialog, "SuppressOpenURLWarning");
  59. Info.ConfirmText = LOCTEXT("OpenURL_yes", "Yes");
  60. Info.CancelText = LOCTEXT("OpenURL_no", "No");
  61. FSuppressableWarningDialog OpenURLWarning(Info);
  62. if (OpenURLWarning.ShowModal() == FSuppressableWarningDialog::Cancel)
  63. {
  64. return false;
  65. }
  66. else
  67. {
  68. FPlatformProcess::LaunchURL(*Link, nullptr, nullptr);
  69. return true;
  70. }
  71. }
  72. if (!FParse::Param(FCommandLine::Get(), TEXT("testdocs")))
  73. {
  74. FString OnDiskPath = FExtDocumentationLink::ToFilePath(Link);
  75. if (IFileManager::Get().FileSize(*OnDiskPath) != INDEX_NONE)
  76. {
  77. DocumentationUrl = FExtDocumentationLink::ToFileUrl(Link, Source);
  78. }
  79. }
  80. if (DocumentationUrl.IsEmpty())
  81. {
  82. // When opening a doc website we always request the most ideal culture for our documentation.
  83. // The DNS will redirect us if necessary.
  84. DocumentationUrl = FExtDocumentationLink::ToUrl(Link, Source, BaseUrlId);
  85. }
  86. if (!DocumentationUrl.IsEmpty())
  87. {
  88. FPlatformProcess::LaunchURL(*DocumentationUrl, NULL, NULL);
  89. }
  90. if (!DocumentationUrl.IsEmpty() && FEngineAnalytics::IsAvailable())
  91. {
  92. FEngineAnalytics::GetProvider().RecordEvent(TEXT("Editor.Usage.Documentation"), TEXT("OpenedPage"), Link);
  93. }
  94. return !DocumentationUrl.IsEmpty();
  95. }
  96. bool FExtDocumentation::Open(const FString& Link, const FCultureRef& Culture, FDocumentationSourceInfo Source, const FString& BaseUrlId) const
  97. {
  98. FString DocumentationUrl;
  99. if (!FParse::Param(FCommandLine::Get(), TEXT("testdocs")))
  100. {
  101. FString OnDiskPath = FExtDocumentationLink::ToFilePath(Link, Culture);
  102. if (IFileManager::Get().FileSize(*OnDiskPath) != INDEX_NONE)
  103. {
  104. DocumentationUrl = FExtDocumentationLink::ToFileUrl(Link, Culture, Source);
  105. }
  106. }
  107. if (DocumentationUrl.IsEmpty())
  108. {
  109. DocumentationUrl = FExtDocumentationLink::ToUrl(Link, Culture, Source, BaseUrlId);
  110. }
  111. if (!DocumentationUrl.IsEmpty())
  112. {
  113. FPlatformProcess::LaunchURL(*DocumentationUrl, NULL, NULL);
  114. }
  115. if (!DocumentationUrl.IsEmpty() && FEngineAnalytics::IsAvailable())
  116. {
  117. FEngineAnalytics::GetProvider().RecordEvent(TEXT("Editor.Usage.Documentation"), TEXT("OpenedPage"), Link);
  118. }
  119. return !DocumentationUrl.IsEmpty();
  120. }
  121. TSharedRef< SWidget > FExtDocumentation::CreateAnchor(const TAttribute<FString>& Link, const FString& PreviewLink, const FString& PreviewExcerptName, const TAttribute<FString>& BaseUrlId) const
  122. {
  123. return SNew( SExtDocumentationAnchor )
  124. .Link(Link)
  125. .PreviewLink(PreviewLink)
  126. .PreviewExcerptName(PreviewExcerptName)
  127. .BaseUrlId(BaseUrlId);
  128. }
  129. TSharedRef< IDocumentationPage > FExtDocumentation::GetPage( const FString& Link, const TSharedPtr< FParserConfiguration >& Config, const FDocumentationStyle& Style )
  130. {
  131. TSharedPtr< IDocumentationPage > Page;
  132. const TWeakPtr< IDocumentationPage >* ExistingPagePtr = LoadedPages.Find( Link );
  133. if ( ExistingPagePtr != NULL )
  134. {
  135. const TSharedPtr< IDocumentationPage > ExistingPage = ExistingPagePtr->Pin();
  136. if ( ExistingPage.IsValid() )
  137. {
  138. Page = ExistingPage;
  139. }
  140. }
  141. if ( !Page.IsValid() )
  142. {
  143. Page = FExtDocumentationPage::Create( Link, FExtUDNParser::Create( Config, Style ) );
  144. LoadedPages.Add( Link, TWeakPtr< IDocumentationPage >( Page ) );
  145. }
  146. return Page.ToSharedRef();
  147. }
  148. bool FExtDocumentation::PageExists(const FString& Link) const
  149. {
  150. const TWeakPtr< IDocumentationPage >* ExistingPagePtr = LoadedPages.Find(Link);
  151. if (ExistingPagePtr != NULL)
  152. {
  153. return true;
  154. }
  155. const FString SourcePath = FExtDocumentationLink::ToSourcePath(Link);
  156. return FPaths::FileExists(SourcePath);
  157. }
  158. bool FExtDocumentation::PageExists(const FString& Link, const FCultureRef& Culture) const
  159. {
  160. const TWeakPtr< IDocumentationPage >* ExistingPagePtr = LoadedPages.Find(Link);
  161. if (ExistingPagePtr != NULL)
  162. {
  163. return true;
  164. }
  165. const FString SourcePath = FExtDocumentationLink::ToSourcePath(Link, Culture);
  166. return FPaths::FileExists(SourcePath);
  167. }
  168. const TArray < FString >& EXT_DOC_NAMESPACE::FExtDocumentation::GetSourcePaths() const
  169. {
  170. return SourcePaths;
  171. }
  172. TSharedRef< class SToolTip > FExtDocumentation::CreateToolTip(const TAttribute<FText>& Text, const TSharedPtr<SWidget>& OverrideContent, const FString& Link, const FString& ExcerptName) const
  173. {
  174. TSharedPtr< SExtDocumentationToolTip > DocToolTip;
  175. if ( !Text.IsBound() && Text.Get().IsEmpty() )
  176. {
  177. return SNew( SToolTip );
  178. }
  179. // hack: use OverrideContent as flag to always show full tooltip
  180. if (OverrideContent.IsValid())
  181. {
  182. SAssignNew(DocToolTip, SExtDocumentationToolTip)
  183. .Text(Text)
  184. .DocumentationLink(Link)
  185. .ExcerptName(ExcerptName)
  186. .AlwaysShowFullToolTip(true);
  187. }
  188. else
  189. {
  190. SAssignNew( DocToolTip, SExtDocumentationToolTip )
  191. .Text( Text )
  192. .DocumentationLink( Link )
  193. .ExcerptName( ExcerptName );
  194. }
  195. return SNew( SToolTip )
  196. .IsInteractive( DocToolTip.ToSharedRef(), &SExtDocumentationToolTip::IsInteractive )
  197. // Emulate text-only tool-tip styling that SToolTip uses when no custom content is supplied. We want documentation tool-tips to
  198. // be styled just like text-only tool-tips
  199. .BorderImage( FCoreStyle::Get().GetBrush("ToolTip.BrightBackground") )
  200. .TextMargin(FMargin(11.0f))
  201. [
  202. DocToolTip.ToSharedRef()
  203. ];
  204. }
  205. TSharedRef< class SToolTip > FExtDocumentation::CreateToolTip(const TAttribute<FText>& Text, const TSharedRef<SWidget>& OverrideContent, const TSharedPtr<SVerticalBox>& DocVerticalBox, const FString& Link, const FString& ExcerptName) const
  206. {
  207. TSharedRef<SExtDocumentationToolTip> DocToolTip =
  208. SNew(SExtDocumentationToolTip)
  209. .Text(Text)
  210. .DocumentationLink(Link)
  211. .ExcerptName(ExcerptName)
  212. .AddDocumentation(false)
  213. .DocumentationMargin(7)
  214. [
  215. OverrideContent
  216. ];
  217. if (DocVerticalBox.IsValid())
  218. {
  219. DocToolTip->AddDocumentation(DocVerticalBox);
  220. }
  221. return SNew(SToolTip)
  222. .IsInteractive(DocToolTip, &SExtDocumentationToolTip::IsInteractive)
  223. // Emulate text-only tool-tip styling that SToolTip uses when no custom content is supplied. We want documentation tool-tips to
  224. // be styled just like text-only tool-tips
  225. .BorderImage( FCoreStyle::Get().GetBrush("ToolTip.BrightBackground") )
  226. .TextMargin(FMargin(11.0f))
  227. [
  228. DocToolTip
  229. ];
  230. }
  231. bool FExtDocumentation::RegisterBaseUrl(const FString& Id, const FString& Url)
  232. {
  233. if (!Id.IsEmpty() && !Url.IsEmpty())
  234. {
  235. if (!RegisteredBaseUrls.Contains(Id))
  236. {
  237. RegisteredBaseUrls.Add(Id, Url);
  238. return true;
  239. }
  240. //UE_LOG(LogDocumentation, Warning, TEXT("Could not register documentation base URL with ID: %s. This ID is already in use."), *Id);
  241. return false;
  242. }
  243. return false;
  244. }
  245. FString FExtDocumentation::GetBaseUrl(const FString& Id) const
  246. {
  247. if (!Id.IsEmpty())
  248. {
  249. const FString* BaseUrl = RegisteredBaseUrls.Find(Id);
  250. if (BaseUrl != NULL && !BaseUrl->IsEmpty())
  251. {
  252. return *BaseUrl;
  253. }
  254. //UE_LOG(LogDocumentation, Warning, TEXT("Could not resolve base URL with ID: %s. It may not have been registered."), *Id);
  255. }
  256. FString DefaultUrl;
  257. FUnrealEdMisc::Get().GetURL(TEXT("DocumentationURL"), DefaultUrl, true);
  258. return DefaultUrl;
  259. }
  260. bool FExtDocumentation::RegisterRedirect(const FName& Owner, const FDocumentationRedirect& Redirect)
  261. {
  262. return RedirectRegistry.Register(Owner, Redirect);
  263. }
  264. void FExtDocumentation::UnregisterRedirects(const FName& Owner)
  265. {
  266. RedirectRegistry.UnregisterAll(Owner);
  267. }
  268. #undef LOCTEXT_NAMESPACE
  269. #ifdef EXT_DOC_NAMESPACE
  270. #undef EXT_DOC_NAMESPACE
  271. #endif