Editor.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450
  1. //---------------------------------------------------------------------------
  2. #include <vcl.h>
  3. #pragma hdrstop
  4. #include "Editor.h"
  5. #include "WinInterface.h"
  6. #include "TextsWin.h"
  7. #include "Tools.h"
  8. #include <Common.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. void __fastcall DoEditorForm(const AnsiString FileName, TCustomForm * ParentForm,
  17. TNotifyEvent OnFileChanged, const AnsiString Caption)
  18. {
  19. TEditorForm * Dialog = new TEditorForm(Application);
  20. try
  21. {
  22. Dialog->FileName = FileName;
  23. Dialog->ParentForm = ParentForm;
  24. Dialog->Caption = Caption.IsEmpty() ? FileName : Caption;
  25. Dialog->OnFileChanged = OnFileChanged;
  26. Dialog->Execute();
  27. }
  28. __finally
  29. {
  30. delete Dialog;
  31. }
  32. }
  33. //---------------------------------------------------------------------------
  34. __fastcall TEditorForm::TEditorForm(TComponent* Owner)
  35. : TForm(Owner)
  36. {
  37. FParentForm = NULL;
  38. FCaretPos.x = -1;
  39. FCaretPos.y = -1;
  40. FLastFindDialog = NULL;
  41. ApplyConfiguration();
  42. FindDialog->FindText = WinConfiguration->Editor.FindText;
  43. TFindOptions Options = FindDialog->Options;
  44. if (WinConfiguration->Editor.FindMatchCase)
  45. {
  46. Options << frMatchCase;
  47. }
  48. if (WinConfiguration->Editor.FindWholeWord)
  49. {
  50. Options << frWholeWord;
  51. }
  52. FindDialog->Options = Options;
  53. ReplaceDialog->FindText = FindDialog->FindText;
  54. ReplaceDialog->Options = FindDialog->Options;
  55. ReplaceDialog->ReplaceText = WinConfiguration->Editor.ReplaceText;
  56. UseSystemFont(this);
  57. }
  58. //---------------------------------------------------------------------------
  59. __fastcall TEditorForm::~TEditorForm()
  60. {
  61. if (FLastFindDialog)
  62. {
  63. WinConfiguration->Editor.FindText = FLastFindDialog->FindText;
  64. WinConfiguration->Editor.ReplaceText = ReplaceDialog->ReplaceText;
  65. WinConfiguration->Editor.FindMatchCase = FLastFindDialog->Options.Contains(frMatchCase);
  66. WinConfiguration->Editor.FindWholeWord = FLastFindDialog->Options.Contains(frWholeWord);
  67. }
  68. }
  69. //---------------------------------------------------------------------------
  70. bool __fastcall TEditorForm::Execute()
  71. {
  72. ShowModal();
  73. return true;
  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. Content->Assign(EditorMemo->Lines);
  212. EditorMemo->WordWrap = WinConfiguration->Editor.WordWrap;
  213. EditorMemo->Lines = Content;
  214. EditorMemo->CaretPos = TPoint(0, 0);
  215. }
  216. __finally
  217. {
  218. delete Content;
  219. }
  220. }
  221. else
  222. {
  223. EditorMemo->WordWrap = WinConfiguration->Editor.WordWrap;
  224. }
  225. }
  226. EditorMemo->Modified = PrevModified;
  227. EditorMemo->ClearUndo();
  228. UpdateControls();
  229. }
  230. //---------------------------------------------------------------------------
  231. void __fastcall TEditorForm::UpdateControls()
  232. {
  233. TPoint ACaretPos = EditorMemo->CaretPos;
  234. if (ACaretPos.x != FCaretPos.x || ACaretPos.y != FCaretPos.y)
  235. {
  236. FCaretPos = ACaretPos;
  237. int Count = EditorMemo->Lines->Count;
  238. StatusBar->Panels->Items[0]->Text = FMTLOAD(EDITOR_LINE_STATUS,
  239. ((int)FCaretPos.y+1, Count));
  240. StatusBar->Panels->Items[1]->Text = FMTLOAD(EDITOR_COLUMN_STATUS,
  241. ((int)FCaretPos.x+1));
  242. AnsiString Character;
  243. if (FCaretPos.y >= 0 && FCaretPos.y < EditorMemo->Lines->Count)
  244. {
  245. AnsiString Line = EditorMemo->Lines->Strings[FCaretPos.y];
  246. if (FCaretPos.x+1 <= Line.Length())
  247. {
  248. Character = FMTLOAD(EDITOR_CHARACTER_STATUS,
  249. (int((unsigned char)Line[FCaretPos.x+1]), int((unsigned char)Line[FCaretPos.x+1])));
  250. }
  251. }
  252. StatusBar->Panels->Items[2]->Text = Character;
  253. }
  254. StatusBar->Panels->Items[3]->Text =
  255. (EditorMemo->Modified ? LoadStr(EDITOR_MODIFIED) : AnsiString(""));
  256. }
  257. //---------------------------------------------------------------------------
  258. void __fastcall TEditorForm::EditorMemoMouseUp(TObject * /*Sender*/,
  259. TMouseButton /*Button*/, TShiftState /*Shift*/, int /*X*/, int /*Y*/)
  260. {
  261. UpdateControls();
  262. }
  263. //---------------------------------------------------------------------------
  264. void __fastcall TEditorForm::EditorMemoKeyUp(TObject * /*Sender*/,
  265. WORD & /*Key*/, TShiftState /*Shift*/)
  266. {
  267. UpdateControls();
  268. }
  269. //---------------------------------------------------------------------------
  270. void __fastcall TEditorForm::EditorMemoChange(TObject * /*Sender*/)
  271. {
  272. UpdateControls();
  273. }
  274. //---------------------------------------------------------------------------
  275. void __fastcall TEditorForm::FindDialogFind(TObject * /*Sender*/)
  276. {
  277. Find();
  278. }
  279. //---------------------------------------------------------------------------
  280. void __fastcall TEditorForm::Find()
  281. {
  282. int NewPos;
  283. int Replacements = 0;
  284. do
  285. {
  286. assert(FLastFindDialog);
  287. TSearchTypes SearchTypes;
  288. // length condition is there to improve performance when large
  289. // block is selected in editor
  290. if (FLastFindDialog == ReplaceDialog &&
  291. (ReplaceDialog->Options.Contains(frReplace) ||
  292. ReplaceDialog->Options.Contains(frReplaceAll)) &&
  293. ReplaceDialog->FindText.Length() == EditorMemo->SelLength &&
  294. AnsiSameText(ReplaceDialog->FindText, EditorMemo->SelText))
  295. {
  296. EditorMemo->SelText = ReplaceDialog->ReplaceText;
  297. Replacements++;
  298. }
  299. if (FLastFindDialog->Options.Contains(frMatchCase))
  300. {
  301. SearchTypes << stMatchCase;
  302. }
  303. if (FLastFindDialog->Options.Contains(frWholeWord))
  304. {
  305. SearchTypes << stWholeWord;
  306. }
  307. NewPos = EditorMemo->FindText(FLastFindDialog->FindText,
  308. EditorMemo->SelLength ? EditorMemo->SelStart+1 : EditorMemo->SelStart,
  309. EditorMemo->Text.Length(), SearchTypes);
  310. if (NewPos >= 0)
  311. {
  312. EditorMemo->SelStart = NewPos;
  313. EditorMemo->SelLength = FLastFindDialog->FindText.Length();
  314. }
  315. if (FLastFindDialog->Handle)
  316. {
  317. PositionFindDialog(true);
  318. }
  319. if (NewPos < 0)
  320. {
  321. if (!Replacements)
  322. {
  323. MessageDialog(FMTLOAD(EDITOR_FIND_END, (FLastFindDialog->FindText)), qtInformation, qaOK, 0);
  324. }
  325. else
  326. {
  327. MessageDialog(FMTLOAD(EDITOR_REPLACE_END, (Replacements)), qtInformation, qaOK, 0);
  328. }
  329. }
  330. }
  331. while (NewPos >= 0 && FLastFindDialog == ReplaceDialog &&
  332. ReplaceDialog->Options.Contains(frReplaceAll));
  333. }
  334. //---------------------------------------------------------------------------
  335. void __fastcall TEditorForm::FormShow(TObject * /*Sender*/)
  336. {
  337. LoadFile();
  338. }
  339. //---------------------------------------------------------------------------
  340. void __fastcall TEditorForm::LoadFile()
  341. {
  342. EditorMemo->Lines->LoadFromFile(FFileName);
  343. EditorMemo->Modified = false;
  344. FCaretPos.x = -1;
  345. ApplyConfiguration();
  346. }
  347. //---------------------------------------------------------------------------
  348. bool __fastcall TEditorForm::CursorInUpperPart()
  349. {
  350. HFONT OldFont;
  351. void *DC;
  352. TTextMetric TM;
  353. TRect Rect;
  354. DC = GetDC(EditorMemo->Handle);
  355. OldFont = SelectObject(DC, EditorMemo->Font->Handle);
  356. try
  357. {
  358. GetTextMetrics(DC, &TM);
  359. EditorMemo->Perform(EM_GETRECT, 0, ((int)&Rect));
  360. }
  361. __finally
  362. {
  363. SelectObject(DC, OldFont);
  364. ReleaseDC(EditorMemo->Handle, DC);
  365. }
  366. int VisibleLines = (Rect.Bottom - Rect.Top) / (TM.tmHeight + TM.tmExternalLeading);
  367. int FirstLine = SendMessage(EditorMemo->Handle, EM_GETFIRSTVISIBLELINE, 0, 0);
  368. TPoint CaretPos = EditorMemo->CaretPos;
  369. return (CaretPos.y - FirstLine) < VisibleLines / 2;
  370. }
  371. //---------------------------------------------------------------------------
  372. void __fastcall TEditorForm::PositionFindDialog(bool VerticalOnly)
  373. {
  374. assert(FLastFindDialog);
  375. if (!VerticalOnly)
  376. {
  377. FLastFindDialog->Left = EditorMemo->Left + EditorMemo->Width / 2 - 100;
  378. }
  379. FLastFindDialog->Top = EditorMemo->Top + (EditorMemo->Height / 4) +
  380. (CursorInUpperPart() ? (EditorMemo->Height / 2) : 0) - 30;
  381. }
  382. //---------------------------------------------------------------------------
  383. void __fastcall TEditorForm::StartFind(bool Find)
  384. {
  385. AnsiString Text = EditorMemo->SelText;
  386. TFindOptions Options;
  387. if (FLastFindDialog)
  388. {
  389. Options = FLastFindDialog->Options;
  390. if (Text.IsEmpty())
  391. {
  392. Text = FLastFindDialog->FindText;
  393. }
  394. }
  395. TFindDialog * Dialog = Find ? FindDialog : ReplaceDialog;
  396. if (FLastFindDialog && Dialog != FLastFindDialog && FLastFindDialog->Handle)
  397. {
  398. FLastFindDialog->CloseDialog();
  399. }
  400. FLastFindDialog = Dialog;
  401. if (!Text.IsEmpty())
  402. {
  403. FLastFindDialog->FindText = Text;
  404. }
  405. if (!Options.Empty())
  406. {
  407. FLastFindDialog->Options = Options;
  408. }
  409. if (!FLastFindDialog->Handle)
  410. {
  411. PositionFindDialog(false);
  412. }
  413. FLastFindDialog->Execute();
  414. }
  415. //---------------------------------------------------------------------------
  416. void __fastcall TEditorForm::GoToLine()
  417. {
  418. AnsiString Str;
  419. if (InputDialog(LoadStr(EDITOR_GO_TO_LINE), LoadStr(EDITOR_LINE_NUMBER), Str))
  420. {
  421. int Line = StrToIntDef(Str, -1);
  422. if (Line <= 0 || Line > EditorMemo->Lines->Count)
  423. {
  424. throw Exception(LoadStr(EDITOR_INVALID_LINE));
  425. }
  426. else
  427. {
  428. EditorMemo->CaretPos = TPoint(0, Line-1);
  429. }
  430. }
  431. }
  432. //---------------------------------------------------------------------------