Skip to content

Commit 0265ec0

Browse files
committed
Add feature to save snippet info to RTF file
Added new USaveInfoMgr unit to handle getting file name from user, generating the RTF from a given snippet's information and saving to file. Added new File | Save Snippet Information menu option and associated action to the main form.
1 parent 9998f4e commit 0265ec0

File tree

5 files changed

+166
-4
lines changed

5 files changed

+166
-4
lines changed

Src/CodeSnip.dpr

+2-1
Original file line numberDiff line numberDiff line change
@@ -374,7 +374,8 @@ uses
374374
Compilers.USettings in 'Compilers.USettings.pas',
375375
FmRegisterCompilersDlg in 'FmRegisterCompilersDlg.pas' {RegisterCompilersDlg},
376376
ClassHelpers.UGraphics in 'ClassHelpers.UGraphics.pas',
377-
ClassHelpers.UActions in 'ClassHelpers.UActions.pas';
377+
ClassHelpers.UActions in 'ClassHelpers.UActions.pas',
378+
USaveInfoMgr in 'USaveInfoMgr.pas';
378379

379380
// Include resources
380381
{$Resource ExternalObj.tlb} // Type library file

Src/CodeSnip.dproj

+1
Original file line numberDiff line numberDiff line change
@@ -581,6 +581,7 @@
581581
</DCCReference>
582582
<DCCReference Include="ClassHelpers.UGraphics.pas"/>
583583
<DCCReference Include="ClassHelpers.UActions.pas"/>
584+
<DCCReference Include="USaveInfoMgr.pas"/>
584585
<None Include="CodeSnip.todo"/>
585586
<BuildConfiguration Include="Base">
586587
<Key>Base</Key>

Src/FmMain.dfm

+13
Original file line numberDiff line numberDiff line change
@@ -877,6 +877,16 @@ inherited MainForm: TMainForm
877877
OnExecute = actDeleteUserDatabaseExecute
878878
OnUpdate = ActNonEmptyUserDBUpdate
879879
end
880+
object actSaveInfo: TAction
881+
Category = 'File'
882+
Caption = 'Save Snippet Information...'
883+
Hint =
884+
'Save snippet information|Save information about the selected sni' +
885+
'ppet to file'
886+
ShortCut = 24649
887+
OnExecute = actSaveInfoExecute
888+
OnUpdate = actSaveInfoUpdate
889+
end
880890
end
881891
object mnuMain: TMainMenu
882892
Images = ilMain
@@ -887,6 +897,9 @@ inherited MainForm: TMainForm
887897
object miSaveSnippet: TMenuItem
888898
Action = actSaveSnippet
889899
end
900+
object miSaveInfo: TMenuItem
901+
Action = actSaveInfo
902+
end
890903
object miSaveUnit: TMenuItem
891904
Action = actSaveUnit
892905
end

Src/FmMain.pas

+18-3
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,8 @@ TMainForm = class(THelpAwareForm)
241241
tbSpacer7: TToolButton;
242242
tbSpacer8: TToolButton;
243243
tbTestCompile: TToolButton;
244+
miSaveInfo: TMenuItem;
245+
actSaveInfo: TAction;
244246
/// <summary>Displays About Box.</summary>
245247
procedure actAboutExecute(Sender: TObject);
246248
/// <summary>Gets a new category from user and adds to database.</summary>
@@ -501,6 +503,8 @@ TMainForm = class(THelpAwareForm)
501503
procedure splitVertCanResize(Sender: TObject; var NewSize: Integer;
502504
var Accept: Boolean);
503505
procedure ActNonEmptyUserDBUpdate(Sender: TObject);
506+
procedure actSaveInfoUpdate(Sender: TObject);
507+
procedure actSaveInfoExecute(Sender: TObject);
504508
strict private
505509
var
506510
/// <summary>Object that notifies user-initiated events by triggering
@@ -596,9 +600,9 @@ implementation
596600
UCodeShareMgr, UCommandBars, UConsts, UCopyInfoMgr,
597601
UCopySourceMgr, UDatabaseLoader, UDatabaseLoaderUI, UDetailTabAction,
598602
UEditSnippetAction, UExceptions, UHelpMgr, UHistoryMenus, UKeysHelper,
599-
UMessageBox, UNotifier, UNulDropTarget, UPrintMgr, UQuery, USaveSnippetMgr,
600-
USaveUnitMgr, USelectionIOMgr, UUrl, UUserDBMgr, UView, UViewItemAction,
601-
UWBExternal;
603+
UMessageBox, UNotifier, UNulDropTarget, UPrintMgr, UQuery, USaveInfoMgr,
604+
USaveSnippetMgr, USaveUnitMgr, USelectionIOMgr, UUrl, UUserDBMgr, UView,
605+
UViewItemAction, UWBExternal;
602606

603607

604608
{$R *.dfm}
@@ -1025,6 +1029,17 @@ procedure TMainForm.actSaveDatabaseUpdate(Sender: TObject);
10251029
(Sender as TAction).Enabled := TUserDBMgr.CanSave;
10261030
end;
10271031

1032+
procedure TMainForm.actSaveInfoExecute(Sender: TObject);
1033+
begin
1034+
TSaveInfoMgr.Execute(fMainDisplayMgr.CurrentView);
1035+
end;
1036+
1037+
procedure TMainForm.actSaveInfoUpdate(Sender: TObject);
1038+
begin
1039+
(Sender as TAction).Enabled :=
1040+
TSaveInfoMgr.CanHandleView(fMainDisplayMgr.CurrentView);
1041+
end;
1042+
10281043
procedure TMainForm.actSaveSelectionExecute(Sender: TObject);
10291044
begin
10301045
TSelectionIOMgr.SaveCurrentSelection;

Src/USaveInfoMgr.pas

+132
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
{
2+
* This Source Code Form is subject to the terms of the Mozilla Public License,
3+
* v. 2.0. If a copy of the MPL was not distributed with this file, You can
4+
* obtain one at https://mozilla.org/MPL/2.0/
5+
*
6+
* Copyright (C) 2025, Peter Johnson (gravatar.com/delphidabbler).
7+
*
8+
* Saves information about a snippet to disk in rich text format. Only routine
9+
* snippet kinds are supported.
10+
}
11+
12+
13+
unit USaveInfoMgr;
14+
15+
interface
16+
17+
uses
18+
// Project
19+
UEncodings,
20+
UView;
21+
22+
23+
type
24+
/// <summary>Method-only record that saves information about a snippet to
25+
/// file in rich text format. The snippet is obtained from a view. Only
26+
/// snippet views are supported.</summary>
27+
TSaveInfoMgr = record
28+
strict private
29+
/// <summary>Attempts to name of the file to be written from the user.
30+
/// </summary>
31+
/// <param name="AFileName"><c>string</c> [out] Set to the name of the file
32+
/// entered by the user. Undefined if the user cancelled.</param>
33+
/// <returns><c>Boolean</c>. <c>True</c> if the user entered and accepted a
34+
/// file name of <c>False</c> if the user cancelled.</returns>
35+
class function TryGetFileNameFromUser(out AFileName: string): Boolean;
36+
static;
37+
/// <summary>Returns encoded data containing a RTF representation of
38+
/// information about the snippet represented by the given view.</summary>
39+
class function GenerateRichText(View: IView): TEncodedData; static;
40+
public
41+
/// <summary>Saves information about the snippet referenced by the a given
42+
/// view to file.</summary>
43+
/// <remarks>The view must be a snippet view.</remarks>
44+
class procedure Execute(View: IView); static;
45+
/// <summary>Checks if a given view can be saved to the clipboard. Returns
46+
/// True only if the view represents a snippet.</summary>
47+
class function CanHandleView(View: IView): Boolean; static;
48+
49+
end;
50+
51+
implementation
52+
53+
uses
54+
// Delphi
55+
SysUtils,
56+
Dialogs,
57+
// Project
58+
Hiliter.UAttrs,
59+
Hiliter.UGlobals,
60+
UIOUtils,
61+
UOpenDialogHelper,
62+
URTFSnippetDoc,
63+
URTFUtils,
64+
USaveDialogEx;
65+
66+
{ TSaveInfoMgr }
67+
68+
class function TSaveInfoMgr.CanHandleView(View: IView): Boolean;
69+
begin
70+
Result := Supports(View, ISnippetView);
71+
end;
72+
73+
class procedure TSaveInfoMgr.Execute(View: IView);
74+
var
75+
FileName: string;
76+
RTF: TRTF;
77+
begin
78+
Assert(Assigned(View), 'TSaveInfoMgr.Execute: View is nil');
79+
Assert(CanHandleView(View), 'TSaveInfoMgr.Execute: View not supported');
80+
if not TryGetFileNameFromUser(FileName) then
81+
Exit;
82+
RTF := TRTF.Create(GenerateRichText(View));
83+
TFileIO.WriteAllBytes(FileName, RTF.ToBytes);
84+
end;
85+
86+
class function TSaveInfoMgr.GenerateRichText(View: IView): TEncodedData;
87+
var
88+
Doc: TRTFSnippetDoc; // object that generates RTF document
89+
HiliteAttrs: IHiliteAttrs; // syntax highlighter formatting attributes
90+
begin
91+
Assert(Supports(View, ISnippetView),
92+
'TSaveInfoMgr.GenerateRichText: View is not a snippet view');
93+
if (View as ISnippetView).Snippet.HiliteSource then
94+
HiliteAttrs := THiliteAttrsFactory.CreateUserAttrs
95+
else
96+
HiliteAttrs := THiliteAttrsFactory.CreateNulAttrs;
97+
Doc := TRTFSnippetDoc.Create(HiliteAttrs);
98+
try
99+
// TRTFSnippetDoc generates stream of ASCII bytes
100+
Result := Doc.Generate((View as ISnippetView).Snippet);
101+
Assert(Result.EncodingType = etASCII,
102+
'TSaveInfoMgr.GenerateRichText: ASCII encoded data expected');
103+
finally
104+
Doc.Free;
105+
end;
106+
end;
107+
108+
class function TSaveInfoMgr.TryGetFileNameFromUser(
109+
out AFileName: string): Boolean;
110+
var
111+
Dlg: TSaveDialogEx;
112+
resourcestring
113+
sCaption = 'Save Snippet Information'; // dialogue box caption
114+
sFilter = 'Rich Text File (*.rtf)|*.rtf|' // file filter
115+
+ 'All files (*.*)|*.*';
116+
begin
117+
Dlg := TSaveDialogEx.Create(nil);
118+
try
119+
Dlg.Title := sCaption;
120+
Dlg.Options := [ofShowHelp, ofNoTestFileCreate, ofEnableSizing];
121+
Dlg.Filter := sFilter;
122+
Dlg.FilterIndex := 1;
123+
Dlg.HelpKeyword := 'SnippetInfoFileDlg';
124+
Result := Dlg.Execute;
125+
if Result then
126+
AFileName := FileOpenFileNameWithExt(Dlg)
127+
finally
128+
Dlg.Free;
129+
end;
130+
end;
131+
132+
end.

0 commit comments

Comments
 (0)