@@ -16,34 +16,94 @@ interface
1616
1717uses
1818 // Project
19+ UBaseObjects,
1920 UEncodings,
21+ USaveSourceDlg,
22+ USourceFileInfo,
2023 UView;
2124
2225
2326type
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
27+ // / <summary>Class that saves information about a snippet to file a user
28+ // / specified format. The snippet is obtained from a view. Only snippet views
29+ // / are supported.</summary>
30+ TSaveInfoMgr = class (TNoPublicConstructObject)
2831 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;
32+ var
33+ fView: IView;
34+ fSaveDlg: TSaveSourceDlg;
35+ fSourceFileInfo: TSourceFileInfo;
36+
3737 // / <summary>Returns encoded data containing a RTF representation of
3838 // / information about the snippet represented by the given view.</summary>
39- class function GenerateRichText (View : IView): TEncodedData; static;
39+ class function GenerateRichText (View : IView; const AUseHiliting: Boolean):
40+ TEncodedData; static;
41+
42+ // / <summary>Returns encoded data containing a plain text representation of
43+ // / information about the snippet represented by the given view.</summary>
44+ function GeneratePlainText : TEncodedData;
45+
46+ // / <summary>Returns type of file selected in the associated save dialogue
47+ // / box.</summary>
48+ function SelectedFileType : TSourceFileType;
49+
50+ // / <summary>Handles the custom save dialogue's <c>OnPreview</c> event.
51+ // / Displays the required snippet information, appropriately formatted, in
52+ // / a preview dialogues box.</summary>
53+ // / <param name="Sender"><c>TObject</c> [in] Reference to the object that
54+ // / triggered the event.</param>
55+ procedure PreviewHandler (Sender: TObject);
56+
57+ // / <summary>Handles the custom save dialogue's <c>OnHiliteQuery</c> event.
58+ // / Determines whether syntax highlighting is supported for the source code
59+ // / section of the required snippet information..</summary>
60+ // / <param name="Sender"><c>TObject</c> [in] Reference to the object that
61+ // / triggered the event.</param>
62+ // / <param name="CanHilite"><c>Boolean</c> [in/out] Set to <c>False</c>
63+ // / when called. Should be set to <c>True</c> iff highlighting is
64+ // / supported.</param>
65+ procedure HighlightQueryHandler (Sender: TObject; var CanHilite: Boolean);
66+
67+ // / <summary>Handles the custom save dialogue's <c>OnEncodingQuery</c>
68+ // / event.</summary>
69+ // / <param name="Sender"><c>TObject</c> [in] Reference to the object that
70+ // / triggered the event.</param>
71+ // / <param name="Encodings"><c>TSourceFileEncodings</c> [in/out] Called
72+ // / with an empty array which the event handler must be set to contain the
73+ // / encodings supported by the currently selected file type.</param>
74+ procedure EncodingQueryHandler (Sender: TObject;
75+ var Encodings: TSourceFileEncodings);
76+
77+ // / <summary>Generates the required snippet information in the requested
78+ // / format.</summary>
79+ // / <param name="FileType"><c>TSourceFileType</c> [in] Type of file to be
80+ // / generated.</param>
81+ // / <returns><c>TEncodedData</c>. The formatted snippet information, syntax
82+ // / highlighted if required.</returns>
83+ function GenerateOutput (const FileType: TSourceFileType): TEncodedData;
84+
85+ // / <summary>Displays the save dialogue box and creates required type of
86+ // / snippet information file if the user OKs.</summary>
87+ procedure DoExecute ;
88+
89+ strict protected
90+
91+ // / <summary>Internal constructor. Initialises managed save source dialogue
92+ // / box and records information about supported file types.</summary>
93+ constructor InternalCreate(AView: IView);
94+
4095 public
96+
97+ // / <summary>Object descructor. Tears down object.</summary>
98+ destructor Destroy; override;
99+
41100 // / <summary>Saves information about the snippet referenced by the a given
42101 // / view to file.</summary>
43102 // / <remarks>The view must be a snippet view.</remarks>
44103 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>
104+
105+ // / <summary>Checks if the given view can be saved to file. Returns
106+ // / <c>True</c> if the view represents a snippet.</summary>
47107 class function CanHandleView (View : IView): Boolean; static;
48108
49109 end ;
@@ -55,13 +115,17 @@ implementation
55115 SysUtils,
56116 Dialogs,
57117 // Project
118+ FmPreviewDlg,
58119 Hiliter.UAttrs,
120+ Hiliter.UFileHiliter,
59121 Hiliter.UGlobals,
60122 UIOUtils,
61123 UOpenDialogHelper,
124+ UPreferences,
62125 URTFSnippetDoc,
63126 URTFUtils,
64- USaveDialogEx;
127+ USourceGen,
128+ UTextSnippetDoc;
65129
66130{ TSaveInfoMgr }
67131
@@ -70,27 +134,101 @@ class function TSaveInfoMgr.CanHandleView(View: IView): Boolean;
70134 Result := Supports(View , ISnippetView);
71135end ;
72136
137+ destructor TSaveInfoMgr.Destroy;
138+ begin
139+ fSourceFileInfo.Free;
140+ fSaveDlg.Free;
141+ inherited ;
142+ end ;
143+
144+ procedure TSaveInfoMgr.DoExecute ;
145+ var
146+ Encoding: TEncoding; // encoding to use for output file
147+ FileContent: string; // output file content before encoding
148+ FileType: TSourceFileType; // type of source file
149+ begin
150+ // Set up dialog box
151+ fSaveDlg.Filter := fSourceFileInfo.FilterString;
152+ fSaveDlg.FilterIndex := FilterDescToIndex(
153+ fSaveDlg.Filter,
154+ fSourceFileInfo.FileTypeInfo[Preferences.SourceDefaultFileType].DisplayName,
155+ 1
156+ );
157+ fSaveDlg.FileName := fSourceFileInfo.DefaultFileName;
158+ // Display dialog box and save file if user OKs
159+ if fSaveDlg.Execute then
160+ begin
161+ FileType := SelectedFileType;
162+ FileContent := GenerateOutput(FileType).ToString;
163+ Encoding := TEncodingHelper.GetEncoding(fSaveDlg.SelectedEncoding);
164+ try
165+ FileContent := GenerateOutput(FileType).ToString;
166+ TFileIO.WriteAllText(fSaveDlg.FileName, FileContent, Encoding, True);
167+ finally
168+ TEncodingHelper.FreeEncoding(Encoding);
169+ end ;
170+ end ;
171+ end ;
172+
173+ procedure TSaveInfoMgr.EncodingQueryHandler (Sender: TObject;
174+ var Encodings: TSourceFileEncodings);
175+ begin
176+ Encodings := fSourceFileInfo.FileTypeInfo[SelectedFileType].Encodings;
177+ end ;
178+
73179class procedure TSaveInfoMgr.Execute (View : IView);
74180var
75- FileName: string;
76- RTFMarkup: TRTFMarkup;
181+ Instance: TSaveInfoMgr;
77182begin
78183 Assert(Assigned(View ), ' TSaveInfoMgr.Execute: View is nil' );
79184 Assert(CanHandleView(View ), ' TSaveInfoMgr.Execute: View not supported' );
80- if not TryGetFileNameFromUser(FileName) then
81- Exit;
82- RTFMarkup := TRTFMarkup.Create(GenerateRichText(View ));
83- TFileIO.WriteAllBytes(FileName, RTFMarkup.ToBytes);
185+
186+ Instance := TSaveInfoMgr.InternalCreate(View );
187+ try
188+ Instance.DoExecute;
189+ finally
190+ Instance.Free;
191+ end ;
84192end ;
85193
86- class function TSaveInfoMgr.GenerateRichText (View : IView): TEncodedData;
194+ function TSaveInfoMgr.GenerateOutput (const FileType: TSourceFileType):
195+ TEncodedData;
196+ var
197+ UseHiliting: Boolean;
198+ begin
199+ UseHiliting := fSaveDlg.UseSyntaxHiliting and
200+ TFileHiliter.IsHilitingSupported(FileType);
201+ case FileType of
202+ sfRTF: Result := GenerateRichText(fView, UseHiliting);
203+ sfText: Result := GeneratePlainText;
204+ end ;
205+ end ;
206+
207+ function TSaveInfoMgr.GeneratePlainText : TEncodedData;
208+ var
209+ Doc: TTextSnippetDoc; // object that generates RTF document
210+ HiliteAttrs: IHiliteAttrs; // syntax highlighter formatting attributes
211+ begin
212+ Assert(Supports(fView, ISnippetView),
213+ ClassName + ' .GeneratePlainText: View is not a snippet view' );
214+ HiliteAttrs := THiliteAttrsFactory.CreateNulAttrs;
215+ Doc := TTextSnippetDoc.Create;
216+ try
217+ Result := Doc.Generate((fView as ISnippetView).Snippet);
218+ finally
219+ Doc.Free;
220+ end ;
221+ end ;
222+
223+ class function TSaveInfoMgr.GenerateRichText (View : IView;
224+ const AUseHiliting: Boolean): TEncodedData;
87225var
88226 Doc: TRTFSnippetDoc; // object that generates RTF document
89227 HiliteAttrs: IHiliteAttrs; // syntax highlighter formatting attributes
90228begin
91229 Assert(Supports(View , ISnippetView),
92230 ' TSaveInfoMgr.GenerateRichText: View is not a snippet view' );
93- if (View as ISnippetView).Snippet.HiliteSource then
231+ if (View as ISnippetView).Snippet.HiliteSource and AUseHiliting then
94232 HiliteAttrs := THiliteAttrsFactory.CreateUserAttrs
95233 else
96234 HiliteAttrs := THiliteAttrsFactory.CreateNulAttrs;
@@ -105,28 +243,103 @@ class function TSaveInfoMgr.GenerateRichText(View: IView): TEncodedData;
105243 end ;
106244end ;
107245
108- class function TSaveInfoMgr.TryGetFileNameFromUser (
109- out AFileName: string): Boolean;
110- var
111- Dlg: TSaveDialogEx;
246+ procedure TSaveInfoMgr.HighlightQueryHandler (Sender: TObject;
247+ var CanHilite: Boolean);
248+ begin
249+ CanHilite := TFileHiliter.IsHilitingSupported(SelectedFileType);
250+ end ;
251+
252+ constructor TSaveInfoMgr.InternalCreate(AView: IView);
253+ const
254+ DlgHelpKeyword = ' SnippetInfoFileDlg' ;
112255resourcestring
113- sCaption = ' Save Snippet Information' ; // dialogue box caption
114- sFilter = ' Rich Text File (*.rtf)|*.rtf|' // file filter
115- + ' All files (*.*)|*.*' ;
256+ sDefFileName = ' SnippetInfo' ;
257+ sDlgCaption = ' Save Snippet Information' ;
258+ // descriptions of supported encodings
259+ sASCIIEncoding = ' ASCII' ;
260+ sANSIDefaultEncoding = ' ANSI (Default)' ;
261+ sUTF8Encoding = ' UTF-8' ;
262+ sUTF16LEEncoding = ' Unicode (Little Endian)' ;
263+ sUTF16BEEncoding = ' Unicode (Big Endian)' ;
264+ // descriptions of supported file filter strings
265+ sRTFDesc = ' Rich text file' ;
266+ sTextDesc = ' Plain text file' ;
116267begin
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;
268+ inherited InternalCreate;
269+ fView := AView;
270+ fSourceFileInfo := TSourceFileInfo.Create;
271+ // RTF and plain text files supported at present
272+ fSourceFileInfo.FileTypeInfo[sfRTF] := TSourceFileTypeInfo.Create(
273+ ' .rtf' ,
274+ sRTFDesc,
275+ [
276+ TSourceFileEncoding.Create(etASCII, sASCIIEncoding)
277+ ]
278+ );
279+ fSourceFileInfo.FileTypeInfo[sfText] := TSourceFileTypeInfo.Create(
280+ ' .txt' ,
281+ sTextDesc,
282+ [
283+ TSourceFileEncoding.Create(etUTF8, sUTF8Encoding),
284+ TSourceFileEncoding.Create(etUTF16LE, sUTF16LEEncoding),
285+ TSourceFileEncoding.Create(etUTF16BE, sUTF16BEEncoding),
286+ TSourceFileEncoding.Create(etSysDefault, sANSIDefaultEncoding)
287+ ]
288+ );
289+ fSourceFileInfo.DefaultFileName := sDefFileName;
290+
291+ fSaveDlg := TSaveSourceDlg.Create(nil );
292+ fSaveDlg.Title := sDlgCaption;
293+ fSaveDlg.HelpKeyword := DlgHelpKeyword;
294+ fSaveDlg.CommentStyle := TCommentStyle.csNone;
295+ fSaveDlg.EnableCommentStyles := False;
296+ fSaveDlg.TruncateComments := Preferences.TruncateSourceComments;
297+ fSaveDlg.UseSyntaxHiliting := Preferences.SourceSyntaxHilited;
298+ fSaveDlg.OnPreview := PreviewHandler;
299+ fSaveDlg.OnHiliteQuery := HighlightQueryHandler;
300+ fSaveDlg.OnEncodingQuery := EncodingQueryHandler;
301+ end ;
302+
303+ procedure TSaveInfoMgr.PreviewHandler (Sender: TObject);
304+ resourcestring
305+ sDocTitle = ' "%0:s" snippet' ;
306+ var
307+ // Type of snippet information document to preview: this is not always the
308+ // same as the selected file type, because preview dialogue box doesn't
309+ // support some types & we have to use an alternate.
310+ PreviewFileType: TSourceFileType;
311+ // Type of preview document supported by preview dialogue box
312+ PreviewDocType: TPreviewDocType;
313+ begin
314+ case SelectedFileType of
315+ sfRTF:
316+ begin
317+ PreviewDocType := dtRTF;
318+ PreviewFileType := sfRTF;
319+ end ;
320+ sfText:
321+ begin
322+ PreviewDocType := dtPlainText;
323+ PreviewFileType := sfText;
324+ end ;
325+ else
326+ raise Exception.Create(
327+ ClassName + ' .PreviewHandler: unsupported file type'
328+ );
129329 end ;
330+ // Display preview dialog box. We use save dialog as owner to ensure preview
331+ // dialog box is aligned over save dialog box
332+ TPreviewDlg.Execute(
333+ fSaveDlg,
334+ GenerateOutput(PreviewFileType),
335+ PreviewDocType,
336+ Format(sDocTitle, [fView.Description])
337+ );
338+ end ;
339+
340+ function TSaveInfoMgr.SelectedFileType : TSourceFileType;
341+ begin
342+ Result := fSourceFileInfo.FileTypeFromFilterIdx(fSaveDlg.FilterIndex);
130343end ;
131344
132345end .
0 commit comments