GUITools.cpp 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754
  1. //---------------------------------------------------------------------------
  2. #include <vcl.h>
  3. #pragma hdrstop
  4. #include <shlobj.h>
  5. #include <Common.h>
  6. #include "GUITools.h"
  7. #include "GUIConfiguration.h"
  8. #include <TextsCore.h>
  9. #include <CoreMain.h>
  10. #include <SessionData.h>
  11. #include <WinInterface.h>
  12. #include <TbxUtils.hpp>
  13. #include <Math.hpp>
  14. #include <WebBrowserEx.hpp>
  15. #include <Tools.h>
  16. #include "PngImageList.hpp"
  17. //---------------------------------------------------------------------------
  18. #pragma package(smart_init)
  19. //---------------------------------------------------------------------------
  20. extern const UnicodeString PageantTool = L"pageant.exe";
  21. extern const UnicodeString PuttygenTool = L"puttygen.exe";
  22. //---------------------------------------------------------------------------
  23. bool __fastcall FindFile(UnicodeString & Path)
  24. {
  25. bool Result = FileExists(ApiPath(Path));
  26. if (!Result)
  27. {
  28. UnicodeString Paths = GetEnvironmentVariable(L"PATH");
  29. if (!Paths.IsEmpty())
  30. {
  31. UnicodeString NewPath = FileSearch(ExtractFileName(Path), Paths);
  32. Result = !NewPath.IsEmpty();
  33. if (Result)
  34. {
  35. Path = NewPath;
  36. }
  37. }
  38. }
  39. return Result;
  40. }
  41. //---------------------------------------------------------------------------
  42. void __fastcall OpenSessionInPutty(const UnicodeString PuttyPath,
  43. TSessionData * SessionData)
  44. {
  45. UnicodeString Program, AParams, Dir;
  46. SplitCommand(PuttyPath, Program, AParams, Dir);
  47. Program = ExpandEnvironmentVariables(Program);
  48. if (FindFile(Program))
  49. {
  50. AParams = ExpandEnvironmentVariables(AParams);
  51. UnicodeString Password = GUIConfiguration->PuttyPassword ? SessionData->Password : UnicodeString();
  52. TCustomCommandData Data(SessionData, SessionData->UserName, Password);
  53. TRemoteCustomCommand RemoteCustomCommand(Data, SessionData->RemoteDirectory);
  54. TWinInteractiveCustomCommand InteractiveCustomCommand(
  55. &RemoteCustomCommand, L"PuTTY");
  56. UnicodeString Params =
  57. RemoteCustomCommand.Complete(InteractiveCustomCommand.Complete(AParams, false), true);
  58. if (!RemoteCustomCommand.IsSiteCommand(AParams))
  59. {
  60. UnicodeString SessionName;
  61. TRegistryStorage * Storage = NULL;
  62. TSessionData * ExportData = NULL;
  63. TRegistryStorage * SourceStorage = NULL;
  64. try
  65. {
  66. Storage = new TRegistryStorage(Configuration->PuttySessionsKey);
  67. Storage->AccessMode = smReadWrite;
  68. // make it compatible with putty
  69. Storage->MungeStringValues = false;
  70. Storage->ForceAnsi = true;
  71. if (Storage->OpenRootKey(true))
  72. {
  73. if (Storage->KeyExists(SessionData->StorageKey))
  74. {
  75. SessionName = SessionData->SessionName;
  76. }
  77. else
  78. {
  79. SourceStorage = new TRegistryStorage(Configuration->PuttySessionsKey);
  80. SourceStorage->MungeStringValues = false;
  81. SourceStorage->ForceAnsi = true;
  82. if (SourceStorage->OpenSubKey(StoredSessions->DefaultSettings->Name, false) &&
  83. Storage->OpenSubKey(GUIConfiguration->PuttySession, true))
  84. {
  85. Storage->Copy(SourceStorage);
  86. Storage->CloseSubKey();
  87. }
  88. ExportData = new TSessionData(L"");
  89. ExportData->Assign(SessionData);
  90. ExportData->Modified = true;
  91. ExportData->Name = GUIConfiguration->PuttySession;
  92. ExportData->Password = L"";
  93. if (SessionData->FSProtocol == fsFTP)
  94. {
  95. if (GUIConfiguration->TelnetForFtpInPutty)
  96. {
  97. ExportData->PuttyProtocol = PuttyTelnetProtocol;
  98. ExportData->PortNumber = TelnetPortNumber;
  99. // PuTTY does not allow -pw for telnet
  100. Password = L"";
  101. }
  102. else
  103. {
  104. ExportData->PuttyProtocol = PuttySshProtocol;
  105. ExportData->PortNumber = SshPortNumber;
  106. }
  107. }
  108. ExportData->Save(Storage, true);
  109. SessionName = GUIConfiguration->PuttySession;
  110. }
  111. }
  112. }
  113. __finally
  114. {
  115. delete Storage;
  116. delete ExportData;
  117. delete SourceStorage;
  118. }
  119. AddToList(Params, FORMAT(L"-load %s", (EscapePuttyCommandParam(SessionName))), L" ");
  120. }
  121. if (!Password.IsEmpty() && !RemoteCustomCommand.IsPasswordCommand(AParams))
  122. {
  123. AddToList(Params, FORMAT(L"-pw %s", (EscapePuttyCommandParam(Password))), L" ");
  124. }
  125. if (!ExecuteShell(Program, Params))
  126. {
  127. throw Exception(FMTLOAD(EXECUTE_APP_ERROR, (Program)));
  128. }
  129. }
  130. else
  131. {
  132. throw Exception(FMTLOAD(FILE_NOT_FOUND, (Program)));
  133. }
  134. }
  135. //---------------------------------------------------------------------------
  136. bool __fastcall FindTool(const UnicodeString & Name, UnicodeString & Path)
  137. {
  138. UnicodeString AppPath = IncludeTrailingBackslash(ExtractFilePath(Application->ExeName));
  139. Path = AppPath + Name;
  140. bool Result = true;
  141. if (!FileExists(ApiPath(Path)))
  142. {
  143. Path = AppPath + L"PuTTY\\" + Name;
  144. if (!FileExists(ApiPath(Path)))
  145. {
  146. Path = Name;
  147. if (!FindFile(Path))
  148. {
  149. Result = false;
  150. }
  151. }
  152. }
  153. return Result;
  154. }
  155. //---------------------------------------------------------------------------
  156. bool __fastcall ExecuteShell(const UnicodeString Path, const UnicodeString Params)
  157. {
  158. return ((int)ShellExecute(NULL, L"open", (wchar_t*)Path.data(),
  159. (wchar_t*)Params.data(), NULL, SW_SHOWNORMAL) > 32);
  160. }
  161. //---------------------------------------------------------------------------
  162. bool __fastcall ExecuteShell(const UnicodeString Path, const UnicodeString Params,
  163. HANDLE & Handle)
  164. {
  165. bool Result;
  166. TShellExecuteInfoW ExecuteInfo;
  167. memset(&ExecuteInfo, 0, sizeof(ExecuteInfo));
  168. ExecuteInfo.cbSize = sizeof(ExecuteInfo);
  169. ExecuteInfo.fMask = SEE_MASK_NOCLOSEPROCESS;
  170. ExecuteInfo.hwnd = Application->Handle;
  171. ExecuteInfo.lpFile = (wchar_t*)Path.data();
  172. ExecuteInfo.lpParameters = (wchar_t*)Params.data();
  173. ExecuteInfo.nShow = SW_SHOW;
  174. Result = (ShellExecuteEx(&ExecuteInfo) != 0);
  175. if (Result)
  176. {
  177. Handle = ExecuteInfo.hProcess;
  178. }
  179. return Result;
  180. }
  181. //---------------------------------------------------------------------------
  182. bool __fastcall ExecuteShellAndWait(HWND Handle, const UnicodeString Path,
  183. const UnicodeString Params, TProcessMessagesEvent ProcessMessages)
  184. {
  185. bool Result;
  186. TShellExecuteInfoW ExecuteInfo;
  187. memset(&ExecuteInfo, 0, sizeof(ExecuteInfo));
  188. ExecuteInfo.cbSize = sizeof(ExecuteInfo);
  189. ExecuteInfo.fMask = SEE_MASK_NOCLOSEPROCESS;
  190. ExecuteInfo.hwnd = Handle;
  191. ExecuteInfo.lpFile = (wchar_t*)Path.data();
  192. ExecuteInfo.lpParameters = (wchar_t*)Params.data();
  193. ExecuteInfo.nShow = SW_SHOW;
  194. Result = (ShellExecuteEx(&ExecuteInfo) != 0);
  195. if (Result)
  196. {
  197. if (ProcessMessages != NULL)
  198. {
  199. unsigned long WaitResult;
  200. do
  201. {
  202. WaitResult = WaitForSingleObject(ExecuteInfo.hProcess, 200);
  203. if (WaitResult == WAIT_FAILED)
  204. {
  205. throw Exception(LoadStr(DOCUMENT_WAIT_ERROR));
  206. }
  207. ProcessMessages();
  208. }
  209. while (WaitResult == WAIT_TIMEOUT);
  210. }
  211. else
  212. {
  213. WaitForSingleObject(ExecuteInfo.hProcess, INFINITE);
  214. }
  215. }
  216. return Result;
  217. }
  218. //---------------------------------------------------------------------------
  219. bool __fastcall ExecuteShellAndWait(HWND Handle, const UnicodeString Command,
  220. TProcessMessagesEvent ProcessMessages)
  221. {
  222. UnicodeString Program, Params, Dir;
  223. SplitCommand(Command, Program, Params, Dir);
  224. return ExecuteShellAndWait(Handle, Program, Params, ProcessMessages);
  225. }
  226. //---------------------------------------------------------------------------
  227. bool __fastcall SpecialFolderLocation(int PathID, UnicodeString & Path)
  228. {
  229. LPITEMIDLIST Pidl;
  230. wchar_t Buf[256];
  231. if (SHGetSpecialFolderLocation(NULL, PathID, &Pidl) == NO_ERROR &&
  232. SHGetPathFromIDList(Pidl, Buf))
  233. {
  234. Path = UnicodeString(Buf);
  235. return true;
  236. }
  237. return false;
  238. }
  239. //---------------------------------------------------------------------------
  240. static UnicodeString __fastcall GetWineHomeFolder()
  241. {
  242. UnicodeString Result;
  243. UnicodeString WineHostHome = GetEnvironmentVariable(L"WINE_HOST_HOME");
  244. if (!WineHostHome.IsEmpty())
  245. {
  246. Result = L"Z:" + FromUnixPath(WineHostHome);
  247. }
  248. else
  249. {
  250. // Should we use WinAPI GetUserName() instead?
  251. UnicodeString UserName = GetEnvironmentVariable(L"USERNAME");
  252. if (!UserName.IsEmpty())
  253. {
  254. Result = L"Z:\\home\\" + UserName;
  255. }
  256. }
  257. if (!DirectoryExists(Result))
  258. {
  259. Result = L"";
  260. }
  261. return Result;
  262. }
  263. //---------------------------------------------------------------------------
  264. UnicodeString __fastcall GetPersonalFolder()
  265. {
  266. UnicodeString Result;
  267. SpecialFolderLocation(CSIDL_PERSONAL, Result);
  268. if (IsWine())
  269. {
  270. UnicodeString WineHome = GetWineHomeFolder();
  271. if (!WineHome.IsEmpty())
  272. {
  273. // if at least home exists, use it
  274. Result = WineHome;
  275. // but try to go deeper to "Documents"
  276. UnicodeString WineDocuments =
  277. IncludeTrailingBackslash(WineHome) + L"Documents";
  278. if (DirectoryExists(WineDocuments))
  279. {
  280. Result = WineDocuments;
  281. }
  282. }
  283. }
  284. return Result;
  285. }
  286. //---------------------------------------------------------------------------
  287. UnicodeString __fastcall GetDesktopFolder()
  288. {
  289. UnicodeString Result;
  290. SpecialFolderLocation(CSIDL_DESKTOPDIRECTORY, Result);
  291. if (IsWine())
  292. {
  293. UnicodeString WineHome = GetWineHomeFolder();
  294. if (!WineHome.IsEmpty())
  295. {
  296. UnicodeString WineDesktop =
  297. IncludeTrailingBackslash(WineHome) + L"Desktop";
  298. if (DirectoryExists(WineHome))
  299. {
  300. Result = WineDesktop;
  301. }
  302. }
  303. }
  304. return Result;
  305. }
  306. //---------------------------------------------------------------------------
  307. UnicodeString __fastcall UniqTempDir(const UnicodeString BaseDir, const UnicodeString Identity,
  308. bool Mask)
  309. {
  310. UnicodeString TempDir;
  311. do
  312. {
  313. TempDir = BaseDir.IsEmpty() ? SystemTemporaryDirectory() : BaseDir;
  314. TempDir = IncludeTrailingBackslash(TempDir) + Identity;
  315. if (Mask)
  316. {
  317. TempDir += L"?????";
  318. }
  319. else
  320. {
  321. TempDir += IncludeTrailingBackslash(FormatDateTime(L"nnzzz", Now()));
  322. }
  323. }
  324. while (!Mask && DirectoryExists(ApiPath(TempDir)));
  325. return TempDir;
  326. }
  327. //---------------------------------------------------------------------------
  328. bool __fastcall DeleteDirectory(const UnicodeString DirName)
  329. {
  330. TSearchRecChecked sr;
  331. bool retval = true;
  332. if (FindFirstUnchecked(DirName + L"\\*", faAnyFile, sr) == 0) // VCL Function
  333. {
  334. if (FLAGSET(sr.Attr, faDirectory))
  335. {
  336. if (sr.Name != L"." && sr.Name != L"..")
  337. retval = DeleteDirectory(DirName + L"\\" + sr.Name);
  338. }
  339. else
  340. {
  341. retval = DeleteFile(ApiPath(DirName + L"\\" + sr.Name));
  342. }
  343. if (retval)
  344. {
  345. while (FindNextChecked(sr) == 0)
  346. { // VCL Function
  347. if (FLAGSET(sr.Attr, faDirectory))
  348. {
  349. if (sr.Name != L"." && sr.Name != L"..")
  350. retval = DeleteDirectory(DirName + L"\\" + sr.Name);
  351. }
  352. else
  353. {
  354. retval = DeleteFile(ApiPath(DirName + L"\\" + sr.Name));
  355. }
  356. if (!retval) break;
  357. }
  358. }
  359. }
  360. FindClose(sr);
  361. if (retval) retval = RemoveDir(ApiPath(DirName)); // VCL function
  362. return retval;
  363. }
  364. //---------------------------------------------------------------------------
  365. UnicodeString __fastcall FormatDateTimeSpan(const UnicodeString TimeFormat, TDateTime DateTime)
  366. {
  367. UnicodeString Result;
  368. if (int(DateTime) > 0)
  369. {
  370. Result = IntToStr(int(DateTime)) + L", ";
  371. }
  372. // days are decremented, because when there are to many of them,
  373. // "integer overflow" error occurs
  374. Result += FormatDateTime(TimeFormat, DateTime - int(DateTime));
  375. return Result;
  376. }
  377. //---------------------------------------------------------------------------
  378. void __fastcall AddSessionColorImage(
  379. TCustomImageList * ImageList, TColor Color, int MaskIndex)
  380. {
  381. // This overly complex drawing is here to support color button on SiteAdvanced
  382. // dialog. There we use plain TImageList, instead of TPngImageList,
  383. // TButton does not work with transparent images
  384. // (not even TBitmap with Transparent = true)
  385. std::unique_ptr<TBitmap> MaskBitmap(new TBitmap());
  386. ImageList->GetBitmap(MaskIndex, MaskBitmap.get());
  387. std::unique_ptr<TPngImage> MaskImage(new TPngImage());
  388. MaskImage->Assign(MaskBitmap.get());
  389. std::unique_ptr<TPngImage> ColorImage(new TPngImage(COLOR_RGB, 16, ImageList->Width, ImageList->Height));
  390. TColor MaskTransparentColor = MaskImage->Pixels[0][0];
  391. TColor TransparentColor = MaskTransparentColor;
  392. // Expecting that the color to be replaced is in the centre of the image (HACK)
  393. TColor MaskColor = MaskImage->Pixels[ImageList->Width / 2][ImageList->Height / 2];
  394. for (int Y = 0; Y < ImageList->Height; Y++)
  395. {
  396. for (int X = 0; X < ImageList->Width; X++)
  397. {
  398. TColor SourceColor = MaskImage->Pixels[X][Y];
  399. TColor DestColor;
  400. // this branch is pointless as long as MaskTransparentColor and
  401. // TransparentColor are the same
  402. if (SourceColor == MaskTransparentColor)
  403. {
  404. DestColor = TransparentColor;
  405. }
  406. else if (SourceColor == MaskColor)
  407. {
  408. DestColor = Color;
  409. }
  410. else
  411. {
  412. DestColor = SourceColor;
  413. }
  414. ColorImage->Pixels[X][Y] = DestColor;
  415. }
  416. }
  417. std::unique_ptr<TBitmap> Bitmap(new TBitmap());
  418. Bitmap->SetSize(ImageList->Width, ImageList->Height);
  419. ColorImage->AssignTo(Bitmap.get());
  420. ImageList->AddMasked(Bitmap.get(), TransparentColor);
  421. }
  422. //---------------------------------------------------------------------------
  423. void __fastcall SetSubmenu(TTBXCustomItem * Item)
  424. {
  425. class TTBXPublicItem : public TTBXCustomItem
  426. {
  427. public:
  428. __property ItemStyle;
  429. };
  430. TTBXPublicItem * PublicItem = reinterpret_cast<TTBXPublicItem *>(Item);
  431. assert(PublicItem != NULL);
  432. // See TTBItemViewer.IsPtInButtonPart (called from TTBItemViewer.MouseDown)
  433. PublicItem->ItemStyle = PublicItem->ItemStyle << tbisSubmenu;
  434. }
  435. //---------------------------------------------------------------------------
  436. bool __fastcall IsEligibleForApplyingTabs(
  437. UnicodeString Line, int & TabPos, UnicodeString & Start, UnicodeString & Remaining)
  438. {
  439. bool Result = false;
  440. TabPos = Line.Pos(L"\t");
  441. if (TabPos > 0)
  442. {
  443. Remaining = Line.SubString(TabPos + 1, Line.Length() - TabPos);
  444. // WORKAROUND
  445. // Some translations still use obsolete hack of consecutive tabs to aling the contents.
  446. // Delete these, so that the following check does not fail on this
  447. while (Remaining.SubString(1, 1) == L"\t")
  448. {
  449. Remaining.Delete(1, 1);
  450. }
  451. // We do not have, not support, mutiple tabs on a single line
  452. if (ALWAYS_TRUE(Remaining.Pos(L"\t") == 0))
  453. {
  454. Start = Line.SubString(1, TabPos - 1);
  455. // WORKAROUND
  456. // Previously we padded the string before tab with spaces,
  457. // to aling the contents across multiple lines
  458. Start = Start.TrimRight();
  459. // at least two normal spaces for separation
  460. Start += L" ";
  461. Result = true;
  462. }
  463. }
  464. return Result;
  465. }
  466. //---------------------------------------------------------------------------
  467. static int __fastcall CalculateWidthByLength(UnicodeString Text, void * /*Arg*/)
  468. {
  469. return Text.Length();
  470. }
  471. //---------------------------------------------------------------------------
  472. void __fastcall ApplyTabs(
  473. UnicodeString & Text, wchar_t Padding,
  474. TCalculateWidth CalculateWidth, void * CalculateWidthArg)
  475. {
  476. if (CalculateWidth == NULL)
  477. {
  478. assert(CalculateWidthArg == NULL);
  479. CalculateWidth = CalculateWidthByLength;
  480. }
  481. std::unique_ptr<TStringList> Lines(TextToStringList(Text));
  482. int MaxWidth = -1;
  483. for (int Index = 0; Index < Lines->Count; Index++)
  484. {
  485. UnicodeString Line = Lines->Strings[Index];
  486. int TabPos;
  487. UnicodeString Start;
  488. UnicodeString Remaining;
  489. if (IsEligibleForApplyingTabs(Line, TabPos, Start, Remaining))
  490. {
  491. int Width = CalculateWidth(Start, CalculateWidthArg);
  492. MaxWidth = Max(MaxWidth, Width);
  493. }
  494. }
  495. // Optimization and also to prevent potential regression for texts without tabs
  496. if (MaxWidth >= 0)
  497. {
  498. for (int Index = 0; Index < Lines->Count; Index++)
  499. {
  500. UnicodeString Line = Lines->Strings[Index];
  501. int TabPos;
  502. UnicodeString Start;
  503. UnicodeString Remaining;
  504. if (IsEligibleForApplyingTabs(Line, TabPos, Start, Remaining))
  505. {
  506. int Width;
  507. while ((Width = CalculateWidth(Start, CalculateWidthArg)) < MaxWidth)
  508. {
  509. int Wider = CalculateWidth(Start + Padding, CalculateWidthArg);
  510. // If padded string is wider than max width by more pixels
  511. // than non-padded string is shorter than max width
  512. if ((Wider > MaxWidth) && ((Wider - MaxWidth) > (MaxWidth - Width)))
  513. {
  514. break;
  515. }
  516. Start += Padding;
  517. }
  518. Lines->Strings[Index] = Start + Remaining;
  519. }
  520. }
  521. Text = Lines->Text;
  522. // remove trailing newline
  523. Text = Text.TrimRight();
  524. }
  525. }
  526. //---------------------------------------------------------------------------
  527. class TBrowserViewer : public TWebBrowserEx
  528. {
  529. public:
  530. __fastcall virtual TBrowserViewer(TComponent* AOwner);
  531. void __fastcall AddLinkHandler(
  532. const UnicodeString & Url, TNotifyEvent Handler);
  533. TControl * LoadingPanel;
  534. protected:
  535. DYNAMIC void __fastcall DoContextPopup(const TPoint & MousePos, bool & Handled);
  536. void __fastcall DocumentComplete(
  537. TObject * Sender, const _di_IDispatch Disp, const OleVariant & URL);
  538. void __fastcall BeforeNavigate2(
  539. TObject * Sender, const _di_IDispatch Disp, const OleVariant & URL,
  540. const OleVariant & Flags, const OleVariant & TargetFrameName,
  541. const OleVariant & PostData, const OleVariant & Headers, WordBool & Cancel);
  542. bool FComplete;
  543. std::map<UnicodeString, TNotifyEvent> FHandlers;
  544. };
  545. //---------------------------------------------------------------------------
  546. __fastcall TBrowserViewer::TBrowserViewer(TComponent* AOwner) :
  547. TWebBrowserEx(AOwner)
  548. {
  549. FComplete = false;
  550. OnDocumentComplete = DocumentComplete;
  551. OnBeforeNavigate2 = BeforeNavigate2;
  552. LoadingPanel = NULL;
  553. }
  554. //---------------------------------------------------------------------------
  555. void __fastcall TBrowserViewer::AddLinkHandler(
  556. const UnicodeString & Url, TNotifyEvent Handler)
  557. {
  558. FHandlers.insert(std::make_pair(Url, Handler));
  559. }
  560. //---------------------------------------------------------------------------
  561. void __fastcall TBrowserViewer::DoContextPopup(const TPoint & MousePos, bool & Handled)
  562. {
  563. // suppress built-in context menu
  564. Handled = true;
  565. TWebBrowserEx::DoContextPopup(MousePos, Handled);
  566. }
  567. //---------------------------------------------------------------------------
  568. void __fastcall TBrowserViewer::DocumentComplete(
  569. TObject * /*Sender*/, const _di_IDispatch /*Disp*/, const OleVariant & /*URL*/)
  570. {
  571. SetBrowserDesignModeOff(this);
  572. FComplete = true;
  573. if (LoadingPanel != NULL)
  574. {
  575. LoadingPanel->Visible = false;
  576. }
  577. }
  578. //---------------------------------------------------------------------------
  579. void __fastcall TBrowserViewer::BeforeNavigate2(
  580. TObject * /*Sender*/, const _di_IDispatch /*Disp*/, const OleVariant & AURL,
  581. const OleVariant & /*Flags*/, const OleVariant & /*TargetFrameName*/,
  582. const OleVariant & /*PostData*/, const OleVariant & /*Headers*/, WordBool & Cancel)
  583. {
  584. // If OnDocumentComplete was not called yet, is has to be our initial message URL,
  585. // opened using TWebBrowserEx::Navigate(), allow it.
  586. // Otherwise it's user navigating, block that and open link
  587. // in an external browser, possibly adding campaign parameters on the way.
  588. if (FComplete)
  589. {
  590. Cancel = 1;
  591. UnicodeString URL = AURL;
  592. if (FHandlers.count(URL) > 0)
  593. {
  594. FHandlers[URL](this);
  595. }
  596. else
  597. {
  598. OpenBrowser(URL);
  599. }
  600. }
  601. }
  602. //---------------------------------------------------------------------------
  603. TPanel * __fastcall CreateLabelPanel(TPanel * Parent, const UnicodeString & Label)
  604. {
  605. TPanel * Result = new TPanel(Parent);
  606. Result->Parent = Parent;
  607. Result->BevelOuter = bvNone;
  608. Result->BevelInner = bvNone; // default
  609. Result->Align = alClient;
  610. Result->Caption = Label;
  611. return Result;
  612. }
  613. //---------------------------------------------------------------------------
  614. TWebBrowserEx * __fastcall CreateBrowserViewer(TPanel * Parent, const UnicodeString & LoadingLabel)
  615. {
  616. TBrowserViewer * Result = new TBrowserViewer(Parent);
  617. // TWebBrowserEx has its own unrelated Name and Parent properties
  618. static_cast<TWinControl *>(Result)->Name = L"BrowserViewer";
  619. static_cast<TWinControl *>(Result)->Parent = Parent;
  620. Result->Align = alClient;
  621. Result->ControlBorder = cbNone;
  622. Result->LoadingPanel = CreateLabelPanel(Parent, LoadingLabel);
  623. return Result;
  624. }
  625. //---------------------------------------------------------------------------
  626. void __fastcall SetBrowserDesignModeOff(TWebBrowserEx * WebBrowser)
  627. {
  628. if (ALWAYS_TRUE(WebBrowser->Document2 != NULL))
  629. {
  630. WebBrowser->Document2->designMode = L"Off";
  631. }
  632. }
  633. //---------------------------------------------------------------------------
  634. void __fastcall AddBrowserLinkHandler(TWebBrowserEx * WebBrowser,
  635. const UnicodeString & Url, TNotifyEvent Handler)
  636. {
  637. TBrowserViewer * BrowserViewer = dynamic_cast<TBrowserViewer *>(WebBrowser);
  638. if (ALWAYS_TRUE(BrowserViewer != NULL))
  639. {
  640. BrowserViewer->AddLinkHandler(Url, Handler);
  641. }
  642. }
  643. //---------------------------------------------------------------------------
  644. TLocalCustomCommand::TLocalCustomCommand()
  645. {
  646. }
  647. //---------------------------------------------------------------------------
  648. TLocalCustomCommand::TLocalCustomCommand(const TCustomCommandData & Data,
  649. const UnicodeString & Path) :
  650. TFileCustomCommand(Data, Path)
  651. {
  652. }
  653. //---------------------------------------------------------------------------
  654. TLocalCustomCommand::TLocalCustomCommand(const TCustomCommandData & Data,
  655. const UnicodeString & Path, const UnicodeString & FileName,
  656. const UnicodeString & LocalFileName, const UnicodeString & FileList) :
  657. TFileCustomCommand(Data, Path, FileName, FileList)
  658. {
  659. FLocalFileName = LocalFileName;
  660. }
  661. //---------------------------------------------------------------------------
  662. int __fastcall TLocalCustomCommand::PatternLen(const UnicodeString & Command, int Index)
  663. {
  664. int Len;
  665. if ((Index < Command.Length()) && (Command[Index + 1] == L'^'))
  666. {
  667. Len = 3;
  668. }
  669. else
  670. {
  671. Len = TFileCustomCommand::PatternLen(Command, Index);
  672. }
  673. return Len;
  674. }
  675. //---------------------------------------------------------------------------
  676. bool __fastcall TLocalCustomCommand::PatternReplacement(
  677. const UnicodeString & Pattern, UnicodeString & Replacement, bool & Delimit)
  678. {
  679. bool Result;
  680. if (Pattern == L"!^!")
  681. {
  682. Replacement = FLocalFileName;
  683. Result = true;
  684. }
  685. else
  686. {
  687. Result = TFileCustomCommand::PatternReplacement(Pattern, Replacement, Delimit);
  688. }
  689. return Result;
  690. }
  691. //---------------------------------------------------------------------------
  692. void __fastcall TLocalCustomCommand::DelimitReplacement(
  693. UnicodeString & /*Replacement*/, wchar_t /*Quote*/)
  694. {
  695. // never delimit local commands
  696. }
  697. //---------------------------------------------------------------------------
  698. bool __fastcall TLocalCustomCommand::HasLocalFileName(const UnicodeString & Command)
  699. {
  700. return FindPattern(Command, L'^');
  701. }
  702. //---------------------------------------------------------------------------
  703. bool __fastcall TLocalCustomCommand::IsFileCommand(const UnicodeString & Command)
  704. {
  705. return TFileCustomCommand::IsFileCommand(Command) || HasLocalFileName(Command);
  706. }