Editor.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487
  1. //---------------------------------------------------------------------------
  2. #include <vcl.h>
  3. #pragma hdrstop
  4. #include <Common.h>
  5. #include "Editor.h"
  6. #include "WinInterface.h"
  7. #include "TextsWin.h"
  8. #include "Tools.h"
  9. #include <ScpMain.h>
  10. #include "VCLCommon.h"
  11. #include "WinConfiguration.h"
  12. //---------------------------------------------------------------------------
  13. #pragma package(smart_init)
  14. #pragma resource "*.dfm"
  15. //---------------------------------------------------------------------------
  16. TForm * __fastcall ShowEditorForm(const AnsiString FileName, TCustomForm * ParentForm,
  17. TNotifyEvent OnFileChanged, TNotifyEvent OnClose, const AnsiString Caption,
  18. bool ShowWindowButton)
  19. {
  20. TEditorForm * Dialog = new TEditorForm(Application);
  21. try
  22. {
  23. Dialog->ShowWindowButton = ShowWindowButton;
  24. Dialog->FileName = FileName;
  25. Dialog->ParentForm = ParentForm;
  26. Dialog->Caption = Caption.IsEmpty() ? FileName : Caption;
  27. Dialog->OnFileChanged = OnFileChanged;
  28. Dialog->OnWindowClose = OnClose;
  29. Dialog->Show();
  30. }
  31. catch(...)
  32. {
  33. delete Dialog;
  34. throw;
  35. }
  36. return Dialog;
  37. }
  38. //---------------------------------------------------------------------------
  39. __fastcall TEditorForm::TEditorForm(TComponent* Owner)
  40. : TForm(Owner)
  41. {
  42. FParentForm = NULL;
  43. FCaretPos.x = -1;
  44. FCaretPos.y = -1;
  45. FLastFindDialog = NULL;
  46. FShowWindowButton = false;
  47. ApplyConfiguration();
  48. FindDialog->FindText = WinConfiguration->Editor.FindText;
  49. TFindOptions Options = FindDialog->Options;
  50. if (WinConfiguration->Editor.FindMatchCase)
  51. {
  52. Options << frMatchCase;
  53. }
  54. if (WinConfiguration->Editor.FindWholeWord)
  55. {
  56. Options << frWholeWord;
  57. }
  58. FindDialog->Options = Options;
  59. ReplaceDialog->FindText = FindDialog->FindText;
  60. ReplaceDialog->Options = FindDialog->Options;
  61. ReplaceDialog->ReplaceText = WinConfiguration->Editor.ReplaceText;
  62. UseSystemSettings(this);
  63. }
  64. //---------------------------------------------------------------------------
  65. __fastcall TEditorForm::~TEditorForm()
  66. {
  67. if (FLastFindDialog)
  68. {
  69. WinConfiguration->Editor.FindText = FLastFindDialog->FindText;
  70. WinConfiguration->Editor.ReplaceText = ReplaceDialog->ReplaceText;
  71. WinConfiguration->Editor.FindMatchCase = FLastFindDialog->Options.Contains(frMatchCase);
  72. WinConfiguration->Editor.FindWholeWord = FLastFindDialog->Options.Contains(frWholeWord);
  73. }
  74. }
  75. //---------------------------------------------------------------------------
  76. void __fastcall TEditorForm::SetFileName(const AnsiString value)
  77. {
  78. if (value != FFileName)
  79. {
  80. FFileName = value;
  81. if (Visible)
  82. {
  83. LoadFile();
  84. }
  85. }
  86. }
  87. //---------------------------------------------------------------------------
  88. void __fastcall TEditorForm::SetParentForm(TCustomForm * value)
  89. {
  90. if (FParentForm != value)
  91. {
  92. FParentForm = value;
  93. if (value)
  94. {
  95. BoundsRect = value->BoundsRect;
  96. }
  97. }
  98. }
  99. //---------------------------------------------------------------------------
  100. void __fastcall TEditorForm::EditorActionsUpdate(TBasicAction *Action,
  101. bool &Handled)
  102. {
  103. Handled = true;
  104. if (Action == SaveAction)
  105. {
  106. SaveAction->Enabled = EditorMemo->Modified;
  107. }
  108. else if (Action == FindNextAction)
  109. {
  110. FindNextAction->Enabled =
  111. FLastFindDialog != NULL || !FindDialog->FindText.IsEmpty();
  112. }
  113. else if (Action == PreferencesAction || Action == CloseAction ||
  114. Action == FindAction || Action == ReplaceAction || Action == GoToLineAction)
  115. {
  116. ((TAction *)Action)->Enabled = true;
  117. }
  118. else
  119. {
  120. Handled = false;
  121. }
  122. }
  123. //---------------------------------------------------------------------------
  124. void __fastcall TEditorForm::EditorActionsExecute(TBasicAction *Action,
  125. bool &Handled)
  126. {
  127. Handled = true;
  128. if (Action == SaveAction)
  129. {
  130. assert(!FFileName.IsEmpty());
  131. EditorMemo->Lines->SaveToFile(FFileName);
  132. if (FOnFileChanged)
  133. {
  134. FOnFileChanged(this);
  135. }
  136. EditorMemo->Modified = false;
  137. UpdateControls();
  138. }
  139. else if (Action == PreferencesAction)
  140. {
  141. if (DoPreferencesDialog(pmEditor))
  142. {
  143. ApplyConfiguration();
  144. }
  145. }
  146. else if (Action == CloseAction)
  147. {
  148. Close();
  149. }
  150. else if (Action == FindAction || Action == ReplaceAction)
  151. {
  152. StartFind(Action == FindAction);
  153. }
  154. else if (Action == FindNextAction)
  155. {
  156. if (!FLastFindDialog)
  157. {
  158. FLastFindDialog = FindDialog;
  159. }
  160. Find();
  161. }
  162. else if (Action == GoToLineAction)
  163. {
  164. GoToLine();
  165. }
  166. else if (Action == EditPaste)
  167. {
  168. // original source: http://home.att.net/~robertdunn/FAQs/Faqs.html
  169. // tell the Rich Edit control to insert unformatted text (CF_TEXT)
  170. REPASTESPECIAL RepasteSpecial = { 0, 0 };
  171. SendMessage(EditorMemo->Handle, EM_PASTESPECIAL, CF_TEXT,
  172. (LPARAM)&RepasteSpecial);
  173. }
  174. else
  175. {
  176. Handled = false;
  177. }
  178. }
  179. //---------------------------------------------------------------------------
  180. void __fastcall TEditorForm::FormCloseQuery(TObject * /*Sender*/,
  181. bool &CanClose)
  182. {
  183. if (EditorMemo->Modified)
  184. {
  185. int Answer = MessageDialog(LoadStr(SAVE_CHANGES), qtConfirmation,
  186. qaYes | qaNo | qaCancel);
  187. CanClose = (Answer != qaCancel);
  188. if (Answer == qaYes)
  189. {
  190. SaveAction->Execute();
  191. }
  192. }
  193. }
  194. //---------------------------------------------------------------------------
  195. void __fastcall TEditorForm::ApplyConfiguration()
  196. {
  197. bool PrevModified = EditorMemo->Modified;
  198. assert(Configuration);
  199. EditorMemo->Font->Name = WinConfiguration->Editor.FontName;
  200. EditorMemo->Font->Height = WinConfiguration->Editor.FontHeight;
  201. EditorMemo->Font->Charset = (TFontCharset)WinConfiguration->Editor.FontCharset;
  202. EditorMemo->Font->Style = IntToFontStyles(WinConfiguration->Editor.FontStyle);
  203. EditorMemo->DefAttributes->Assign(EditorMemo->Font);
  204. if (EditorMemo->WordWrap != WinConfiguration->Editor.WordWrap)
  205. {
  206. if (Visible)
  207. {
  208. TStrings * Content = new TStringList();
  209. try
  210. {
  211. EditorMemo->WordWrap = False;
  212. Content->Assign(EditorMemo->Lines);
  213. EditorMemo->WordWrap = WinConfiguration->Editor.WordWrap;
  214. EditorMemo->Lines = Content;
  215. EditorMemo->CaretPos = TPoint(0, 0);
  216. }
  217. __finally
  218. {
  219. delete Content;
  220. }
  221. }
  222. else
  223. {
  224. EditorMemo->WordWrap = WinConfiguration->Editor.WordWrap;
  225. }
  226. }
  227. EditorMemo->Modified = PrevModified;
  228. EditorMemo->ClearUndo();
  229. UpdateControls();
  230. }
  231. //---------------------------------------------------------------------------
  232. void __fastcall TEditorForm::UpdateControls()
  233. {
  234. TPoint ACaretPos = EditorMemo->CaretPos;
  235. if (ACaretPos.x != FCaretPos.x || ACaretPos.y != FCaretPos.y)
  236. {
  237. FCaretPos = ACaretPos;
  238. int Count = EditorMemo->Lines->Count;
  239. StatusBar->Panels->Items[0]->Text = FMTLOAD(EDITOR_LINE_STATUS,
  240. ((int)FCaretPos.y+1, Count));
  241. StatusBar->Panels->Items[1]->Text = FMTLOAD(EDITOR_COLUMN_STATUS,
  242. ((int)FCaretPos.x+1));
  243. AnsiString Character;
  244. if (FCaretPos.y >= 0 && FCaretPos.y < EditorMemo->Lines->Count)
  245. {
  246. AnsiString Line = EditorMemo->Lines->Strings[FCaretPos.y];
  247. if (FCaretPos.x+1 <= Line.Length())
  248. {
  249. Character = FMTLOAD(EDITOR_CHARACTER_STATUS,
  250. (int((unsigned char)Line[FCaretPos.x+1]), int((unsigned char)Line[FCaretPos.x+1])));
  251. }
  252. }
  253. StatusBar->Panels->Items[2]->Text = Character;
  254. }
  255. StatusBar->Panels->Items[3]->Text =
  256. (EditorMemo->Modified ? LoadStr(EDITOR_MODIFIED) : AnsiString(""));
  257. EditorActions->UpdateAction(SaveAction);
  258. }
  259. //---------------------------------------------------------------------------
  260. void __fastcall TEditorForm::EditorMemoMouseUp(TObject * /*Sender*/,
  261. TMouseButton /*Button*/, TShiftState /*Shift*/, int /*X*/, int /*Y*/)
  262. {
  263. UpdateControls();
  264. }
  265. //---------------------------------------------------------------------------
  266. void __fastcall TEditorForm::EditorMemoKeyUp(TObject * /*Sender*/,
  267. WORD & /*Key*/, TShiftState /*Shift*/)
  268. {
  269. UpdateControls();
  270. }
  271. //---------------------------------------------------------------------------
  272. void __fastcall TEditorForm::EditorMemoChange(TObject * /*Sender*/)
  273. {
  274. UpdateControls();
  275. }
  276. //---------------------------------------------------------------------------
  277. void __fastcall TEditorForm::FindDialogFind(TObject * /*Sender*/)
  278. {
  279. Find();
  280. }
  281. //---------------------------------------------------------------------------
  282. void __fastcall TEditorForm::Find()
  283. {
  284. int NewPos;
  285. int Replacements = 0;
  286. do
  287. {
  288. assert(FLastFindDialog);
  289. TSearchTypes SearchTypes;
  290. // length condition is there to improve performance when large
  291. // block is selected in editor
  292. if (FLastFindDialog == ReplaceDialog &&
  293. (ReplaceDialog->Options.Contains(frReplace) ||
  294. ReplaceDialog->Options.Contains(frReplaceAll)) &&
  295. ReplaceDialog->FindText.Length() == EditorMemo->SelLength &&
  296. AnsiSameText(ReplaceDialog->FindText, EditorMemo->SelText))
  297. {
  298. EditorMemo->SelText = ReplaceDialog->ReplaceText;
  299. Replacements++;
  300. }
  301. if (FLastFindDialog->Options.Contains(frMatchCase))
  302. {
  303. SearchTypes << stMatchCase;
  304. }
  305. if (FLastFindDialog->Options.Contains(frWholeWord))
  306. {
  307. SearchTypes << stWholeWord;
  308. }
  309. NewPos = EditorMemo->FindText(FLastFindDialog->FindText,
  310. EditorMemo->SelLength ? EditorMemo->SelStart+1 : EditorMemo->SelStart,
  311. EditorMemo->Text.Length(), SearchTypes);
  312. if (NewPos >= 0)
  313. {
  314. EditorMemo->SelStart = NewPos;
  315. EditorMemo->SelLength = FLastFindDialog->FindText.Length();
  316. }
  317. if (FLastFindDialog->Handle)
  318. {
  319. PositionFindDialog(true);
  320. }
  321. if (NewPos < 0)
  322. {
  323. if (!Replacements)
  324. {
  325. MessageDialog(FMTLOAD(EDITOR_FIND_END, (FLastFindDialog->FindText)), qtInformation, qaOK, 0);
  326. }
  327. else
  328. {
  329. MessageDialog(FMTLOAD(EDITOR_REPLACE_END, (Replacements)), qtInformation, qaOK, 0);
  330. }
  331. }
  332. }
  333. while (NewPos >= 0 && FLastFindDialog == ReplaceDialog &&
  334. ReplaceDialog->Options.Contains(frReplaceAll));
  335. }
  336. //---------------------------------------------------------------------------
  337. void __fastcall TEditorForm::FormShow(TObject * /*Sender*/)
  338. {
  339. LoadFile();
  340. }
  341. //---------------------------------------------------------------------------
  342. void __fastcall TEditorForm::LoadFile()
  343. {
  344. EditorMemo->Lines->LoadFromFile(FFileName);
  345. EditorMemo->Modified = false;
  346. FCaretPos.x = -1;
  347. ApplyConfiguration();
  348. }
  349. //---------------------------------------------------------------------------
  350. bool __fastcall TEditorForm::CursorInUpperPart()
  351. {
  352. HFONT OldFont;
  353. void *DC;
  354. TTextMetric TM;
  355. TRect Rect;
  356. DC = GetDC(EditorMemo->Handle);
  357. OldFont = SelectObject(DC, EditorMemo->Font->Handle);
  358. try
  359. {
  360. GetTextMetrics(DC, &TM);
  361. EditorMemo->Perform(EM_GETRECT, 0, ((int)&Rect));
  362. }
  363. __finally
  364. {
  365. SelectObject(DC, OldFont);
  366. ReleaseDC(EditorMemo->Handle, DC);
  367. }
  368. int VisibleLines = (Rect.Bottom - Rect.Top) / (TM.tmHeight + TM.tmExternalLeading);
  369. int FirstLine = SendMessage(EditorMemo->Handle, EM_GETFIRSTVISIBLELINE, 0, 0);
  370. TPoint CaretPos = EditorMemo->CaretPos;
  371. return (CaretPos.y - FirstLine) < VisibleLines / 2;
  372. }
  373. //---------------------------------------------------------------------------
  374. void __fastcall TEditorForm::PositionFindDialog(bool VerticalOnly)
  375. {
  376. assert(FLastFindDialog);
  377. if (!VerticalOnly)
  378. {
  379. FLastFindDialog->Left = EditorMemo->Left + EditorMemo->Width / 2 - 100;
  380. }
  381. FLastFindDialog->Top = EditorMemo->Top + (EditorMemo->Height / 4) +
  382. (CursorInUpperPart() ? (EditorMemo->Height / 2) : 0) - 30;
  383. }
  384. //---------------------------------------------------------------------------
  385. void __fastcall TEditorForm::StartFind(bool Find)
  386. {
  387. AnsiString Text = EditorMemo->SelText;
  388. TFindOptions Options;
  389. if (FLastFindDialog)
  390. {
  391. Options = FLastFindDialog->Options;
  392. if (Text.IsEmpty())
  393. {
  394. Text = FLastFindDialog->FindText;
  395. }
  396. }
  397. TFindDialog * Dialog = Find ? FindDialog : ReplaceDialog;
  398. if (FLastFindDialog && Dialog != FLastFindDialog && FLastFindDialog->Handle)
  399. {
  400. FLastFindDialog->CloseDialog();
  401. }
  402. FLastFindDialog = Dialog;
  403. if (!Text.IsEmpty())
  404. {
  405. FLastFindDialog->FindText = Text;
  406. }
  407. if (!Options.Empty())
  408. {
  409. FLastFindDialog->Options = Options;
  410. }
  411. if (!FLastFindDialog->Handle)
  412. {
  413. PositionFindDialog(false);
  414. }
  415. FLastFindDialog->Execute();
  416. }
  417. //---------------------------------------------------------------------------
  418. void __fastcall TEditorForm::GoToLine()
  419. {
  420. AnsiString Str;
  421. if (InputDialog(LoadStr(EDITOR_GO_TO_LINE), LoadStr(EDITOR_LINE_NUMBER), Str))
  422. {
  423. int Line = StrToIntDef(Str, -1);
  424. if (Line <= 0 || Line > EditorMemo->Lines->Count)
  425. {
  426. throw Exception(LoadStr(EDITOR_INVALID_LINE));
  427. }
  428. else
  429. {
  430. EditorMemo->CaretPos = TPoint(0, Line-1);
  431. }
  432. }
  433. }
  434. //---------------------------------------------------------------------------
  435. void __fastcall TEditorForm::FormClose(TObject * Sender,
  436. TCloseAction & Action)
  437. {
  438. if (FOnWindowClose != NULL)
  439. {
  440. try
  441. {
  442. FOnWindowClose(Sender);
  443. }
  444. catch(Exception & E)
  445. {
  446. ShowExtendedException(&E);
  447. }
  448. }
  449. Action = caFree;
  450. }
  451. //---------------------------------------------------------------------------
  452. void __fastcall TEditorForm::SetShowWindowButton(bool value)
  453. {
  454. if (value != ShowWindowButton)
  455. {
  456. FShowWindowButton = value;
  457. RecreateWnd();
  458. }
  459. }
  460. //---------------------------------------------------------------------------
  461. void __fastcall TEditorForm::CreateParams(TCreateParams & Params)
  462. {
  463. TForm::CreateParams(Params);
  464. if (ShowWindowButton)
  465. {
  466. Params.WndParent = GetDesktopWindow();
  467. }
  468. }
  469. //---------------------------------------------------------------------------