lazarus/components/jcf2/Settings/JcfRegistrySettings.pas
2008-12-24 08:43:04 +00:00

645 lines
18 KiB
ObjectPascal

unit JcfRegistrySettings;
{ AFS 2 Jan 2002
Store Gui state in registry
This is not the format options file, that lives in a file so that it can be shared
This registry file is intended to
- tell you where the format options file is
- other GUI config settings that should not be shared, ie
- logging
}
{(*}
(*------------------------------------------------------------------------------
Delphi Code formatter source code
The Original Code is JcfRegistrySettings, released May 2003.
The Initial Developer of the Original Code is Anthony Steele.
Portions created by Anthony Steele are Copyright (C) 1999-2008 Anthony Steele.
All Rights Reserved.
Contributor(s): Anthony Steele.
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/NPL/
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.
Alternatively, the contents of this file may be used under the terms of
the GNU General Public License Version 2 or later (the "GPL")
See http://www.gnu.org/licenses/gpl.html
------------------------------------------------------------------------------*)
{*)}
{$I JcfGlobal.inc}
interface
uses
{ delphi }
Registry, Classes,
{ local }
ConvertTypes;
type
TLogLevel = (eLogErrorsOnly, eLogFiles, eLogTokens);
TLogPlace = (eLogTempDir, eLogAppDIr, eLogSpecifiedDir);
TFormatFileWriteOption = (eAlwaysWrite, eQuietFail, eNeverWrite);
TJCFRegistrySettings = class(TObject)
private
fcReg: TRegIniFile;
fbHasRead: boolean;
{ general settings }
fShowParseTreeOption: TShowParseTreeOption;
{ ui settings }
fsFormatConfigFileName: string;
fbFormatConfigNameSpecified: boolean;
fsLastSettingsPage: string;
feFormatFileWriteOption: TFormatFileWriteOption;
{notepad settings }
fsInputDir: string;
fsOutputDir: string;
{ MRU files settings }
fiMRUMaxItems: integer;
{ log settings }
feLogLevel: TLogLevel;
feLogPlace: TLogPlace;
fsSpecifiedDirectory: string;
fbViewLogAfterRun: boolean;
fbLogTime: boolean;
fbLogStats: boolean;
{ file settings }
feBackupMode: TBackupMode;
feSourceMode: TSourceMode;
fsBackupExtension, fsOutputExtension: string;
fsInput: string;
fcExclusionsFiles: TStringList;
fcExclusionsDirs: TStringList;
fbCheckMultiByteChars: boolean;
{ this is ref not owned }
fcMRUFiles: TStrings;
fbEditorIntegration: boolean;
fbFormatBeforeSave: boolean;
fbFormatAfterLoad: boolean;
procedure ReadMRUFiles;
procedure WriteMRUFiles;
procedure ReadStrings(const psSection, psKey: string; pcStrings: TStrings);
procedure WriteStrings(const psSection, psKey: string; pcStrings: TStrings);
function GetBackupExtension: string;
function GetOutputExtension: string;
public
constructor Create;
destructor Destroy; override;
function CanClearMRU: boolean;
procedure ClearMRU;
procedure ReadAll;
procedure WriteAll;
property HasRead: boolean Read fbHasRead;
{ general settings }
property FormatConfigFileName: string Read fsFormatConfigFileName
Write fsFormatConfigFileName;
property FormatConfigNameSpecified: boolean Read fbFormatConfigNameSpecified;
property FormatFileWriteOption: TFormatFileWriteOption
Read feFormatFileWriteOption Write feFormatFileWriteOption;
{ ui settings }
property ShowParseTreeOption: TShowParseTreeOption
Read fShowParseTreeOption Write fShowParseTreeOption;
property LastSettingsPage: string Read fsLastSettingsPage Write fsLastSettingsPage;
{ notepad settings }
property InputDir: string Read fsInputDir Write fsInputDir;
property OutputDir: string Read fsOutputDir Write fsOutputDir;
{ MRU files settings }
property MRUMaxItems: integer Read fiMRUMaxItems Write fiMRUMaxItems;
property MRUFiles: TStrings Read fcMRUFiles Write fcMRUFiles;
{ log settings }
function LogDirectory: string;
function LogFileName: string;
property LogLevel: TLogLevel Read feLogLevel Write feLogLevel;
property LogPlace: TLogPlace Read feLogPlace Write feLogPlace;
property SpecifiedDirectory: string Read fsSpecifiedDirectory
Write fsSpecifiedDirectory;
property ViewLogAfterRun: boolean Read fbViewLogAfterRun Write fbViewLogAfterRun;
property LogTime: boolean Read fbLogTime Write fbLogTime;
property LogStats: boolean Read fbLogStats Write fbLogStats;
procedure ViewLog;
{ files settings }
property BackupMode: TBackupMode Read feBackupMode Write feBackupMode;
property SourceMode: TSourceMode Read feSourceMode Write feSourceMode;
property BackupExtension: string Read GetBackupExtension Write fsBackupExtension;
property OutputExtension: string Read GetOutputExtension Write fsOutputExtension;
property CheckMultiByteChars: boolean Read fbCheckMultiByteChars
Write fbCheckMultiByteChars;
function GetOutputFileName(const psIn: string): string; overload;
function GetOutputFileName(const psIn: string; peMode: TBackupMode): string;
overload;
function Output: string;
function FileIsExcluded(const psFile: string): boolean;
function DirIsExcluded(const psDir: string): boolean;
property Input: string Read fsInput Write fsInput;
property ExclusionsFiles: TStringList Read fcExclusionsFiles;
property ExclusionsDirs: TStringList Read fcExclusionsDirs;
{ IDE integration settings }
property EditorIntegration: boolean Read fbEditorIntegration
Write fbEditorIntegration;
property FormatBeforeSave: boolean Read fbFormatBeforeSave Write fbFormatBeforeSave;
property FormatAfterLoad: boolean Read fbFormatAfterLoad Write fbFormatAfterLoad;
end;
function GetRegSettings: TJCFRegistrySettings;
implementation
uses
{ delphi }
{$ifndef fpc}Windows,{$endif} SysUtils, Dialogs,
{ jcf }
JcfStringUtils, JcfMiscFunctions;
const
REG_GENERAL_SECTION = 'General';
REG_NOTEPAD_SECTION = 'NotepadSettings';
REG_MRU_FILES_SECTION = 'MRUFiles';
REG_LOG_SECTION = 'Log';
REG_UI_SECTION = 'UI';
REG_FILES_SECTION = 'Files';
REG_IDE_SECTION = 'IDE';
REG_LOG_LEVEL = 'LogLevel';
REG_LOG_PLACE = 'LogPlace';
REG_SPECIFIED_DIRECTORY = 'SpecifiedDirectory';
REG_VIEW_LOG_AFTER_RUN = 'ViewLogAfterRun';
REG_LOG_TIME = 'LogTime';
REG_LOG_STATS = 'LogStats';
REG_LAST_SETTINGS_PAGE = 'LastSettingsPage';
REG_INPUT = 'Input';
REG_BACKUP_MODE = 'BackupMode';
REG_SOURCE_MODE = 'SourceMode';
REG_BACKUP_EXT = 'BackupExt';
REG_OUTPUT_EXT = 'OutputExt';
REG_EXCLUSIONS_FILES = 'ExclusionsFiles';
REG_EXCLUSIONS_DIRS = 'ExclusionsDirs';
REG_CHECK_MULTIBYTE_CHARS = 'CheckMultiByteChars';
REG_EDITOR_INTEGRATION = 'EditorIntegration';
REG_FORMAT_BEFORE_SAVE = 'FormatBeforeSave';
REG_FORMAT_AFTER_LOAD = 'FormatAfterLoad';
{
file-based settings, ie
- read from the settings file if it exists, else use the registry
- always write to the file
}
function GetDefaultSettingsFileName: string;
begin
Result := IncludeTrailingPathDelimiter(GetApplicationFolder) + 'JCFSettings.cfg';
end;
constructor TJCFRegistrySettings.Create;
var
Registry: TRegistry;
begin
inherited;
// Move old registry content to new registry location if applicable
Registry := TRegistry.Create;
try
Registry.Access := KEY_ALL_ACCESS;
Registry.RootKey := HKEY_CURRENT_USER;
if not (Registry.OpenKey(REG_ROOT_KEY, False)) then
begin
if (Registry.OpenKey(OLD_REG_ROOT_KEY, False)) then
begin
Registry.MoveKey(OLD_REG_ROOT_KEY, REG_ROOT_KEY, True);
Registry.CloseKey;
if (Registry.OpenKey('\Software\Jedi', False)) then
begin
if not Registry.HasSubKeys then
begin
Registry.CloseKey;
if (Registry.OpenKey('\Software', False)) then
begin
Registry.DeleteKey('Jedi');
Registry.CloseKey;
end;
end
else
Registry.CloseKey;
end;
end;
end
else
Registry.CloseKey;
finally
Registry.Free;
end;
// New registry location
fcReg := TRegIniFile.Create(REG_ROOT_KEY);
fcExclusionsFiles := TStringList.Create;
fcExclusionsDirs := TStringList.Create;
end;
destructor TJCFRegistrySettings.Destroy;
begin
FreeAndNil(fcExclusionsFiles);
FreeAndNil(fcExclusionsDirs);
FreeAndNil(fcReg);
inherited;
end;
procedure TJCFRegistrySettings.ReadStrings(const psSection, psKey: string;
pcStrings: TStrings);
var
lsKey, lsValue: string;
liCount: integer;
begin
Assert(pcStrings <> nil);
pcStrings.Clear;
liCount := 0;
while True do
begin
lsKey := psKey + IntToStr(liCount);
lsValue := fcReg.ReadString(psSection, lsKey, '');
if lsValue = '' then
break // done
else
pcStrings.Add(lsValue);
Inc(liCount);
end;
end;
procedure TJCFRegistrySettings.WriteStrings(const psSection, psKey: string;
pcStrings: TStrings);
var
lsKey: string;
liLoop: integer;
begin
Assert(pcStrings <> nil);
for liLoop := 0 to pcStrings.Count - 1 do
begin
lsKey := psKey + IntToStr(liLoop);
fcReg.WriteString(psSection, lsKey, pcStrings.Strings[liLoop]);
end;
// null-terminate the list
lsKey := psKey + IntToStr(pcStrings.Count);
fcReg.WriteString(psSection, lsKey, '');
end;
procedure TJCFRegistrySettings.ReadMRUFiles;
var
lcItems: TStringList;
liLoop: integer;
begin
if fcMRUFiles = nil then
exit;
fcMRUFiles.Clear;
lcItems := TStringList.Create;
try
ReadStrings(REG_MRU_FILES_SECTION, 'MRUFile', lcItems);
{ add them in reverse order to work around a bug in TJvMRUManager
where the order reverses every time it is read/written
}
for liLoop := lcItems.Count - 1 downto 0 do
begin
fcMRUFiles.Add(lcItems.Strings[liLoop]);
end;
finally
lcItems.Free;
end;
end;
procedure TJCFRegistrySettings.WriteMRUFiles;
begin
if fcMRUFiles = nil then
exit;
WriteStrings(REG_MRU_FILES_SECTION, 'MRUFile', fcMRUFiles);
end;
procedure TJCFRegistrySettings.ReadAll;
begin
{ general section }
fsFormatConfigFileName := fcReg.ReadString(REG_GENERAL_SECTION,
'FormatConfigFileName', '');
// was a config file specified
fbFormatConfigNameSpecified := (fsFormatConfigFileName <> '');
if not fbFormatConfigNameSpecified then
begin
fsFormatConfigFileName := GetDefaultSettingsFileName;
end;
feFormatFileWriteOption := TFormatFileWriteOption(
fcReg.ReadInteger(REG_GENERAL_SECTION, 'FormatFileWriteOption', Ord(eAlwaysWrite)));
{notepad settings }
InputDir := fcReg.ReadString(REG_NOTEPAD_SECTION, 'InputDir', '');
OutputDir := fcReg.ReadString(REG_NOTEPAD_SECTION, 'OutputDir', '');
{ MRU section }
MRUMaxItems := fcReg.ReadInteger(REG_NOTEPAD_SECTION, 'MRUMaxItems', 6);
ReadMRUFiles;
{ log section }
feLogLevel := TLogLevel(fcReg.ReadInteger(REG_LOG_SECTION, REG_LOG_LEVEL,
Ord(eLogFiles)));
feLogPlace := TLogPlace(fcReg.ReadInteger(REG_LOG_SECTION, REG_LOG_PLACE,
Ord(eLogTempDir)));
fsSpecifiedDirectory := fcReg.ReadString(REG_LOG_SECTION,
REG_SPECIFIED_DIRECTORY, 'c:\');
fbViewLogAfterRun := fcReg.ReadBool(REG_LOG_SECTION, REG_VIEW_LOG_AFTER_RUN, False);
fbLogTime := fcReg.ReadBool(REG_LOG_SECTION, REG_LOG_TIME, False);
fbLogStats := fcReg.ReadBool(REG_LOG_SECTION, REG_LOG_STATS, False);
{ ui }
fsLastSettingsPage := fcReg.ReadString(REG_UI_SECTION, REG_LAST_SETTINGS_PAGE, '');
ShowParseTreeOption := TShowParseTreeOption(
fcReg.ReadInteger(REG_UI_SECTION, 'ParseTreeOption', Ord(eShowOnError)));
{ files}
feBackupMode := TBackupMode(fcReg.ReadInteger(REG_FILES_SECTION,
REG_BACKUP_MODE, Ord(cmSeperateOutput)));
feSourceMode := TSourceMode(fcReg.ReadInteger(REG_FILES_SECTION,
REG_SOURCE_MODE, Ord(fmSingleFile)));
fsInput := fcReg.ReadString(REG_FILES_SECTION, REG_INPUT, '');
fsBackupExtension := fcReg.ReadString(REG_FILES_SECTION, REG_BACKUP_EXT, 'bak');
fsOutputExtension := fcReg.ReadString(REG_FILES_SECTION, REG_OUTPUT_EXT, 'out');
ReadStrings(REG_FILES_SECTION, REG_EXCLUSIONS_FILES, fcExclusionsFiles);
ReadStrings(REG_FILES_SECTION, REG_EXCLUSIONS_DIRS, fcExclusionsDirs);
fbCheckMultiByteChars := fcReg.ReadBool(REG_FILES_SECTION,
REG_CHECK_MULTIBYTE_CHARS, False);
{ IDE }
fbEditorIntegration := fcReg.ReadBool(REG_IDE_SECTION, REG_EDITOR_INTEGRATION, False);
fbFormatBeforeSave := fcReg.ReadBool(REG_IDE_SECTION, REG_FORMAT_BEFORE_SAVE, False);
fbFormatAfterLoad := fcReg.ReadBool(REG_IDE_SECTION, REG_FORMAT_AFTER_LOAD, False);
fbHasRead := True;
end;
procedure TJCFRegistrySettings.WriteAll;
begin
{ general section }
fcReg.WriteString(REG_GENERAL_SECTION, 'FormatConfigFileName', fsFormatConfigFileName);
fcReg.WriteInteger(REG_GENERAL_SECTION, 'FormatFileWriteOption',
Ord(feFormatFileWriteOption));
{ notepad section }
fcReg.WriteString(REG_NOTEPAD_SECTION, 'InputDir', InputDir);
fcReg.WriteString(REG_NOTEPAD_SECTION, 'OutputDir', OutputDir);
{ mru section}
fcReg.WriteInteger(REG_MRU_FILES_SECTION, 'MRUMaxItems', MRUMaxItems);
WriteMRUFiles;
{ log section }
fcReg.WriteInteger(REG_LOG_SECTION, REG_LOG_LEVEL, Ord(feLogLevel));
fcReg.WriteInteger(REG_LOG_SECTION, REG_LOG_PLACE, Ord(feLogPlace));
fcReg.WriteString(REG_LOG_SECTION, REG_SPECIFIED_DIRECTORY, fsSpecifiedDirectory);
fcReg.WriteBool(REG_LOG_SECTION, REG_VIEW_LOG_AFTER_RUN, fbViewLogAfterRun);
fcReg.WriteBool(REG_LOG_SECTION, REG_LOG_TIME, fbLogTime);
fcReg.WriteBool(REG_LOG_SECTION, REG_LOG_STATS, fbLogStats);
{ ui section }
fcReg.WriteString(REG_UI_SECTION, REG_LAST_SETTINGS_PAGE, fsLastSettingsPage);
fcReg.WriteInteger(REG_UI_SECTION, 'ParseTreeOption', Ord(ShowParseTreeOption));
{ files section }
fcReg.WriteInteger(REG_FILES_SECTION, REG_BACKUP_MODE, Ord(feBackupMode));
fcReg.WriteInteger(REG_FILES_SECTION, REG_SOURCE_MODE, Ord(feSourceMode));
fcReg.WriteString(REG_FILES_SECTION, REG_INPUT, fsInput);
fcReg.WriteString(REG_FILES_SECTION, REG_BACKUP_EXT, fsBackupExtension);
fcReg.WriteString(REG_FILES_SECTION, REG_OUTPUT_EXT, fsOutputExtension);
WriteStrings(REG_FILES_SECTION, REG_EXCLUSIONS_FILES, fcExclusionsFiles);
WriteStrings(REG_FILES_SECTION, REG_EXCLUSIONS_DIRS, fcExclusionsDirs);
fcReg.WriteBool(REG_FILES_SECTION, REG_CHECK_MULTIBYTE_CHARS, fbCheckMultiByteChars);
{ IDE }
fcReg.WriteBool(REG_IDE_SECTION, REG_EDITOR_INTEGRATION, fbEditorIntegration);
fcReg.WriteBool(REG_IDE_SECTION, REG_FORMAT_BEFORE_SAVE, fbFormatBeforeSave);
fcReg.WriteBool(REG_IDE_SECTION, REG_FORMAT_AFTER_LOAD, fbFormatAfterLoad);
end;
function TJCFRegistrySettings.CanClearMRU: boolean;
begin
Result := (MRUFiles <> nil) and (MRUFiles.Count > 0);
end;
procedure TJCFRegistrySettings.ClearMRU;
begin
if MRUFiles <> nil then
MRUFiles.Clear;
end;
function TJCFRegistrySettings.LogDirectory: string;
begin
case feLogPlace of
eLogTempDir:
Result := GetWindowsTempFolder;
eLogAppDir:
Result := ExtractFileDir(ParamStr(0));
eLogSpecifiedDir:
Result := fsSpecifiedDirectory;
end;
Result := IncludeTrailingPathDelimiter(Result);
end;
function TJCFRegistrySettings.LogFileName: string;
begin
Result := LogDirectory + 'JediCodeFormat.log';
end;
procedure TJCFRegistrySettings.ViewLog;
var
lsFile: string;
begin
lsFile := LogFileName;
if FileExists(lsFile) then
begin
ShellExecEx('notepad.exe ', lsFile);
end
else
ShowMessage('No log file found at ' + lsFile);
end;
function TJCFRegistrySettings.DirIsExcluded(const psDir: string): boolean;
var
liPos: integer;
lsBareDir: string;
begin
{ exact match }
Result := (fcExclusionsDirs.IndexOf(psDir) >= 0);
if not Result then
begin
liPos := StrLastPos('/', psDir);
if liPos > 0 then
begin
lsBareDir := StrRestOf(psDir, liPos + 1);
Result := (fcExclusionsDirs.IndexOf(lsBareDir) >= 0);
end;
end;
end;
function TJCFRegistrySettings.FileIsExcluded(const psFile: string): boolean;
var
lsBareFile: string;
begin
{ exact match }
Result := (fcExclusionsFiles.IndexOf(psFile) >= 0);
if not Result then
begin
// no exact match? then extract the bare file name - no path or ext
lsBareFile := PathExtractFileNameNoExt(psFile);
Result := (fcExclusionsFiles.IndexOf(lsBareFile) >= 0);
end;
end;
function TJCFRegistrySettings.GetOutputFileName(const psIn: string;
peMode: TBackupMode): string;
var
lsExt: string;
liMainFileNameLength: integer;
begin
if PathExtractFileNameNoExt(psIn) = '' then
begin
Result := '';
exit;
end;
if (peMode = cmInPlace) then
begin
Result := '';
end
else if peMode in [cmInPlaceWithBackup, cmSeperateOutput] then
begin
lsExt := ExtractFileExt(psIn);
liMainFileNameLength := Length(psIn) - Length(lsExt);
Result := StrLeft(psIn, liMainFileNameLength);
if peMode = cmInPlaceWithBackup then
Result := Result + '.' + BackupExtension
else
Result := Result + '.' + OutputExtension;
end
else
raise Exception.Create('TCodeFormatSettings.Output: bad backup mode ');
end;
function TJCFRegistrySettings.GetOutputFileName(const psIn: string): string;
begin
// use the currently selected mode
Result := GetOutputFileName(psIn, BackupMode);
end;
function TJCFRegistrySettings.Output: string;
begin
Result := GetOutputFileName(Input);
end;
function TJCFRegistrySettings.GetBackupExtension: string;
begin
if fsBackupExtension = '' then
Result := 'bak'
else
Result := fsBackupExtension;
end;
function TJCFRegistrySettings.GetOutputExtension: string;
begin
if fsOutputExtension = '' then
Result := 'out'
else
Result := fsOutputExtension;
end;
{--------------------------------------------
singleton accessor }
var
mcRegistrySettings: TJCFRegistrySettings = nil;
function GetRegSettings: TJCFRegistrySettings;
begin
if mcRegistrySettings = nil then
begin
mcRegistrySettings := TJCFRegistrySettings.Create;
mcRegistrySettings.ReadAll;
end;
Result := mcRegistrySettings;
end;
initialization
finalization
FreeAndNil(mcRegistrySettings);
end.