diff --git a/Resources/Details.bmp b/Resources/Details.bmp new file mode 100644 index 0000000..2187b4b Binary files /dev/null and b/Resources/Details.bmp differ diff --git a/Resources/Error.bmp b/Resources/Error.bmp new file mode 100644 index 0000000..eb67a1c Binary files /dev/null and b/Resources/Error.bmp differ diff --git a/Resources/Info.bmp b/Resources/Info.bmp new file mode 100644 index 0000000..f498639 Binary files /dev/null and b/Resources/Info.bmp differ diff --git a/Resources/Verbose.bmp b/Resources/Verbose.bmp new file mode 100644 index 0000000..e3fb642 Binary files /dev/null and b/Resources/Verbose.bmp differ diff --git a/Resources/Warning.bmp b/Resources/Warning.bmp new file mode 100644 index 0000000..a68ac6e Binary files /dev/null and b/Resources/Warning.bmp differ diff --git a/Test/X2LogTest.dpr b/Test/X2LogTest.dpr index 0a4af8d..7e8778a 100644 --- a/Test/X2LogTest.dpr +++ b/Test/X2LogTest.dpr @@ -1,6 +1,11 @@ program X2LogTest; uses + madExcept, + madLinkDisAsm, + madListHardware, + madListProcesses, + madListModules, Forms, MainFrm in 'source\MainFrm.pas' {MainForm}, X2Log.Intf in '..\X2Log.Intf.pas', @@ -24,6 +29,7 @@ var begin Application.Initialize; Application.MainFormOnTaskbar := True; + Application.Title := 'X²LogTest'; Application.CreateForm(TMainForm, MainForm); Application.Run; end. diff --git a/Test/X2LogTest.dproj b/Test/X2LogTest.dproj index 35a1f50..29eb114 100644 --- a/Test/X2LogTest.dproj +++ b/Test/X2LogTest.dproj @@ -84,6 +84,8 @@ DEBUG;$(DCC_Define) + madExcept;$(DCC_Define) + 3 $(BDS)\bin\default_app.manifest true 1033 diff --git a/Test/source/MainFrm.dfm b/Test/source/MainFrm.dfm index 672e37f..89de2cd 100644 --- a/Test/source/MainFrm.dfm +++ b/Test/source/MainFrm.dfm @@ -32,6 +32,10 @@ object MainForm: TMainForm OnChange = pcObserversChange object tsEvent: TTabSheet Caption = 'Event Observer ' + ExplicitLeft = 0 + ExplicitTop = 0 + ExplicitWidth = 0 + ExplicitHeight = 0 object mmoEvent: TMemo AlignWithMargins = True Left = 8 @@ -51,6 +55,10 @@ object MainForm: TMainForm object tsFile: TTabSheet Caption = 'File Observer' ImageIndex = 1 + ExplicitLeft = 0 + ExplicitTop = 0 + ExplicitWidth = 0 + ExplicitHeight = 0 end object tsNamedPipe: TTabSheet Caption = 'Named Pipe Observer' @@ -78,7 +86,18 @@ object MainForm: TMainForm Align = alRight Cancel = True Caption = 'Close' + TabOrder = 1 + end + object btnMonitorForm: TButton + Left = 0 + Top = 0 + Width = 145 + Height = 25 + Align = alLeft + Cancel = True + Caption = 'Monitor Form Observer' TabOrder = 0 + OnClick = btnMonitorFormClick end end object GroupBox1: TGroupBox diff --git a/Test/source/MainFrm.pas b/Test/source/MainFrm.pas index 9eb5948..85b7042 100644 --- a/Test/source/MainFrm.pas +++ b/Test/source/MainFrm.pas @@ -28,6 +28,7 @@ type edtException: TEdit; btnException: TButton; tsNamedPipe: TTabSheet; + btnMonitorForm: TButton; procedure FormCreate(Sender: TObject); procedure FormDestroy(Sender: TObject); @@ -36,6 +37,7 @@ type procedure edtExceptionKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); procedure edtMessageKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); procedure btnExceptionClick(Sender: TObject); + procedure btnMonitorFormClick(Sender: TObject); private FLog: IX2Log; FObserver: IX2LogObserver; @@ -56,6 +58,7 @@ uses X2Log.Exception.madExcept, X2Log.Observer.Event, X2Log.Observer.LogFile, + X2Log.Observer.MonitorForm, X2Log.Observer.NamedPipe; @@ -65,11 +68,15 @@ uses { TMainForm } procedure TMainForm.FormCreate(Sender: TObject); begin + { Testing the localization (Dutch) } SetLogResourceString(@LogLevelVerbose, 'Uitgebreid'); SetLogResourceString(@LogLevelInfo, 'Informatie'); SetLogResourceString(@LogLevelWarning, 'Waarschuwing'); SetLogResourceString(@LogLevelError, 'Fout'); + SetLogResourceString(@LogMonitorFormColumnTime, 'Tijd'); + SetLogResourceString(@LogMonitorFormColumnMessage, 'Melding'); + FLog := TX2Log.Create; FLog.SetExceptionStrategy(TX2LogmadExceptExceptionStrategy.Create); @@ -164,4 +171,10 @@ begin end; end; + +procedure TMainForm.btnMonitorFormClick(Sender: TObject); +begin + TX2LogObserverMonitorForm.ShowInstance(FLog); +end; + end. diff --git a/X2Log.Constants.pas b/X2Log.Constants.pas index ffc0546..7621d1e 100644 --- a/X2Log.Constants.pas +++ b/X2Log.Constants.pas @@ -26,6 +26,19 @@ resourcestring LogFileLineDetails = ' (details: %s)'; + { + X2Log.Observer.MonitorForm + } + + { Caption of the monitor form. %s is optional and will be replaced + with the application's title } + LogMonitorFormCaption = '%s - Live Log'; + + { Caption of the columns in the live log view } + LogMonitorFormColumnTime = 'Time'; + LogMonitorFormColumnMessage = 'Message'; + + function GetLogLevelText(ALogLevel: TX2LogLevel): string; diff --git a/X2Log.Global.pas b/X2Log.Global.pas index 2c1faca..d6172d1 100644 --- a/X2Log.Global.pas +++ b/X2Log.Global.pas @@ -9,8 +9,10 @@ uses type TX2GlobalLog = class(TObject) - private - class var FInstance: IX2Log; + private class var + FInstance: IX2Log; + protected + class procedure CleanupInstance; public class function Instance: IX2Log; @@ -46,6 +48,13 @@ begin end; +class procedure TX2GlobalLog.CleanupInstance; +begin + if Assigned(FInstance) then + FreeAndNil(FInstance); +end; + + class procedure TX2GlobalLog.Attach(AObserver: IX2LogObserver); begin Instance.Attach(AObserver); @@ -99,4 +108,9 @@ begin Instance.Exception(AException, AMessage, ADetails); end; + +initialization +finalization + TX2GlobalLog.CleanupInstance; + end. diff --git a/X2Log.Observer.MonitorForm.dfm b/X2Log.Observer.MonitorForm.dfm index 994b316..b85915c 100644 --- a/X2Log.Observer.MonitorForm.dfm +++ b/X2Log.Observer.MonitorForm.dfm @@ -1,7 +1,7 @@ object X2LogObserverMonitorForm: TX2LogObserverMonitorForm Left = 0 Top = 0 - Caption = 'Log' + Caption = 'Live Log' ClientHeight = 519 ClientWidth = 658 Color = clBtnFace @@ -11,6 +11,321 @@ object X2LogObserverMonitorForm: TX2LogObserverMonitorForm Font.Name = 'Tahoma' Font.Style = [] OldCreateOrder = False + OnClose = FormClose + OnShow = FormShow PixelsPerInch = 96 TextHeight = 13 + object vstLog: TVirtualStringTree + Left = 0 + Top = 0 + Width = 658 + Height = 519 + Align = alClient + Header.AutoSizeIndex = 2 + Header.Font.Charset = DEFAULT_CHARSET + Header.Font.Color = clWindowText + Header.Font.Height = -11 + Header.Font.Name = 'Tahoma' + Header.Font.Style = [] + Header.Options = [hoAutoResize, hoColumnResize, hoDrag, hoShowSortGlyphs, hoVisible, hoHeaderClickAutoSort] + Images = ilsLog + TabOrder = 0 + TreeOptions.PaintOptions = [toHideFocusRect, toShowButtons, toShowDropmark, toThemeAware] + TreeOptions.SelectionOptions = [toFullRowSelect] + OnFreeNode = vstLogFreeNode + OnGetText = vstLogGetText + OnGetImageIndex = vstLogGetImageIndex + OnInitNode = vstLogInitNode + Columns = < + item + Options = [coAllowClick, coDraggable, coEnabled, coParentBidiMode, coParentColor, coShowDropMark, coVisible, coAllowFocus] + Position = 0 + Width = 24 + end + item + Position = 1 + Width = 150 + WideText = 'Time' + end + item + Position = 2 + Width = 480 + WideText = 'Message' + end> + end + object ilsLog: TImageList + Left = 584 + Top = 48 + Bitmap = { + 494C010105004000480010001000FFFFFFFFFF10FFFFFFFFFFFFFFFF424D3600 + 0000000000003600000028000000400000002000000001002000000000000020 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000000000000000000000000000000000000000009B7C6C009B7C + 6C009B7C6C009B7C6C009B7C6C009B7C6C009B7C6C009B7C6C009B7C6C009B7C + 6C009B7C6C009B7C6C0000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000000000000000000000000000000000000000009B776600FFFF + FF00FAF4E900FAF4E900FAF4E900FAF4E900FAF4E900FAF4E900FAF4E900F9EF + E000F9EFE0009779670000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000A27F6F00FFFF + FF00DDC1B400DDC1B400DDC1B400DDC1B400DDBEAD00DDBEAD00DCBAA500DCBA + A500F9EFE0009779670000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000A3807000FFFF + FF00DBC4BD00DBC4BD00DDC1B400DDC1B400DDBEAD00DDBEAD00DCBAA500DCBA + A500FAF4E9009B7C6C0000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000A9877800FFFF + FF00DBC6C200DBC4BD00DBC4BD00DDC1B400DBBFB400DCBAA500DDBEAD00DDBE + AD00FAF4E9009779670000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000AB897A00FFFF + FF00DBC6C200DBC6C200DBC4BD00DBC4BD00DBBFB400DCBAA500DDBEAD00DCBA + A500FAF4E9009B7C6C0000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000AB897A00FFFF + FF00DBC6C200DBC4BD00DBC4BD00DBC4BD00DDC1B400DBBFB400DCBAA500DDBE + AD00FAF4E9009B7C6C0000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000B1908000FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FCF9F500FCF9F500FCF9F500FAF4 + E900FAF4E9009B7C6C0000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000AF8F8000FFFF + FF00DFCDCB00DFCDCB00DBC6C200DBC4BD00DBC4BD00DDC1B400DDBEAD00DDBE + AD00FCF9F5009B7C6C0000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000B1908000FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FCF9F500FCF9F500FAF4 + E900F0E8E0009B7C6C0000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000B1908000FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FCF9F500A3807000A380 + 7000A3807000A380700000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000B8988800FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FCF9F500FFFFFF00A3807000F5E2 + D900B08E7D00AB9E980000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000B8988800FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00A3807000B08E + 7D00AB9E98000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000B8988800B898 + 8800B1908000B1908000B08E7D00B08E7D00AC887700AC887700A3807000AB9E + 9800000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000005C8F5C002979270014700D0014700D00277525005C8F5C000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000A6795F00A1552D00A2481400A04615009E543000A47965000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000000000000000000000000000000000005E63B2001221BA000812 + B1000812B1000810AA00080EA600080EA600080EA600080A9D00080EA6000606 + 9A00080A9D00080A9D006060A400000000000000000000000000000000000000 + 00000F7D0F00088800000888000013880000217D000032720000266D0000126D + 0D00000000000000000000000000000000000000000000000000000000000000 + 0000AD4F0F00BE580000C55F0000BE580000BE580000B04A0000A94300009D43 + 14000000000000000000000000000000000000000000749AAC003593B9002F95 + BC002693BB002693BB001A92B9001492B9000F92B8000B91B6000B91B6000C8F + B5000C8FB5001B80A800000000000000000000000000192CC6002441E000001E + D700001ED7000526DB000015C9000013C7000013C7000008B7000921C7000004 + AD000009AB000004A200080EA600000000000000000000000000000000000585 + 070004A00800009D010004A00800009D0100009D0100009500001E7E0000396B + 000010690200000000000000000000000000000000000000000000000000B752 + 0200D56D0000D56D0000D2670000EB952800F8B04F00DC750000BE580000A943 + 0000A03D0600000000000000000000000000000000003D98BD00A6EBF70084E1 + F1006CE2F10056E3F10040E9F50019F1FA002AF7F70000FEFE0000FEFE0000FE + FE0000FEFE0000FEFE001083AB0000000000000000001C32CE00264AEE000020 + E6000533F200B0C1EF001641F100001ED7000015C9001C40E500D0DEFF002441 + E0000008B7000009AB0006069A00000000000000000000000000158816000BA8 + 170004A0080036C15400DCF3E9007ADD9B00009D010000950000009D01001285 + 0000396B0000126D0D0000000000000000000000000000000000B65A1000DC75 + 0000D56D0000D56D0000DA985000F4FEFF00FEFFFF00FFFAE100D56D0000BE58 + 0000B04A00009D4314000000000000000000000000003593B900A5E7F3007EDB + ED0069DBEC0055DEEE0032E3FD001E374000453C380009FFFF0000FEFE0000FE + FE0000FEFE0000FEFE000C8FB5000000000000000000213AD200294FF7000028 + F800C0C7E400F1EDE000D9DFEC000F3BF1000C34EB00E1EAFD00FFFFF900EFF8 + FF002441E0000004AD0006069A0000000000000000006097600024A82F0008A9 + 1B002BB43E00F6F0F500FCF6FA00FFFEFF007ADD9B00009D0100009D01000095 + 0000217D0000266D00005C8F5C000000000000000000AE795400D97E1B00DC75 + 0000DC750000DC750000CA844900ECF9FF00F4FEFF00FEEED500D96D0000C862 + 0000BE580000A9430000A47965000000000000000000709EB30069C3DD0089DE + F00069DBEC005ADCED0044E3F4000B91B600129DB80008F5FC0000F4F90000FE + FE0000FEFE0000E4EE005585A1000000000000000000213AD2002852FF00A0AC + E200EDEADD00E4E4E300F1F0E900D4DCF300CFD9F800FFFFF900FFFFF900FFFF + F900DEEDFF000921C700080EA60000000000000000002C8E2B0039BF4F0024A8 + 2F00ECE6EA00F5EEF400FCF6FA00FFFEFF00FFFEFF007ADD9B00009F0900009D + 01000095000032720000277525000000000000000000B8662400E9912400E27C + 0000E27C0000E27C0000D96D0000CA6C1000D6853000D96D0000D56D0000C862 + 0000C8620000B04A0000A1552D000000000000000000000000002F9BC50094E2 + F0007EDBED005ADCED0056E3F10032E6EB0046DCDD0016ECF70006EEF60000F4 + F90000FEFE00128AB1000000000000000000000000002945DB003764FF000533 + F200D7D7E000ECEBE500EDEDEB00F4F4F100FAF9F600FFFFF900FFFFF900FFFF + F9002E54EC000008B700080A9D0000000000000000001E93220039BF4F00AAC9 + A700FAEAF900D1E1D1001EAF3300DAEEDD00FFFEFF00FFFEFF007ADD9B00009D + 0100009D0100297C000014700D000000000000000000C4691600ED992A00E881 + 0000E8810000E8810000F4971600FFD89400FFD58F00FFC76400D96D0000D56D + 0000CE680000BE580000A24814000000000000000000000000000000000049B3 + D60087DFEF0069DBEC0058E4F6001A888E004074720026F2FE0016ECF70008F5 + FC0002C6DA006E9AAA000000000000000000000000002C48DE004473FF00003C + FF000537F800D2D6E800EDEDEB00F4F4F100FFFFF900FFFFF900EAEFFF001D46 + EF000014D2000012BF00060CA3000000000000000000219624005DD27C0017A3 + 25008EBF880011AB24001BB940000BAC2600DAEEDD00FFFEFF00FFFEFF007ADD + 9B00009D01001B86000014700D000000000000000000CA6C1000F6A73C00EF88 + 0000EF880000EF880000EB952800FEFFFF00FEFFFF00FFE7B900DC750000D56D + 0000D56D0000C55F0000A248140000000000000000000000000000000000409F + C20087DFEF007EDBED0047E8FF00243A3E003F3635001DFBFF002BE5F20021EE + F600268CAA00000000000000000000000000000000002F4EE3004D81FF00044A + FF00002CF600B0BAE800EDEDEB00F4F4F100F4F4F100FFFFF900D0DEFF00012D + ED00001ED7000013C7000009AB0000000000000000002C922C0077DC95002CC5 + 59001BB940002CC5590026C04E0022BB45000BAC2600DAEEDD00FFFEFF00FFFE + FF0078DB960013880000267D26000000000000000000BF6B2000FCBA5A00F68F + 0000F7900000F68F0000E28D2500F4FEFF00FEFFFF00FFE2B200E1750000D771 + 0000D56D0000C55F0000A4582B00000000000000000000000000000000000000 + 000038ABD00094E2F00038D2F600211210003827260020CEDA0040E9F5001EAC + CF0000000000000000000000000000000000000000003253E500568EFF000031 + EB00B6B8DC00ECEBE500EDEDEB00F4F4F100F4F4F100FFFFF900FFFFF900E1EA + FD000031EB000013C7000810AA000000000000000000629C620053C66C0061D8 + 890031CA630031CA63002CC5590026C04E0022BB45000BAC2600DAEEDD00FCF6 + FA00CAECD7000E8E08005C905C000000000000000000B57B4E00F8B04F00FDA9 + 2C00FD960000FD960000DA842300EAF2FB00EFF2F700F5D6A900E1750000DC75 + 0000D56D0000C55F0000A6795F00000000000000000000000000000000000000 + 00005AA3C00082D3E80045CFF100110602002B14100023C9E50055DEEE003C92 + B7000000000000000000000000000000000000000000385AEA004F77EC009A98 + CB00EDEADD00E4E4E300F1F0E900D2D6E800DFE3F400FFFFF900FFFFF900FFFF + F900D0DEFF000526DB000611B2000000000000000000000000001E9A230083E5 + A7004CD3790031CA630031CA630027C3530022BB45001CB53A0008A91B007ACC + 850011AB24000F7D0F0000000000000000000000000000000000D1761900FFC7 + 6400FFA21300FF980000CF7A2600DFEEFE00E3EFFB00E4CBAC00E1750000DC75 + 0000D7710000AE510E0000000000000000000000000000000000000000000000 + 00000000000031A1C9009DE6F60031B0D30027ADCF0067E5FA0031A1C9000000 + 00000000000000000000000000000000000000000000385AEA0067A4FF000F35 + D200D8D4D800ECEBE500D9D8E4000533F200003CFF00F4F4F100FFFFF900FFFF + F9001944F9000015C9000012BF000000000000000000000000000000000024A4 + 2D0083E5A7005ED8880031CA630027C3530022BB45001CB53A0016B02E000BAC + 2600058A08000000000000000000000000000000000000000000BE916D00DA84 + 2300FFC76400FFAD2600DC750000CD6E0F00D5760F00DA790B00E27C0000E27C + 0000BD5700000000000000000000000000000000000000000000000000000000 + 00000000000074A9BD006FC7E300A5E7F30094E2F00077D4E7005398B5000000 + 000000000000000000000000000000000000000000003D60F0006DABFF00116E + FF001136D300BDB9D4000633E300044AFF00003CFF000537F800D4DCF3000C3B + F9000020E600001ED7000611B200000000000000000000000000000000000000 + 00001E9A230056CA730077E09C005DD27C0043C8660036C154001EAA2F001588 + 160000000000000000000000000000000000000000000000000000000000BE91 + 6D00D1761900F8B04F00FFBF4E00FDA92C00F69A1900EF911500DA790B00BA5C + 0C00000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000031A1C900B8E8F200B1E9F600369DC100000000000000 + 00000000000000000000000000000000000000000000355DF200BAE0FF005CA0 + FF00569AFF003A60E4004584FF003F76FF003764FF00295AFF001944F9001944 + F9001D46EF001D38DB001326C300000000000000000000000000000000000000 + 000000000000629C62002C922C00229A28001E9322002C922C00629C62000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000B57B4E00C26F2100CD6E0F00CA6C1000BF6B2000AE7954000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000000000000000003D98BD00369DC10000000000000000000000 + 000000000000000000000000000000000000000000006373CE00365DEF004162 + EE00385AEA00385AEA00385AEA003253E500304DE2002945DB002945DB002441 + E000213AD2001C32CE00656DB900000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000000000000000000000000000424D3E000000000000003E000000 + 2800000040000000200000000100010000000000000100000000000000000000 + 000000000000000000000000FFFFFF00FFFF000000000000C003000000000000 + C003000000000000C003000000000000C003000000000000C003000000000000 + C003000000000000C003000000000000C003000000000000C003000000000000 + C003000000000000C003000000000000C003000000000000C007000000000000 + C00F000000000000FFFF000000000000FFFFFFFFFFFFFFFFF81FF81FFFFF8001 + F00FF00F80038001E007E00780018001C003C003800180018001800180018001 + 80018001C003800180018001E003800180018001E007800180018001F00F8001 + 80018001F00F8001C003C003F81F8001E007C007F81F8001F00FE00FFC3F8001 + F81FF81FFE7F8001FFFFFFFFFFFFFFFF00000000000000000000000000000000 + 000000000000} + end end diff --git a/X2Log.Observer.MonitorForm.pas b/X2Log.Observer.MonitorForm.pas index 9167aac..b11f9b3 100644 --- a/X2Log.Observer.MonitorForm.pas +++ b/X2Log.Observer.MonitorForm.pas @@ -2,8 +2,12 @@ unit X2Log.Observer.MonitorForm; interface uses + System.Classes, + System.Generics.Collections, Vcl.Controls, Vcl.Forms, + Vcl.ImgList, + VirtualTrees, Winapi.Messages, X2Log.Intf; @@ -15,26 +19,185 @@ const type TX2LogObserverMonitorForm = class(TForm, IX2LogObserver) + vstLog: TVirtualStringTree; + ilsLog: TImageList; + + procedure FormShow(Sender: TObject); + procedure FormClose(Sender: TObject; var Action: TCloseAction); + procedure vstLogInitNode(Sender: TBaseVirtualTree; ParentNode, Node: PVirtualNode; var InitialStates: TVirtualNodeInitStates); + procedure vstLogFreeNode(Sender: TBaseVirtualTree; Node: PVirtualNode); + procedure vstLogGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType; var CellText: string); + procedure vstLogGetImageIndex(Sender: TBaseVirtualTree; Node: PVirtualNode; Kind: TVTImageKind; Column: TColumnIndex; var Ghosted: Boolean; var ImageIndex: Integer); + private class var + FInstances: TDictionary; + private + FFreeOnClose: Boolean; + FLogToAttach: IX2Log; + FLogAttached: Boolean; protected + class function GetInstance(ALog: IX2Log; out AForm: TX2LogObserverMonitorForm): Boolean; + class procedure RemoveInstance(AForm: TX2LogObserverMonitorForm); + class procedure CleanupInstances; + procedure CreateParams(var Params: TCreateParams); override; procedure WMEnable(var Msg: TWMEnable); message WM_ENABLE; procedure CMReenable(var Msg: TMessage); message CM_REENABLE; + + property LogToAttach: IX2Log read FLogToAttach; + property LogAttached: Boolean read FLogAttached; public + class function Instance(ALog: IX2Log): TX2LogObserverMonitorForm; + + class procedure ShowInstance(ALog: IX2Log); + class procedure CloseInstance(ALog: IX2Log); + + constructor Create(AOwner: TComponent; ALogToAttach: IX2Log = nil); reintroduce; + destructor Destroy; override; + { IX2LogObserver } procedure Log(ALevel: TX2LogLevel; const AMessage: string; const ADetails: string = ''); + + property FreeOnClose: Boolean read FFreeOnClose write FFreeOnClose; end; implementation uses - Winapi.Windows; + System.DateUtils, + System.SysUtils, + Winapi.Windows, + + X2Log.Constants; {$R *.dfm} +type + TLogEntryNodeData = record + Time: TDateTime; + Level: TX2LogLevel; + Message: string; + Details: string; + + procedure Initialize(ALevel: TX2LogLevel; const AMessage, ADetails: string); + end; + + PLogEntryNodeData = ^TLogEntryNodeData; + + +const + ColumnLevel = 0; + ColumnTime = 1; + ColumnMessage = 2; + + +{ TLogEntryNode } +procedure TLogEntryNodeData.Initialize(ALevel: TX2LogLevel; const AMessage, ADetails: string); +begin + Time := Now; + Level := ALevel; + Message := AMessage; + Details := ADetails; +end; + + { TX2LogObserverMonitorForm } +class function TX2LogObserverMonitorForm.Instance(ALog: IX2Log): TX2LogObserverMonitorForm; +var + log: IX2Log; + +begin + { Explicit cast ensures we're getting the same pointer every time if, for example, + the implementing interface is a descendant of IX2Log } + log := (ALog as IX2Log); + + if not Assigned(FInstances) then + FInstances := TDictionary.Create; + + if not FInstances.TryGetValue(log, Result) then + begin + Result := TX2LogObserverMonitorForm.Create(nil, log); + Result.FreeOnClose := True; + + FInstances.Add(log, Result); + end; +end; + + +class procedure TX2LogObserverMonitorForm.ShowInstance(ALog: IX2Log); +begin + Instance(ALog).Show; +end; + + +class procedure TX2LogObserverMonitorForm.CloseInstance(ALog: IX2Log); +var + monitorForm: TX2LogObserverMonitorForm; + +begin + if GetInstance(ALog, monitorForm) then + monitorForm.Close; +end; + + +class function TX2LogObserverMonitorForm.GetInstance(ALog: IX2Log; out AForm: TX2LogObserverMonitorForm): Boolean; +begin + Result := False; + + if Assigned(FInstances) then + Result := FInstances.TryGetValue(ALog as IX2Log, AForm); +end; + + +class procedure TX2LogObserverMonitorForm.RemoveInstance(AForm: TX2LogObserverMonitorForm); +var + log: IX2Log; + +begin + if Assigned(FInstances) then + begin + for log in FInstances.Keys do + begin + if FInstances[log] = AForm then + begin + FInstances.Remove(log); + break; + end; + end; + end; +end; + + +class procedure TX2LogObserverMonitorForm.CleanupInstances; +begin + if Assigned(FInstances) then + FreeAndNil(FInstances); +end; + + +constructor TX2LogObserverMonitorForm.Create(AOwner: TComponent; ALogToAttach: IX2Log); +var + captionFormat: string; + +begin + inherited Create(AOwner); + + FLogToAttach := ALogToAttach; + + captionFormat := GetLogResourceString(@LogMonitorFormCaption); + if Pos('%s', captionFormat) > 0 then + Caption := Format(captionFormat, [Application.Title]) + else + Caption := captionFormat; + + vstLog.NodeDataSize := SizeOf(TLogEntryNodeData); + vstLog.Header.Columns[ColumnTime].Text := GetLogResourceString(@LogMonitorFormColumnTime); + vstLog.Header.Columns[ColumnMessage].Text := GetLogResourceString(@LogMonitorFormColumnMessage); +end; + + procedure TX2LogObserverMonitorForm.CreateParams(var Params: TCreateParams); begin inherited CreateParams(Params); @@ -43,9 +206,51 @@ begin end; -procedure TX2LogObserverMonitorForm.Log(ALevel: TX2LogLevel; const AMessage, ADetails: string); +destructor TX2LogObserverMonitorForm.Destroy; begin - // + if Assigned(FLogToAttach) and FLogAttached then + FLogToAttach.Detach(Self); + + RemoveInstance(Self); + + inherited Destroy; +end; + + +procedure TX2LogObserverMonitorForm.FormShow(Sender: TObject); +begin + if Assigned(FLogToAttach) and (not FLogAttached) then + begin + FLogToAttach.Attach(Self); + FLogAttached := True; + end; +end; + + +procedure TX2LogObserverMonitorForm.FormClose(Sender: TObject; var Action: TCloseAction); +begin + if Assigned(FLogToAttach) and FLogAttached then + begin + FLogToAttach.Detach(Self); + FLogAttached := False; + end; + + if FreeOnClose then + Action := caFree + else + Action := caHide; +end; + + +procedure TX2LogObserverMonitorForm.Log(ALevel: TX2LogLevel; const AMessage, ADetails: string); +var + node: PVirtualNode; + nodeData: PLogEntryNodeData; + +begin + node := vstLog.AddChild(nil); + nodeData := vstLog.GetNodeData(node); + nodeData^.Initialize(ALevel, AMessage, ADetails); end; @@ -62,4 +267,71 @@ begin EnableWindow(Self.Handle, True); end; + +procedure TX2LogObserverMonitorForm.vstLogInitNode(Sender: TBaseVirtualTree; ParentNode, Node: PVirtualNode; + var InitialStates: TVirtualNodeInitStates); +var + nodeData: PLogEntryNodeData; + +begin + nodeData := Sender.GetNodeData(Node); + Initialize(nodeData^); +end; + + +procedure TX2LogObserverMonitorForm.vstLogFreeNode(Sender: TBaseVirtualTree; Node: PVirtualNode); +var + nodeData: PLogEntryNodeData; + +begin + nodeData := Sender.GetNodeData(Node); + Finalize(nodeData^); +end; + + +procedure TX2LogObserverMonitorForm.vstLogGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; + TextType: TVSTTextType; var CellText: string); +var + nodeData: PLogEntryNodeData; + +begin + CellText := ''; + nodeData := Sender.GetNodeData(Node); + + case Column of + ColumnTime: + CellText := DateTimeToStr(nodeData^.Time); + + ColumnMessage: + CellText := nodeData^.Message; + end; +end; + + +procedure TX2LogObserverMonitorForm.vstLogGetImageIndex(Sender: TBaseVirtualTree; Node: PVirtualNode; Kind: TVTImageKind; + Column: TColumnIndex; var Ghosted: Boolean; var ImageIndex: Integer); +var + nodeData: PLogEntryNodeData; + +begin + if Kind in [ikNormal, ikSelected] then + begin + nodeData := Sender.GetNodeData(Node); + + case Column of + ColumnLevel: + case nodeData^.Level of + TX2LogLevel.Verbose: ImageIndex := 0; + TX2LogLevel.Info: ImageIndex := 1; + TX2LogLevel.Warning: ImageIndex := 2; + TX2LogLevel.Error: ImageIndex := 3; + end; + + ColumnMessage: + if Length(nodeData^.Details) > 0 then + ImageIndex := 4; + end; + end; +end; + end.