Editor.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451
  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. UseSystemSettings(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. 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. }
  258. //---------------------------------------------------------------------------
  259. void __fastcall TEditorForm::EditorMemoMouseUp(TObject * /*Sender*/,
  260. TMouseButton /*Button*/, TShiftState /*Shift*/, int /*X*/, int /*Y*/)
  261. {
  262. UpdateControls();
  263. }
  264. //---------------------------------------------------------------------------
  265. void __fastcall TEditorForm::EditorMemoKeyUp(TObject * /*Sender*/,
  266. WORD & /*Key*/, TShiftState /*Shift*/)
  267. {
  268. UpdateControls();
  269. }
  270. //---------------------------------------------------------------------------
  271. void __fastcall TEditorForm::EditorMemoChange(TObject * /*Sender*/)
  272. {
  273. UpdateControls();
  274. }
  275. //---------------------------------------------------------------------------
  276. void __fastcall TEditorForm::FindDialogFind(TObject * /*Sender*/)
  277. {
  278. Find();
  279. }
  280. //---------------------------------------------------------------------------
  281. void __fastcall TEditorForm::Find()
  282. {
  283. int NewPos;
  284. int Replacements = 0;
  285. do
  286. {
  287. assert(FLastFindDialog);
  288. TSearchTypes SearchTypes;
  289. // length condition is there to improve performance when large
  290. // block is selected in editor
  291. if (FLastFindDialog == ReplaceDialog &&
  292. (ReplaceDialog->Options.Contains(frReplace) ||
  293. ReplaceDialog->Options.Contains(frReplaceAll)) &&
  294. ReplaceDialog->FindText.Length() == EditorMemo->SelLength &&
  295. AnsiSameText(ReplaceDialog->FindText, EditorMemo->SelText))
  296. {
  297. EditorMemo->SelText = ReplaceDialog->ReplaceText;
  298. Replacements++;
  299. }
  300. if (FLastFindDialog->Options.Contains(frMatchCase))
  301. {
  302. SearchTypes << stMatchCase;
  303. }
  304. if (FLastFindDialog->Options.Contains(frWholeWord))
  305. {
  306. SearchTypes << stWholeWord;
  307. }
  308. NewPos = EditorMemo->FindText(FLastFindDialog->FindText,
  309. EditorMemo->SelLength ? EditorMemo->SelStart+1 : EditorMemo->SelStart,
  310. EditorMemo->Text.Length(), SearchTypes);
  311. if (NewPos >= 0)
  312. {
  313. EditorMemo->SelStart = NewPos;
  314. EditorMemo->SelLength = FLastFindDialog->FindText.Length();
  315. }
  316. if (FLastFindDialog->Handle)
  317. {
  318. PositionFindDialog(true);
  319. }
  320. if (NewPos < 0)
  321. {
  322. if (!Replacements)
  323. {
  324. MessageDialog(FMTLOAD(EDITOR_FIND_END, (FLastFindDialog->FindText)), qtInformation, qaOK, 0);
  325. }
  326. else
  327. {
  328. MessageDialog(FMTLOAD(EDITOR_REPLACE_END, (Replacements)), qtInformation, qaOK, 0);
  329. }
  330. }
  331. }
  332. while (NewPos >= 0 && FLastFindDialog == ReplaceDialog &&
  333. ReplaceDialog->Options.Contains(frReplaceAll));
  334. }
  335. //---------------------------------------------------------------------------
  336. void __fastcall TEditorForm::FormShow(TObject * /*Sender*/)
  337. {
  338. LoadFile();
  339. }
  340. //---------------------------------------------------------------------------
  341. void __fastcall TEditorForm::LoadFile()
  342. {
  343. EditorMemo->Lines->LoadFromFile(FFileName);
  344. EditorMemo->Modified = false;
  345. FCaretPos.x = -1;
  346. ApplyConfiguration();
  347. }
  348. //---------------------------------------------------------------------------
  349. bool __fastcall TEditorForm::CursorInUpperPart()
  350. {
  351. HFONT OldFont;
  352. void *DC;
  353. TTextMetric TM;
  354. TRect Rect;
  355. DC = GetDC(EditorMemo->Handle);
  356. OldFont = SelectObject(DC, EditorMemo->Font->Handle);
  357. try
  358. {
  359. GetTextMetrics(DC, &TM);
  360. EditorMemo->Perform(EM_GETRECT, 0, ((int)&Rect));
  361. }
  362. __finally
  363. {
  364. SelectObject(DC, OldFont);
  365. ReleaseDC(EditorMemo->Handle, DC);
  366. }
  367. int VisibleLines = (Rect.Bottom - Rect.Top) / (TM.tmHeight + TM.tmExternalLeading);
  368. int FirstLine = SendMessage(EditorMemo->Handle, EM_GETFIRSTVISIBLELINE, 0, 0);
  369. TPoint CaretPos = EditorMemo->CaretPos;
  370. return (CaretPos.y - FirstLine) < VisibleLines / 2;
  371. }
  372. //---------------------------------------------------------------------------
  373. void __fastcall TEditorForm::PositionFindDialog(bool VerticalOnly)
  374. {
  375. assert(FLastFindDialog);
  376. if (!VerticalOnly)
  377. {
  378. FLastFindDialog->Left = EditorMemo->Left + EditorMemo->Width / 2 - 100;
  379. }
  380. FLastFindDialog->Top = EditorMemo->Top + (EditorMemo->Height / 4) +
  381. (CursorInUpperPart() ? (EditorMemo->Height / 2) : 0) - 30;
  382. }
  383. //---------------------------------------------------------------------------
  384. void __fastcall TEditorForm::StartFind(bool Find)
  385. {
  386. AnsiString Text = EditorMemo->SelText;
  387. TFindOptions Options;
  388. if (FLastFindDialog)
  389. {
  390. Options = FLastFindDialog->Options;
  391. if (Text.IsEmpty())
  392. {
  393. Text = FLastFindDialog->FindText;
  394. }
  395. }
  396. TFindDialog * Dialog = Find ? FindDialog : ReplaceDialog;
  397. if (FLastFindDialog && Dialog != FLastFindDialog && FLastFindDialog->Handle)
  398. {
  399. FLastFindDialog->CloseDialog();
  400. }
  401. FLastFindDialog = Dialog;
  402. if (!Text.IsEmpty())
  403. {
  404. FLastFindDialog->FindText = Text;
  405. }
  406. if (!Options.Empty())
  407. {
  408. FLastFindDialog->Options = Options;
  409. }
  410. if (!FLastFindDialog->Handle)
  411. {
  412. PositionFindDialog(false);
  413. }
  414. FLastFindDialog->Execute();
  415. }
  416. //---------------------------------------------------------------------------
  417. void __fastcall TEditorForm::GoToLine()
  418. {
  419. AnsiString Str;
  420. if (InputDialog(LoadStr(EDITOR_GO_TO_LINE), LoadStr(EDITOR_LINE_NUMBER), Str))
  421. {
  422. int Line = StrToIntDef(Str, -1);
  423. if (Line <= 0 || Line > EditorMemo->Lines->Count)
  424. {
  425. throw Exception(LoadStr(EDITOR_INVALID_LINE));
  426. }
  427. else
  428. {
  429. EditorMemo->CaretPos = TPoint(0, Line-1);
  430. }
  431. }
  432. }
  433. //---------------------------------------------------------------------------