Menu

[r736]: / trunk / Src / USaveSourceDlg.pas  Maximize  Restore  History

Download this file

551 lines (489 with data), 19.9 kB

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 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
 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
112
113
114
115
116
117
118
119
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
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
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
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
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
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
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
{
* USaveSourceDlg.pas
*
* Implements customised Save dialog box for source code. Dialog has additional
* controls to allow user to choose output file format, commenting style and
* syntax highlighting.
*
* Unit originally named USaveSnippetDlg.pas. Renamed as USaveSourceDlg.pas as
* at v1.1.
*
* $Rev$
* $Date$
*
* ***** BEGIN LICENSE BLOCK *****
*
* Version: MPL 1.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
* the specific language governing rights and limitations under the License.
*
* The Original Code is USaveSourceDlg.pas
*
* The Initial Developer of the Original Code is Peter Johnson
* (http://www.delphidabbler.com/).
*
* Portions created by the Initial Developer are Copyright (C) 2005-2010 Peter
* Johnson. All Rights Reserved.
*
* Contributor(s)
* NONE
*
* ***** END LICENSE BLOCK *****
}
unit USaveSourceDlg;
interface
uses
// Delphi
Classes, StdCtrls, ExtCtrls,
// Project
USaveDialogEx, USourceGen;
type
{
THiliteQuery:
Type of handler for event triggered by TSaveSourceDlg to check if a file
type supports syntax highlighting.
@param Sender [in] TSaveSourceDlg dialog object triggering event.
@param Ext [in] Extension of file type being checked.
@param CanHilite [in/out] Flag that handler sets true if syntax
highlighting supported (default value is False).
}
THiliteQuery = procedure(Sender: TObject; const Ext: string;
var CanHilite: Boolean) of object;
{
TSaveSourceDlg:
Extended save dialog box used when saving code snippets. It displays
additional controls used to specify attributes of source code. Requires
SAVESNIPPETEXT dialog resource. Dialog also adjusts any file name entered
without extension to include extension associated with any current filter.
}
TSaveSourceDlg = class(TSaveDialogEx)
strict private
fPanel: TPanel; // Panel thats hold controls added to dialog
fLblCommentStyle: TLabel; // Label for comment style combo
fCmbCommentStyle: TComboBox; // Combo box used to select commenting style
fChkSyntaxHilite: TCheckBox; // Check box that toggles syntax highlighting
fHelpBtn: TButton; // Help button added to dialog
fPreviewBtn: TButton; // Preview button added to dialog
fCommentStyle: TCommentStyle; // Style of commenting to be used source code
fOnPreview: TNotifyEvent; // Event handler for OnPreview event
fOnHiliteQuery: THiliteQuery; // Event handler for OnHiliteQuery event
fUseSyntaxHiliting: Boolean; // Flags whether source is syntax highlighted
fSelectedFilterIdx: Integer; // Store index of selected file type.
procedure HelpClickHandler(Sender: TObject);
{Handles click on help button. Calls help with required keyword.
@param Sender [in] Not used.
}
procedure PreviewClickHandler(Sender: TObject);
{Handles click on preview button. Updates properties then triggers
dialog's OnPreview event.
@param Sender [in] Not used.
}
procedure SetOnPreview(const Value: TNotifyEvent);
{Write accessor for OnPreview event. Enables / disables preview button
depending on if event handler assigned.
@param Value [in] Required event handler.
}
procedure UpdateSyntaxHiliting;
{Updates value of UseSyntaxHiliting property per state of dialog box
controls.
}
procedure UpdateCommentStyle;
{Selects appropriate item in comment style combo box per current comment
style property.
}
procedure CommentStyleChange(Sender: TObject);
{Comment style combo box OnChange event handler. Updates CommentStyle
property.
@param Sender [in] Not used.
}
function GetSelectedExt: string;
{Read accessor for SelectedExt property. Extracts extension for selected
file type from Filter property.
@return Selected extension with leading '.'.
}
function AdjustFileName(const AFileName: string): string;
{Adjusts any file name supplied without an extension by appending
extension associated with the currently selected file type. If the file
has an extension or if the file type is *.* then the file name is not
changed.
@param AFileName [in] File name to be adjusted.
@return Adjusted file name.
}
function GetFilterIndex: Integer;
{Gets index of selected filter.
@return Selected filter index.
}
procedure SetFilterIndex(const Value: Integer);
{Records index of selected file filter.
@param Value [in] New value of selected file filter.
}
strict protected
procedure DoClose; override;
{Tidies up and sets properties from controls when dialog is about to
close.
}
function DoCanClose: Boolean; override;
{Called to check if dialog can close. We check for existing file (after
adding required extension) and inhibit closure if file exists and user
doesn't want to overwrite.
@return True if dialog can close and false otherwise.
}
procedure DoShow; override;
{Sets up dialog just before it is displayed.
}
procedure DoTypeChange; override;
{Notifies when a different file type is selected in file type combo box.
Checks if syntax highlighting supported for selected file type.
}
public
constructor Create(AOwner: TComponent); override;
{Class constructor. Creates dialog box and adds custom controls to it.
@param AOwner [in] Owning component. Dialog box will be aligned over
AOwner.
}
function Execute: Boolean; override;
{Displays dialog box. Sets required dialog box template if new style
dialogs being used. Adjusts any extension-less file name to have extension
of selected file type.
@return True if user OKs and false if cancels.
}
property SelectedExt: string
read GetSelectedExt;
{Extension relating to selected file type}
published
property CommentStyle: TCommentStyle
read fCommentStyle write fCommentStyle;
{Commenting style selected in dialog box. Determines default comment style
selection in dialog box when set}
property UseSyntaxHiliting: Boolean
read fUseSyntaxHiliting write fUseSyntaxHiliting;
{Flag true if syntax highlighting is to be used when saving / previewing
the source code. This is case when check box is checked and selected file
type supports highlighting. Set the property to check the box}
property OnPreview: TNotifyEvent
read fOnPreview write SetOnPreview;
{Event triggered when preview button clicked. Handlers should display file
that will be generated when Save button is clicked}
property OnHiliteQuery: THiliteQuery
read fOnHiliteQuery write fOnHiliteQuery;
{Event triggered when a file type is selected. Handlers should determine
if the file type supports syntax highlighting}
property FilterIndex: Integer read GetFilterIndex write SetFilterIndex;
{Re-implementation of inherited property. Used to overcome apparent bug
where property forgets selected filter when dialog box is closed}
end;
implementation
uses
// Delphi
SysUtils, Forms, Dialogs, Dlgs, Controls, Windows,
// Project
UConsts, UMessageBox, UOpenDialogHelper, UStructs;
resourcestring
// Component captions
sLblCommentStyle = 'Comment style:';
sChkSyntaxHilite = 'Use syntax highlighting';
sBtnPreview = '&Preview...';
sBtnHelp = '&Help';
const
// Name of dialog box template resource ** do not localise
cTemplateName = 'SAVESNIPPETEXT';
{ TSaveSourceDlg }
function TSaveSourceDlg.AdjustFileName(const AFileName: string): string;
{Adjusts any file name supplied without an extension by appending extension
associated with the currently selected file type. If the file has an extension
or if the file type is *.* then the file name is not changed.
@param AFileName [in] File name to be adjusted.
@return Adjusted file name.
}
begin
Result := AFileName;
if ExtractFileExt(Result) = '' then
begin
if SelectedExt <> '.*' then
Result := Result + SelectedExt;
end;
end;
procedure TSaveSourceDlg.CommentStyleChange(Sender: TObject);
{Comment style combo box OnChange event handler. Updates CommentStyle
property.
@param Sender [in] Not used.
}
begin
fCommentStyle := TCommentStyle(
fCmbCommentStyle.Items.Objects[fCmbCommentStyle.ItemIndex]
);
end;
constructor TSaveSourceDlg.Create(AOwner: TComponent);
{Class constructor. Creates dialog box and adds custom controls to it.
@param AOwner [in] Owning component. Dialog box will be aligned over AOwner.
}
begin
inherited Create(AOwner);
// Create additional controls
// (Order of creation is important - tab order is reverse of creation order)
// panel that stores all extra controls
fPanel := TPanel.Create(Self);
fPanel.Caption := '';
fPanel.BevelOuter := bvNone;
fPanel.TabStop := True;
// custom help button
fHelpBtn := TButton.Create(Self);
fHelpBtn.Parent := fPanel;
fHelpBtn.OnClick := HelpClickHandler;
// preview button
fPreviewBtn := TButton.Create(Self);
fPreviewBtn.Parent := fPanel;
fPreviewBtn.OnClick := PreviewClickHandler;
// label for comment style combo
fLblCommentStyle := TLabel.Create(Self);
fLblCommentStyle.Parent := fPanel;
fLblCommentStyle.Caption := sLblCommentStyle;
// combo box used to select commenting style
fCmbCommentStyle := TComboBox.Create(Self);
fCmbCommentStyle.Parent := fPanel;
fCmbCommentStyle.Style := csDropDownList;
fCmbCommentStyle.OnChange := CommentStyleChange;
// check box used to determine whether to use syntax highlighting
fChkSyntaxHilite := TCheckBox.Create(Self);
fChkSyntaxHilite.Parent := fPanel;
fChkSyntaxHilite.Caption := sChkSyntaxHilite;
// Set dialog box properties
// set default button values and states
SetOnPreview(nil); // updates state of preview button
// set dialog options
Options := [ofPathMustExist, ofEnableIncludeNotify];
// inhibit default help processing: we provide own help button and handling
WantDefaultHelpSupport := False;
end;
function TSaveSourceDlg.DoCanClose: Boolean;
{Called to check if dialog can close. We check for existing file (after adding
required extension) and inhibit closure if file exists and user doesn't want
to overwrite.
@return True if dialog can close and false otherwise.
}
// ---------------------------------------------------------------------------
function QueryOverwrite(const FileName: string): Boolean;
{Displays a dialog box asking permission to overwrite a file.
@param FileName [in] Name of file to be overwritten.
@return True if user agrees that file can be overwritten, false if not.
}
resourcestring
// Text of query displayed in dialog box
sQueryMsg = '%s already exists.' + EOL + 'Do you want to replace it?';
begin
Result := TMessageBox.Confirm(Self, Format(sQueryMsg, [FileName]));
end;
// ---------------------------------------------------------------------------
var
AFileName: string; // Current file name, adjusted to ensure it has extension
begin
// Check if user wants to inhibit closure by triggering OnCanClose event
Result := inherited DoCanClose;
if not Result then
Exit;
// Ask user for permission to overwrite any existing file
AFileName := AdjustFileName(FileOpenEditedFileName(Self));
if FileExists(AFileName) and not QueryOverwrite(AFileName) then
Result := False;
end;
procedure TSaveSourceDlg.DoClose;
{Tidies up and sets properties from controls when dialog is about to close.
}
begin
// Update value of SyntaxHiliting property
UpdateSyntaxHiliting;
inherited DoClose;
// Hide any hint left on screen
Application.HideHint;
end;
procedure TSaveSourceDlg.DoShow;
{Sets up dialog just before it is displayed.
}
// ---------------------------------------------------------------------------
function GetDlgCtrlRect(CtrlID: Integer): TRect;
{Get bounding rectangle of control with given id.
@return Bounding rectangle.
}
begin
// Get bounds in screen co-ords (controls are children of parent window)
GetWindowRect(GetDlgItem(GetParent(Handle), CtrlID), Result);
// Map co-ords to this window
MapWindowPoints(0, Handle, Result, 2);
end;
// ---------------------------------------------------------------------------
var
FileTypeCmbBounds: TRectEx; // bounds of dlg's filetype combo box
FileTypeLblBounds: TRect; // bounds of dlg's filetype label
ButtonBounds: TRect; // bounds of one of dlg's buttons
StaticBounds: TRect; // bounds of dlg's hidden ctrl (per dlg resource)
PanelBounds: TRect; // bounds of panel we add to dlg
CSIdx: TCommentStyle; // loops thru comment styles
begin
// Get bounding rectangle of various dialog box controls
// bounds of hidden static text control per our custom dialog resource
StaticBounds := inherited GetStaticRect;
// bounds of file type combo and associated text (used to align added ctrls)
FileTypeCmbBounds := GetDlgCtrlRect(cmb1);
FileTypeLblBounds := GetDlgCtrlRect(stc2);
// bounds of OK button (used to size buttons we add)
ButtonBounds := GetDlgCtrlRect(IDOK);
// Set up TPanel that holds all newly added controls
GetClientRect(Handle, PanelBounds); // first size to whole client area
PanelBounds.Top := StaticBounds.Bottom; // set top to below hidden ctrl
fPanel.BoundsRect := PanelBounds;
fPanel.ParentWindow := Handle; // make dlg parent of panel
// Align syntax highlight check box file type combo
fChkSyntaxHilite.Left := FileTypeCmbBounds.Left;
fChkSyntaxHilite.Top := 0;
fChkSyntaxHilite.Width := FileTypeCmbBounds.Width;
fChkSyntaxHilite.Checked := fUseSyntaxHiliting;
// Size and align comment style combo box with file type combo box
fCmbCommentStyle.Left := FileTypeCmbBounds.Left;
fCmbCommentStyle.Top := fChkSyntaxHilite.Top + fChkSyntaxHilite.Height + 6;
fCmbCommentStyle.Width := FileTypeCmbBounds.Width;
// Set up combo box text (can't be done in constructor since a parent window
// is required and host panel doesn't have one at that point)
if fCmbCommentStyle.Items.Count = 0 then
begin
// Populate comment style combo
for CSIdx := Low(TCommentStyle) to High(TCommentStyle) do
fCmbCommentStyle.Items.AddObject(
TSourceComments.CommentStyleDesc(CSIdx), TObject(CSIdx)
);
end;
UpdateCommentStyle;
// Align comment style label within group box
fLblCommentStyle.Left := FileTypeLblBounds.Left;
fLblCommentStyle.Top := fCmbCommentStyle.Top +
(fCmbCommentStyle.Height - fLblCommentStyle.Height) div 2;
// Size preview button and align under above buttons
fPreviewBtn.BoundsRect := ButtonBounds;
fPreviewBtn.Top := 0;
fPreviewBtn.Caption := sBtnPreview;
// Size help button, enable/disable as required & align under preview buttons
fHelpBtn.BoundsRect := ButtonBounds;
fHelpBtn.Top := fPreviewBtn.Top + fPreviewBtn.Height + 6;
fHelpBtn.Caption := sBtnHelp;
fHelpBtn.Enabled := (HelpKeyword <> '');
// Call this to ensure we trigger type change event for default file type
DoTypeChange;
inherited;
end;
procedure TSaveSourceDlg.DoTypeChange;
{Notifies when a different file type is selected in file type combo box.
Checks if syntax highlighting supported for selected file type.
}
var
CanHilite: Boolean; // flag true if syntax highlighting supported
begin
// Assume highlighting not supported
CanHilite := False;
// Trigger event where user specifies if highlighting supported
if Assigned(fOnHiliteQuery) then
fOnHiliteQuery(Self, SelectedExt, CanHilite);
// Enable / disable highlighting check box as required
fChkSyntaxHilite.Enabled := CanHilite;
fSelectedFilterIdx := inherited FilterIndex;
inherited;
end;
function TSaveSourceDlg.Execute: Boolean;
{Displays dialog box. Sets required dialog box template if new style dialogs
being used. Adjusts any extension-less file name to have extension of selected
file type.
@return True if user OKs and false if cancels.
}
begin
// Set up template for customisation
if NewStyleControls and not (ofOldStyleDialog in Options) then
Template := cTemplateName
else
Template := nil;
// Display dialog box
Result := inherited Execute;
if Result then
// Adjust file name, adding any missing extension
FileName := AdjustFileName(FileName);
end;
function TSaveSourceDlg.GetFilterIndex: Integer;
{Gets index of selected filter.
@return Selected filter index.
}
begin
if Handle <> 0 then
// dialog box is open: use inherited FilterIndex property
Result := inherited FilterIndex
else
// dialog box is closed: use recorded index to overcome apparent bug
Result := fSelectedFilterIdx;
end;
function TSaveSourceDlg.GetSelectedExt: string;
{Read accessor for SelectedExt property. Extracts extension for selected file
type from Filter property.
@return Selected extension with leading '.'.
}
begin
Result := FilterIndexToExt(Self);
end;
procedure TSaveSourceDlg.HelpClickHandler(Sender: TObject);
{Handles click on help button. Calls help with required keyword.
@param Sender [in] Not used.
}
begin
DisplayHelp;
end;
procedure TSaveSourceDlg.PreviewClickHandler(Sender: TObject);
{Handles click on preview button. Updates properties then triggers OnPreview
event.
@param Sender [in] Not used.
}
begin
UpdateSyntaxHiliting;
if Assigned(fOnPreview) then
fOnPreview(Self);
end;
procedure TSaveSourceDlg.SetFilterIndex(const Value: Integer);
{Records index of selected file filter.
@param Value [in] New value of selected file filter.
}
begin
// record index in inherited property
inherited FilterIndex := Value;
// also record filter in own field: used to overcome apparent bug
fSelectedFilterIdx := Value;
end;
procedure TSaveSourceDlg.SetOnPreview(const Value: TNotifyEvent);
{Write accessor for OnPreview event. Enables / disables preview button
depending on if event handler assigned.
@param Value [in] Required event handler.
}
begin
fOnPreview := Value;
fPreviewBtn.Enabled := Assigned(Value);
end;
procedure TSaveSourceDlg.UpdateCommentStyle;
{Selects appropriate item in comment style combo box per current comment style
property.
}
var
Idx: Integer; // loops thru combo box items
begin
for Idx := 0 to Pred(fCmbCommentStyle.Items.Count) do
begin
// comment style stored in Objects[] property
if TCommentStyle(fCmbCommentStyle.Items.Objects[Idx]) = fCommentStyle then
fCmbCommentStyle.ItemIndex := Idx;
end;
end;
procedure TSaveSourceDlg.UpdateSyntaxHiliting;
{Updates value of UseSyntaxHiliting property per state of dialog box controls.
}
begin
fUseSyntaxHiliting := fChkSyntaxHilite.Checked;
end;
end.
Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.