{ Debug server main form Copyright (C) 2009 Michael Van Canneyt (michael@freepascal.org) This source is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This code is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. A copy of the GNU General Public License is available on the World Wide Web at . You can also obtain it by writing to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1335, USA. } unit frmmain; {$mode objfpc}{$H+} interface uses Classes, SysUtils, IniFiles, simpleipc, dbugmsg, Forms, Controls, Dialogs, Menus, ActnList, ComCtrls, ExtCtrls, Clipbrd; type { TMainForm } TMainForm = class(TForm) AClear: TAction; ACopyLines: TAction; AShow: TAction; AResume: TAction; ASelectAll: TAction; ASave: TAction; AHide: TAction; AOptions: TAction; APause: TAction; AQuit: TAction; ALMain: TActionList; ITMessages: TIdleTimer; ILMain: TImageList; ILMessages: TImageList; LVMessages: TListView; MEdit: TMenuItem; MenuItem1: TMenuItem; MISelectAll: TMenuItem; PMIQuit: TMenuItem; PMIShow: TMenuItem; PMIClear: TMenuItem; MenuItem5: TMenuItem; PMIPause: TMenuItem; MIToolbar: TMenuItem; MIAlwaysOntop: TMenuItem; MView: TMenuItem; MISave: TMenuItem; MICopy: TMenuItem; MIClear: TMenuItem; MIHide: TMenuItem; MIQuit: TMenuItem; MIOptions: TMenuItem; MIPause: TMenuItem; MFile: TMenuItem; MMDebugServer: TMainMenu; PMTray: TPopupMenu; SDMessages: TSaveDialog; TBMain: TToolBar; TBPause: TToolButton; TBCopyMessages: TToolButton; TBQuit: TToolButton; TBSave: TToolButton; TBHideMessagesWindow: TToolButton; TBClearMessages: TToolButton; ToolButton3: TToolButton; TIDebug: TTrayIcon; TBSaveSelected: TToolButton; procedure AClearExecute(Sender: TObject); procedure ACopyLinesExecute(Sender: TObject); procedure ACopyLinesUpdate(Sender: TObject); procedure AHideExecute(Sender: TObject); procedure AOptionsExecute(Sender: TObject); procedure APauseExecute(Sender: TObject); procedure AQuitExecute(Sender: TObject); procedure AResumeExecute(Sender: TObject); procedure ASaveExecute(Sender: TObject); procedure ASelectAllExecute(Sender: TObject); procedure AShowExecute(Sender: TObject); procedure FormClose(Sender: TObject; var CloseAction: TCloseAction); procedure FormCreate(Sender: TObject); procedure FormDestroy(Sender: TObject); procedure ITMessagesTimer(Sender: TObject); procedure LVMessagesDblClick(Sender: TObject); procedure MIAlwaysOntopClick(Sender: TObject); procedure MIToolbarClick(Sender: TObject); procedure MViewClick(Sender: TObject); private FPaused : Boolean; FSrv : TSimpleIPCServer; FShowOnStartUp, FShowOnmessage, FKeepVisible : Boolean; FCleanLog : Boolean; FAtBottom : Boolean; FQuitting : Boolean; FDiscarded : Int64; procedure CheckDebugMessages; procedure CheckMessages(Sender: TObject; Var Done : Boolean); procedure ClearMessages; procedure CopySelectedToClipBoard; procedure GetMessagesAsText(L: TStrings; SelectedOnly: Boolean); function GetShowToolbar: Boolean; function GetStayOnTop: Boolean; procedure LoadSettings; procedure ReadDebugMessage; procedure ResumeMessages; procedure SaveMessagesToFile(SelectedOnly: Boolean); procedure SaveSettings; procedure SelectAllMessages; procedure SetPauseAction(AAction: TAction); procedure SetShowToolBar(const AValue: Boolean); procedure SetStayOnTop(const AValue: Boolean); procedure ShowCurrentMessage; procedure ShowDebugmessage(const Msg: TDebugmessage); procedure ShowMessageWindow; procedure ShowOptions; procedure StartServer; procedure StopServer; public Property StayOnTop : Boolean Read GetStayOnTop Write SetStayOnTop; Property ShowToolbar : Boolean Read GetShowToolbar Write SetShowToolBar; end; var MainForm: TMainForm; implementation {$R *.lfm} uses frmoptions; { TMainForm } { --------------------------------------------------------------------- Event handlers ---------------------------------------------------------------------} procedure TMainForm.AShowExecute(Sender: TObject); begin ShowMessageWindow; end; procedure TMainForm.FormClose(Sender: TObject; var CloseAction: TCloseAction); begin If FQuitting Then CloseAction:=caFree else CloseAction:=caHide end; procedure TMainForm.FormCreate(Sender: TObject); begin FormatSettings.LongTimeFormat := 'hh:nn:ss.zzz'; LoadSettings; If Not FShowOnStartup Then Hide; StartServer; end; procedure TMainForm.AQuitExecute(Sender: TObject); begin FQuitting:=True; Close; end; procedure TMainForm.AResumeExecute(Sender: TObject); begin ResumeMessages; SetPauseAction(APause); end; procedure TMainForm.ASaveExecute(Sender: TObject); begin SaveMessagesToFile(False); end; procedure TMainForm.ASelectAllExecute(Sender: TObject); begin SelectAllMessages; end; procedure TMainForm.FormDestroy(Sender: TObject); begin StopServer; end; procedure TMainForm.ITMessagesTimer(Sender: TObject); begin CheckDebugMessages; end; procedure TMainForm.LVMessagesDblClick(Sender: TObject); begin ShowCurrentMessage; end; procedure TMainForm.MIAlwaysOntopClick(Sender: TObject); begin StayOnTop:=(Sender as TMenuItem).Checked; end; procedure TMainForm.MIToolbarClick(Sender: TObject); begin ShowToolBar:=(Sender as TMenuItem).Checked; end; procedure TMainForm.MViewClick(Sender: TObject); begin MIAlwaysOnTop.Checked:=STayOnTop; MIToolbar.Checked:=ShowToolbar; end; procedure TMainForm.CheckMessages(Sender: TObject; Var Done : Boolean); begin CheckDebugMessages; end; procedure TMainForm.AClearExecute(Sender: TObject); begin ClearMessages; end; procedure TMainForm.ACopyLinesExecute(Sender: TObject); begin CopySelectedToClipBoard; end; procedure TMainForm.ACopyLinesUpdate(Sender: TObject); begin (Sender as TAction).Enabled:=(LVMessages.SelCount>0); end; procedure TMainForm.AHideExecute(Sender: TObject); begin Hide; end; procedure TMainForm.AOptionsExecute(Sender: TObject); begin ShowOptions; end; procedure TMainForm.APauseExecute(Sender: TObject); begin FPaused:=True; SetPauseAction(AResume); end; { --------------------------------------------------------------------- Methods that do the actual work ---------------------------------------------------------------------} procedure TMainForm.StartServer; begin FSrv:=TSimpleIPCServer.Create(self); FSrv.ServerID:=DebugServerID; FSrv.Global:=True; //cause This operation is illegal when the server is active: FSrv.Active:=True; FSrv.StartServer; Application.OnIdle:=@CheckMessages; ITMessages.Enabled:=True; end; procedure TMainForm.StopServer; begin Application.OnIdle:=Nil; ITMessages.Enabled:=False; FreeAndNil(FSrv); end; procedure TMainForm.SaveMessagesToFile(SelectedOnly : Boolean); Var L : TStrings; FN : String; begin With SDMessages do If Execute then FN:=FileName else Exit; L:=TstringList.Create; try Self.GetMessagesAsText(L,SelectedOnly); L.SaveToFile(FN); finally L.Free; end; end; procedure TMainForm.SetPauseAction(AAction : TAction); begin MIPause.Action:=AAction; PMIPause.Action:=AAction; TBPause.Action:=AAction; end; procedure TMainForm.SelectAllMessages; Var I : Integer; begin LVmessages.Items.BeginUpdate; try For I:=0 to LVmessages.Items.Count-1 do LVmessages.Items[I].Selected:=True; finally LVmessages.Items.EndUpdate; end; end; procedure TMainForm.ShowCurrentMessage; begin If LVMessages.Selected<>Nil then ShowMessage(LVMessages.Selected.SubItems[1]); end; function TMainForm.GetShowToolbar: Boolean; begin Result:=TBMain.Visible; end; function TMainForm.GetStayOnTop: Boolean; begin Result:=FormStyle=fsSystemStayOnTop; end; procedure TMainForm.CheckDebugMessages; begin While FSrv.PeekMessage(1,True) do ReadDebugMessage; end; procedure TMainForm.ReadDebugMessage; Var Msg : TDebugMessage; begin FSrv.MsgData.Seek(0,soFrombeginning); ReadDebugMessageFromStream(FSrv.MsgData,MSg); If not FPaused then ShowDebugMessage(Msg) else Inc(FDiscarded); end; procedure TMainForm.ShowDebugmessage(Const Msg : TDebugmessage); Var LI : TListItem; begin if (Msg.MsgType = lctIdentify) and FCleanLog then ClearMessages; LVmessages.Items.BeginUpdate; try if FAtBottom then LI:=LVmessages.Items.Add else LI:=LVmessages.Items.Insert(0); If (Msg.MsgType=lctStop) then LI.ImageIndex:=4 else LI.ImageIndex:=Msg.MsgType; LI.Caption:=DebugMessageName(Msg.MsgType); LI.Subitems.Add(TimeToStr(Msg.MsgTimeStamp)); LI.SubItems.Add(Msg.Msg); finally LVmessages.Items.EndUpdate; if FKeepVisible then LI.MakeVisible(False); end; If FShowOnMessage then ShowMessageWindow; end; procedure TMainForm.ShowMessageWindow; begin If Not Visible then Show; If (WindowState=wsMinimized) then WindowState:=wsNormal; end; procedure TMainForm.ClearMessages; begin LVMessages.Items.Clear; end; procedure TMainForm.CopySelectedToClipBoard; Var L : TStringList; begin L:=TStringList.Create; try GetMessagesAsText(L,True); ClipBoard.AsText:=L.Text; finally L.Free; end; end; procedure TMainForm.GetMessagesAsText(L : TStrings; SelectedOnly : Boolean); Var I : Integer; S : String; LI : TListItem; begin For I:=0 to LVMessages.Items.Count-1 do begin LI:=LVMessages.Items[i]; If (Not SelectedOnly) or LI.Selected then begin S:=LI.Caption; S:=S+': ['+Li.SubItems[0]+'] '; S:=S+Li.SubItems[1]; L.Add(S); end; end; end; procedure TMainForm.ShowOptions; begin With TOptionsForm.Create(Self) do try ShowOnStartUp:=FShowOnStartUp; ShowOnMessage:=FShowOnmessage; NewMessageAtBottom:=FAtBottom; NewMessageVisible:=FKeepVisible; CleanLogOnNewProcess := FCleanLog; If (ShowModal=mrOk) then begin FShowOnStartUp:=ShowOnStartUp; FShowOnmessage:=ShowOnMessage; FAtBottom:=NewMessageAtBottom; FKeepVisible:=NewMessageVisible; FCleanLog:=CleanLogOnNewProcess; SaveSettings; end; finally Free; end; end; procedure TMainForm.ResumeMessages; Var Msg : TDebugmessage; begin FPaused:=False; Msg.MsgTimeStamp:=Now; Msg.MsgType:=lctInformation; Msg.Msg:=Format('Discarded %d messages while paused.',[FDiscarded]); FDiscarded:=0; ShowDebugMessage(Msg); end; procedure TMainForm.SetShowToolBar(const AValue: Boolean); begin TBMain.Visible:=AValue; end; procedure TMainForm.SetStayOnTop(const AValue: Boolean); begin if AValue then FormStyle:=fsSystemStayOnTop else FormStyle:=fsNormal; end; Const SSettings = 'Settings'; KeyShowOnStartup = 'ShowOnStartup'; KeyShowOnMessage = 'ShowOnMessage'; KeyAtBottom = 'NewAtBottom'; KeyNewVisible = 'NewVisible'; KeyCleanLog = 'CleanLog'; KeyStayOnTop = 'StayOnTop'; KeyToolBar = 'ShowToolBar'; procedure TMainForm.LoadSettings; Var Ini : TMemIniFile; begin Ini:=TMeminiFile.Create(GetAppConfigFile(False)); With Ini do try FShowOnStartUp:=ReadBool(SSettings,KeyShowOnStartup,True); FShowOnMessage:=ReadBool(SSettings,KeyShowOnMessage,True); FAtBottom:=ReadBool(SSettings,KeyAtBottom,False); FKeepVisible:=ReadBool(SSettings,KeyNewVisible,True); FCleanLog:=ReadBool(SSettings,KeyCleanLog,False); StayOnTop:=ReadBool(SSettings,KeyStayOnTop,False); ShowToolBar:=ReadBool(SSettings,KeyToolBar,True); finally Free; end; end; procedure TMainForm.SaveSettings; Var Ini : TMemIniFile; begin if not(DirectoryExists(GetAppConfigDir(False))) Then if not(CreateDir (GetAppConfigDir(False))) Then ShowMessage('Cannot create config dir'); Ini:=TMeminiFile.Create(GetAppConfigFile(False)); With Ini do try WriteBool(SSettings,KeyShowOnStartup,FShowOnStartUp); WriteBool(SSettings,KeyShowOnMessage,FShowOnMessage); WriteBool(SSettings,KeyAtBottom,FAtBottom); WriteBool(SSettings,KeyNewVisible,FKeepVisible); WriteBool(SSettings,KeyCleanLog,FCleanLog); WriteBool(SSettings,KeyStayOnTop,StayOnTop); WriteBool(SSettings,KeyToolBar,ShowToolBar); finally Free; end; end; Function MyGetAppName : String; begin Result:='FPCDebugSrv'; end; initialization OnGetApplicationName:=@MyGetAppName; end.