Subversion Repositories fastphp

Rev

Rev 89 | Rev 93 | Go to most recent revision | Show entire file | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 89 Rev 91
Line 9... Line 9...
9
    "Microsoft Internet Controls"
9
    "Microsoft Internet Controls"
10
  - SynEdit
10
  - SynEdit
11
    You can obtain SynEdit via Embarcadero GetIt
11
    You can obtain SynEdit via Embarcadero GetIt
12
*)
12
*)
13
 
13
 
14
// TODO: "DragAcceptFiles" does not work with Delphi Dark Design Template !!!
14
// TODO: "crHourGlass" does not work if F9 is pressed!
15
 
-
 
16
// TODO: if a scrapfile is already open, create a new scrap file (scrap2.php)
15
// TODO: if a scrapfile is already open, create a new scrap file (scrap2.php)
17
// TODO: localize
16
// TODO: localize
18
// TODO: wieso geht copy paste im twebbrowser nicht???
17
// TODO: wieso geht copy paste im twebbrowser nicht???
19
// TODO: Wieso dauert webbrowser1 erste kompilierung so lange???
18
// TODO: Wieso dauert webbrowser1 erste kompilierung so lange???
20
// TODO: wieso kommt syntax fehler zweimal? einmal stderr einmal stdout?
19
// TODO: wieso kommt syntax fehler zweimal? einmal stderr einmal stdout?
21
// TODO: Browser titlebar (link preview)
20
// TODO: Browser titlebar (link preview)
22
// TODO: "jump to next/prev todo" buttons/shortcuts
21
// TODO: "jump to next/prev todo" buttons/shortcuts
23
// TODO: "increase/decrease indent" buttons/shortcuts
22
// TODO: "increase/decrease indent" buttons/shortcuts
24
 
23
 
-
 
24
// In regards Unicode:
-
 
25
// - Solve compiler warnings
-
 
26
// - If you place Unicode symbols in a ANSI file, they will be replaced during saving
-
 
27
//   by "?" without asking the user if the code should be converted to Unicode!
-
 
28
// - FastPHP can only read a UTF-8 file correctly if it has a BOM
-
 
29
//   However, the PSR-1 standard requires that files have UTF-8 without BOM!
-
 
30
//   So we need auto-detect (since many people are working with ANSI!)
-
 
31
// - When a file is correctly loaded with UTF-8/BOM,
-
 
32
//   the run output (Plaintext and HTML) will show UTF-8 instead of Unicode
-
 
33
//   (that COULD be intended since the Windows CMD is not Unicode ready?)
-
 
34
//   But HTML is also shown as UTF-8 even though I have added <meta charset="UTF-8"> ?!
-
 
35
// - Is it possible that UTF8 BOM automatically gets removed by FastPHP, generating pure ANSI?
-
 
36
 
25
// Small things:
37
// Small things:
26
// - The scroll bars of SynEdit are not affected by the dark theme
38
// - The scroll bars of SynEdit are not affected by the dark theme
27
 
39
 
28
// Future ideas
40
// Future ideas
29
// - code insight
41
// - code insight
30
// - verschiedene php versionen?
42
// - verschiedene php versionen?
31
// - webbrowser1 nur laden, wenn man den tab anwählt?
43
// - webbrowser1 nur laden, wenn man den tab anwählt?
32
// - doppelklick auf tab soll diesen schließen
44
// - doppelklick auf tab soll diesen schließen
33
// - Onlinehelp (www) aufrufen
45
// - Onlinehelp (www) aufrufen oder CHM datei
34
// - Let all colors be adjustable
46
// - Let all colors be adjustable
35
// - code in bildschirmmitte (horizontal)?
47
// - code in bildschirmmitte (horizontal)?
36
// - search in files of a directory
48
// - search in files of a directory
37
// - multi tab?
49
// - Files in multiple tabs?
38
// - DDE (drag n drop)
50
// - Configurable tabulator display-width
39
 
51
 
40
interface
52
interface
41
 
53
 
42
uses
54
uses
43
  // TODO: "{$IFDEF USE_SHDOCVW_TLB}_TLB{$ENDIF}" does not work with Delphi 10.2
55
  // TODO: "{$IFDEF USE_SHDOCVW_TLB}_TLB{$ENDIF}" does not work with Delphi 10.2
Line 113... Line 125...
113
    BtnLight: TImage;
125
    BtnLight: TImage;
114
    StartUpTimer: TTimer;
126
    StartUpTimer: TTimer;
115
    FileModTimer: TTimer;
127
    FileModTimer: TTimer;
116
    GotoPHPdir1: TMenuItem;
128
    GotoPHPdir1: TMenuItem;
117
    PHPShell1: TMenuItem;
129
    PHPShell1: TMenuItem;
-
 
130
    ActionSaveAs: TAction;
-
 
131
    ActionGoToPHPDir: TAction;
-
 
132
    ActionPHPInteractiveShell: TAction;
118
    procedure Run(Sender: TObject);
133
    procedure Run(Sender: TObject);
119
    procedure RunConsole(Sender: TObject);
134
    procedure RunConsole(Sender: TObject);
120
    procedure FormShow(Sender: TObject);
135
    procedure FormShow(Sender: TObject);
121
    procedure FormCreate(Sender: TObject);
136
    procedure FormCreate(Sender: TObject);
122
    procedure FormDestroy(Sender: TObject);
137
    procedure FormDestroy(Sender: TObject);
Line 164... Line 179...
164
    procedure SynEdit1PaintTransient(Sender: TObject; Canvas: TCanvas;
179
    procedure SynEdit1PaintTransient(Sender: TObject; Canvas: TCanvas;
165
      TransientType: TTransientType);
180
      TransientType: TTransientType);
166
    procedure ActionLintExecute(Sender: TObject);
181
    procedure ActionLintExecute(Sender: TObject);
167
    procedure ActionRunConsoleExecute(Sender: TObject);
182
    procedure ActionRunConsoleExecute(Sender: TObject);
168
    procedure SynEdit1Change(Sender: TObject);
183
    procedure SynEdit1Change(Sender: TObject);
169
    procedure Saveas1Click(Sender: TObject);
-
 
170
    procedure Save1Click(Sender: TObject);
-
 
171
    procedure BtnSpecialCharsClick(Sender: TObject);
184
    procedure BtnSpecialCharsClick(Sender: TObject);
172
    procedure WebBrowser1WindowClosing(ASender: TObject;
185
    procedure WebBrowser1WindowClosing(ASender: TObject;
173
      IsChildWindow: WordBool; var Cancel: WordBool);
186
      IsChildWindow: WordBool; var Cancel: WordBool);
174
    procedure BtnLightClick(Sender: TObject);
187
    procedure BtnLightClick(Sender: TObject);
175
    procedure StartUpTimerTimer(Sender: TObject);
188
    procedure StartUpTimerTimer(Sender: TObject);
176
    procedure FileModTimerTimer(Sender: TObject);
189
    procedure FileModTimerTimer(Sender: TObject);
177
    procedure GotoPHPdir1Click(Sender: TObject);
-
 
178
    procedure PHPShell1Click(Sender: TObject);
-
 
179
    procedure SynEdit1DropFiles(Sender: TObject; X, Y: Integer;
190
    procedure SynEdit1DropFiles(Sender: TObject; X, Y: Integer;
180
      AFiles: TStrings);
191
      AFiles: TStrings);
-
 
192
    procedure ActionSaveAsExecute(Sender: TObject);
-
 
193
    procedure ActionGoToPHPDirExecute(Sender: TObject);
-
 
194
    procedure ActionPHPInteractiveShellExecute(Sender: TObject);
181
  private
195
  private
182
    hMutex: THandle;
196
    hMutex: THandle;
183
    CurSearchTerm: string;
197
    CurSearchTerm: string;
184
    HlpPrevPageIndex: integer;
198
    HlpPrevPageIndex: integer;
185
    SrcRep: TSynEditFindReplace;
199
    SrcRep: TSynEditFindReplace;
186
    {$IFDEF OnlineHelp}
200
    {$IFDEF OnlineHelp}
187
    gOnlineHelpWord: string;
201
    gOnlineHelpWord: string;
188
    {$ENDIF}
202
    {$ENDIF}
189
    FileModLast: TDateTime;
203
    FileModLast: TDateTime;
-
 
204
    FormShowRanOnce: boolean;
-
 
205
    BrowserLoadedOnce: boolean;
190
    procedure Help;
206
    procedure Help;
191
    function InputRequestCallback(var data: AnsiString): boolean;
207
    function InputRequestCallback(var data: AnsiString): boolean;
192
    function OutputNotifyCallback(const data: AnsiString): boolean;
208
    function OutputNotifyCallback(const data: AnsiString): boolean;
193
    procedure RightTrimAll;
209
    procedure RightTrimAll;
194
  protected
210
  protected
Line 247... Line 263...
247
 
263
 
248
procedure TForm1.ActionGotoExecute(Sender: TObject);
264
procedure TForm1.ActionGotoExecute(Sender: TObject);
249
var
265
var
250
  val: string;
266
  val: string;
251
  lineno: integer;
267
  lineno: integer;
-
 
268
resourcestring
-
 
269
  SGoTo = 'Go to';
-
 
270
  SLineNumber = 'Line number:';
252
begin
271
begin
253
  // TODO: VK_LMENU does not work! only works with AltGr but not Alt
272
  // TODO: VK_LMENU does not work! only works with AltGr but not Alt
254
  // http://stackoverflow.com/questions/16828250/delphi-xe2-how-to-prevent-the-alt-key-stealing-focus ?
273
  // http://stackoverflow.com/questions/16828250/delphi-xe2-how-to-prevent-the-alt-key-stealing-focus ?
255
 
274
 
256
  InputQuery('Go to', 'Line number:', val);
275
  if not InputQuery(SGoTo, SLineNumber, val) or
257
  if not TryStrToInt(val, lineno) then
276
     not TryStrToInt(val, lineno) then
258
  begin
277
  begin
259
    if SynEdit1.CanFocus then SynEdit1.SetFocus;
278
    if SynEdit1.CanFocus then SynEdit1.SetFocus;
260
    exit;
279
    exit;
261
  end;
280
  end;
262
  GotoLineNo(lineno);
281
  GotoLineNo(lineno);
263
end;
282
end;
264
 
283
 
-
 
284
procedure TForm1.ActionGoToPHPDirExecute(Sender: TObject);
-
 
285
var
-
 
286
  phpExe: string;
-
 
287
begin
-
 
288
  phpExe := GetPHPExe;
-
 
289
  if phpExe <> '' then
-
 
290
    ShellExecute(Handle, 'open', 'explorer.exe', PChar(ExtractFilePath(phpExe)), '', SW_NORMAL);
-
 
291
end;
-
 
292
 
265
procedure TForm1.ActionHelpExecute(Sender: TObject);
293
procedure TForm1.ActionHelpExecute(Sender: TObject);
266
begin
294
begin
267
  Help;
295
  Help;
268
  if PageControl2.ActivePage = HelpTabsheet then
296
  if PageControl2.ActivePage = HelpTabsheet then
269
    WebBrowser2.SetFocus
297
    WebBrowser2.SetFocus
Line 283... Line 311...
283
  begin
311
  begin
284
    ShellExecute(0, 'open', PChar(ParamStr(0)), PChar('"' + OpenDialog3.FileName + '"'), '', SW_NORMAL);
312
    ShellExecute(0, 'open', PChar(ParamStr(0)), PChar('"' + OpenDialog3.FileName + '"'), '', SW_NORMAL);
285
  end;
313
  end;
286
end;
314
end;
287
 
315
 
-
 
316
procedure TForm1.ActionPHPInteractiveShellExecute(Sender: TObject);
-
 
317
var
-
 
318
  phpExe: string;
-
 
319
begin
-
 
320
  phpExe := GetPHPExe;
-
 
321
  if phpExe <> '' then
-
 
322
    ShellExecute(Handle, 'open', PChar(phpExe), '-a', PChar(ExtractFilePath(phpExe)), SW_NORMAL);
-
 
323
end;
-
 
324
 
288
procedure TForm1.ActionReplaceExecute(Sender: TObject);
325
procedure TForm1.ActionReplaceExecute(Sender: TObject);
289
begin
326
begin
290
  SrcRep.ReplaceExecute;
327
  SrcRep.ReplaceExecute;
291
end;
328
end;
292
 
329
 
Line 323... Line 360...
323
    SynEdit1.SelEnd   := Length(SynEdit1.Text)-1;
360
    SynEdit1.SelEnd   := Length(SynEdit1.Text)-1;
324
  end;
361
  end;
325
  *)
362
  *)
326
end;
363
end;
327
 
364
 
-
 
365
procedure TForm1.ActionSaveAsExecute(Sender: TObject);
-
 
366
var
-
 
367
  hMutexNew: THandle;
-
 
368
resourcestring
-
 
369
  SCannotSaveBecauseMutex = 'Cannot save because file "%s", because it is alrady open in another FastPHP window!';
-
 
370
begin
-
 
371
  if SaveDialog1.Execute then
-
 
372
  begin
-
 
373
    {$REGION 'Switch mutex'}
-
 
374
    hMutexNew := CreateMutex(nil, True, PChar('FastPHP'+md5(UpperCase(SaveDialog1.FileName))));
-
 
375
    if GetLastError = ERROR_ALREADY_EXISTS then
-
 
376
    begin
-
 
377
      ShowMessageFmt(SCannotSaveBecauseMutex, [SaveDialog1.FileName]);
-
 
378
      Close;
-
 
379
    end;
-
 
380
 
-
 
381
    if hMutex <> 0 then CloseHandle(hMutex); // Note: ReleaseMutex does not work as expected!
-
 
382
    hMutex := hMutexNew;
-
 
383
    {$ENDREGION}
-
 
384
 
-
 
385
    FSaveAsFilename := SaveDialog1.FileName;
-
 
386
    Caption := Copy(Caption, 1, Pos(' - ', Caption)-1) + ' - ' + FSaveAsFilename;
-
 
387
    Application.Title := Format('%s - FastPHP', [ExtractFileName(FSaveAsFilename)]); // do not translate!
-
 
388
    Button7.Click;
-
 
389
  end;
-
 
390
end;
-
 
391
 
328
procedure TForm1.ActionSaveExecute(Sender: TObject);
392
procedure TForm1.ActionSaveExecute(Sender: TObject);
329
begin
393
begin
330
  RightTrimAll;
394
  RightTrimAll;
331
  SaveToFile(GetScrapFile);
395
  SaveToFile(GetScrapFile);
332
  SynEdit1.Modified := false;
396
  SynEdit1.Modified := false;
Line 405... Line 469...
405
var
469
var
406
  val: string;
470
  val: string;
407
  ind: integer;
471
  ind: integer;
408
resourcestring
472
resourcestring
409
  SNoLinesAvailable = 'No lines with spaces at the beginning available';
473
  SNoLinesAvailable = 'No lines with spaces at the beginning available';
-
 
474
  SSpacesToLabs = 'Spaces to tabs';
-
 
475
  SIndent = 'Indent:';
410
begin
476
begin
411
  // TODO: if something is selected, only process the selected part
477
  // TODO: if something is selected, only process the selected part
412
 
478
 
413
  if not SpacesAvailable(SynEdit1.Lines) then
479
  if not SpacesAvailable(SynEdit1.Lines) then
414
  begin
480
  begin
Line 417... Line 483...
417
  end;
483
  end;
418
 
484
 
419
  ind := GuessIndent(SynEdit1.Lines);
485
  ind := GuessIndent(SynEdit1.Lines);
420
  if ind <> -1 then val := IntToStr(ind);
486
  if ind <> -1 then val := IntToStr(ind);
421
 
487
 
422
  InputQuery('Spaces to tabs', 'Indent:', val); // TODO: handle CANCEL correctly...
488
  if not InputQuery(SSpacesToLabs, SIndent, val) or
423
  if TryStrToInt(Trim(val), ind) then
489
     not TryStrToInt(Trim(val), ind) then
424
  begin
490
  begin
425
    if ind = 0 then exit;
491
    if SynEdit1.CanFocus then SynEdit1.SetFocus;
426
    SpaceToTab(SynEdit1.Lines, ind);
492
    exit;
427
  end;
493
  end;
428
 
494
 
-
 
495
  if ind = 0 then exit;
429
  if SynEdit1.CanFocus then SynEdit1.SetFocus;
496
  SpaceToTab(SynEdit1.Lines, ind);
430
end;
497
end;
431
 
498
 
432
procedure TForm1.ActionESCExecute(Sender: TObject);
499
procedure TForm1.ActionESCExecute(Sender: TObject);
433
begin
500
begin
434
  if (HlpPrevPageIndex <> -1) and (PageControl2.ActivePage = HelpTabSheet) and
501
  if (HlpPrevPageIndex <> -1) and (PageControl2.ActivePage = HelpTabSheet) and
Line 445... Line 512...
445
procedure TForm1.ActionFindExecute(Sender: TObject);
512
procedure TForm1.ActionFindExecute(Sender: TObject);
446
begin
513
begin
447
  SrcRep.FindExecute;
514
  SrcRep.FindExecute;
448
end;
515
end;
449
 
516
 
450
var
-
 
451
  firstTimeBrowserLoad: boolean = true;
-
 
452
procedure TForm1.Run(Sender: TObject);
517
procedure TForm1.Run(Sender: TObject);
453
var
518
var
454
  bakTS: TTabSheet;
519
  bakTS: TTabSheet;
455
  //ss: TStringStream;
520
  //ss: TStringStream;
456
  //bakPos: Int64;
521
  //bakPos: Int64;
457
begin
522
begin
458
  memo2.Lines.Text := '';
523
  memo2.Lines.Text := '';
459
 
524
 
460
  if firstTimeBrowserLoad then
525
  if not BrowserLoadedOnce then
461
  begin
526
  begin
462
    bakTS := PageControl1.ActivePage;
527
    bakTS := PageControl1.ActivePage;
463
    try
528
    try
464
      PageControl1.ActivePage := HtmlTabSheet; // Required for the first time, otherwise, WebBrowser1.Clear will hang
529
      PageControl1.ActivePage := HtmlTabSheet; // Required for the first time, otherwise, WebBrowser1.Clear will hang
465
      Webbrowser1.Clear;
530
      Webbrowser1.Clear;
466
    finally
531
    finally
467
      PageControl1.ActivePage := bakTS;
532
      PageControl1.ActivePage := bakTS;
468
    end;
533
    end;
469
    firstTimeBrowserLoad := false;
534
    BrowserLoadedOnce := true;
470
  end
535
  end
471
  else
536
  else
472
    Webbrowser1.Clear;
537
    Webbrowser1.Clear;
473
 
538
 
474
  Screen.Cursor := crHourGlass;
539
  Screen.Cursor := crHourGlass; // TODO: Doesn't work with F9
475
  Application.ProcessMessages;
540
  Application.ProcessMessages;
476
 
541
 
477
  try
542
  try
478
    ActionSave.Execute; // TODO: if it is not the scrap file: do not save the file, since the user did not intended to save... better create a temporary file and run it instead.
543
    ActionSave.Execute; // TODO: if it is not the scrap file: do not save the file, since the user did not intended to save... better create a temporary file and run it instead.
479
 
544
 
Line 519... Line 584...
519
  AFiles: TStrings);
584
  AFiles: TStrings);
520
var
585
var
521
  FileName: string;
586
  FileName: string;
522
const
587
const
523
  WARN_FILE_COUNT = 10;
588
  WARN_FILE_COUNT = 10;
-
 
589
resourcestring
-
 
590
  SAreYouSure = 'Are you sure you want to open %d files?';
524
begin
591
begin
525
  if AFiles.Count > WARN_FILE_COUNT then
592
  if AFiles.Count > WARN_FILE_COUNT then
526
  begin
593
  begin
527
    if not MessageDlg(Format('Are you sure you want to open %d files?', [WARN_FILE_COUNT]), mtConfirmation, mbYesNoCancel, 0) <> mrYes then
594
    if not MessageDlg(Format(SAreYouSure, [WARN_FILE_COUNT]), mtConfirmation, mbYesNoCancel, 0) <> mrYes then
528
      exit;
595
      exit;
529
  end;
596
  end;
530
 
597
 
531
  for FileName in AFiles do
598
  for FileName in AFiles do
532
  begin
599
  begin
Line 749... Line 816...
749
end;
816
end;
750
 
817
 
751
procedure TForm1.Theme_Dark;
818
procedure TForm1.Theme_Dark;
752
begin
819
begin
753
  if IsThemeDark then exit;
820
  if IsThemeDark then exit;
754
  TStyleManager.TrySetStyle('Windows10 SlateGray');
821
  TStyleManager.TrySetStyle('Windows10 SlateGray'); // do not translate
755
  Color := 1316887;
822
  Color := 1316887;
756
  Font.Color := clCream;
823
  Font.Color := clCream;
757
  //Memo2.Font.Color := clCream;
824
  //Memo2.Font.Color := clCream;
758
  //Memo2.ParentColor := true;
825
  //Memo2.ParentColor := true;
759
  SynEdit1.ActiveLineColor := 2238502;
826
  SynEdit1.ActiveLineColor := 2238502;
Line 773... Line 840...
773
end;
840
end;
774
 
841
 
775
procedure TForm1.Theme_Light;
842
procedure TForm1.Theme_Light;
776
begin
843
begin
777
  if not IsThemeDark then exit;
844
  if not IsThemeDark then exit;
778
  TStyleManager.TrySetStyle('Windows');
845
  TStyleManager.TrySetStyle('Windows'); // do not translate
779
  Color := clBtnFace;
846
  Color := clBtnFace;
780
  Font.Color := clWindowText;
847
  Font.Color := clWindowText;
781
  //Memo2.Font.Color := clWindowText;
848
  //Memo2.Font.Color := clWindowText;
782
  SynEdit1.ActiveLineColor := 14680010;
849
  SynEdit1.ActiveLineColor := 14680010;
783
  SynEdit1.Color := clWindow;
850
  SynEdit1.Color := clCream;
784
  SynEdit1.Font.Color := clWindowText;
851
  SynEdit1.Font.Color := clWindowText;
785
  SynEdit1.Gutter.Color := clBtnFace;
852
  SynEdit1.Gutter.Color := clBtnFace;
786
  SynEdit1.Gutter.Font.Color := clWindowText;
853
  SynEdit1.Gutter.Font.Color := clWindowText;
787
  SynEdit1.Gutter.GradientStartcolor := cl3dLight;
854
  SynEdit1.Gutter.GradientStartcolor := cl3dLight;
788
  SynEdit1.Gutter.GradientEndColor := clBtnFace;;
855
  SynEdit1.Gutter.GradientEndColor := clBtnFace;;
Line 837... Line 904...
837
*)
904
*)
838
 
905
 
839
procedure TForm1.WebBrowser1WindowClosing(ASender: TObject;
906
procedure TForm1.WebBrowser1WindowClosing(ASender: TObject;
840
  IsChildWindow: WordBool; var Cancel: WordBool);
907
  IsChildWindow: WordBool; var Cancel: WordBool);
841
resourcestring
908
resourcestring
842
  LNG_CLOSE_REQUEST = 'A script has requested the window to be closed. The window of a standalone script would now close.';
909
  SCloseRequest = 'A script has requested the window to be closed. The window of a standalone script would now close.';
843
begin
910
begin
844
  ShowMessage(LNG_CLOSE_REQUEST);
911
  ShowMessage(SCloseRequest);
845
  TWebBrowser(ASender).Clear;
912
  TWebBrowser(ASender).Clear;
846
  Cancel := true;
913
  Cancel := true;
847
end;
914
end;
848
 
915
 
849
procedure TForm1.BeforeNavigate(const URL: OleVariant; var Cancel: WordBool);
916
procedure TForm1.BeforeNavigate(const URL: OleVariant; var Cancel: WordBool);
Line 928... Line 995...
928
  end;
995
  end;
929
  SynEdit1.Options := opts;
996
  SynEdit1.Options := opts;
930
end;
997
end;
931
 
998
 
932
procedure TForm1.FileModTimerTimer(Sender: TObject);
999
procedure TForm1.FileModTimerTimer(Sender: TObject);
-
 
1000
resourcestring
-
 
1001
  SChangeConflict = 'The file was changed in a different application BUT IT WAS ALSO MODIFIED HERE! Reload file AND LOSE CHANGES HERE?';
-
 
1002
  SChangeNotify = 'The file was changed in a different application! Reload file?';
933
begin
1003
begin
934
  FileModTimer.Enabled := false;
1004
  FileModTimer.Enabled := false;
935
  if FileModLast <> FileAge(GetScrapFile) then
1005
  if FileModLast <> FileAge(GetScrapFile) then
936
  begin
1006
  begin
937
    FileModLast := FileAge(GetScrapFile);
1007
    FileModLast := FileAge(GetScrapFile);
938
    if SynEdit1.Modified then
1008
    if SynEdit1.Modified then
939
    begin
1009
    begin
940
      if MessageDlg('The file was changed in a different application BUT IT WAS ALSO MODIFIED HERE! Reload file AND LOSE CHANGES HERE?', mtWarning, mbYesNoCancel, 0) = mrYes then
1010
      if MessageDlg(SChangeConflict, mtWarning, mbYesNoCancel, 0) = mrYes then
941
      begin
1011
      begin
942
        SynEdit1.Lines.LoadFromFile(GetScrapFile);
1012
        SynEdit1.Lines.LoadFromFile(GetScrapFile);
943
      end;
1013
      end;
944
    end
1014
    end
945
    else
1015
    else
946
    begin
1016
    begin
947
      if MessageDlg('The file was changed in a different application! Reload file?', mtConfirmation, mbYesNoCancel, 0) = mrYes then
1017
      if MessageDlg(SChangeNotify, mtConfirmation, mbYesNoCancel, 0) = mrYes then
948
      begin
1018
      begin
949
        SynEdit1.Lines.LoadFromFile(GetScrapFile);
1019
        SynEdit1.Lines.LoadFromFile(GetScrapFile);
950
      end;
1020
      end;
951
    end;
1021
    end;
952
  end;
1022
  end;
Line 960... Line 1030...
960
end;
1030
end;
961
 
1031
 
962
procedure TForm1.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
1032
procedure TForm1.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
963
var
1033
var
964
  r: integer;
1034
  r: integer;
-
 
1035
resourcestring
-
 
1036
  SWantToSave = 'Do you want to save?';
965
begin
1037
begin
966
  if SynEdit1.Modified then
1038
  if SynEdit1.Modified then
967
  begin
1039
  begin
968
    if (ParamStr(1) <> '') or (FSaveAsFilename <> '') then
1040
    if (ParamStr(1) <> '') or (FSaveAsFilename <> '') then
969
    begin
1041
    begin
970
      r := MessageDlg('Do you want to save?', mtConfirmation, mbYesNoCancel, 0);
1042
      r := MessageDlg(SWantToSave, mtConfirmation, mbYesNoCancel, 0);
971
      if r = mrCancel then
1043
      if r = mrCancel then
972
      begin
1044
      begin
973
        CanClose := false;
1045
        CanClose := false;
974
        Exit;
1046
        Exit;
975
      end
1047
      end
Line 994... Line 1066...
994
begin
1066
begin
995
  HlpPrevPageIndex := -1;
1067
  HlpPrevPageIndex := -1;
996
  CurSearchTerm := '';
1068
  CurSearchTerm := '';
997
  sScrapFile := GetScrapFile;
1069
  sScrapFile := GetScrapFile;
998
  Caption := Caption + ' - ' + sScrapFile;
1070
  Caption := Caption + ' - ' + sScrapFile;
999
  Application.Title := Format('%s - FastPHP', [ExtractFileName(sScrapFile)]);
1071
  Application.Title := Format('%s - FastPHP', [ExtractFileName(sScrapFile)]); // do not translate!
1000
  SrcRep := TSynEditFindReplace.Create(self);
1072
  SrcRep := TSynEditFindReplace.Create(self);
1001
  SrcRep.Editor := SynEdit1;
1073
  SrcRep.Editor := SynEdit1;
1002
  SynEdit1.Gutter.Gradient := HighColorWindows;
1074
  SynEdit1.Gutter.Gradient := HighColorWindows;
1003
 
1075
 
1004
  Screen.Cursors[crMouseGutter] := LoadCursor(hInstance, 'MOUSEGUTTER');
1076
  Screen.Cursors[crMouseGutter] := LoadCursor(hInstance, 'MOUSEGUTTER');
Line 1027... Line 1099...
1027
    codeExplorer.WaitFor;
1099
    codeExplorer.WaitFor;
1028
    FreeAndNil(codeExplorer);
1100
    FreeAndNil(codeExplorer);
1029
  end;
1101
  end;
1030
end;
1102
end;
1031
 
1103
 
1032
var
-
 
1033
  FormShowRanOnce: boolean;
-
 
1034
procedure TForm1.FormShow(Sender: TObject);
1104
procedure TForm1.FormShow(Sender: TObject);
1035
var
1105
var
1036
  ScrapFile: string;
1106
  ScrapFile: string;
1037
  tmpFontSize: integer;
1107
  tmpFontSize: integer;
1038
  opts: TSynEditorOptions;
1108
  opts: TSynEditorOptions;
-
 
1109
resourcestring
-
 
1110
  SFileAlreadyOpen = 'File "%s" is alrady open!';
1039
begin
1111
begin
1040
  if FormShowRanOnce then exit; // If the theme is changed from normal to dark, OnShow will be called another time
1112
  if FormShowRanOnce then exit; // If the theme is changed from normal to dark, OnShow will be called another time
1041
  FormShowRanOnce := true;
1113
  FormShowRanOnce := true;
1042
 
1114
 
1043
  ScrapFile := GetScrapFile;
1115
  ScrapFile := GetScrapFile;
Line 1066... Line 1138...
1066
    begin
1138
    begin
1067
      hMutex := CreateMutex(nil, True, PChar('FastPHP'+md5(UpperCase(ScrapFile))));
1139
      hMutex := CreateMutex(nil, True, PChar('FastPHP'+md5(UpperCase(ScrapFile))));
1068
      if GetLastError = ERROR_ALREADY_EXISTS then
1140
      if GetLastError = ERROR_ALREADY_EXISTS then
1069
      begin
1141
      begin
1070
        // TODO: It would be great if the window of that FastPHP instance would switched to foreground
1142
        // TODO: It would be great if the window of that FastPHP instance would switched to foreground
1071
        ShowMessageFmt('File "%s" is alrady open!', [ScrapFile]);
1143
        ShowMessageFmt(SFileAlreadyOpen, [ScrapFile]);
1072
        Close;
1144
        Close;
1073
      end;
1145
      end;
1074
 
1146
 
1075
      SynEdit1.Lines.LoadFromFile(ScrapFile);
1147
      SynEdit1.Lines.LoadFromFile(ScrapFile);
1076
    end;
1148
    end;
Line 1093... Line 1165...
1093
  DragAcceptFiles(Handle, True);
1165
  DragAcceptFiles(Handle, True);
1094
 
1166
 
1095
  StartupTimer.Enabled := true;
1167
  StartupTimer.Enabled := true;
1096
end;
1168
end;
1097
 
1169
 
1098
procedure TForm1.Save1Click(Sender: TObject);
-
 
1099
begin
-
 
1100
  Button7.Click;
-
 
1101
end;
-
 
1102
 
-
 
1103
procedure TForm1.Saveas1Click(Sender: TObject);
-
 
1104
var
-
 
1105
  hMutexNew: THandle;
-
 
1106
begin
-
 
1107
  if SaveDialog1.Execute then
-
 
1108
  begin
-
 
1109
    {$REGION 'Switch mutex'}
-
 
1110
    hMutexNew := CreateMutex(nil, True, PChar('FastPHP'+md5(UpperCase(SaveDialog1.FileName))));
-
 
1111
    if GetLastError = ERROR_ALREADY_EXISTS then
-
 
1112
    begin
-
 
1113
      ShowMessageFmt('Cannot save because file "%s", because it is alrady open in another FastPHP window!', [SaveDialog1.FileName]);
-
 
1114
      Close;
-
 
1115
    end;
-
 
1116
 
-
 
1117
    if hMutex <> 0 then CloseHandle(hMutex); // Note: ReleaseMutex does not work as expected!
-
 
1118
    hMutex := hMutexNew;
-
 
1119
    {$ENDREGION}
-
 
1120
 
-
 
1121
    FSaveAsFilename := SaveDialog1.FileName;
-
 
1122
    Caption := Copy(Caption, 1, Pos(' - ', Caption)-1) + ' - ' + FSaveAsFilename;
-
 
1123
    Application.Title := Format('%s - FastPHP', [ExtractFileName(FSaveAsFilename)]);
-
 
1124
    Button7.Click;
-
 
1125
  end;
-
 
1126
end;
-
 
1127
 
-
 
1128
procedure TForm1.SaveToFile(filename: string);
1170
procedure TForm1.SaveToFile(filename: string);
1129
var
1171
var
1130
  ss: TStringStream;
1172
  ss: TStringStream;
1131
  ms: TMemoryStream;
1173
  ms: TMemoryStream;
1132
  fs: TFileStream;
1174
  fs: TFileStream;
Line 1236... Line 1278...
1236
end;
1278
end;
1237
 
1279
 
1238
function TForm1.GetScrapFile: string;
1280
function TForm1.GetScrapFile: string;
1239
var
1281
var
1240
  tmpPath: string;
1282
  tmpPath: string;
-
 
1283
resourcestring
-
 
1284
  SFileDoesNotExistsCreate = 'File %s does not exist. Create it?';
-
 
1285
  SPathDoesNotExistTryAgain = 'Path does not exist! Please try again.';
1241
begin
1286
begin
1242
  if FSaveAsFilename <> '' then
1287
  if FSaveAsFilename <> '' then
1243
  begin
1288
  begin
1244
    result := FSaveAsFilename;
1289
    result := FSaveAsFilename;
1245
    exit;
1290
    exit;
Line 1257... Line 1302...
1257
 
1302
 
1258
    result := ParamStr(1);
1303
    result := ParamStr(1);
1259
 
1304
 
1260
    if not FileExists(result) then
1305
    if not FileExists(result) then
1261
    begin
1306
    begin
1262
      case MessageDlg(Format('File %s does not exist. Create it?', [result]), mtConfirmation, mbYesNoCancel, 0) of
1307
      case MessageDlg(Format(SFileDoesNotExistsCreate, [result]), mtConfirmation, mbYesNoCancel, 0) of
1263
        mrYes:
1308
        mrYes:
1264
          try
1309
          try
1265
            SaveToFile(result);
1310
            SaveToFile(result);
1266
          except
1311
          except
1267
            on E: Exception do
1312
            on E: Exception do
Line 1323... Line 1368...
1323
          exit;
1368
          exit;
1324
        end;
1369
        end;
1325
 
1370
 
1326
        if not DirectoryExists(ExtractFilePath(OpenDialog3.FileName)) then
1371
        if not DirectoryExists(ExtractFilePath(OpenDialog3.FileName)) then
1327
        begin
1372
        begin
1328
          MessageDlg('Path does not exist! Please try again.', mtWarning, [mbOk], 0);
1373
          MessageDlg(SPathDoesNotExistTryAgain, mtWarning, [mbOk], 0);
1329
        end
1374
        end
1330
        else
1375
        else
1331
        begin
1376
        begin
1332
          result := OpenDialog3.FileName;
1377
          result := OpenDialog3.FileName;
1333
        end;
1378
        end;
Line 1358... Line 1403...
1358
 
1403
 
1359
procedure TForm1.Help;
1404
procedure TForm1.Help;
1360
var
1405
var
1361
  IndexFile, chmFile, w, OriginalWord, url: string;
1406
  IndexFile, chmFile, w, OriginalWord, url: string;
1362
  internalHtmlFile: string;
1407
  internalHtmlFile: string;
-
 
1408
resourcestring
-
 
1409
  SChmFileNotAValidPHPDocumentation = 'The CHM file is not a valid PHP documentation. Cannot use help.';
-
 
1410
  SUnknownErrorCannotUseHelp = 'Unknown error. Cannot use help.';
-
 
1411
  SNoHelpAvailable = 'No help for "%s" available';
1363
begin
1412
begin
1364
  if not Assigned(ChmIndex) then
1413
  if not Assigned(ChmIndex) then
1365
  begin
1414
  begin
1366
    IndexFile := TFastPHPConfig.HelpIndex;
1415
    IndexFile := TFastPHPConfig.HelpIndex;
1367
    IndexFile := ChangeFileExt(IndexFile, '.ini'); // Just to be sure. Maybe someone wrote manually the ".chm" file in there
1416
    IndexFile := ChangeFileExt(IndexFile, '.ini'); // Just to be sure. Maybe someone wrote manually the ".chm" file in there
Line 1400... Line 1449...
1400
      Screen.Cursor := crHourGlass;
1449
      Screen.Cursor := crHourGlass;
1401
      Application.ProcessMessages;
1450
      Application.ProcessMessages;
1402
      try
1451
      try
1403
        if not ParseCHM(chmFile) then
1452
        if not ParseCHM(chmFile) then
1404
        begin
1453
        begin
1405
          MessageDlg('The CHM file is not a valid PHP documentation. Cannot use help.', mtError, [mbOk], 0);
1454
          MessageDlg(SChmFileNotAValidPHPDocumentation, mtError, [mbOk], 0);
1406
          exit;
1455
          exit;
1407
        end;
1456
        end;
1408
      finally
1457
      finally
1409
        Screen.Cursor := crDefault;
1458
        Screen.Cursor := crDefault;
1410
        Panel1.Visible := false;
1459
        Panel1.Visible := false;
1411
      end;
1460
      end;
1412
 
1461
 
1413
      if not FileExists(IndexFile) then
1462
      if not FileExists(IndexFile) then
1414
      begin
1463
      begin
1415
        MessageDlg('Unknown error. Cannot use help.', mtError, [mbOk], 0);
1464
        MessageDlg(SUnknownErrorCannotUseHelp, mtError, [mbOk], 0);
1416
        exit;
1465
        exit;
1417
      end;
1466
      end;
1418
    end;
1467
    end;
1419
 
1468
 
1420
    TFastPHPConfig.HelpIndex := IndexFile;
1469
    TFastPHPConfig.HelpIndex := IndexFile;
Line 1433... Line 1482...
1433
  Originalword := w;
1482
  Originalword := w;
1434
//  w := StringReplace(w, '_', '-', [rfReplaceAll]);
1483
//  w := StringReplace(w, '_', '-', [rfReplaceAll]);
1435
  w := LowerCase(w);
1484
  w := LowerCase(w);
1436
  CurSearchTerm := w;
1485
  CurSearchTerm := w;
1437
 
1486
 
1438
  internalHtmlFile := ChmIndex.ReadString('function', CurSearchTerm, '');
1487
  internalHtmlFile := ChmIndex.ReadString('function', CurSearchTerm, ''); // do not translate
1439
  if internalHtmlFile = '' then
1488
  if internalHtmlFile = '' then
1440
    internalHtmlFile := ChmIndex.ReadString('_HelpWords_', CurSearchTerm, '');
1489
    internalHtmlFile := ChmIndex.ReadString('_HelpWords_', CurSearchTerm, ''); // do not translate
1441
  if internalHtmlFile = '' then
1490
  if internalHtmlFile = '' then
1442
  begin
1491
  begin
1443
    HelpTabsheet.TabVisible := false;
1492
    HelpTabsheet.TabVisible := false;
1444
    HlpPrevPageIndex := -1;
1493
    HlpPrevPageIndex := -1;
1445
    ShowMessageFmt('No help for "%s" available', [Originalword]);
1494
    ShowMessageFmt(SNoHelpAvailable, [Originalword]);
1446
    Exit;
1495
    Exit;
1447
  end;
1496
  end;
1448
 
1497
 
1449
  url := 'mk:@MSITStore:'+ChmFile+'::'+internalHtmlFile;
1498
  url := 'mk:@MSITStore:'+ChmFile+'::'+internalHtmlFile;
1450
 
1499
 
Line 1479... Line 1528...
1479
 
1528
 
1480
  PageControl2.ActivePage := CodeTabsheet;
1529
  PageControl2.ActivePage := CodeTabsheet;
1481
  if SynEdit1.CanFocus then SynEdit1.SetFocus;
1530
  if SynEdit1.CanFocus then SynEdit1.SetFocus;
1482
end;
1531
end;
1483
 
1532
 
1484
procedure TForm1.GotoPHPdir1Click(Sender: TObject);
-
 
1485
var
-
 
1486
  phpExe: string;
-
 
1487
begin
-
 
1488
  phpExe := GetPHPExe;
-
 
1489
  if phpExe <> '' then
-
 
1490
    ShellExecute(Handle, 'open', 'explorer.exe', PChar(ExtractFilePath(phpExe)), '', SW_NORMAL);
-
 
1491
end;
-
 
1492
 
-
 
1493
procedure TForm1.PageControl2Changing(Sender: TObject;
1533
procedure TForm1.PageControl2Changing(Sender: TObject;
1494
  var AllowChange: Boolean);
1534
  var AllowChange: Boolean);
1495
begin
1535
begin
1496
  if PageControl2.ActivePage = HelpTabsheet then
1536
  if PageControl2.ActivePage = HelpTabsheet then
1497
    HlpPrevPageIndex := -1
1537
    HlpPrevPageIndex := -1
Line 1499... Line 1539...
1499
    HlpPrevPageIndex := PageControl2.ActivePageIndex;
1539
    HlpPrevPageIndex := PageControl2.ActivePageIndex;
1500
 
1540
 
1501
  AllowChange := true;
1541
  AllowChange := true;
1502
end;
1542
end;
1503
 
1543
 
1504
procedure TForm1.PHPShell1Click(Sender: TObject);
-
 
1505
var
-
 
1506
  phpExe: string;
-
 
1507
begin
-
 
1508
  phpExe := GetPHPExe;
-
 
1509
  if phpExe <> '' then
-
 
1510
    ShellExecute(Handle, 'open', PChar(phpExe), '-a', PChar(ExtractFilePath(phpExe)), SW_NORMAL);
-
 
1511
end;
-
 
1512
 
-
 
1513
procedure TForm1.Memo2DblClick(Sender: TObject);
1544
procedure TForm1.Memo2DblClick(Sender: TObject);
1514
var
1545
var
1515
  line: string;
1546
  line: string;
1516
 
1547
 
1517
  procedure _process(toFind: string);
1548
  procedure _process(toFind: string);
Line 1536... Line 1567...
1536
  {$REGION 'Possibility 1: filename.php:lineno'}
1567
  {$REGION 'Possibility 1: filename.php:lineno'}
1537
  _process(ExtractFileName(GetScrapFile) + ':');
1568
  _process(ExtractFileName(GetScrapFile) + ':');
1538
  {$ENDREGION}
1569
  {$ENDREGION}
1539
 
1570
 
1540
  {$REGION 'Possibility 2: on line xx'}
1571
  {$REGION 'Possibility 2: on line xx'}
1541
  _process(ExtractFileName(GetScrapFile) + ' on line ');
1572
  _process(ExtractFileName(GetScrapFile) + ' on line '); // do not translate!
1542
  {$ENDREGION}
1573
  {$ENDREGION}
1543
end;
1574
end;
1544
 
1575
 
1545
procedure TForm1.Memo2KeyDown(Sender: TObject; var Key: Word;
1576
procedure TForm1.Memo2KeyDown(Sender: TObject; var Key: Word;
1546
  Shift: TShiftState);
1577
  Shift: TShiftState);
Line 1591... Line 1622...
1591
  {$REGION 'Possibility 1: filename.php:lineno'}
1622
  {$REGION 'Possibility 1: filename.php:lineno'}
1592
  _process(ExtractFileName(GetScrapFile) + ':');
1623
  _process(ExtractFileName(GetScrapFile) + ':');
1593
  {$ENDREGION}
1624
  {$ENDREGION}
1594
 
1625
 
1595
  {$REGION 'Possibility 2: on line xx'}
1626
  {$REGION 'Possibility 2: on line xx'}
1596
  _process(ExtractFileName(GetScrapFile) + ' on line ');
1627
  _process(ExtractFileName(GetScrapFile) + ' on line '); // do not translate!
1597
  {$ENDREGION}
1628
  {$ENDREGION}
1598
 
1629
 
1599
  result := cont;
1630
  result := cont;
1600
end;
1631
end;
1601
 
1632
 
Line 1610... Line 1641...
1610
  result := Assigned(TStyleManager.ActiveStyle) and (TStyleManager.ActiveStyle.Name<>'Windows');
1641
  result := Assigned(TStyleManager.ActiveStyle) and (TStyleManager.ActiveStyle.Name<>'Windows');
1611
end;
1642
end;
1612
 
1643
 
1613
function TForm1.OutputNotifyCallback(const data: AnsiString): boolean;
1644
function TForm1.OutputNotifyCallback(const data: AnsiString): boolean;
1614
begin
1645
begin
1615
  result := TreeView1.FillWithFastPHPData(data);
1646
  result := TreeView1.FillWithFastPHPData(string(data));
1616
end;
1647
end;
1617
 
1648
 
1618
end.
1649
end.