Subversion Repositories fastphp

Rev

Rev 86 | Rev 89 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
8 daniel-mar 1
unit EditorMain;
2 daniel-mar 2
 
25 daniel-mar 3
{$Include 'FastPHP.inc'}
4
 
4 daniel-mar 5
(*
6
  This program requires
7
  - Microsoft Internet Controls (TWebBrowser)
8
    If you are using Delphi 10.1 Starter Edition, please import the ActiveX TLB
9
    "Microsoft Internet Controls"
10
  - SynEdit
11
    You can obtain SynEdit via Embarcadero GetIt
12
*)
13
 
86 daniel-mar 14
// TODO: "DragAcceptFiles" does not work with Delphi Dark Design Template !!!
15
 
72 daniel-mar 16
// TODO: if a scrapfile is already open, create a new scrap file (scrap2.php)
2 daniel-mar 17
// TODO: localize
18
// TODO: wieso geht copy paste im twebbrowser nicht???
49 daniel-mar 19
// TODO: Wieso dauert webbrowser1 erste kompilierung so lange???
5 daniel-mar 20
// TODO: wieso kommt syntax fehler zweimal? einmal stderr einmal stdout?
21
// TODO: Browser titlebar (link preview)
49 daniel-mar 22
// TODO: "jump to next/prev todo" buttons/shortcuts
23
// TODO: "increase/decrease indent" buttons/shortcuts
2 daniel-mar 24
 
63 daniel-mar 25
// Small things:
26
// - The scroll bars of SynEdit are not affected by the dark theme
27
 
2 daniel-mar 28
// Future ideas
31 daniel-mar 29
// - code insight
2 daniel-mar 30
// - verschiedene php versionen?
31
// - webbrowser1 nur laden, wenn man den tab anwählt?
32
// - doppelklick auf tab soll diesen schließen
5 daniel-mar 33
// - Onlinehelp (www) aufrufen
13 daniel-mar 34
// - Let all colors be adjustable
21 daniel-mar 35
// - code in bildschirmmitte (horizontal)?
72 daniel-mar 36
// - search in files of a directory
37
// - multi tab?
38
// - DDE (drag n drop)
2 daniel-mar 39
 
40
interface
41
 
42
uses
27 daniel-mar 43
  // TODO: "{$IFDEF USE_SHDOCVW_TLB}_TLB{$ENDIF}" does not work with Delphi 10.2
2 daniel-mar 44
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
4 daniel-mar 45
  Dialogs, StdCtrls, OleCtrls, ComCtrls, ExtCtrls, ToolWin, IniFiles,
80 daniel-mar 46
  SynEditHighlighter, SynHighlighterPHP, SynEdit, ShDocVw, FindReplace,
45 daniel-mar 47
  ActnList, SynEditMiscClasses, SynEditSearch, RunPHP, ImgList, SynUnicode,
83 daniel-mar 48
  System.ImageList, System.Actions, Vcl.Menus, Vcl.Themes, System.UITypes;
2 daniel-mar 49
 
23 daniel-mar 50
{.$DEFINE OnlineHelp}
51
 
2 daniel-mar 52
type
53
  TForm1 = class(TForm)
54
    PageControl1: TPageControl;
55
    PlaintextTabSheet: TTabSheet;
56
    HtmlTabSheet: TTabSheet;
57
    Memo2: TMemo;
58
    WebBrowser1: TWebBrowser;
59
    Splitter1: TSplitter;
60
    PageControl2: TPageControl;
20 daniel-mar 61
    CodeTabsheet: TTabSheet;
2 daniel-mar 62
    HelpTabsheet: TTabSheet;
63
    WebBrowser2: TWebBrowser;
64
    OpenDialog1: TOpenDialog;
65
    Panel1: TPanel;
66
    OpenDialog3: TOpenDialog;
4 daniel-mar 67
    SynEdit1: TSynEdit;
68
    SynPHPSyn1: TSynPHPSyn;
5 daniel-mar 69
    Panel2: TPanel;
70
    SynEditFocusTimer: TTimer;
71
    Button1: TButton;
72
    Button2: TButton;
73
    Button3: TButton;
13 daniel-mar 74
    Button4: TButton;
75
    Button5: TButton;
76
    Button6: TButton;
77
    ActionList: TActionList;
78
    ActionFind: TAction;
79
    ActionReplace: TAction;
80
    ActionFindNext: TAction;
81
    ActionGoto: TAction;
82
    ActionSave: TAction;
83
    ActionHelp: TAction;
84
    ActionRun: TAction;
85
    ActionESC: TAction;
86
    Button7: TButton;
15 daniel-mar 87
    ActionOpen: TAction;
88
    Button8: TButton;
22 daniel-mar 89
    Button9: TButton;
90
    ActionFindPrev: TAction;
23 daniel-mar 91
    Timer1: TTimer;
92
    ActionSpaceToTab: TAction;
93
    Button11: TButton;
24 daniel-mar 94
    SynEditSearch1: TSynEditSearch;
27 daniel-mar 95
    TreeView1: TTreeView;
26 daniel-mar 96
    Splitter2: TSplitter;
33 daniel-mar 97
    btnLint: TButton;
98
    ActionLint: TAction;
36 daniel-mar 99
    ImageList1: TImageList;
45 daniel-mar 100
    RunPopup: TPopupMenu;
101
    OpeninIDE1: TMenuItem;
102
    ActionRunConsole: TAction;
103
    Runinconsole1: TMenuItem;
56 daniel-mar 104
    SavePopup: TPopupMenu;
105
    Saveas1: TMenuItem;
106
    Save1: TMenuItem;
107
    SaveDialog1: TSaveDialog;
57 daniel-mar 108
    BtnSpecialChars: TImage;
109
    BtnSpecialCharsOff: TImage;
110
    BtnSpecialCharsOn: TImage;
62 daniel-mar 111
    BtnLightOn: TImage;
112
    BtnLightOff: TImage;
113
    BtnLight: TImage;
114
    StartUpTimer: TTimer;
83 daniel-mar 115
    FileModTimer: TTimer;
87 daniel-mar 116
    GotoPHPdir1: TMenuItem;
117
    PHPShell1: TMenuItem;
2 daniel-mar 118
    procedure Run(Sender: TObject);
45 daniel-mar 119
    procedure RunConsole(Sender: TObject);
2 daniel-mar 120
    procedure FormShow(Sender: TObject);
121
    procedure FormCreate(Sender: TObject);
122
    procedure FormDestroy(Sender: TObject);
123
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
124
    procedure PageControl2Changing(Sender: TObject; var AllowChange: Boolean);
5 daniel-mar 125
    procedure Memo2DblClick(Sender: TObject);
45 daniel-mar 126
    (*
44 daniel-mar 127
    {$IFDEF USE_SHDOCVW_TLB}
45 daniel-mar 128
    *)
5 daniel-mar 129
    procedure WebBrowser1BeforeNavigate2(ASender: TObject;
27 daniel-mar 130
      const pDisp: IDispatch; const URL, Flags, TargetFrameName, PostData,
5 daniel-mar 131
      Headers: OleVariant; var Cancel: WordBool);
45 daniel-mar 132
    (*
44 daniel-mar 133
    {$ELSE}
134
    procedure WebBrowser1BeforeNavigate2(ASender: TObject;
135
      const pDisp: IDispatch; var URL, Flags, TargetFrameName, PostData,
136
      Headers: OleVariant; var Cancel: WordBool);
137
    {$ENDIF}
45 daniel-mar 138
    *)
44 daniel-mar 139
    procedure BeforeNavigate(const URL: OleVariant; var Cancel: WordBool);
5 daniel-mar 140
    procedure SynEditFocusTimerTimer(Sender: TObject);
13 daniel-mar 141
    procedure ActionFindExecute(Sender: TObject);
142
    procedure ActionReplaceExecute(Sender: TObject);
143
    procedure ActionFindNextExecute(Sender: TObject);
144
    procedure ActionGotoExecute(Sender: TObject);
145
    procedure ActionSaveExecute(Sender: TObject);
146
    procedure ActionHelpExecute(Sender: TObject);
147
    procedure ActionRunExecute(Sender: TObject);
148
    procedure ActionESCExecute(Sender: TObject);
149
    procedure SynEdit1MouseWheelDown(Sender: TObject; Shift: TShiftState;
150
      MousePos: TPoint; var Handled: Boolean);
151
    procedure SynEdit1MouseWheelUp(Sender: TObject; Shift: TShiftState;
152
      MousePos: TPoint; var Handled: Boolean);
15 daniel-mar 153
    procedure ActionOpenExecute(Sender: TObject);
154
    procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
17 daniel-mar 155
    procedure Memo2KeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
22 daniel-mar 156
    procedure ActionFindPrevExecute(Sender: TObject);
23 daniel-mar 157
    procedure SynEdit1MouseCursor(Sender: TObject;
158
      const aLineCharPos: TBufferCoord; var aCursor: TCursor);
159
    procedure Timer1Timer(Sender: TObject);
160
    procedure ActionSpaceToTabExecute(Sender: TObject);
27 daniel-mar 161
    procedure TreeView1DblClick(Sender: TObject);
30 daniel-mar 162
    procedure SynEdit1GutterClick(Sender: TObject; Button: TMouseButton; X, Y,
163
      Line: Integer; Mark: TSynEditMark);
31 daniel-mar 164
    procedure SynEdit1PaintTransient(Sender: TObject; Canvas: TCanvas;
165
      TransientType: TTransientType);
33 daniel-mar 166
    procedure ActionLintExecute(Sender: TObject);
45 daniel-mar 167
    procedure ActionRunConsoleExecute(Sender: TObject);
47 daniel-mar 168
    procedure SynEdit1Change(Sender: TObject);
56 daniel-mar 169
    procedure Saveas1Click(Sender: TObject);
170
    procedure Save1Click(Sender: TObject);
57 daniel-mar 171
    procedure BtnSpecialCharsClick(Sender: TObject);
60 daniel-mar 172
    procedure WebBrowser1WindowClosing(ASender: TObject;
173
      IsChildWindow: WordBool; var Cancel: WordBool);
62 daniel-mar 174
    procedure BtnLightClick(Sender: TObject);
175
    procedure StartUpTimerTimer(Sender: TObject);
83 daniel-mar 176
    procedure FileModTimerTimer(Sender: TObject);
87 daniel-mar 177
    procedure GotoPHPdir1Click(Sender: TObject);
178
    procedure PHPShell1Click(Sender: TObject);
2 daniel-mar 179
  private
67 daniel-mar 180
    hMutex: THandle;
2 daniel-mar 181
    CurSearchTerm: string;
182
    HlpPrevPageIndex: integer;
24 daniel-mar 183
    SrcRep: TSynEditFindReplace;
23 daniel-mar 184
    {$IFDEF OnlineHelp}
185
    gOnlineHelpWord: string;
186
    {$ENDIF}
83 daniel-mar 187
    FileModLast: TDateTime;
2 daniel-mar 188
    procedure Help;
40 daniel-mar 189
    function InputRequestCallback(var data: AnsiString): boolean;
190
    function OutputNotifyCallback(const data: AnsiString): boolean;
67 daniel-mar 191
    procedure RightTrimAll;
86 daniel-mar 192
    procedure WMDropFiles(var Msg: TWMDropFiles); message WM_DROPFILES;
2 daniel-mar 193
  protected
194
    ChmIndex: TMemIniFile;
19 daniel-mar 195
    FScrapFile: string;
56 daniel-mar 196
    FSaveAsFilename: string;
27 daniel-mar 197
    codeExplorer: TRunCodeExplorer;
198
    procedure GotoLineNo(LineNo: integer);
2 daniel-mar 199
    function GetScrapFile: string;
27 daniel-mar 200
    procedure StartCodeExplorer;
47 daniel-mar 201
    procedure RefreshModifySign;
62 daniel-mar 202
    procedure Theme_Light;
203
    procedure Theme_Dark;
204
    function IsThemeDark: boolean;
67 daniel-mar 205
    function MarkUpLineReference(cont: string): string;
76 daniel-mar 206
    procedure SaveToFile(filename: string);
2 daniel-mar 207
  end;
208
 
209
var
210
  Form1: TForm1;
211
 
212
implementation
213
 
214
{$R *.dfm}
215
 
30 daniel-mar 216
{$R Cursors.res}
217
 
2 daniel-mar 218
uses
25 daniel-mar 219
  Functions, StrUtils, WebBrowserUtils, FastPHPUtils, Math, ShellAPI, RichEdit,
49 daniel-mar 220
  FastPHPTreeView, ImageListEx, FastPHPConfig;
2 daniel-mar 221
 
30 daniel-mar 222
const
223
  crMouseGutter = 1;
224
 
47 daniel-mar 225
procedure TForm1.RefreshModifySign;
226
var
227
  tmp: string;
228
begin
229
  tmp := Caption;
230
 
231
  tmp := StringReplace(tmp, '*', '', [rfReplaceAll]);
232
  if SynEdit1.Modified then tmp := tmp + '*';
233
 
234
  if Caption <> tmp then Caption := tmp;
235
end;
236
 
13 daniel-mar 237
procedure TForm1.ActionFindNextExecute(Sender: TObject);
238
begin
239
  SrcRep.FindNext;
240
end;
241
 
22 daniel-mar 242
procedure TForm1.ActionFindPrevExecute(Sender: TObject);
243
begin
244
  SrcRep.FindPrev;
245
end;
246
 
13 daniel-mar 247
procedure TForm1.ActionGotoExecute(Sender: TObject);
5 daniel-mar 248
var
249
  val: string;
250
  lineno: integer;
251
begin
13 daniel-mar 252
  // TODO: VK_LMENU does not work! only works with AltGr but not Alt
253
  // http://stackoverflow.com/questions/16828250/delphi-xe2-how-to-prevent-the-alt-key-stealing-focus ?
5 daniel-mar 254
 
13 daniel-mar 255
  InputQuery('Go to', 'Line number:', val);
256
  if not TryStrToInt(val, lineno) then
257
  begin
258
    if SynEdit1.CanFocus then SynEdit1.SetFocus;
259
    exit;
260
  end;
261
  GotoLineNo(lineno);
262
end;
5 daniel-mar 263
 
13 daniel-mar 264
procedure TForm1.ActionHelpExecute(Sender: TObject);
265
begin
266
  Help;
267
  if PageControl2.ActivePage = HelpTabsheet then
268
    WebBrowser2.SetFocus
20 daniel-mar 269
  else if PageControl2.ActivePage = CodeTabsheet then
13 daniel-mar 270
    SynEdit1.SetFocus;
271
end;
8 daniel-mar 272
 
33 daniel-mar 273
procedure TForm1.ActionLintExecute(Sender: TObject);
274
begin
275
  Run(Sender);
276
  SynEdit1.SetFocus;
277
end;
278
 
15 daniel-mar 279
procedure TForm1.ActionOpenExecute(Sender: TObject);
280
begin
281
  If OpenDialog3.Execute then
282
  begin
62 daniel-mar 283
    ShellExecute(0, 'open', PChar(ParamStr(0)), PChar('"' + OpenDialog3.FileName + '"'), '', SW_NORMAL);
15 daniel-mar 284
  end;
285
end;
286
 
13 daniel-mar 287
procedure TForm1.ActionReplaceExecute(Sender: TObject);
288
begin
289
  SrcRep.ReplaceExecute;
290
end;
5 daniel-mar 291
 
45 daniel-mar 292
procedure TForm1.ActionRunConsoleExecute(Sender: TObject);
293
begin
294
  RunConsole(Sender);
295
  SynEdit1.SetFocus;
296
end;
297
 
13 daniel-mar 298
procedure TForm1.ActionRunExecute(Sender: TObject);
299
begin
300
  Run(Sender);
301
  SynEdit1.SetFocus;
302
end;
5 daniel-mar 303
 
67 daniel-mar 304
procedure TForm1.RightTrimAll;
305
var
306
  i: integer;
307
begin
68 daniel-mar 308
  for i := 0 to SynEdit1.Lines.Count-1 do
67 daniel-mar 309
  begin
310
    SynEdit1.Lines.Strings[i] := TrimRight(SynEdit1.Lines.Strings[i]);
311
  end;
77 daniel-mar 312
 
313
  (*
314
  while (SynEdit1.Lines.Count > 0) and (SynEdit1.Lines.Strings[SynEdit1.Lines.Count-1] = '') do
315
  begin
316
    SynEdit1.Lines.Delete(SynEdit1.Lines.Count-1);
317
  end;
318
  if SynEdit1.SelStart > Length(SynEdit1.Text)-1 then
319
  begin
320
    // TODO: This code does not work...
321
    SynEdit1.SelStart := Length(SynEdit1.Text)-1;
322
    SynEdit1.SelEnd   := Length(SynEdit1.Text)-1;
323
  end;
324
  *)
67 daniel-mar 325
end;
326
 
13 daniel-mar 327
procedure TForm1.ActionSaveExecute(Sender: TObject);
328
begin
67 daniel-mar 329
  RightTrimAll;
76 daniel-mar 330
  SaveToFile(GetScrapFile);
16 daniel-mar 331
  SynEdit1.Modified := false;
47 daniel-mar 332
  RefreshModifySign;
68 daniel-mar 333
  if SynEdit1.CanFocus then SynEdit1.SetFocus;
13 daniel-mar 334
end;
335
 
23 daniel-mar 336
procedure TForm1.ActionSpaceToTabExecute(Sender: TObject);
337
 
338
    function SpacesAtBeginning(line: string): integer;
339
    begin
340
      result := 0;
44 daniel-mar 341
      if Trim(line) = '' then exit;
23 daniel-mar 342
      while line[result+1] = ' ' do
343
      begin
344
        inc(result);
345
      end;
346
    end;
347
 
44 daniel-mar 348
    function GuessIndent(lines: {$IFDEF UNICODE}TStrings{$ELSE}TUnicodeStrings{$ENDIF}): integer;
23 daniel-mar 349
      function _Check(indent: integer): boolean;
350
      var
351
        i: integer;
352
      begin
353
        result := true;
354
        for i := 0 to lines.Count-1 do
355
          if SpacesAtBeginning(lines.Strings[i]) mod indent <> 0 then
356
          begin
357
            // ShowMessageFmt('Zeile "%s" nicht durch %d teilbar!', [lines.strings[i], indent]);
44 daniel-mar 358
            result := false;
359
            exit;
23 daniel-mar 360
          end;
361
      end;
362
    var
363
      i: integer;
364
    begin
365
      for i := 8 downto 2 do
366
      begin
44 daniel-mar 367
        if _Check(i) then
368
        begin
369
          result := i;
370
          exit;
371
        end;
23 daniel-mar 372
      end;
373
      result := -1;
374
    end;
375
 
44 daniel-mar 376
    procedure SpaceToTab(lines: {$IFDEF UNICODE}TStrings{$ELSE}TUnicodeStrings{$ENDIF}; indent: integer);
23 daniel-mar 377
    var
378
      i, spaces: integer;
379
    begin
380
      for i := 0 to lines.Count-1 do
381
      begin
382
        spaces := SpacesAtBeginning(lines.Strings[i]);
383
        lines.Strings[i] := StringOfChar(#9, spaces div indent) + StringOfChar(' ', spaces mod indent) + Copy(lines.Strings[i], spaces+1, Length(lines.Strings[i])-spaces);
384
      end;
385
    end;
386
 
44 daniel-mar 387
    function SpacesAvailable(lines: {$IFDEF UNICODE}TStrings{$ELSE}TUnicodeStrings{$ENDIF}): boolean;
23 daniel-mar 388
    var
389
      i, spaces: integer;
390
    begin
391
      for i := 0 to lines.Count-1 do
392
      begin
393
        spaces := SpacesAtBeginning(lines.Strings[i]);
44 daniel-mar 394
        if spaces > 0 then
395
        begin
396
          result := true;
397
          exit;
398
        end;
23 daniel-mar 399
      end;
44 daniel-mar 400
      result := false;
401
      exit;
23 daniel-mar 402
    end;
403
 
404
var
405
  val: string;
406
  ind: integer;
407
resourcestring
408
  SNoLinesAvailable = 'No lines with spaces at the beginning available';
409
begin
410
  // TODO: if something is selected, only process the selected part
411
 
412
  if not SpacesAvailable(SynEdit1.Lines) then
413
  begin
49 daniel-mar 414
    MessageDlg(SNoLinesAvailable, mtInformation, [mbOk], 0);
23 daniel-mar 415
    exit;
416
  end;
417
 
418
  ind := GuessIndent(SynEdit1.Lines);
419
  if ind <> -1 then val := IntToStr(ind);
420
 
421
  InputQuery('Spaces to tabs', 'Indent:', val); // TODO: handle CANCEL correctly...
44 daniel-mar 422
  if TryStrToInt(Trim(val), ind) then
23 daniel-mar 423
  begin
424
    if ind = 0 then exit;
425
    SpaceToTab(SynEdit1.Lines, ind);
426
  end;
427
 
428
  if SynEdit1.CanFocus then SynEdit1.SetFocus;
429
end;
430
 
13 daniel-mar 431
procedure TForm1.ActionESCExecute(Sender: TObject);
432
begin
433
  if (HlpPrevPageIndex <> -1) and (PageControl2.ActivePage = HelpTabSheet) and
434
     (HelpTabsheet.TabVisible) then
435
  begin
436
    PageControl2.ActivePageIndex := HlpPrevPageIndex;
437
    HelpTabsheet.TabVisible := false;
2 daniel-mar 438
  end;
13 daniel-mar 439
 
440
  // Dirty hack...
22 daniel-mar 441
  SrcRep.CloseDialogs;
2 daniel-mar 442
end;
443
 
13 daniel-mar 444
procedure TForm1.ActionFindExecute(Sender: TObject);
445
begin
446
  SrcRep.FindExecute;
447
end;
448
 
16 daniel-mar 449
var
450
  firstTimeBrowserLoad: boolean = true;
2 daniel-mar 451
procedure TForm1.Run(Sender: TObject);
16 daniel-mar 452
var
453
  bakTS: TTabSheet;
67 daniel-mar 454
  //ss: TStringStream;
455
  //bakPos: Int64;
2 daniel-mar 456
begin
5 daniel-mar 457
  memo2.Lines.Text := '';
16 daniel-mar 458
 
459
  if firstTimeBrowserLoad then
460
  begin
461
    bakTS := PageControl1.ActivePage;
462
    try
463
      PageControl1.ActivePage := HtmlTabSheet; // Required for the first time, otherwise, WebBrowser1.Clear will hang
464
      Webbrowser1.Clear;
465
    finally
466
      PageControl1.ActivePage := bakTS;
467
    end;
468
    firstTimeBrowserLoad := false;
469
  end
470
  else
471
    Webbrowser1.Clear;
472
 
5 daniel-mar 473
  Screen.Cursor := crHourGlass;
474
  Application.ProcessMessages;
475
 
476
  try
47 daniel-mar 477
    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.
5 daniel-mar 478
 
62 daniel-mar 479
    // TODO 70421 * <fastphp> flush() mittels ContentCallBack implementieren... ich möchte bei langen scripts statusanzeigen realisieren können mit javascript das stück für stück geladen wird !!!!!!!!
480
    // TODO 70422 * <fastphp> wenn ein script hängt, soll man es abwürgen dürfen!!!!!!
45 daniel-mar 481
    memo2.Lines.Text := RunPHPScript(GetScrapFile, Sender=ActionLint, False);
5 daniel-mar 482
 
72 daniel-mar 483
    {$REGION 'Show in Web Browser'}
484
    Webbrowser1.LoadHTML(MarkUpLineReference(memo2.Lines.Text), GetScrapFile);
5 daniel-mar 485
 
62 daniel-mar 486
    // Alternatively:
487
    (*
488
    ss := TstringStream.Create;
489
    ss.WriteString(MarkUpLineReference(memo2.Lines.Text));
490
    ss.Position := 0;
491
    Webbrowser1.LoadStream(ss, GetScrapFile);
492
    Webbrowser1.Wait;
493
    ss.Free;
494
    *)
72 daniel-mar 495
    {$ENDREGION}
62 daniel-mar 496
 
5 daniel-mar 497
    if IsTextHTML(memo2.lines.text) then
498
      PageControl1.ActivePage := HtmlTabSheet
499
    else
500
      PageControl1.ActivePage := PlaintextTabSheet;
501
  finally
502
    Screen.Cursor := crDefault;
2 daniel-mar 503
  end;
5 daniel-mar 504
end;
2 daniel-mar 505
 
45 daniel-mar 506
procedure TForm1.RunConsole(Sender: TObject);
507
begin
47 daniel-mar 508
  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.
45 daniel-mar 509
  RunPHPScript(GetScrapFile, Sender=ActionLint, True);
510
end;
511
 
47 daniel-mar 512
procedure TForm1.SynEdit1Change(Sender: TObject);
513
begin
514
  RefreshModifySign;
515
end;
516
 
30 daniel-mar 517
procedure TForm1.SynEdit1GutterClick(Sender: TObject; Button: TMouseButton; X,
518
  Y, Line: Integer; Mark: TSynEditMark);
519
begin
520
  (*
521
  TSynEdit(Sender).CaretX := 1;
522
  TSynEdit(Sender).CaretY := Line;
523
  TSynEdit(Sender).SelLength := Length(TSynEdit(Sender).LineText);
524
  *)
525
end;
526
 
23 daniel-mar 527
procedure TForm1.SynEdit1MouseCursor(Sender: TObject; const aLineCharPos: TBufferCoord; var aCursor: TCursor);
528
{$IFDEF OnlineHelp}
529
var
530
  Line: Integer;
531
  Column: Integer;
532
  word: string;
533
begin
534
  Line  := aLineCharPos.Line-1;
535
  Column := aLineCharPos.Char-1;
536
  word := GetWordUnderPos(TSynEdit(Sender), Line, Column);
537
  if word <> gOnlineHelpWord then
538
  begin
539
    gOnlineHelpWord := word;
540
    Timer1.Enabled := false;
541
    Timer1.Enabled := true;
542
  end;
543
{$ELSE}
544
begin
545
{$ENDIF}
546
end;
547
 
13 daniel-mar 548
procedure TForm1.SynEdit1MouseWheelDown(Sender: TObject; Shift: TShiftState;
549
  MousePos: TPoint; var Handled: Boolean);
550
begin
551
  if ssCtrl in Shift then
552
  begin
553
    SynEdit1.Font.Size := Max(SynEdit1.Font.Size - 1, 5);
23 daniel-mar 554
    Handled := true;
555
  end
556
  else Handled := false;
13 daniel-mar 557
end;
558
 
559
procedure TForm1.SynEdit1MouseWheelUp(Sender: TObject; Shift: TShiftState;
560
  MousePos: TPoint; var Handled: Boolean);
561
begin
562
  if ssCtrl in Shift then
563
  begin
564
    SynEdit1.Font.Size := SynEdit1.Font.Size + 1;
23 daniel-mar 565
    Handled := true;
566
  end
567
  else Handled := false;
13 daniel-mar 568
end;
569
 
31 daniel-mar 570
procedure TForm1.SynEdit1PaintTransient(Sender: TObject; Canvas: TCanvas; TransientType: TTransientType);
571
var
572
  Editor: TSynEdit;
573
  OpenChars: array of WideChar;//[0..2] of WideChar=();
574
  CloseChars: array of WideChar;//[0..2] of WideChar=();
575
 
576
  function IsCharBracket(AChar: WideChar): Boolean;
577
  begin
578
    case AChar of
579
      '{','[','(','<','}',']',')','>':
580
        Result := True;
581
      else
582
        Result := False;
583
    end;
584
  end;
585
 
586
  function CharToPixels(P: TBufferCoord): TPoint;
587
  begin
588
    Result := Editor.RowColumnToPixels(Editor.BufferToDisplayPos(P));
589
  end;
590
 
591
var
63 daniel-mar 592
  COLOR_FG: TColor;
593
  COLOR_BG: TColor;
31 daniel-mar 594
  P: TBufferCoord;
595
  Pix: TPoint;
596
  D: TDisplayCoord;
597
  S: UnicodeString;
598
  I: Integer;
599
  Attri: TSynHighlighterAttributes;
600
  ArrayLength: Integer;
601
  start: Integer;
602
  TmpCharA, TmpCharB: WideChar;
63 daniel-mar 603
begin
31 daniel-mar 604
  // Source: https://github.com/SynEdit/SynEdit/blob/master/Demos/OnPaintTransientDemo/Unit1.pas
605
 
63 daniel-mar 606
  if IsThemeDark then
607
  begin
608
    COLOR_FG := clLime;
609
    COLOR_BG := clGreen;
610
  end
611
  else
612
  begin
613
    COLOR_FG := clGreen;
614
    COLOR_BG := clLime;
615
  end;
616
 
31 daniel-mar 617
  if TSynEdit(Sender).SelAvail then exit;
618
  Editor := TSynEdit(Sender);
619
  ArrayLength:= 3;
620
 
621
  (*
622
  if (Editor.Highlighter = shHTML) or (Editor.Highlighter = shXML) then
623
    inc(ArrayLength);
624
  *)
625
 
626
  SetLength(OpenChars, ArrayLength);
627
  SetLength(CloseChars, ArrayLength);
628
  for i := 0 to ArrayLength - 1 do
629
  begin
630
    case i of
631
      0: begin OpenChars[i] := '('; CloseChars[i] := ')'; end;
632
      1: begin OpenChars[i] := '{'; CloseChars[i] := '}'; end;
633
      2: begin OpenChars[i] := '['; CloseChars[i] := ']'; end;
634
      3: begin OpenChars[i] := '<'; CloseChars[i] := '>'; end;
635
    end;
636
  end;
637
 
638
  P := Editor.CaretXY;
639
  D := Editor.DisplayXY;
640
 
641
  Start := Editor.SelStart;
642
 
643
  if (Start > 0) and (Start <= length(Editor.Text)) then
644
    TmpCharA := Editor.Text[Start]
645
  else
646
    TmpCharA := #0;
647
 
44 daniel-mar 648
  if (Start > 0){Added by VTS} and (Start < length(Editor.Text)) then
31 daniel-mar 649
    TmpCharB := Editor.Text[Start + 1]
650
  else
651
    TmpCharB := #0;
652
 
653
  if not IsCharBracket(TmpCharA) and not IsCharBracket(TmpCharB) then exit;
654
  S := TmpCharB;
655
  if not IsCharBracket(TmpCharB) then
656
  begin
657
    P.Char := P.Char - 1;
658
    S := TmpCharA;
659
  end;
660
  Editor.GetHighlighterAttriAtRowCol(P, S, Attri);
661
 
662
  if (Editor.Highlighter.SymbolAttribute = Attri) then
663
  begin
664
    for i := low(OpenChars) to High(OpenChars) do
665
    begin
666
      if (S = OpenChars[i]) or (S = CloseChars[i]) then
667
      begin
668
        Pix := CharToPixels(P);
669
 
670
        Editor.Canvas.Brush.Style := bsSolid;//Clear;
671
        Editor.Canvas.Font.Assign(Editor.Font);
672
        Editor.Canvas.Font.Style := Attri.Style;
673
 
674
        if (TransientType = ttAfter) then
675
        begin
676
          Editor.Canvas.Font.Color := COLOR_FG;
677
          Editor.Canvas.Brush.Color := COLOR_BG;
678
        end
679
        else
680
        begin
681
          Editor.Canvas.Font.Color := Attri.Foreground;
682
          Editor.Canvas.Brush.Color := Attri.Background;
683
        end;
684
        if Editor.Canvas.Font.Color = clNone then
685
          Editor.Canvas.Font.Color := Editor.Font.Color;
686
        if Editor.Canvas.Brush.Color = clNone then
687
          Editor.Canvas.Brush.Color := Editor.Color;
688
 
689
        Editor.Canvas.TextOut(Pix.X, Pix.Y, S);
690
        P := Editor.GetMatchingBracketEx(P);
691
 
692
        if (P.Char > 0) and (P.Line > 0) then
693
        begin
694
          Pix := CharToPixels(P);
695
          if Pix.X > Editor.Gutter.Width then
696
          begin
697
            {$REGION 'Added by ViaThinkSoft'}
698
            if (TransientType = ttAfter) then
699
            begin
700
              Editor.Canvas.Font.Color := COLOR_FG;
701
              Editor.Canvas.Brush.Color := COLOR_BG;
702
            end
703
            else
704
            begin
705
              Editor.Canvas.Font.Color := Attri.Foreground;
706
              Editor.Canvas.Brush.Color := Attri.Background;
707
            end;
708
            if Editor.Canvas.Font.Color = clNone then
709
              Editor.Canvas.Font.Color := Editor.Font.Color;
710
            if Editor.Canvas.Brush.Color = clNone then
711
              Editor.Canvas.Brush.Color := Editor.Color;
712
            {$ENDREGION}
713
            if S = OpenChars[i] then
714
              Editor.Canvas.TextOut(Pix.X, Pix.Y, CloseChars[i])
715
            else Editor.Canvas.TextOut(Pix.X, Pix.Y, OpenChars[i]);
716
          end;
717
        end;
718
      end;
719
    end;
720
    Editor.Canvas.Brush.Style := bsSolid;
721
  end;
722
end;
723
 
5 daniel-mar 724
procedure TForm1.SynEditFocusTimerTimer(Sender: TObject);
725
begin
726
  SynEditFocusTimer.Enabled := false;
727
  Button1.SetFocus; // Workaround for weird bug... This (and the timer) is necessary to get the focus to SynEdit1
728
  SynEdit1.SetFocus;
729
end;
2 daniel-mar 730
 
62 daniel-mar 731
procedure TForm1.Theme_Dark;
732
begin
733
  if IsThemeDark then exit;
734
  TStyleManager.TrySetStyle('Windows10 SlateGray');
735
  Color := 1316887;
736
  Font.Color := clCream;
737
  //Memo2.Font.Color := clCream;
738
  //Memo2.ParentColor := true;
739
  SynEdit1.ActiveLineColor := 2238502;
740
  SynEdit1.Color := 1316887;
741
  SynEdit1.Font.Color := clCream;
742
  SynEdit1.Gutter.Color := 1316887;
743
  SynEdit1.Gutter.Font.Color := clCream;
744
  SynEdit1.Gutter.GradientStartColor := 2238502;
745
  SynEdit1.Gutter.GradientEndColor := 1316887;
64 daniel-mar 746
  SynPHPSyn1.CommentAttri.Foreground := $00837B82;
62 daniel-mar 747
  SynPHPSyn1.IdentifierAttri.Foreground := 9627120;
748
  SynPHPSyn1.KeyAttri.Foreground := 4157595;
749
  SynPHPSyn1.NumberAttri.Foreground := 5008079;
750
  SynPHPSyn1.StringAttri.Foreground := 6987151;
751
  SynPHPSyn1.SymbolAttri.Foreground := 8769754;
752
  SynPHPSyn1.VariableAttri.Foreground := 6924493;
753
end;
754
 
755
procedure TForm1.Theme_Light;
756
begin
757
  if not IsThemeDark then exit;
758
  TStyleManager.TrySetStyle('Windows');
759
  Color := clBtnFace;
760
  Font.Color := clWindowText;
761
  //Memo2.Font.Color := clWindowText;
762
  SynEdit1.ActiveLineColor := 14680010;
763
  SynEdit1.Color := clWindow;
764
  SynEdit1.Font.Color := clWindowText;
765
  SynEdit1.Gutter.Color := clBtnFace;
766
  SynEdit1.Gutter.Font.Color := clWindowText;
767
  SynEdit1.Gutter.GradientStartcolor := cl3dLight;
768
  SynEdit1.Gutter.GradientEndColor := clBtnFace;;
769
  SynPHPSyn1.CommentAttri.Foreground := 33023;
770
  SynPHPSyn1.IdentifierAttri.Foreground := 4194304;
771
  SynPHPSyn1.KeyAttri.Foreground := 4227072;
772
  SynPHPSyn1.NumberAttri.Foreground := 213;
773
  SynPHPSyn1.StringAttri.Foreground := 13762560;
774
  SynPHPSyn1.SymbolAttri.Foreground := 4227072;
775
  SynPHPSyn1.VariableAttri.Foreground := 213;
776
end;
777
 
23 daniel-mar 778
procedure TForm1.Timer1Timer(Sender: TObject);
779
begin
780
  {$IFDEF OnlineHelp}
781
  Timer1.Enabled := false;
782
 
783
  // TODO: Insert a small online help hint
784
  //Caption := gOnlineHelpWord;
785
  {$ENDIF}
786
end;
787
 
27 daniel-mar 788
procedure TForm1.TreeView1DblClick(Sender: TObject);
789
var
790
  tn: TTreeNode;
32 daniel-mar 791
  lineNo: integer;
27 daniel-mar 792
begin
793
  tn := TTreeView(Sender).Selected;
794
  if tn = nil then exit;
32 daniel-mar 795
  lineNo := Integer(tn.Data);
796
  if lineNo > 0 then GotoLineNo(lineNo);
27 daniel-mar 797
end;
798
 
45 daniel-mar 799
(*
44 daniel-mar 800
{$IFDEF USE_SHDOCVW_TLB}
45 daniel-mar 801
*)
5 daniel-mar 802
procedure TForm1.WebBrowser1BeforeNavigate2(ASender: TObject;
27 daniel-mar 803
  const pDisp: IDispatch; const URL, Flags, TargetFrameName, PostData,
5 daniel-mar 804
  Headers: OleVariant; var Cancel: WordBool);
44 daniel-mar 805
begin
806
  BeforeNavigate(URL, Cancel);
807
end;
45 daniel-mar 808
(*
44 daniel-mar 809
{$ELSE}
810
procedure TForm1.WebBrowser1BeforeNavigate2(ASender: TObject;
811
  const pDisp: IDispatch; var URL, Flags, TargetFrameName, PostData,
812
  Headers: OleVariant; var Cancel: WordBool);
813
begin
814
  BeforeNavigate(URL, Cancel);
815
end;
816
{$ENDIF}
45 daniel-mar 817
*)
44 daniel-mar 818
 
67 daniel-mar 819
procedure TForm1.WebBrowser1WindowClosing(ASender: TObject;
820
  IsChildWindow: WordBool; var Cancel: WordBool);
821
resourcestring
822
  LNG_CLOSE_REQUEST = 'A script has requested the window to be closed. The window of a standalone script would now close.';
823
begin
824
  ShowMessage(LNG_CLOSE_REQUEST);
825
  TWebBrowser(ASender).Clear;
826
  Cancel := true;
827
end;
828
 
86 daniel-mar 829
procedure TForm1.WMDropFiles(var Msg: TWMDropFiles);
830
var
831
   DropH: HDROP;               // drop handle
832
   DroppedFileCount: Integer;  // number of files dropped
833
   FileNameLength: Integer;    // length of a dropped file name
834
   FileName: string;           // a dropped file name
835
   I: Integer;                 // loops thru all dropped files
836
   DropPoint: TPoint;          // point where files dropped
837
 begin
838
   inherited;
839
   // Store drop handle from the message
840
   DropH := Msg.Drop;
841
   try
842
     // Get count of files dropped
843
     DroppedFileCount := DragQueryFile(DropH, $FFFFFFFF, nil, 0);
844
     // Get name of each file dropped and process it
845
     for I := 0 to Pred(DroppedFileCount) do
846
     begin
847
       // get length of file name
848
       FileNameLength := DragQueryFile(DropH, I, nil, 0);
849
       // create string large enough to store file
850
       SetLength(FileName, FileNameLength);
851
       // get the file name
852
       DragQueryFile(DropH, I, PChar(FileName), FileNameLength + 1);
853
       // process file name (application specific)
854
       // ... processing code here
855
       ShellExecute(0, 'open', PChar(ParamStr(0)), PChar('"' + FileName + '"'), '', SW_NORMAL);
856
     end;
857
     // Optional: Get point at which files were dropped
858
     DragQueryPoint(DropH, DropPoint);
859
     // ... do something with drop point here
860
   finally
861
     // Tidy up - release the drop handle
862
     // don't use DropH again after this
863
     DragFinish(DropH);
864
   end;
865
   // Note we handled message
866
   Msg.Result := 0;
867
end;
868
 
44 daniel-mar 869
procedure TForm1.BeforeNavigate(const URL: OleVariant; var Cancel: WordBool);
5 daniel-mar 870
var
8 daniel-mar 871
  s, myURL: string;
5 daniel-mar 872
  lineno: integer;
7 daniel-mar 873
  p: integer;
5 daniel-mar 874
begin
7 daniel-mar 875
  {$REGION 'Line number references (PHP errors and warnings)'}
8 daniel-mar 876
  if Copy(URL, 1, length(FASTPHP_GOTO_URI_PREFIX)) = FASTPHP_GOTO_URI_PREFIX then
5 daniel-mar 877
  begin
878
    try
8 daniel-mar 879
      s := copy(URL, length(FASTPHP_GOTO_URI_PREFIX)+1, 99);
5 daniel-mar 880
      if not TryStrToInt(s, lineno) then exit;
881
      GotoLineNo(lineno);
882
      SynEditFocusTimer.Enabled := true;
883
    finally
884
      Cancel := true;
885
    end;
8 daniel-mar 886
    Exit;
5 daniel-mar 887
  end;
7 daniel-mar 888
  {$ENDREGION}
889
 
62 daniel-mar 890
  {$REGION 'Intelligent browser (executes PHP scripts which are clicked in a hyperlink)'}
7 daniel-mar 891
  if URL <> 'about:blank' then
892
  begin
893
    myUrl := URL;
894
 
8 daniel-mar 895
    p := Pos('?', myUrl);
896
    if p >= 1 then myURL := copy(myURL, 1, p-1);
7 daniel-mar 897
 
8 daniel-mar 898
    // TODO: myURL urldecode
899
    // TODO: maybe we could even open that file in the editor!
62 daniel-mar 900
    // TODO: ?parameter=....
7 daniel-mar 901
 
8 daniel-mar 902
    if FileExists(myURL) and (EndsText('.php', myURL) or EndsText('.php3', myURL) or EndsText('.php4', myURL) or EndsText('.php5', myURL) or EndsText('.phps', myURL)) then
7 daniel-mar 903
    begin
27 daniel-mar 904
      WebBrowser1.LoadHTML(RunPHPScript(myURL), myUrl);
7 daniel-mar 905
      Cancel := true;
906
    end;
907
  end;
908
  {$ENDREGION}
5 daniel-mar 909
end;
2 daniel-mar 910
 
62 daniel-mar 911
procedure TForm1.BtnLightClick(Sender: TObject);
66 daniel-mar 912
var
913
  CanClose: boolean;
62 daniel-mar 914
begin
66 daniel-mar 915
  FormCloseQuery(Form1, CanClose);
916
  if not CanClose then exit;
917
 
62 daniel-mar 918
  if IsThemeDark then
919
  begin
920
    BtnLight.Picture.Assign(BtnLightOn.Picture);
921
    Theme_Light;
922
    TFastPHPConfig.DarkTheme := false;
923
  end
924
  else
925
  begin
926
    BtnLight.Picture.Assign(BtnLightOff.Picture);
927
    Theme_Dark;
928
    TFastPHPConfig.DarkTheme := true;
929
  end;
930
end;
931
 
57 daniel-mar 932
procedure TForm1.BtnSpecialCharsClick(Sender: TObject);
933
var
934
  opts: TSynEditorOptions;
935
begin
936
  opts := SynEdit1.Options;
937
  if eoShowSpecialChars in SynEdit1.Options then
938
  begin
939
    BtnSpecialChars.Picture.Assign(BtnSpecialCharsOff.Picture);
940
    Exclude(opts, eoShowSpecialChars);
941
    TFastPHPConfig.SpecialChars := false;
942
  end
943
  else
944
  begin
945
    BtnSpecialChars.Picture.Assign(BtnSpecialCharsOn.Picture);
946
    Include(opts, eoShowSpecialChars);
947
    TFastPHPConfig.SpecialChars := true;
948
  end;
949
  SynEdit1.Options := opts;
950
end;
951
 
83 daniel-mar 952
procedure TForm1.FileModTimerTimer(Sender: TObject);
953
begin
954
  FileModTimer.Enabled := false;
955
  if FileModLast <> FileAge(GetScrapFile) then
956
  begin
957
    FileModLast := FileAge(GetScrapFile);
958
    if SynEdit1.Modified then
959
    begin
960
      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
961
      begin
962
        SynEdit1.Lines.LoadFromFile(GetScrapFile);
963
      end;
964
    end
965
    else
966
    begin
967
      if MessageDlg('The file was changed in a different application! Reload file?', mtConfirmation, mbYesNoCancel, 0) = mrYes then
968
      begin
969
        SynEdit1.Lines.LoadFromFile(GetScrapFile);
970
      end;
971
    end;
972
  end;
973
  FileModTimer.Enabled := true;
974
end;
975
 
2 daniel-mar 976
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
977
begin
86 daniel-mar 978
  DragAcceptFiles(Handle, False);
49 daniel-mar 979
  TFastPHPConfig.FontSize := SynEdit1.Font.Size;
2 daniel-mar 980
end;
981
 
15 daniel-mar 982
procedure TForm1.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
983
var
984
  r: integer;
985
begin
986
  if SynEdit1.Modified then
987
  begin
56 daniel-mar 988
    if (ParamStr(1) <> '') or (FSaveAsFilename <> '') then
15 daniel-mar 989
    begin
990
      r := MessageDlg('Do you want to save?', mtConfirmation, mbYesNoCancel, 0);
991
      if r = mrCancel then
992
      begin
993
        CanClose := false;
994
        Exit;
995
      end
996
      else if r = mrYes then
997
      begin
47 daniel-mar 998
        ActionSave.Execute;
15 daniel-mar 999
        CanClose := true;
1000
      end;
1001
    end
1002
    else
1003
    begin
47 daniel-mar 1004
      ActionSave.Execute;
15 daniel-mar 1005
      CanClose := true;
1006
    end;
1007
  end;
1008
end;
1009
 
2 daniel-mar 1010
procedure TForm1.FormCreate(Sender: TObject);
44 daniel-mar 1011
var
1012
  exeDir: string;
83 daniel-mar 1013
  sScrapFile: string;
2 daniel-mar 1014
begin
1015
  HlpPrevPageIndex := -1;
1016
  CurSearchTerm := '';
83 daniel-mar 1017
  sScrapFile := GetScrapFile;
1018
  Caption := Caption + ' - ' + sScrapFile;
1019
  Application.Title := Format('%s - FastPHP', [ExtractFileName(sScrapFile)]);
24 daniel-mar 1020
  SrcRep := TSynEditFindReplace.Create(self);
13 daniel-mar 1021
  SrcRep.Editor := SynEdit1;
29 daniel-mar 1022
  SynEdit1.Gutter.Gradient := HighColorWindows;
30 daniel-mar 1023
 
1024
  Screen.Cursors[crMouseGutter] := LoadCursor(hInstance, 'MOUSEGUTTER');
1025
  SynEdit1.Gutter.Cursor := crMouseGutter;
36 daniel-mar 1026
 
44 daniel-mar 1027
  exeDir := IncludeTrailingPathDelimiter(ExtractFilePath(ParamStr(0)));
1028
  if FileExists(exeDir + 'codeexplorer.bmp') then ImageList1.LoadAndSplitImages(exeDir + 'codeexplorer.bmp');
83 daniel-mar 1029
 
1030
  FileModLast := FileAge(sScrapFile);
1031
  FileModTimer.Enabled := True;
2 daniel-mar 1032
end;
1033
 
1034
procedure TForm1.FormDestroy(Sender: TObject);
1035
begin
1036
  if Assigned(ChmIndex) then
1037
  begin
1038
    FreeAndNil(ChmIndex);
1039
  end;
13 daniel-mar 1040
  FreeAndNil(SrcRep);
27 daniel-mar 1041
 
75 daniel-mar 1042
  if hMutex <> 0 then CloseHandle(hMutex); // Note: ReleaseMutex does not work as expected!
67 daniel-mar 1043
 
27 daniel-mar 1044
  if Assigned(codeExplorer) then
1045
  begin
1046
    codeExplorer.Terminate;
1047
    codeExplorer.WaitFor;
1048
    FreeAndNil(codeExplorer);
1049
  end;
2 daniel-mar 1050
end;
1051
 
71 daniel-mar 1052
var
1053
  FormShowRanOnce: boolean;
2 daniel-mar 1054
procedure TForm1.FormShow(Sender: TObject);
1055
var
1056
  ScrapFile: string;
49 daniel-mar 1057
  tmpFontSize: integer;
57 daniel-mar 1058
  opts: TSynEditorOptions;
2 daniel-mar 1059
begin
71 daniel-mar 1060
  if FormShowRanOnce then exit; // If the theme is changed from normal to dark, OnShow will be called another time
1061
  FormShowRanOnce := true;
1062
 
2 daniel-mar 1063
  ScrapFile := GetScrapFile;
1064
  if ScrapFile = '' then
1065
  begin
10 daniel-mar 1066
    Application.Terminate; // Close;
2 daniel-mar 1067
    exit;
1068
  end;
57 daniel-mar 1069
 
1070
  opts := SynEdit1.Options;
1071
  if TFastPHPConfig.SpecialChars then
1072
  begin
1073
    BtnSpecialChars.Picture.Assign(BtnSpecialCharsOn.Picture);
1074
    Include(opts, eoShowSpecialChars);
1075
  end
1076
  else
1077
  begin
1078
    BtnSpecialChars.Picture.Assign(BtnSpecialCharsOff.Picture);
1079
    Exclude(opts, eoShowSpecialChars);
1080
  end;
1081
  SynEdit1.Options := opts;
1082
 
15 daniel-mar 1083
  if FileExists(ScrapFile) then
67 daniel-mar 1084
  begin
71 daniel-mar 1085
    if hMutex = 0 then
67 daniel-mar 1086
    begin
75 daniel-mar 1087
      hMutex := CreateMutex(nil, True, PChar('FastPHP'+md5(UpperCase(ScrapFile))));
69 daniel-mar 1088
      if GetLastError = ERROR_ALREADY_EXISTS then
1089
      begin
1090
        // TODO: It would be great if the window of that FastPHP instance would switched to foreground
1091
        ShowMessageFmt('File "%s" is alrady open!', [ScrapFile]);
1092
        Close;
1093
      end;
1094
 
1095
      SynEdit1.Lines.LoadFromFile(ScrapFile);
67 daniel-mar 1096
    end;
1097
  end
15 daniel-mar 1098
  else
1099
    SynEdit1.Lines.Clear;
2 daniel-mar 1100
 
1101
  PageControl1.ActivePage := PlaintextTabSheet;
1102
 
20 daniel-mar 1103
  PageControl2.ActivePage := CodeTabsheet;
2 daniel-mar 1104
  HelpTabsheet.TabVisible := false;
5 daniel-mar 1105
 
49 daniel-mar 1106
  tmpFontSize := TFastPHPConfig.FontSize;
1107
  if tmpFontSize <> -1 then SynEdit1.Font.Size := tmpFontSize;
5 daniel-mar 1108
  SynEdit1.SetFocus;
27 daniel-mar 1109
 
1110
  DoubleBuffered := true;
1111
  StartCodeExplorer;
62 daniel-mar 1112
 
86 daniel-mar 1113
  DragAcceptFiles(Handle, True);
1114
 
62 daniel-mar 1115
  StartupTimer.Enabled := true;
2 daniel-mar 1116
end;
1117
 
56 daniel-mar 1118
procedure TForm1.Save1Click(Sender: TObject);
1119
begin
1120
  Button7.Click;
1121
end;
1122
 
1123
procedure TForm1.Saveas1Click(Sender: TObject);
75 daniel-mar 1124
var
1125
  hMutexNew: THandle;
56 daniel-mar 1126
begin
1127
  if SaveDialog1.Execute then
1128
  begin
75 daniel-mar 1129
    {$REGION 'Switch mutex'}
1130
    hMutexNew := CreateMutex(nil, True, PChar('FastPHP'+md5(UpperCase(SaveDialog1.FileName))));
1131
    if GetLastError = ERROR_ALREADY_EXISTS then
1132
    begin
1133
      ShowMessageFmt('Cannot save because file "%s", because it is alrady open in another FastPHP window!', [SaveDialog1.FileName]);
1134
      Close;
1135
    end;
1136
 
1137
    if hMutex <> 0 then CloseHandle(hMutex); // Note: ReleaseMutex does not work as expected!
1138
    hMutex := hMutexNew;
1139
    {$ENDREGION}
1140
 
56 daniel-mar 1141
    FSaveAsFilename := SaveDialog1.FileName;
1142
    Caption := Copy(Caption, 1, Pos(' - ', Caption)-1) + ' - ' + FSaveAsFilename;
83 daniel-mar 1143
    Application.Title := Format('%s - FastPHP', [ExtractFileName(FSaveAsFilename)]);
56 daniel-mar 1144
    Button7.Click;
1145
  end;
1146
end;
1147
 
76 daniel-mar 1148
procedure TForm1.SaveToFile(filename: string);
1149
var
79 daniel-mar 1150
  ss: TStringStream;
78 daniel-mar 1151
  ms: TMemoryStream;
1152
  fs: TFileStream;
79 daniel-mar 1153
  eolStyle: string;
1154
  str: string;
76 daniel-mar 1155
begin
83 daniel-mar 1156
  FileModTimer.Enabled := false;
1157
 
78 daniel-mar 1158
  ms := TMemoryStream.Create;
79 daniel-mar 1159
  ss := TStringStream.Create('');
78 daniel-mar 1160
  fs := TFileStream.Create(filename, fmCreate);
76 daniel-mar 1161
  try
79 daniel-mar 1162
    // Save everything in a memory stream and then to a string
1163
    // in comparison to "str := SynEdit1.Lines.Text;",
1164
    // This approach should preserve LF / CRLF line endings
78 daniel-mar 1165
    SynEdit1.Lines.SaveToStream(ms);
79 daniel-mar 1166
    ms.Position := 0;
1167
    ss.CopyFrom(ms, ms.Size);
1168
    ss.Position := 0;
1169
    str := ss.ReadString(ss.Size);
1170
    ss.Size := 0; // clear string-stream, because we need it later again
77 daniel-mar 1171
 
79 daniel-mar 1172
    // Detect current line-endings
1173
    if Copy(str, 1, 2) = '#!' then
77 daniel-mar 1174
    begin
79 daniel-mar 1175
      // Shebang. Use ONLY Linux LF
1176
      str := StringReplace(str, #13#10, #10, [rfReplaceAll]);
1177
      eolStyle := #10 // Linux LF
1178
    end
1179
    else
1180
    begin
1181
      if Pos(#13#10, str) > 0 then
1182
        eolStyle := #13#10 // Windows CRLF
1183
      else if Pos(#10, str) > 0 then
1184
        eolStyle := #10 // Linux LF
78 daniel-mar 1185
      else
1186
      begin
79 daniel-mar 1187
        if DefaultTextLineBreakStyle = tlbsLF then
1188
          eolStyle := #10 // Linux LF
1189
        else if DefaultTextLineBreakStyle = tlbsCRLF then
1190
          eolStyle := #13#10 // Windows CRLF
1191
        //else if DefaultTextLineBreakStyle = tlbsCR then
1192
        //  eolStyle := #13 // Old Mac CR
1193
        else
1194
          eolStyle := #13#10; // (Should not happen)
78 daniel-mar 1195
      end;
77 daniel-mar 1196
    end;
1197
 
79 daniel-mar 1198
    // Unitfy line-endings
1199
    str := StringReplace(str, #13#10, eolStyle, [rfReplaceAll]);
1200
    str := StringReplace(str, #10, eolStyle, [rfReplaceAll]);
1201
    str := StringReplace(str, #13, '', [rfReplaceAll]);
1202
 
1203
    // Replace all trailing linebreaks by a single line break
1204
    // Note: Removing all line breaks is not good, since Linux's "nano" will
1205
    //       re-add a linebreak at the end of the file
1206
    str := TrimRight(str) + eolStyle;
1207
 
78 daniel-mar 1208
    // Old versions of Delphi/SynEdit write an UTF-8 BOM, which makes problems
1209
    // e.g. with AJAX handlers (because AJAX reponses must not have a BOM).
1210
    // So we try to avoid that.
1211
    // Note that the output is still UTF-8 encoded if the input file was UTF-8 encoded
79 daniel-mar 1212
    if Copy(str,1,3) = #$EF#$BB#$BF then Delete(str, 1, 3);
77 daniel-mar 1213
 
78 daniel-mar 1214
    // Now save to the file
79 daniel-mar 1215
    ss.WriteString(str);
1216
    ss.Position := 0;
1217
    fs.CopyFrom(ss, ss.Size-ss.Position);
76 daniel-mar 1218
  finally
78 daniel-mar 1219
    FreeAndNil(ms);
79 daniel-mar 1220
    FreeAndNil(ss);
78 daniel-mar 1221
    FreeAndNil(fs);
76 daniel-mar 1222
  end;
83 daniel-mar 1223
 
1224
  FileModLast := FileAge(GetScrapFile);
1225
  FileModTimer.Enabled := True;
76 daniel-mar 1226
end;
1227
 
27 daniel-mar 1228
procedure TForm1.StartCodeExplorer;
1229
begin
1230
  codeExplorer := TRunCodeExplorer.Create(true);
1231
  codeExplorer.InputRequestCallback := InputRequestCallback;
1232
  codeExplorer.OutputNotifyCallback := OutputNotifyCallback;
1233
  codeExplorer.PhpExe := GetPHPExe;
1234
  codeExplorer.PhpFile := IncludeTrailingPathDelimiter(ExtractFileDir(Application.ExeName)) + 'codeexplorer.php'; // GetScrapFile;
1235
  codeExplorer.WorkDir := ExtractFileDir(Application.ExeName);
44 daniel-mar 1236
  codeExplorer.Resume;
27 daniel-mar 1237
end;
1238
 
62 daniel-mar 1239
procedure TForm1.StartUpTimerTimer(Sender: TObject);
1240
begin
1241
  StartupTimer.Enabled := false;
1242
 
1243
  // We need this timer because we cannot change the Theme during OnShow,
1244
  // because the Delphi VCL Theme is buggy!
1245
 
1246
  if TFastPHPConfig.DarkTheme then
1247
  begin
1248
    BtnLight.Picture.Assign(BtnLightOff.Picture);
1249
    Theme_Dark;
1250
  end
1251
  else
1252
  begin
1253
    BtnLight.Picture.Assign(BtnLightOn.Picture);
1254
    Theme_Light;
1255
  end;
1256
end;
1257
 
2 daniel-mar 1258
function TForm1.GetScrapFile: string;
49 daniel-mar 1259
var
1260
  tmpPath: string;
2 daniel-mar 1261
begin
56 daniel-mar 1262
  if FSaveAsFilename <> '' then
1263
  begin
1264
    result := FSaveAsFilename;
1265
    exit;
1266
  end;
1267
 
44 daniel-mar 1268
  if FScrapFile <> '' then
1269
  begin
1270
    result := FScrapFile;
1271
    exit;
1272
  end;
19 daniel-mar 1273
 
15 daniel-mar 1274
  if ParamStr(1) <> '' then
49 daniel-mar 1275
  begin
1276
    // Program was started with a filename
1277
 
1278
    result := ParamStr(1);
1279
 
1280
    if not FileExists(result) then
1281
    begin
1282
      case MessageDlg(Format('File %s does not exist. Create it?', [result]), mtConfirmation, mbYesNoCancel, 0) of
1283
        mrYes:
1284
          try
76 daniel-mar 1285
            SaveToFile(result);
49 daniel-mar 1286
          except
1287
            on E: Exception do
1288
            begin
1289
              MessageDlg(E.Message, mtError, [mbOk], 0);
1290
              Application.Terminate;
1291
              result := '';
1292
              exit;
1293
            end;
1294
          end;
1295
        mrNo:
1296
          begin
1297
            Application.Terminate;
1298
            result := '';
1299
            exit;
1300
          end;
1301
        mrCancel:
1302
          begin
1303
            Application.Terminate;
1304
            result := '';
1305
            exit;
1306
          end;
1307
      end;
1308
    end;
1309
  end
13 daniel-mar 1310
  else
2 daniel-mar 1311
  begin
49 daniel-mar 1312
    // Program is started without filename -> use scrap file
2 daniel-mar 1313
 
49 daniel-mar 1314
    result := TFastPHPConfig.ScrapFile;
1315
 
1316
    if not FileExists(result) then
1317
    begin
1318
      repeat
1319
        {$REGION 'Determinate opendialog initial directory'}
1320
        if result <> '' then
1321
        begin
1322
          tmpPath := ExtractFilePath(result);
1323
          if DirectoryExists(tmpPath) then
1324
          begin
1325
            OpenDialog3.InitialDir := tmpPath;
1326
            OpenDialog3.FileName := Result;
1327
          end
1328
          else
1329
          begin
1330
            OpenDialog3.InitialDir := GetMyDocumentsFolder;
1331
          end;
1332
        end
1333
        else
1334
        begin
1335
          OpenDialog3.InitialDir := GetMyDocumentsFolder;
1336
        end;
1337
        {$ENDREGION}
1338
 
1339
        if not OpenDialog3.Execute then
1340
        begin
1341
          Application.Terminate;
1342
          result := '';
1343
          exit;
1344
        end;
1345
 
1346
        if not DirectoryExists(ExtractFilePath(OpenDialog3.FileName)) then
1347
        begin
1348
          MessageDlg('Path does not exist! Please try again.', mtWarning, [mbOk], 0);
1349
        end
1350
        else
1351
        begin
1352
          result := OpenDialog3.FileName;
1353
        end;
1354
      until result <> '';
1355
 
1356
      if not FileExists(result) then
19 daniel-mar 1357
      begin
49 daniel-mar 1358
        try
1359
          // Try saving the file; check if we have permissions
1360
          //SynEdit1.Lines.Clear;
76 daniel-mar 1361
          SaveToFile(result);
49 daniel-mar 1362
        except
1363
          on E: Exception do
1364
          begin
1365
            MessageDlg(E.Message, mtError, [mbOk], 0);
1366
            Application.Terminate;
1367
            result := '';
1368
            exit;
1369
          end;
1370
        end;
19 daniel-mar 1371
      end;
2 daniel-mar 1372
 
49 daniel-mar 1373
      TFastPHPConfig.ScrapFile := result;
1374
      FScrapFile := result;
1375
    end;
2 daniel-mar 1376
  end;
1377
end;
1378
 
1379
procedure TForm1.Help;
1380
var
19 daniel-mar 1381
  IndexFile, chmFile, w, OriginalWord, url: string;
2 daniel-mar 1382
  internalHtmlFile: string;
1383
begin
1384
  if not Assigned(ChmIndex) then
1385
  begin
49 daniel-mar 1386
    IndexFile := TFastPHPConfig.HelpIndex;
2 daniel-mar 1387
    IndexFile := ChangeFileExt(IndexFile, '.ini'); // Just to be sure. Maybe someone wrote manually the ".chm" file in there
1388
    if FileExists(IndexFile) then
1389
    begin
1390
      ChmIndex := TMemIniFile.Create(IndexFile);
1391
    end;
1392
  end;
1393
 
1394
  if Assigned(ChmIndex) then
1395
  begin
49 daniel-mar 1396
    IndexFile := TFastPHPConfig.HelpIndex;
2 daniel-mar 1397
    // We don't check if IndexFile still exists. It is not important since we have ChmIndex pre-loaded in memory
1398
 
1399
    chmFile := ChangeFileExt(IndexFile, '.chm');
1400
    if not FileExists(chmFile) then
1401
    begin
1402
      FreeAndNil(ChmIndex);
1403
    end;
1404
  end;
1405
 
1406
  if not Assigned(ChmIndex) then
1407
  begin
1408
    if not OpenDialog1.Execute then exit;
1409
 
1410
    chmFile := OpenDialog1.FileName;
1411
    if not FileExists(chmFile) then exit;
1412
 
1413
    IndexFile := ChangeFileExt(chmFile, '.ini');
1414
 
1415
    if not FileExists(IndexFile) then
1416
    begin
1417
      Panel1.Align := alClient;
1418
      Panel1.Visible := true;
1419
      Panel1.BringToFront;
1420
      Screen.Cursor := crHourGlass;
1421
      Application.ProcessMessages;
1422
      try
1423
        if not ParseCHM(chmFile) then
1424
        begin
49 daniel-mar 1425
          MessageDlg('The CHM file is not a valid PHP documentation. Cannot use help.', mtError, [mbOk], 0);
2 daniel-mar 1426
          exit;
1427
        end;
1428
      finally
1429
        Screen.Cursor := crDefault;
1430
        Panel1.Visible := false;
1431
      end;
1432
 
1433
      if not FileExists(IndexFile) then
1434
      begin
49 daniel-mar 1435
        MessageDlg('Unknown error. Cannot use help.', mtError, [mbOk], 0);
2 daniel-mar 1436
        exit;
1437
      end;
1438
    end;
1439
 
49 daniel-mar 1440
    TFastPHPConfig.HelpIndex := IndexFile;
2 daniel-mar 1441
 
1442
    ChmIndex := TMemIniFile.Create(IndexFile);
1443
  end;
1444
 
4 daniel-mar 1445
  w := GetWordUnderCaret(SynEdit1);
2 daniel-mar 1446
  if w = '' then exit;
44 daniel-mar 1447
  {$IFDEF UNICODE}
8 daniel-mar 1448
  if CharInSet(w[1], ['0'..'9']) then exit;
44 daniel-mar 1449
  {$ELSE}
1450
  if w[1] in ['0'..'9'] then exit;
1451
  {$ENDIF}
19 daniel-mar 1452
 
1453
  Originalword := w;
1454
//  w := StringReplace(w, '_', '-', [rfReplaceAll]);
2 daniel-mar 1455
  w := LowerCase(w);
1456
  CurSearchTerm := w;
1457
 
72 daniel-mar 1458
  internalHtmlFile := ChmIndex.ReadString('function', CurSearchTerm, '');
2 daniel-mar 1459
  if internalHtmlFile = '' then
72 daniel-mar 1460
    internalHtmlFile := ChmIndex.ReadString('_HelpWords_', CurSearchTerm, '');
1461
  if internalHtmlFile = '' then
2 daniel-mar 1462
  begin
1463
    HelpTabsheet.TabVisible := false;
1464
    HlpPrevPageIndex := -1;
19 daniel-mar 1465
    ShowMessageFmt('No help for "%s" available', [Originalword]);
2 daniel-mar 1466
    Exit;
1467
  end;
1468
 
1469
  url := 'mk:@MSITStore:'+ChmFile+'::'+internalHtmlFile;
1470
 
1471
  HlpPrevPageIndex := PageControl2.ActivePageIndex; // Return by pressing ESC
1472
  HelpTabsheet.TabVisible := true;
1473
  PageControl2.ActivePage := HelpTabsheet;
8 daniel-mar 1474
  WebBrowser2.Navigate(url);
1475
  WebBrowser2.Wait;
2 daniel-mar 1476
end;
1477
 
5 daniel-mar 1478
procedure TForm1.GotoLineNo(LineNo:integer);
1479
var
1480
  line: string;
1481
  i: integer;
2 daniel-mar 1482
begin
5 daniel-mar 1483
  SynEdit1.GotoLineAndCenter(LineNo);
1484
 
1485
  // Skip indent
1486
  line := SynEdit1.Lines[SynEdit1.CaretY];
1487
  for i := 1 to Length(line) do
1488
  begin
44 daniel-mar 1489
    {$IFDEF UNICODE}
8 daniel-mar 1490
    if not CharInSet(line[i], [' ', #9]) then
44 daniel-mar 1491
    {$ELSE}
1492
    if not (line[i] in [' ', #9]) then
1493
    {$ENDIF}
5 daniel-mar 1494
    begin
1495
      SynEdit1.CaretX := i-1;
1496
      break;
1497
    end;
1498
  end;
1499
 
20 daniel-mar 1500
  PageControl2.ActivePage := CodeTabsheet;
5 daniel-mar 1501
  if SynEdit1.CanFocus then SynEdit1.SetFocus;
2 daniel-mar 1502
end;
1503
 
87 daniel-mar 1504
procedure TForm1.GotoPHPdir1Click(Sender: TObject);
1505
var
1506
  phpExe: string;
1507
begin
1508
  phpExe := GetPHPExe;
1509
  if phpExe <> '' then
1510
    ShellExecute(Handle, 'open', 'explorer.exe', PChar(ExtractFilePath(phpExe)), '', SW_NORMAL);
1511
end;
1512
 
8 daniel-mar 1513
procedure TForm1.PageControl2Changing(Sender: TObject;
1514
  var AllowChange: Boolean);
1515
begin
1516
  if PageControl2.ActivePage = HelpTabsheet then
1517
    HlpPrevPageIndex := -1
1518
  else
1519
    HlpPrevPageIndex := PageControl2.ActivePageIndex;
1520
 
1521
  AllowChange := true;
1522
end;
1523
 
87 daniel-mar 1524
procedure TForm1.PHPShell1Click(Sender: TObject);
1525
var
1526
  phpExe: string;
1527
begin
1528
  phpExe := GetPHPExe;
1529
  if phpExe <> '' then
1530
    ShellExecute(Handle, 'open', PChar(phpExe), '-a', PChar(ExtractFilePath(phpExe)), SW_NORMAL);
1531
end;
1532
 
5 daniel-mar 1533
procedure TForm1.Memo2DblClick(Sender: TObject);
1534
var
22 daniel-mar 1535
  line: string;
1536
 
1537
  procedure _process(toFind: string);
1538
  var
1539
    p, lineno: integer;
1540
  begin
1541
    if FileSystemCaseSensitive then
1542
      p := Pos(toFind, line)
1543
    else
44 daniel-mar 1544
      p := Pos(LowerCase(toFind), LowerCase(line));
22 daniel-mar 1545
    if p <> 0 then
1546
    begin
1547
      line := copy(line, p+length(toFind), 99);
1548
      if not TryStrToInt(line, lineno) then exit;
1549
      GotoLineNo(lineno);
1550
    end;
1551
  end;
1552
 
5 daniel-mar 1553
begin
1554
  line := memo2.Lines.Strings[Memo2.CaretPos.Y];
16 daniel-mar 1555
 
18 daniel-mar 1556
  {$REGION 'Possibility 1: filename.php:lineno'}
22 daniel-mar 1557
  _process(ExtractFileName(GetScrapFile) + ':');
18 daniel-mar 1558
  {$ENDREGION}
16 daniel-mar 1559
 
18 daniel-mar 1560
  {$REGION 'Possibility 2: on line xx'}
22 daniel-mar 1561
  _process(ExtractFileName(GetScrapFile) + ' on line ');
18 daniel-mar 1562
  {$ENDREGION}
5 daniel-mar 1563
end;
1564
 
17 daniel-mar 1565
procedure TForm1.Memo2KeyDown(Sender: TObject; var Key: Word;
1566
  Shift: TShiftState);
1567
begin
1568
  if ((ssCtrl in Shift) and (Key = 65)) then TMemo(Sender).SelectAll;
1569
end;
1570
 
5 daniel-mar 1571
function TForm1.MarkUpLineReference(cont: string): string;
18 daniel-mar 1572
 
1573
  procedure _process(toFind: string);
22 daniel-mar 1574
  var
1575
    p, a, b: integer;
1576
    num: integer;
1577
    insert_a, insert_b: string;
5 daniel-mar 1578
  begin
22 daniel-mar 1579
    if FileSystemCaseSensitive then
1580
      p := Pos(toFind, cont)
1581
    else
44 daniel-mar 1582
      p := Pos(LowerCase(toFind), LowerCase(cont));
18 daniel-mar 1583
    while p >= 1 do
5 daniel-mar 1584
    begin
22 daniel-mar 1585
      a := p;
1586
      b := p + length(toFind);
18 daniel-mar 1587
      num := 0;
44 daniel-mar 1588
      {$IFDEF UNICODE}
18 daniel-mar 1589
      while CharInSet(cont[b], ['0'..'9']) do
44 daniel-mar 1590
      {$ELSE}
1591
      while cont[b] in ['0'..'9'] do
1592
      {$ENDIF}
18 daniel-mar 1593
      begin
1594
        num := num*10 + StrToInt(cont[b]);
1595
        inc(b);
1596
      end;
5 daniel-mar 1597
 
18 daniel-mar 1598
      insert_b := '</a>';
22 daniel-mar 1599
      insert_a := '<a href="' + FASTPHP_GOTO_URI_PREFIX + IntToStr(num) + '">';
5 daniel-mar 1600
 
18 daniel-mar 1601
      insert(insert_b, cont, b);
1602
      insert(insert_a, cont, a);
5 daniel-mar 1603
 
18 daniel-mar 1604
      p := b + Length(insert_a) + Length(insert_b);
5 daniel-mar 1605
 
18 daniel-mar 1606
      p := PosEx(toFind, cont, p+1);
1607
    end;
5 daniel-mar 1608
  end;
22 daniel-mar 1609
 
18 daniel-mar 1610
begin
1611
  {$REGION 'Possibility 1: filename.php:lineno'}
22 daniel-mar 1612
  _process(ExtractFileName(GetScrapFile) + ':');
18 daniel-mar 1613
  {$ENDREGION}
5 daniel-mar 1614
 
18 daniel-mar 1615
  {$REGION 'Possibility 2: on line xx'}
22 daniel-mar 1616
  _process(ExtractFileName(GetScrapFile) + ' on line ');
18 daniel-mar 1617
  {$ENDREGION}
1618
 
5 daniel-mar 1619
  result := cont;
1620
end;
1621
 
40 daniel-mar 1622
function TForm1.InputRequestCallback(var data: AnsiString): boolean;
27 daniel-mar 1623
begin
40 daniel-mar 1624
  data := UTF8Encode(SynEdit1.Text);
1625
  result := true;
27 daniel-mar 1626
end;
1627
 
62 daniel-mar 1628
function TForm1.IsThemeDark: boolean;
1629
begin
1630
  result := Assigned(TStyleManager.ActiveStyle) and (TStyleManager.ActiveStyle.Name<>'Windows');
1631
end;
1632
 
40 daniel-mar 1633
function TForm1.OutputNotifyCallback(const data: AnsiString): boolean;
27 daniel-mar 1634
begin
40 daniel-mar 1635
  result := TreeView1.FillWithFastPHPData(data);
27 daniel-mar 1636
end;
1637
 
2 daniel-mar 1638
end.