Check-in [3d17dc47ac]
Not logged in

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Added statusbar, and TRenderer.SummarizeInfo to populate it; always display file icon on the status bar. Added RendererSelected event, to react to a new renderer. Removed obsolete code (TfrmInfo.Populate, CreateGraphicFromFile). Removed various memory leaks.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | feature/windows-preview-host
Files: files | file ages | folders
SHA1:3d17dc47aca933ed4f1b00c14bc180ce710f9be6
User & Date: Martijn 2015-02-15 13:51:01
Context
2015-02-15
16:22
Moved WLX plugin support to its own preview engine. Will need to revise existing plugin architecture to support adding and removing of renderers after initialisation. check-in: 9cfd6a0721 user: Martijn tags: feature/windows-preview-host
13:51
Added statusbar, and TRenderer.SummarizeInfo to populate it; always display file icon on the status bar. Added RendererSelected event, to react to a new renderer. Removed obsolete code (TfrmInfo.Populate, CreateGraphicFromFile). Removed various memory leaks. check-in: 3d17dc47ac user: Martijn tags: feature/windows-preview-host
2015-02-13
22:44
Clear each engine when its form is being hidden. check-in: 623b494832 user: Martijn tags: feature/windows-preview-host
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to ZPreview/doc/WindowsPreviewHandlers.md.

1
2
3
4
5
6
7
8
9
10
11
12
13
14

15
16
17
18
19
20
21
Windows Preview Handlers
========================

Since Vista, Windows includes a standard framework for displaying previews for any file type. This means any software vendor can create a preview of any file type — and allow _any other software_ to display a preview for their files. Microsoft Office provides several preview handlers by default, for the Office document formats.
You can find and install other Windows preview handlers online.

For example, if you install the free [PDF Xchange Reader](http://www.tracker-software.com/product/pdf-xchange-viewer), it installs a preview handler for PDF files. [ZPreview](../readme.md) will then display PDFs as well. (Even if you don't use PDF Xchange otherwise, or have associated PDF files with another program, [like Nitro PDF](https://www.gonitro.com/pdf-reader)).

Here are some other free preview handler packs:

* [https://previewhandlers.codeplex.com/](https://previewhandlers.codeplex.com/) - various source code files with syntax highlighting
* [http://code.google.com/p/delphi-preview-handler/](http://code.google.com/p/delphi-preview-handler/) - some more source code files with syntax highlighting

Since it's possible to have multiple preview handlers for the same file type, but only one associated with it, Stephen Toub has written a [Preview Handler Association Editor](http://blogs.msdn.com/b/toub/archive/2006/12/14/preview-handler-association-editor.aspx), which lets you choose. It also provides an overview of all installed Preview Handlers.


Technical documentation
-----------------------
* [Preview Handlers and Shell Preview Host](https://msdn.microsoft.com/en-us/library/windows/desktop/cc144143.aspx) by Microsoft
* [Hosting Preview Handlers in Delphi VCL Applications](https://theroadtodelphi.wordpress.com/2013/05/24/hosting-preview-handlers-in-delphi-vcl-applications/) by Rodrigo Ruz
* [Delphi Preview Handler](http://code.google.com/p/delphi-preview-handler/) by Rodrigo Ruz
* [Windows 7 Previews – the Delphi Way](http://www.uweraabe.de/Blog/2011/06/01/windows-7-previews-the-delphi-way/) by Uwe Raabe



|










>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
Windows Preview Handlers
========================

Since Vista, Windows includes a standard framework for displaying previews for any file type. This means any software vendor can create a preview of any file type — and allow any _other_ software to display a preview for their files. Microsoft Office provides several preview handlers by default, for the Office document formats.
You can find and install other Windows preview handlers online.

For example, if you install the free [PDF Xchange Reader](http://www.tracker-software.com/product/pdf-xchange-viewer), it installs a preview handler for PDF files. [ZPreview](../readme.md) will then display PDFs as well. (Even if you don't use PDF Xchange otherwise, or have associated PDF files with another program, [like Nitro PDF](https://www.gonitro.com/pdf-reader)).

Here are some other free preview handler packs:

* [https://previewhandlers.codeplex.com/](https://previewhandlers.codeplex.com/) - various source code files with syntax highlighting
* [http://code.google.com/p/delphi-preview-handler/](http://code.google.com/p/delphi-preview-handler/) - some more source code files with syntax highlighting

Since it's possible to have multiple preview handlers for the same file type, but only one associated with it, Stephen Toub has written a [Preview Handler Association Editor](http://blogs.msdn.com/b/toub/archive/2006/12/14/preview-handler-association-editor.aspx), which lets you choose. It also provides an overview of all installed Preview Handlers.
Since version 1.2, ZPreview allows you to use any preview handler installed on the system, and switch between them at will.

Technical documentation
-----------------------
* [Preview Handlers and Shell Preview Host](https://msdn.microsoft.com/en-us/library/windows/desktop/cc144143.aspx) by Microsoft
* [Hosting Preview Handlers in Delphi VCL Applications](https://theroadtodelphi.wordpress.com/2013/05/24/hosting-preview-handlers-in-delphi-vcl-applications/) by Rodrigo Ruz
* [Delphi Preview Handler](http://code.google.com/p/delphi-preview-handler/) by Rodrigo Ruz
* [Windows 7 Previews – the Delphi Way](http://www.uweraabe.de/Blog/2011/06/01/windows-7-previews-the-delphi-way/) by Uwe Raabe

Changes to ZPreview/src/Delphi/F_Info.pas.

27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
...
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190

191
192
    procedure Add(const Group, Name: string; const Value: string); overload;
    procedure Add(const Group, Name: string; const Value: Integer; const Names: array of string); overload;

    procedure PopulateFileName(const Filename: string);
    procedure AutosizeColumns;
  public
    { Public declarations }
    procedure Populate(const Filename: string); overload;

    procedure StartPopulatingLines(const Filename: string; const Clear: boolean = False);
    procedure PopulateLine(const Group, Key, Short, Long: string);
    procedure StopPopulatingLines;
  end;

var
  frmInfo: TfrmInfo;
................................................................................
{ ------------------------------------------------------------------------------------------------ }
procedure TfrmInfo.StopPopulatingLines;
begin
  AutosizeColumns;
  lvwFields.Items.EndUpdate;
end {TfrmInfo.StopPopulatingLines};

{ ------------------------------------------------------------------------------------------------ }
procedure TfrmInfo.Populate(const Filename: string);
begin
  lvwFields.Items.BeginUpdate;
  try
    lvwFields.Clear;

    PopulateFileName(Filename);

    {$MESSAGE WARN 'TODO: TfrmInfo.Populate'}

    AutosizeColumns;
  finally
    lvwFields.Items.EndUpdate;
  end;
end {TfrmInfo.Populate};

{ ------------------------------------------------------------------------------------------------ }
procedure TfrmInfo.AutosizeColumns;
var
  Column: TCollectionItem;
begin
  for Column in lvwFields.Columns do
  begin
    TListColumn(Column).Width := -2;
  end;
end;


end.







<
<







 







<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<






<

<
<
>


27
28
29
30
31
32
33


34
35
36
37
38
39
40
...
155
156
157
158
159
160
161

















162
163
164
165
166
167

168


169
170
171
    procedure Add(const Group, Name: string; const Value: string); overload;
    procedure Add(const Group, Name: string; const Value: Integer; const Names: array of string); overload;

    procedure PopulateFileName(const Filename: string);
    procedure AutosizeColumns;
  public
    { Public declarations }


    procedure StartPopulatingLines(const Filename: string; const Clear: boolean = False);
    procedure PopulateLine(const Group, Key, Short, Long: string);
    procedure StopPopulatingLines;
  end;

var
  frmInfo: TfrmInfo;
................................................................................
{ ------------------------------------------------------------------------------------------------ }
procedure TfrmInfo.StopPopulatingLines;
begin
  AutosizeColumns;
  lvwFields.Items.EndUpdate;
end {TfrmInfo.StopPopulatingLines};


















{ ------------------------------------------------------------------------------------------------ }
procedure TfrmInfo.AutosizeColumns;
var
  Column: TCollectionItem;
begin
  for Column in lvwFields.Columns do

    TListColumn(Column).Width := -2;


end {TfrmInfo.AutosizeColumns};

end.

Changes to ZPreview/src/Delphi/F_Main.dfm.

18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

33
34
35
36
37
38
39
40
41

42
43
44
45
46
47
48
..
86
87
88
89
90
91
92
93
94
95
96
97
98



























99
100
101
102
103
104
105
...
114
115
116
117
118
119
120






121
122
123
124
125
126
127
...
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
  PixelsPerInch = 96
  TextHeight = 13
  object tbcPreview: TTabControl
    AlignWithMargins = True
    Left = 3
    Top = 70
    Width = 806
    Height = 432
    Align = alClient
    DoubleBuffered = True
    ParentDoubleBuffered = False
    TabOrder = 0
    Tabs.Strings = (
      'Sophie.jpg')
    TabIndex = 0

    object pnlPluginParent: TPanel
      Left = 4
      Top = 24
      Width = 798
      Height = 404
      Align = alClient
      BevelOuter = bvNone
      TabOrder = 0
      Visible = False

    end
  end
  object pnlError: TPanel
    Left = 0
    Top = 26
    Width = 816
    Height = 41
................................................................................
    ShowHint = True
    Spacing = 0
  end
  object pnlRight: TPanel
    Left = 812
    Top = 67
    Width = 4
    Height = 438
    Align = alRight
    AutoSize = True
    Constraints.MaxWidth = 4
    DockSite = True
    TabOrder = 3



























  end
  object ActionManager: TActionManager
    ActionBars = <
      item
        Items = <
          item
            Action = actRefresh
................................................................................
          item
            Action = actActivateZTreeWin
            Caption = '&ZTreeWin'
            ImageIndex = 2
            ShowCaption = False
            ShortCut = 24666
          end






          item
            Caption = '-'
          end
          item
            Action = actViewImageInfo
            ImageIndex = 6
            ShowCaption = False
................................................................................
          end
          item
            Action = actViewSentinel
            ImageIndex = 5
            ShowCaption = False
            ShortCut = 24659
          end
          item
            Action = actFileProperties
            Caption = 'Pr&operties...'
            ImageIndex = 16
            ShowCaption = False
          end
          item
            Action = actViewFullScreen
            ImageIndex = 3
            ShowCaption = False
            ShortCut = 24646
          end
          item







|







>




|




>







 







|





>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







 







>
>
>
>
>
>







 







<
<
<
<
<
<







18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
..
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
...
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
...
164
165
166
167
168
169
170






171
172
173
174
175
176
177
  PixelsPerInch = 96
  TextHeight = 13
  object tbcPreview: TTabControl
    AlignWithMargins = True
    Left = 3
    Top = 70
    Width = 806
    Height = 413
    Align = alClient
    DoubleBuffered = True
    ParentDoubleBuffered = False
    TabOrder = 0
    Tabs.Strings = (
      'Sophie.jpg')
    TabIndex = 0
    ExplicitHeight = 432
    object pnlPluginParent: TPanel
      Left = 4
      Top = 24
      Width = 798
      Height = 385
      Align = alClient
      BevelOuter = bvNone
      TabOrder = 0
      Visible = False
      ExplicitHeight = 404
    end
  end
  object pnlError: TPanel
    Left = 0
    Top = 26
    Width = 816
    Height = 41
................................................................................
    ShowHint = True
    Spacing = 0
  end
  object pnlRight: TPanel
    Left = 812
    Top = 67
    Width = 4
    Height = 419
    Align = alRight
    AutoSize = True
    Constraints.MaxWidth = 4
    DockSite = True
    TabOrder = 3
    ExplicitHeight = 438
  end
  object sbrMain: TStatusBar
    Left = 0
    Top = 486
    Width = 816
    Height = 19
    Panels = <
      item
        Alignment = taCenter
        Bevel = pbNone
        Style = psOwnerDraw
        Text = '(icon)'
        Width = 20
      end
      item
        Text = '(preview engine)'
        Width = 250
      end
      item
        Text = '(file info summary)'
        Width = -2
      end>
    OnDrawPanel = sbrMainDrawPanel
    ExplicitLeft = 280
    ExplicitTop = 504
    ExplicitWidth = 0
  end
  object ActionManager: TActionManager
    ActionBars = <
      item
        Items = <
          item
            Action = actRefresh
................................................................................
          item
            Action = actActivateZTreeWin
            Caption = '&ZTreeWin'
            ImageIndex = 2
            ShowCaption = False
            ShortCut = 24666
          end
          item
            Action = actFileProperties
            Caption = 'Pr&operties...'
            ImageIndex = 16
            ShowCaption = False
          end
          item
            Caption = '-'
          end
          item
            Action = actViewImageInfo
            ImageIndex = 6
            ShowCaption = False
................................................................................
          end
          item
            Action = actViewSentinel
            ImageIndex = 5
            ShowCaption = False
            ShortCut = 24659
          end






          item
            Action = actViewFullScreen
            ImageIndex = 3
            ShowCaption = False
            ShortCut = 24646
          end
          item

Changes to ZPreview/src/Delphi/F_Main.pas.

31
32
33
34
35
36
37

38
39
40
41
42
43
44
..
50
51
52
53
54
55
56


57
58
59
60
61
62
63

64
65
66
67
68
69
70
71
72
73
74
75
76
77

78
79

80
81
82
83
84
85
86
87
88
89
90
91
92

93
94
95
96
97

98
99
100
101
102
103
104
...
113
114
115
116
117
118
119

































120
121
122
123
124
125
126
...
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
...
390
391
392
393
394
395
396




397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
...
419
420
421
422
423
424
425



















426
427
428
429
430
431
432
    actFileExit: TFileExit;
    actWindowMinimize: TAction;
    pnlRight: TPanel;
    actPreviewEngine: TAction;
    actEngineManage: TAction;
    actEngineAutoselect: TAction;
    actFileProperties: TAction;

    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
    procedure ApplicationException(Sender: TObject; E: Exception);
    procedure actAutoRefreshExecute(Sender: TObject);
    procedure actRefreshExecute(Sender: TObject);
    procedure actViewSentinelExecute(Sender: TObject);
................................................................................
    procedure actFileLoadPluginAccept(Sender: TObject);
    procedure actViewTopmostUpdate(Sender: TObject);
    procedure actViewTopmostExecute(Sender: TObject);
    procedure actWindowMinimizeExecute(Sender: TObject);
    procedure actPreviewEngineExecute(Sender: TObject);
    procedure actEngineAutoselectExecute(Sender: TObject);
    procedure actFilePropertiesExecute(Sender: TObject);


  private
    { Private declarations }
//    FWatcher: TThread;
    FInitialized: Boolean;
    FEngineManager: TPreviewEngineUIManager;

    FWlxPlugin: TWlxPluginWrapper;


    procedure LoadSentinel;
    procedure ProcessPamphlet;
  public
    { Public declarations }
    FSentinel: TZaapSentinelFile;
  end;

var
  frmMain: TfrmMain;

implementation
uses
  IOUtils, Types, PsApi, System.Masks, System.Generics.Defaults,

  Vcl.Imaging.GIFImg, Vcl.Imaging.jpeg, Vcl.Imaging.pngimage,
  Winapi.ShellAPI,

  F_Sentinel, F_Info;

{$R *.dfm}


{ ------------------------------------------------------------------------------------------------ }
procedure TfrmMain.FormCreate(Sender: TObject);
begin
  Application.OnException := ApplicationException;

  FEngineManager := TPreviewEngineUIManager.Create(ActionManager,
                                                   tbcPreview,
                                                   actPreviewEngine);

end {TfrmMain.FormCreate};

{ ------------------------------------------------------------------------------------------------ }
procedure TfrmMain.FormDestroy(Sender: TObject);
begin

  if Assigned(FWlxPlugin) then
    FWlxPlugin.Free;
  FSentinel.Free;

  FEngineManager.Free;
end {TfrmMain.FormDestroy};

................................................................................
procedure TfrmMain.ApplicationException(Sender: TObject; E: Exception);
begin
  MessageBeep(MB_ICONERROR);
  lblError.Caption := E.Message;
  lblError.Font.Color := clRed;
  pnlError.Show;
end {TfrmMain.ApplicationException};


































{ ------------------------------------------------------------------------------------------------ }
procedure TfrmMain.LoadSentinel;
var
  Sentinels: TStringDynArray;
  SentinelFile: string;
begin
................................................................................
    {$MESSAGE HINT 'TODO: Make this behaviour optional?  MCO 13-02-2015'}
    Self.WindowState := wsMinimized;
  end;
end {TfrmMain.actFilePropertiesExecute};

{ ------------------------------------------------------------------------------------------------ }
procedure TfrmMain.actPreviewEngineExecute(Sender: TObject);
var
  Renderer: TRenderer;
begin
  Renderer := FEngineManager.NextRenderer;
  if Assigned(Renderer) and frmInfo.Visible then begin
    frmInfo.StartPopulatingLines(FEngineManager.Filename, True);
    try
      Renderer.PopulateInfo(frmInfo);
    finally
      frmInfo.StopPopulatingLines;
    end;
  end;
end {TfrmMain.actPreviewEngineExecute};

{ ------------------------------------------------------------------------------------------------ }
function CreateGraphicFromFile(const FileName: string; const Load: boolean): TGraphic;
const
  cGraphicClasses: array[0..5] of TGraphicClass = (TJPEGImage, TPngImage, TGIFImage, TBitmap, TMetafile, TWICImage);
var
  GC: TGraphicClass;
  Masks: TArray<string>;
  Mask: string;
begin
  Result := nil;
  for GC in cGraphicClasses do begin
    Masks := GraphicFileMask(GC).Split([';']);
    for Mask in Masks do begin
      if MatchesMask(FileName, Mask) then begin
        try
          Result := GC.Create;
          if Load then
            Result.LoadFromFile(FileName);
          Exit;
        except
          if Assigned(Result) then
            FreeAndNil(Result);
          // ignore error, just try the next one
        end;
      end;
    end {for Mask};
  end {for GC};
end {CreateGraphicFromFile};

{ ------------------------------------------------------------------------------------------------ }
procedure TfrmMain.ProcessPamphlet;
var
  Buffer: array[0..1023] of Char;
  BufferSize: integer;
  i: Integer;
  Shortcut: TShortcut;
  Renderer: TRenderer;
begin
  Caption := FSentinel.ThisPath + ' - ' + Application.Title;

  if frmInfoSentinel.Visible then
    frmInfoSentinel.Populate(FSentinel);

  // process shortcut keys
................................................................................
    end {if};
  end {if};

  tbcPreview.Tabs[tbcPreview.TabIndex] := ExtractFileName(FSentinel.ThisPath);

  pnlError.Hide;
  try




    Renderer := FEngineManager.ShowFile(FSentinel.ThisPath);
    if Assigned(Renderer) and frmInfo.Visible then begin
      frmInfo.StartPopulatingLines(FEngineManager.Filename, True);
      try
        Renderer.PopulateInfo(frmInfo);
      finally
        frmInfo.StopPopulatingLines;
      end;
    end;

    {$MESSAGE WARN 'TODO: Rewrite this, harness the new preview engine structure  MCO 10-02-2015'}
    pnlPluginParent.Show;
    if Assigned(FWlxPlugin) then begin
      if FWlxPlugin.LoadedFilename = '' then begin
        pnlPluginParent.Visible := 0 <> FWlxPlugin.Load(FSentinel.ThisPath, 0);
      end else if not SameFileName(FSentinel.ThisPath, FWlxPlugin.LoadedFilename) then begin
................................................................................
    MessageBeep(MB_ICONERROR);
    BufferSize := ExceptionErrorMessage(ExceptObject, ExceptAddr, Buffer, Length(Buffer));
    lblError.Caption := Copy(Buffer, 1, BufferSize);
    lblError.Font.Color := clRed;
    pnlError.Show;
  end;
end {TfrmMain.DoRefresh};




















{ ------------------------------------------------------------------------------------------------ }
procedure TfrmMain.pnlErrorDblClick(Sender: TObject);
begin
  pnlError.Hide;
end;








>







 







>
>







>













|
>

<
>













>





>







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







 







<
<

|
<
<
<
<
<
<
<
<


<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







<







 







>
>
>
>
|
<
<
<
<
<
<
<
<







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
..
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83

84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
...
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
...
339
340
341
342
343
344
345


346
347








348
349





























350
351
352
353
354
355
356

357
358
359
360
361
362
363
...
390
391
392
393
394
395
396
397
398
399
400
401








402
403
404
405
406
407
408
...
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
    actFileExit: TFileExit;
    actWindowMinimize: TAction;
    pnlRight: TPanel;
    actPreviewEngine: TAction;
    actEngineManage: TAction;
    actEngineAutoselect: TAction;
    actFileProperties: TAction;
    sbrMain: TStatusBar;
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
    procedure ApplicationException(Sender: TObject; E: Exception);
    procedure actAutoRefreshExecute(Sender: TObject);
    procedure actRefreshExecute(Sender: TObject);
    procedure actViewSentinelExecute(Sender: TObject);
................................................................................
    procedure actFileLoadPluginAccept(Sender: TObject);
    procedure actViewTopmostUpdate(Sender: TObject);
    procedure actViewTopmostExecute(Sender: TObject);
    procedure actWindowMinimizeExecute(Sender: TObject);
    procedure actPreviewEngineExecute(Sender: TObject);
    procedure actEngineAutoselectExecute(Sender: TObject);
    procedure actFilePropertiesExecute(Sender: TObject);
    procedure EngineManagerRendererSelected(Sender: TObject);
    procedure sbrMainDrawPanel(StatusBar: TStatusBar; Panel: TStatusPanel; const Rect: TRect);
  private
    { Private declarations }
//    FWatcher: TThread;
    FInitialized: Boolean;
    FEngineManager: TPreviewEngineUIManager;

    FWlxPlugin: TWlxPluginWrapper;
    FFileIconBitmap: TBitmap;

    procedure LoadSentinel;
    procedure ProcessPamphlet;
  public
    { Public declarations }
    FSentinel: TZaapSentinelFile;
  end;

var
  frmMain: TfrmMain;

implementation
uses
  System.IOUtils, System.Types, System.Masks, System.Generics.Defaults,
  Winapi.PsApi, Winapi.ShellAPI,
  Vcl.Imaging.GIFImg, Vcl.Imaging.jpeg, Vcl.Imaging.pngimage,

  U_ShellItemImage,
  F_Sentinel, F_Info;

{$R *.dfm}


{ ------------------------------------------------------------------------------------------------ }
procedure TfrmMain.FormCreate(Sender: TObject);
begin
  Application.OnException := ApplicationException;

  FEngineManager := TPreviewEngineUIManager.Create(ActionManager,
                                                   tbcPreview,
                                                   actPreviewEngine);
  FEngineManager.OnRendererSelected := EngineManagerRendererSelected;
end {TfrmMain.FormCreate};

{ ------------------------------------------------------------------------------------------------ }
procedure TfrmMain.FormDestroy(Sender: TObject);
begin
  FFileIconBitmap.Free;
  if Assigned(FWlxPlugin) then
    FWlxPlugin.Free;
  FSentinel.Free;

  FEngineManager.Free;
end {TfrmMain.FormDestroy};

................................................................................
procedure TfrmMain.ApplicationException(Sender: TObject; E: Exception);
begin
  MessageBeep(MB_ICONERROR);
  lblError.Caption := E.Message;
  lblError.Font.Color := clRed;
  pnlError.Show;
end {TfrmMain.ApplicationException};

{ ------------------------------------------------------------------------------------------------ }
procedure TfrmMain.EngineManagerRendererSelected(Sender: TObject);
var
  Renderer: TRenderer;
  Summary: string;
begin
  Renderer := FEngineManager.SelectedRenderer;
  if Assigned(Renderer) then begin
    sbrMain.Panels[1].Text := Renderer.DisplayName + ' (' + Renderer.Form.Caption + ')';
    Summary := Renderer.SummarizeInfo;
    if Summary = #0 then begin
      sbrMain.Panels[2].Text := '';
      sbrMain.Panels[2].Bevel := pbNone;
    end else begin
      sbrMain.Panels[2].Text := Summary;
      sbrMain.Panels[2].Bevel := pbLowered;
    end;
  end else begin
    sbrMain.Panels[1].Text := '(no preview engine)';
    sbrMain.Panels[2].Bevel := pbNone;
  end;

  if frmInfo.Visible then begin
    frmInfo.StartPopulatingLines(FEngineManager.Filename, True);
    try
      if Assigned(Renderer) then
        Renderer.PopulateInfo(frmInfo);
    finally
      frmInfo.StopPopulatingLines;
    end;
  end;
end {TfrmMain.EngineManagerRendererSelected};

{ ------------------------------------------------------------------------------------------------ }
procedure TfrmMain.LoadSentinel;
var
  Sentinels: TStringDynArray;
  SentinelFile: string;
begin
................................................................................
    {$MESSAGE HINT 'TODO: Make this behaviour optional?  MCO 13-02-2015'}
    Self.WindowState := wsMinimized;
  end;
end {TfrmMain.actFilePropertiesExecute};

{ ------------------------------------------------------------------------------------------------ }
procedure TfrmMain.actPreviewEngineExecute(Sender: TObject);


begin
  FEngineManager.NextRenderer;








end {TfrmMain.actPreviewEngineExecute};






























{ ------------------------------------------------------------------------------------------------ }
procedure TfrmMain.ProcessPamphlet;
var
  Buffer: array[0..1023] of Char;
  BufferSize: integer;
  i: Integer;
  Shortcut: TShortcut;

begin
  Caption := FSentinel.ThisPath + ' - ' + Application.Title;

  if frmInfoSentinel.Visible then
    frmInfoSentinel.Populate(FSentinel);

  // process shortcut keys
................................................................................
    end {if};
  end {if};

  tbcPreview.Tabs[tbcPreview.TabIndex] := ExtractFileName(FSentinel.ThisPath);

  pnlError.Hide;
  try
    {$MESSAGE WARN 'TODO: only when the file name changes!'}
    FreeAndNil(FFileIconBitmap);
    sbrMain.Invalidate;

    FEngineManager.ShowFile(FSentinel.ThisPath);









    {$MESSAGE WARN 'TODO: Rewrite this, harness the new preview engine structure  MCO 10-02-2015'}
    pnlPluginParent.Show;
    if Assigned(FWlxPlugin) then begin
      if FWlxPlugin.LoadedFilename = '' then begin
        pnlPluginParent.Visible := 0 <> FWlxPlugin.Load(FSentinel.ThisPath, 0);
      end else if not SameFileName(FSentinel.ThisPath, FWlxPlugin.LoadedFilename) then begin
................................................................................
    MessageBeep(MB_ICONERROR);
    BufferSize := ExceptionErrorMessage(ExceptObject, ExceptAddr, Buffer, Length(Buffer));
    lblError.Caption := Copy(Buffer, 1, BufferSize);
    lblError.Font.Color := clRed;
    pnlError.Show;
  end;
end {TfrmMain.DoRefresh};

{ ------------------------------------------------------------------------------------------------ }
procedure TfrmMain.sbrMainDrawPanel(StatusBar: TStatusBar; Panel: TStatusPanel; const Rect: TRect);
begin
  if Panel.Text = '(icon)' then begin
    if (FFileIconBitmap = nil) and (FSentinel <> nil) then begin
      FFileIconBitmap := U_ShellItemImage.GetFileIcon(FSentinel.ThisPath, Rect.Width, Rect.Height);
      FFileIconBitmap.Transparent := False;
    end;
    StatusBar.Canvas.Lock;
    try
      StatusBar.Canvas.FillRect(Rect);
      if FFileIconBitmap <> nil then
        StatusBar.Canvas.StretchDraw(Rect, FFileIconBitmap);
    finally
      StatusBar.Canvas.Unlock;
    end;
  end;
end {TfrmMain.sbrMainDrawPanel};

{ ------------------------------------------------------------------------------------------------ }
procedure TfrmMain.pnlErrorDblClick(Sender: TObject);
begin
  pnlError.Hide;
end;

Changes to ZPreview/src/Delphi/F_PE_FreeImage.pas.

41
42
43
44
45
46
47

48
49
50
51
52
53
54
55

56
57
58
59
60
61
62
..
85
86
87
88
89
90
91












92
93
94
95
96
97
98
...
227
228
229
230
231
232
233

234
235
236
237
238
239
240
...
296
297
298
299
300
301
302














303
304
305
306
307
308
309
310
type
  { ------------------------------------------------------------------------------------------------ }
  TFreeImageRenderer = class(TRenderer)
  public
    constructor Create(const Parent: TCustomPreviewEngineForm);
    function  CouldShowFile(const FileName: string): boolean; override;
    function  TryShowFile(const FileName: string): boolean; override;

    procedure PopulateInfo(const Lines: IInfoLineDisplayer); override;
  end {TFreeImageRenderer};

  { ------------------------------------------------------------------------------------------------ }
  TFreeImageMultiRenderer = class(TFreeImageRenderer)
  public
//    function  CouldShowFile(const FileName: string): boolean; override;
//    function  TryShowFile(const FileName: string): boolean; override;

//    procedure PopulateInfo(const Lines: IInfoLineDisplayer); override;
  end {TFreeImageRenderer};



{ ================================================================================================ }
{ TFreeImageRenderer }
................................................................................
  {$MESSAGE WARN 'TFreeImageRenderer.TryShowFile'}
  FIB := TFreeWinBitmap.Create;
  Result := FIB.LoadU(FileName);
  if Result then begin
    TfrmPEFreeImage(Self.Form).FreeBitmap := FIB;
  end;
end {TFreeImageRenderer.TryShowFile};













{ ------------------------------------------------------------------------------------------------ }
procedure TFreeImageRenderer.PopulateInfo(const Lines: IInfoLineDisplayer);
const
  scColorType: array[FIC_MINISWHITE..FIC_CMYK] of string =
              ( 'min value is white'                  // FIC_MINISWHITE
              , 'min value is black'                  // FIC_MINISBLACK
................................................................................
destructor TfrmPEFreeImage.Destroy;
var
  i: integer;
begin
  try
    for i := High(FEngines) downto Low(FEngines) do
      FreeAndNil(FEngines[i]);

  finally
    inherited;
  end;
end {TfrmPEFreeImage.Destroy};

{ ------------------------------------------------------------------------------------------------ }
procedure TfrmPEFreeImage.Clear;
................................................................................
  pbxPreview.Canvas.Lock;
  try
    FFreeBitmap.Draw(pbxPreview.Canvas.Handle, R);
  finally
    pbxPreview.Canvas.Unlock;
  end;
end {TfrmPEFreeImage.pbxPreviewPaint};

















////////////////////////////////////////////////////////////////////////////////////////////////////
initialization
  TCustomPreviewEngineForm.RegisterForm(TfrmPEFreeImage);

end.







>






|

>







 







>
>
>
>
>
>
>
>
>
>
>
>







 







>







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>








41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
..
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
...
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
...
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
type
  { ------------------------------------------------------------------------------------------------ }
  TFreeImageRenderer = class(TRenderer)
  public
    constructor Create(const Parent: TCustomPreviewEngineForm);
    function  CouldShowFile(const FileName: string): boolean; override;
    function  TryShowFile(const FileName: string): boolean; override;
    function  SummarizeInfo: string; override;
    procedure PopulateInfo(const Lines: IInfoLineDisplayer); override;
  end {TFreeImageRenderer};

  { ------------------------------------------------------------------------------------------------ }
  TFreeImageMultiRenderer = class(TFreeImageRenderer)
  public
    function  CouldShowFile(const FileName: string): boolean; override;
//    function  TryShowFile(const FileName: string): boolean; override;
//    function  SummarizeInfo: string; override;
//    procedure PopulateInfo(const Lines: IInfoLineDisplayer); override;
  end {TFreeImageRenderer};



{ ================================================================================================ }
{ TFreeImageRenderer }
................................................................................
  {$MESSAGE WARN 'TFreeImageRenderer.TryShowFile'}
  FIB := TFreeWinBitmap.Create;
  Result := FIB.LoadU(FileName);
  if Result then begin
    TfrmPEFreeImage(Self.Form).FreeBitmap := FIB;
  end;
end {TFreeImageRenderer.TryShowFile};

{ ------------------------------------------------------------------------------------------------ }
function TFreeImageRenderer.SummarizeInfo: string;
var
  FIB: TFreeWinBitmap;
begin
  Result := '';
  FIB := TfrmPEFreeImage(Self.Form).FreeBitmap;
  if Assigned(FIB) and FIB.IsValid then begin
    Result := Format('%d x %d', [FIB.GetWidth, FIB.GetHeight]);
  end;
end {TFreeImageRenderer.SummarizeInfo};

{ ------------------------------------------------------------------------------------------------ }
procedure TFreeImageRenderer.PopulateInfo(const Lines: IInfoLineDisplayer);
const
  scColorType: array[FIC_MINISWHITE..FIC_CMYK] of string =
              ( 'min value is white'                  // FIC_MINISWHITE
              , 'min value is black'                  // FIC_MINISBLACK
................................................................................
destructor TfrmPEFreeImage.Destroy;
var
  i: integer;
begin
  try
    for i := High(FEngines) downto Low(FEngines) do
      FreeAndNil(FEngines[i]);
    FFreeBitmap.Free;
  finally
    inherited;
  end;
end {TfrmPEFreeImage.Destroy};

{ ------------------------------------------------------------------------------------------------ }
procedure TfrmPEFreeImage.Clear;
................................................................................
  pbxPreview.Canvas.Lock;
  try
    FFreeBitmap.Draw(pbxPreview.Canvas.Handle, R);
  finally
    pbxPreview.Canvas.Unlock;
  end;
end {TfrmPEFreeImage.pbxPreviewPaint};


{ ================================================================================================ }
{ TFreeImageMultiRenderer }

{ ------------------------------------------------------------------------------------------------ }
function TFreeImageMultiRenderer.CouldShowFile(const FileName: string): boolean;
var
  fif: FREE_IMAGE_FORMAT;
begin
  fif := FreeImage_GetFIFFromFilenameU(PWideChar(FileName));
  Result := (fif in [FIF_TIFF, FIF_ICO, FIF_GIF]) and FreeImage_FIFSupportsReading(FIF);
end {TFreeImageMultiRenderer.CouldShowFile};




////////////////////////////////////////////////////////////////////////////////////////////////////
initialization
  TCustomPreviewEngineForm.RegisterForm(TfrmPEFreeImage);

end.

Changes to ZPreview/src/Delphi/F_PE_Graphics.pas.

42
43
44
45
46
47
48

49
50
51
52
53
54
55
...
150
151
152
153
154
155
156

















157
158
159
160
161
162
163
...
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
  private
    FGraphicClass: TGraphicClass;
  public
    constructor Create(const Parent: TCustomPreviewEngineForm;
                       const GraphicClass: TGraphicClass);
    function  CouldShowFile(const FileName: string): boolean; override;
    function  TryShowFile(const FileName: string): boolean; override;

    procedure PopulateInfo(const Lines: IInfoLineDisplayer); override;
  end {TGraphicRenderer};

  { ------------------------------------------------------------------------------------------------ }
  TWICRenderer = class(TGraphicRenderer)
  public
    constructor Create(const Parent: TCustomPreviewEngineForm);
................................................................................
        Graphic := nil;
      end;
    end {with};
  finally
    G.Free;
  end;
end {TGraphicPreviewEngine.TryShowFile};


















{ ------------------------------------------------------------------------------------------------ }
procedure TGraphicRenderer.PopulateInfo(const Lines: IInfoLineDisplayer);
const
  scGIFVersions: array[TGIFVersion] of string = ('Unknown', '87a', '89a');
  scJPEGPixelFormats: array[TJPEGPixelFormat] of string = ('24-bits', '8-bits');
  scWICImageFormats: array[TWICImageFormat] of string = ('BMP', 'PNG', 'JPEG', 'GIF', 'TIFF', 'WMPhoto', '(other)');
................................................................................
  end else if G is TWICImage then begin
    Group := 'Windows Imaging Component';
    Lines.Add(Group, 'Image format', Ord(TWICImage(G).ImageFormat), scWICImageFormats);
    Lines.Add(Group, 'Encoder container format', GUIDToString(TWICImage(G).EncoderContainerFormat));

  end;
end {TGraphicPreviewEngine.PopulateInfo};


{ ================================================================================================ }
{ TWICPreviewEngine }

{ ------------------------------------------------------------------------------------------------ }
class constructor TWICRenderer.Create;
begin







>







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







 







<







42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
...
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
...
246
247
248
249
250
251
252

253
254
255
256
257
258
259
  private
    FGraphicClass: TGraphicClass;
  public
    constructor Create(const Parent: TCustomPreviewEngineForm;
                       const GraphicClass: TGraphicClass);
    function  CouldShowFile(const FileName: string): boolean; override;
    function  TryShowFile(const FileName: string): boolean; override;
    function  SummarizeInfo: string; override;
    procedure PopulateInfo(const Lines: IInfoLineDisplayer); override;
  end {TGraphicRenderer};

  { ------------------------------------------------------------------------------------------------ }
  TWICRenderer = class(TGraphicRenderer)
  public
    constructor Create(const Parent: TCustomPreviewEngineForm);
................................................................................
        Graphic := nil;
      end;
    end {with};
  finally
    G.Free;
  end;
end {TGraphicPreviewEngine.TryShowFile};

{ ------------------------------------------------------------------------------------------------ }
function TGraphicRenderer.SummarizeInfo: string;
var
  G: TGraphic;
begin
  G := TfrmPEGraphics(Form).imgPreview.Picture.Graphic;
  if G = nil then begin
    Result := '';
  end else begin
    Result := Format('%d x %d', [G.Width, G.Height]);
    if G is TGIFImage then begin
      if TGIFImage(G).Images.Count > 1 then
        Result := Result + Format('; %d frames', [TGIFImage(G).Images.Count]);
    end;
  end;
end {TGraphicRenderer.SummarizeInfo};

{ ------------------------------------------------------------------------------------------------ }
procedure TGraphicRenderer.PopulateInfo(const Lines: IInfoLineDisplayer);
const
  scGIFVersions: array[TGIFVersion] of string = ('Unknown', '87a', '89a');
  scJPEGPixelFormats: array[TJPEGPixelFormat] of string = ('24-bits', '8-bits');
  scWICImageFormats: array[TWICImageFormat] of string = ('BMP', 'PNG', 'JPEG', 'GIF', 'TIFF', 'WMPhoto', '(other)');
................................................................................
  end else if G is TWICImage then begin
    Group := 'Windows Imaging Component';
    Lines.Add(Group, 'Image format', Ord(TWICImage(G).ImageFormat), scWICImageFormats);
    Lines.Add(Group, 'Encoder container format', GUIDToString(TWICImage(G).EncoderContainerFormat));

  end;
end {TGraphicPreviewEngine.PopulateInfo};


{ ================================================================================================ }
{ TWICPreviewEngine }

{ ------------------------------------------------------------------------------------------------ }
class constructor TWICRenderer.Create;
begin

Changes to ZPreview/src/Delphi/M_Main.dfm.

3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
...
675
676
677
678
679
680
681
682



683

  Height = 405
  Width = 473
  object imlMain: TImageList
    ColorDepth = cd32Bit
    Left = 115
    Top = 118
    Bitmap = {
      494C010111001500080010001000FFFFFFFF2110FFFFFFFFFFFFFFFF424D3600
      0000000000003600000028000000400000005000000001002000000000000050
      0000000000000000000000000000000000000000000000000000000000000000
      0000000000000000000000000000000000000000000000000000000000000000
      0000000000000000000000000000000000000000000000000000000000000000
      0000000000000000000000000000000000000000000000000000000000000000
      0000000000000000000000000000000000000000000000000000000000000000
      0000000000000000000000000000000000000000000000000000000000000000
................................................................................
      000000000000}
  end
  object tmrStart: TTimer
    Interval = 250
    OnTimer = tmrStartTimer
    Left = 208
    Top = 120
  end



end








|







 








>
>
>
|
>
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
...
675
676
677
678
679
680
681
682
683
684
685
686
687
  Height = 405
  Width = 473
  object imlMain: TImageList
    ColorDepth = cd32Bit
    Left = 115
    Top = 118
    Bitmap = {
      494C0101110015000C0010001000FFFFFFFF2110FFFFFFFFFFFFFFFF424D3600
      0000000000003600000028000000400000005000000001002000000000000050
      0000000000000000000000000000000000000000000000000000000000000000
      0000000000000000000000000000000000000000000000000000000000000000
      0000000000000000000000000000000000000000000000000000000000000000
      0000000000000000000000000000000000000000000000000000000000000000
      0000000000000000000000000000000000000000000000000000000000000000
      0000000000000000000000000000000000000000000000000000000000000000
................................................................................
      000000000000}
  end
  object tmrStart: TTimer
    Interval = 250
    OnTimer = tmrStartTimer
    Left = 208
    Top = 120
  end
  object imlFileIcons: TImageList
    Left = 112
    Top = 168
  end
end

Changes to ZPreview/src/Delphi/M_Main.pas.

8
9
10
11
12
13
14

15
16
17
18
19
20
21
  Vcl.ActnMan, Vcl.ExtCtrls,
  U_PreviewEngine;

type
  TmodMain = class(TDataModule)
    imlMain: TImageList;
    tmrStart: TTimer;

    procedure tmrStartTimer(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;








>







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
  Vcl.ActnMan, Vcl.ExtCtrls,
  U_PreviewEngine;

type
  TmodMain = class(TDataModule)
    imlMain: TImageList;
    tmrStart: TTimer;
    imlFileIcons: TImageList;
    procedure tmrStartTimer(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

Changes to ZPreview/src/Delphi/U_PreviewEngine.pas.

30
31
32
33
34
35
36

37
38
39
40
41
42
43
...
164
165
166
167
168
169
170





171
172
173
  public
    constructor Create(const Parent: TCustomPreviewEngineForm;
                       const Name: string = '');

    function  CouldShowFile(const FileName: string): boolean; virtual; abstract;
    function  TryShowFile(const FileName: string): boolean; virtual; abstract;
    procedure PopulateInfo(const IInfoLines: IInfoLineDisplayer); virtual; abstract;


    property Form: TCustomPreviewEngineForm read FParent;
    property Name: string                   read FName;
    property DisplayName: string            read FDisplayName write FDisplayName;
  end {TPreviewEngine};


................................................................................
  if Name <> '' then
    FName := Name
  else
    FName := Self.ClassName;
  FDisplayName := FName;
end {TPreviewEngine.Create};








end.







>







 







>
>
>
>
>

<

30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
...
165
166
167
168
169
170
171
172
173
174
175
176
177

178
  public
    constructor Create(const Parent: TCustomPreviewEngineForm;
                       const Name: string = '');

    function  CouldShowFile(const FileName: string): boolean; virtual; abstract;
    function  TryShowFile(const FileName: string): boolean; virtual; abstract;
    procedure PopulateInfo(const IInfoLines: IInfoLineDisplayer); virtual; abstract;
    function  SummarizeInfo: string; virtual;

    property Form: TCustomPreviewEngineForm read FParent;
    property Name: string                   read FName;
    property DisplayName: string            read FDisplayName write FDisplayName;
  end {TPreviewEngine};


................................................................................
  if Name <> '' then
    FName := Name
  else
    FName := Self.ClassName;
  FDisplayName := FName;
end {TPreviewEngine.Create};

{ ------------------------------------------------------------------------------------------------ }
function TRenderer.SummarizeInfo: string;
begin
  Result := #0;
end {TRenderer.SummarizeInfo};


end.

Changes to ZPreview/src/Delphi/U_PreviewEngineUIManager.pas.

1
2
3
4
5
6
7
8
9
10
11
12
13
..
18
19
20
21
22
23
24


25
26
27
28
29
30
31
32
33


34
35
36
37
38
39
40
41
42
43
44
45
46
47


48
49
50
51
52
53
54
55
56
57
58
59
60
..
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
...
288
289
290
291
292
293
294
295
296







297
298
299
300
301
302
303
unit U_PreviewEngineUIManager;

interface

uses
  System.Generics.Collections,
  Vcl.Controls, Vcl.ActnMan, Vcl.ActnList,
  U_PreviewEngine;

type
  TPreviewEngineUIManager = class
  private
    FActionMgr: TActionManager;
................................................................................
    FEngineSelectors: TDictionary<TCustomPreviewEngineForm,TAction>;
    FRendererSelectors: TDictionary<TRenderer,TAction>;
    FEngineEnablers: TDictionary<TCustomPreviewEngineForm,TAction>;

    FFileName: string;
    FSelectedRenderer: TRenderer;



    procedure InitializeEngines;
    procedure InitializeUI;

    procedure actSelectEngineExecute(Sender: TObject);
    procedure actSelectRendererExecute(Sender: TObject);
    procedure actSelectRendererUpdate(Sender: TObject);
    procedure actEnableEngineExecute(Sender: TObject);

    procedure SetSelectedRenderer(const Value: TRenderer);


  public
    constructor Create(const ActionManager: TActionManager;
                       const PreviewContainer: TWinControl;
                       const ActionPreviewEngine: TAction);
    destructor  Destroy; override;

    function ShowFile(const FileName: string): TRenderer;
    function NextRenderer: TRenderer;

    property ActionManager: TActionManager  read FActionMgr;
    property Container: TWinControl         read FContainer;

    property Filename: string               read FFileName;
    property SelectedRenderer: TRenderer    read FSelectedRenderer;


  end;

implementation

uses
  System.SysUtils, System.Classes, System.Generics.Defaults,
  Winapi.Windows,
  Vcl.Forms, Vcl.Graphics;

{ ================================================================================================ }
{ TUIPreviewEngineManager }

{ ------------------------------------------------------------------------------------------------ }
................................................................................

{ ------------------------------------------------------------------------------------------------ }
procedure TPreviewEngineUIManager.InitializeEngines;
var
  FormClass: TCustomPreviewEngineFormClass;
  Form: TCustomPreviewEngineForm;
begin
  FEngineForms := TObjectList<TCustomPreviewEngineForm>.Create(TComparer<TCustomPreviewEngineForm>.Construct(
                      function(const Left, Right: TCustomPreviewEngineForm): integer
                      begin
                        {$MESSAGE HINT 'TODO: sort engine forms -- MCO 2015-02-09'}
                        // TODO: look 'em up in some list, then base their order on that list.
                        // TODO: if they don't occur in the list, move them to the end
                        Result := 0;
                      end));
  for FormClass in TCustomPreviewEngineFormClass.RegisteredForms do begin
    Form := FormClass.Create(nil);
    Form.Parent := FContainer;
    Form.Align := alClient;
    Form.BorderStyle := bsNone;
    Form.Enabled := True; // TODO: read from ini or something
    Form.Color := clWindow;
................................................................................
  // Update the menu item for the renderer
  actSelectRenderer := FRendererSelectors.Items[Value];
  ActionManager.FindItemByAction(actSelectRenderer).Default := True;

  FActionPreviewEngine.Hint := Format('%1:s (%0:s)', [Value.Form.Caption, Value.DisplayName]);
  FActionPreviewEngine.ImageIndex := actSelectEngine.ImageIndex;

  {$MESSAGE HINT 'TODO: raise an event, so the info can be populated'}
end {TUIPreviewEngineManager.SetSelectedRenderer};








{ ------------------------------------------------------------------------------------------------ }
procedure TPreviewEngineUIManager.actEnableEngineExecute(Sender: TObject);
var
  actEnableEngine: TAction;
  Form: TCustomPreviewEngineForm;
  Renderer: TRenderer;





|







 







>
>









>
>









|
|

|
|
>
>





|







 







|
|
|
|
|
|
|
|







 







|

>
>
>
>
>
>
>







1
2
3
4
5
6
7
8
9
10
11
12
13
..
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
..
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
...
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
unit U_PreviewEngineUIManager;

interface

uses
  System.Classes, System.Generics.Collections,
  Vcl.Controls, Vcl.ActnMan, Vcl.ActnList,
  U_PreviewEngine;

type
  TPreviewEngineUIManager = class
  private
    FActionMgr: TActionManager;
................................................................................
    FEngineSelectors: TDictionary<TCustomPreviewEngineForm,TAction>;
    FRendererSelectors: TDictionary<TRenderer,TAction>;
    FEngineEnablers: TDictionary<TCustomPreviewEngineForm,TAction>;

    FFileName: string;
    FSelectedRenderer: TRenderer;

    FOnRendererSelected: TNotifyEvent;

    procedure InitializeEngines;
    procedure InitializeUI;

    procedure actSelectEngineExecute(Sender: TObject);
    procedure actSelectRendererExecute(Sender: TObject);
    procedure actSelectRendererUpdate(Sender: TObject);
    procedure actEnableEngineExecute(Sender: TObject);

    procedure SetSelectedRenderer(const Value: TRenderer);
  protected
    procedure DoRendererSelected;
  public
    constructor Create(const ActionManager: TActionManager;
                       const PreviewContainer: TWinControl;
                       const ActionPreviewEngine: TAction);
    destructor  Destroy; override;

    function ShowFile(const FileName: string): TRenderer;
    function NextRenderer: TRenderer;

    property ActionManager: TActionManager    read FActionMgr;
    property Container: TWinControl           read FContainer;

    property Filename: string                 read FFileName;
    property SelectedRenderer: TRenderer      read FSelectedRenderer;

    property OnRendererSelected: TNotifyEvent read FOnRendererSelected  write FOnRendererSelected;
  end;

implementation

uses
  System.SysUtils, System.Generics.Defaults,
  Winapi.Windows,
  Vcl.Forms, Vcl.Graphics;

{ ================================================================================================ }
{ TUIPreviewEngineManager }

{ ------------------------------------------------------------------------------------------------ }
................................................................................

{ ------------------------------------------------------------------------------------------------ }
procedure TPreviewEngineUIManager.InitializeEngines;
var
  FormClass: TCustomPreviewEngineFormClass;
  Form: TCustomPreviewEngineForm;
begin
//  FEngineForms := TObjectList<TCustomPreviewEngineForm>.Create(TComparer<TCustomPreviewEngineForm>.Construct(
//                      function(const Left, Right: TCustomPreviewEngineForm): integer
//                      begin
//                        {$MESSAGE HINT 'TODO: sort engine forms -- MCO 2015-02-09'}
//                        // TODO: look 'em up in some list, then base their order on that list.
//                        // TODO: if they don't occur in the list, move them to the end
//                        Result := 0;
//                      end));
  for FormClass in TCustomPreviewEngineFormClass.RegisteredForms do begin
    Form := FormClass.Create(nil);
    Form.Parent := FContainer;
    Form.Align := alClient;
    Form.BorderStyle := bsNone;
    Form.Enabled := True; // TODO: read from ini or something
    Form.Color := clWindow;
................................................................................
  // Update the menu item for the renderer
  actSelectRenderer := FRendererSelectors.Items[Value];
  ActionManager.FindItemByAction(actSelectRenderer).Default := True;

  FActionPreviewEngine.Hint := Format('%1:s (%0:s)', [Value.Form.Caption, Value.DisplayName]);
  FActionPreviewEngine.ImageIndex := actSelectEngine.ImageIndex;

  DoRendererSelected;
end {TUIPreviewEngineManager.SetSelectedRenderer};

{ ------------------------------------------------------------------------------------------------ }
procedure TPreviewEngineUIManager.DoRendererSelected;
begin
  if Assigned(FOnRendererSelected) then
    FOnRendererSelected(Self);
end {TPreviewEngineUIManager.DoRendererSelected};

{ ------------------------------------------------------------------------------------------------ }
procedure TPreviewEngineUIManager.actEnableEngineExecute(Sender: TObject);
var
  actEnableEngine: TAction;
  Form: TCustomPreviewEngineForm;
  Renderer: TRenderer;

Changes to ZPreview/src/Delphi/ZPreview.dpr.

6
7
8
9
10
11
12

13
14
15
16
17
18
19
20
21
  F_Sentinel in 'F_Sentinel.pas' {frmInfoSentinel},
  F_Info in 'F_Info.pas' {frmInfo},
  M_Main in 'M_Main.pas' {modMain: TDataModule};

{$R *.res}

begin

  Application.Initialize;
  Application.MainFormOnTaskbar := True;
  Application.Title := 'ZPreview';
  Application.CreateForm(TmodMain, modMain);
  Application.CreateForm(TfrmMain, frmMain);
  Application.CreateForm(TfrmInfoSentinel, frmInfoSentinel);
  Application.CreateForm(TfrmInfo, frmInfo);
  Application.Run;
end.







>









6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
  F_Sentinel in 'F_Sentinel.pas' {frmInfoSentinel},
  F_Info in 'F_Info.pas' {frmInfo},
  M_Main in 'M_Main.pas' {modMain: TDataModule};

{$R *.res}

begin
  ReportMemoryLeaksOnShutdown := True;
  Application.Initialize;
  Application.MainFormOnTaskbar := True;
  Application.Title := 'ZPreview';
  Application.CreateForm(TmodMain, modMain);
  Application.CreateForm(TfrmMain, frmMain);
  Application.CreateForm(TfrmInfoSentinel, frmInfoSentinel);
  Application.CreateForm(TfrmInfo, frmInfo);
  Application.Run;
end.