//
unit ads_DlgUserPreferences; {Copyright(c)2016 Advanced Delphi Systems Richard Maley Advanced Delphi Systems 12613 Maidens Bower Drive Potomac, MD 20854 USA phone 301-840-1554 dickmaley@advdelphisys.com The code herein can be used or modified by anyone. Please retain references to Richard Maley at Advanced Delphi Systems. If you make improvements to the code please send your improvements to dickmaley@advdelphisys.com so that the entire Delphi community can benefit. All comments are welcome. } (*UnitIndex Master Index Implementation Section Download Units
Description: ads_DlgUserPreferences.pas This unit contains the following routines.
TfrmUserPreferences.btnCancelClick TfrmUserPreferences.btnOKClick TfrmUserPreferences.CheckListBoxDrawItem TfrmUserPreferences.FormActivate TfrmUserPreferences.FormClose TfrmUserPreferences.FormCreate TfrmUserPreferences.FormDestroy TfrmUserPreferences.OptionsDrawItem TfrmUserPreferences.OptionsInit TfrmUserPreferences.Reset TfrmUserPreferences.UpdateOptionsFromFile UserPreferencesDlgDetail UserPreferencesEdit UserPreferencesInit UserPreferencesReset
*) interface Uses ActnList; Type TUserPreferences=class Public Constructor Create(); destructor Destroy();override; class Function Edit (var a:TActionList): Boolean; class Function Init (var a:TActionList): Boolean; class Function Reset(var a:TActionList): Boolean; End; Var UserPreferences: TUserPreferences; { Description: - This unit facilitates the integration of Action Items into a user preferences system. The objective is that it is simple and easy to use. - Each ActionItem should have a unique caption and icon. - The Tag value of the ActionItem tells the system how to present the action to the user for their user preference selection. Tag =0: This Action Item is available for user enabling/disabling Tag =2: This Action Item is not optional. Tag>=3: This Action Item is not visible ever. - User preferences are written to and read from file. A separate file is created for each user. - Add ads_DlgUserPreferences to the uses clause of the application and any unit that calls TUserPreferences routines. - In the project file (*.dpr) add a call to UserPreferences.Init just before Application.Run. example: ... UserPreferences.Init(???????.ActionList); Application.Run; end. The assumption is that by this time all gui elements have been created and default to visible=True. Only visible=false ActionItems are saved to file and persist between user sessions. This entry in the project file restores saved user preferences. - To give the user the opportunity to set their user preferences use the following code: UserPreferences.Edit(???????.ActionList); If the user presses the OK button the values are automatically updated and saved to file. - To restore default settings call: UserPreferences.Reset(???????.ActionList); - In the examples above replace ???????.ActionList with the appropriate reference to your ActionList. For example, Form1.ActionList1. - UserPreferences: TUserPreferences does not have to be created or destroyed because that is being handled in the initialization and finalization sections of this unit. } implementation Uses Windows, ads_Exception, ads_File, Buttons, CheckLst, Classes, Controls, Dialogs, ExtCtrls, Forms, Graphics, StdCtrls, SysUtils ; Var UnitName : String='ads_DlgUserPreferences'; type TfrmUserPreferences = Class(TScrollingWinControl) Public Constructor Create(AOwner: TComponent); Override; Destructor Destroy; Override; Public Panel1: TPanel; Panel2: TPanel; btnCancel: TBitBtn; btnOK: TBitBtn; CheckListBox: TCheckListBox; //procedure Loaded;override; procedure FormCreate(Sender: TObject); procedure FormActivate(Sender: TObject); procedure btnCancelClick(Sender: TObject); procedure btnOKClick(Sender: TObject); procedure FormClose(Sender: TObject; var Action: TCloseAction); procedure CheckListBoxDrawItem(Control: TWinControl; Index: Integer; Rect: TRect; State: TOwnerDrawState); procedure FormDestroy(Sender: TObject); protected { Protected declarations } ActionList : TActionList; DirLocalApp : String; DirLocalThisApp: String; ExeName : String; ExePath : String; FilePersist : String; List : TStringList; procedure OptionsDrawItem(ActionList:TActionList;Mask:TColor;Control:TWinControl;Index:Integer;Rect:TRect;State:TOwnerDrawState); public { Public declarations } Success : Boolean; procedure OptionsInit(); procedure Reset(var ActionLst: TActionList); procedure UpdateOptionsFromFile(var ActionLst: TActionList); end; //Unit Description UnitIndex Master Index
procedure TfrmUserPreferences.FormCreate(Sender: TObject); Var ProcName: String; begin ProcName := 'TfrmUserPreferences.FormCreate'; Try inherited; Success:=False; If List=nil Then List:= TStringList.Create(); List.Duplicates:=dupIgnore; List.Sorted:=True; ExeName := ExtractFileName(ParamStr(0)); ExeName := LowerCase(Copy(ExeName,1,Length(ExeName)-4)); ExeName := UpperCase(Copy(ExeName,1,1))+Copy(ExeName,2,Length(ExeName)-1); ExePath := ExtractFilePath(ParamStr(0)); DirLocalApp := PathOfAppDataLocal(); DirLocalThisApp := DirLocalApp+ExeName+'\'; If Not DirectoryExists(DirLocalThisApp) Then ForceDirectories(DirLocalThisApp); FilePersist := DirLocalThisApp+ExeName+'.Options.txt'; Except On E : Exception Do RaiseError(UnitName,ProcName,E); End; end; //Unit Description UnitIndex Master Index
procedure TfrmUserPreferences.FormActivate(Sender: TObject); Var ProcName: String; begin ProcName := 'TfrmUserPreferences.FormActivate'; Try If Tag=0 Then Begin Success:=False; List.Clear; OptionsInit(); End; btnCancel.Refresh; Application.ProcessMessages(); Except On E : Exception Do RaiseError(UnitName,ProcName,E); End; end; //Unit Description UnitIndex Master Index
procedure TfrmUserPreferences.btnCancelClick(Sender: TObject); Var ProcName: String; begin ProcName := 'TfrmUserPreferences.btnCancelClick'; Try Tag:=0; Except On E : Exception Do RaiseError(UnitName,ProcName,E); End; end; //Unit Description UnitIndex Master Index
procedure TfrmUserPreferences.btnOKClick(Sender: TObject); Var i : Integer; inIndex : Integer; ActionItem: TAction; sgCaption : String; sgPersist : String; ProcName : String; begin ProcName := 'TfrmUserPreferences.btnOKClick'; Try Success:=True; Tag:=0; sgPersist := ''; For i:=0 To CheckListBox.Count-1 Do Begin sgCaption:=CheckListBox.Items[i]; If sgCaption='' Then Continue; If CheckListBox.State[i]=cbUnchecked Then Begin sgPersist:=sgPersist+sgCaption+#13+#10; End; inIndex:=List.IndexOf(sgCaption); If List.Objects[inIndex]=nil Then Continue; ActionItem:=TAction(List.Objects[inIndex]); If CheckListBox.State[i]=cbUnchecked Then Begin ActionItem.Visible:=False; End Else Begin If CheckListBox.State[i]=cbChecked Then Begin ActionItem.Visible:=True; End; End; End; StrToFile(sgPersist,FilePersist); UpdateOptionsFromFile(ActionList); Except On E : Exception Do RaiseError(UnitName,ProcName,E); End; end; //Unit Description UnitIndex Master Index
procedure TfrmUserPreferences.FormClose(Sender: TObject; var Action: TCloseAction); Var ProcName: String; begin ProcName := 'TfrmUserPreferences.FormClose'; Try Tag:=0; Except On E : Exception Do RaiseError(UnitName,ProcName,E); End; end; //Unit Description UnitIndex Master Index
procedure TfrmUserPreferences.CheckListBoxDrawItem(Control: TWinControl; Index: Integer; Rect: TRect; State: TOwnerDrawState); Var Mask : TColor; ProcName : String; begin ProcName := 'TfrmUserPreferences.CheckListBoxDrawItem'; Try Mask := clNone; OptionsDrawItem( ActionList , //ActionList : TActionList; Mask , //Mask : TColor; Control , //Control : TWinControl; Index , //Index : Integer; Rect , //Rect : TRect; State ); //State : TOwnerDrawState); Except On E : Exception Do RaiseError(UnitName,ProcName,E); End; end; //Unit Description UnitIndex Master Index
procedure TfrmUserPreferences.OptionsDrawItem(ActionList: TActionList; Mask: TColor; Control: TWinControl; Index: Integer; Rect: TRect; State: TOwnerDrawState); Var Bitmap : TBitmap; Offset : Integer; inCounter : Integer; inMax : Integer; sgText : String; Images : TImageList; Action : TAction; ProcName : String; begin ProcName := 'TfrmUserPreferences.OptionsDrawItem'; Try Bitmap := TBitmap.Create(); inMax := ActionList.ActionCount - 1; Try Images := TImageList(ActionList.Images); Bitmap.Mask(Mask); With (Control as TCheckListBox).Canvas Do Begin FillRect(Rect); { clear the rectangle } Offset := 2; { provide default offset } { get the bitmap } sgText := (Control as TCheckListBox).Items[Index]; For inCounter := 0 To inMax Do Begin Action := TAction(ActionList.Actions[inCounter]); If sgText = Action.Caption Then Begin Try Images.GetBitmap(Action.ImageIndex,Bitmap); Except End; Break; End; End; If Bitmap <> nil Then Begin BrushCopy( Bounds(Rect.Left + 2, Rect.Top, Bitmap.Width, Bitmap.Height), Bitmap, Bounds(0, 0, Bitmap.Width, Bitmap.Height), clRed); {render bitmap} {add four pixels between bitmap and text} Offset := Bitmap.Width + 6; End; {display the text} TextOut( Rect.Left + Offset, Rect.Top, (Control as TCheckListBox).Items[Index]) End; Finally Bitmap.Free; End; Except On E : Exception Do RaiseError(UnitName,ProcName,E); End; end; //Unit Description UnitIndex Master Index
procedure TfrmUserPreferences.OptionsInit(); Var Action : TAction; inActions : Integer; inActMax : Integer; inActTag : Integer; inIndex : Integer; ProcName : String; sgCaption : String; Begin ProcName := 'TfrmUserPreferences.OptionsInit'; Try CheckListBox.Items.Clear; CheckListBox.Sorted := True; inActMax := ActionList.ActionCount-1; For inActions := 0 To inActMax Do Begin Action := TAction(ActionList.Actions[inActions]); inActTag := Action.Tag; //A tag = 2 means this action is not optional If inActTag = 2 Then Continue; If inActTag > 2 Then Begin //These actions are disabled in this application. Action.Visible := False; Continue; End; sgCaption := Trim(Action.Caption); If sgCaption='' Then Continue; sgCaption:=StringReplace(sgCaption,'&','',[rfReplaceAll]); If List=nil Then List:=TStringList.Create(); List.Add(sgCaption); inIndex:=List.IndexOf(sgCaption); List.Objects[inIndex]:=TAction(ActionList.Actions[inActions]); CheckListBox.Items.Add(sgCaption); CheckListBox.Refresh; inIndex := CheckListBox.Items.IndexOf(sgCaption); Try CheckListBox.Checked[inIndex] := Action.Visible;Except End; End; Tag:=1; Except On E : Exception Do RaiseError(UnitName,ProcName,E); End; End; //Unit Description UnitIndex Master Index
procedure TfrmUserPreferences.FormDestroy(Sender: TObject); Var ProcName: String; begin ProcName := 'TfrmUserPreferences.FormDestroy'; Try FreeAndNil(List); Except On E : Exception Do RaiseError(UnitName,ProcName,E); End; end; //Unit Description UnitIndex Master Index
procedure TfrmUserPreferences.UpdateOptionsFromFile(var ActionLst: TActionList); Var i,j : Integer; sgCaption : String; inActMax : Integer; Action : TAction; ProcName: String; begin ProcName := 'TfrmUserPreferences.UpdateOptionsFromFile'; Try ActionList:=ActionLst; If FilePersist='' Then Begin ExeName := ExtractFileName(ParamStr(0)); ExeName := LowerCase(Copy(ExeName,1,Length(ExeName)-4)); ExeName := UpperCase(Copy(ExeName,1,1))+Copy(ExeName,2,Length(ExeName)-1); ExePath := ExtractFilePath(ParamStr(0)); DirLocalApp := PathOfAppDataLocal(); DirLocalThisApp := DirLocalApp+ExeName+'\'; If Not DirectoryExists(DirLocalThisApp) Then ForceDirectories(DirLocalThisApp); FilePersist := DirLocalThisApp+ExeName+'.Options.txt'; End; If Not FileExists(FilePersist) Then Exit; If List=nil Then List:=TStringList.Create(); List.LoadFromFile(FilePersist); If ActionList=nil Then Exit; inActMax := ActionList.ActionCount-1; For j:=0 To inActMax Do Begin Action:=TAction(ActionList.Actions[j]); If Action.Tag<3 Then Action.Visible:=True; End; For i:=0 To List.Count-1 Do Begin sgCaption := List[i]; For j:=0 To inActMax Do Begin Action:=TAction(ActionList.Actions[j]); If Trim(Action.Caption)='' Then Continue; If Trim(Action.Caption)=sgCaption Then Begin Action.Visible:=False; End; End; End; Except On E : Exception Do RaiseError(UnitName,ProcName,E); End; end; //Unit Description UnitIndex Master Index
procedure TfrmUserPreferences.Reset(var ActionLst: TActionList); Var ProcName: String; s : String; begin ProcName := 'TfrmUserPreferences.Reset'; Try s := ''; If FilePersist='' Then Begin ExeName := ExtractFileName(ParamStr(0)); ExeName := LowerCase(Copy(ExeName,1,Length(ExeName)-4)); ExeName := UpperCase(Copy(ExeName,1,1))+Copy(ExeName,2,Length(ExeName)-1); ExePath := ExtractFilePath(ParamStr(0)); DirLocalApp := PathOfAppDataLocal(); DirLocalThisApp := DirLocalApp+ExeName+'\'; If Not DirectoryExists(DirLocalThisApp) Then ForceDirectories(DirLocalThisApp); FilePersist := DirLocalThisApp+ExeName+'.Options.txt'; End; StrToFile(s,FilePersist); UpdateOptionsFromFile(ActionLst); Except On E : Exception Do RaiseError(UnitName,ProcName,E); End; end; Constructor TfrmUserPreferences.Create(AOwner: TComponent); Function IsControl(Obj: TObject): Boolean; Begin Result := (Obj is TControl); End; Var ProcName: String; Begin ProcName := 'TfrmUserPreferences.Create'; Try inherited; Self.Parent := TWincontrol(AOwner); Panel1 := TPanel.Create(AOwner); With Panel1 Do Begin If IsControl(Panel1) Then Begin Parent := Self; End; Left := 0; Top := 423; Width := 210; Height := 30; Align := alBottom; BevelOuter := bvNone; Caption := ' '; TabOrder := 0; End; Panel2 := TPanel.Create(AOwner); With Panel2 Do Begin Parent := Panel1; Left := 46; Top := 0; Width := 164; Height := 30; Align := alRight; BevelOuter := bvNone; Caption := ' '; TabOrder := 0; End; btnCancel := TBitBtn.Create(AOwner); With btnCancel Do Begin Parent := Panel2; Left := 82; Top := 2; Width := 75; Height := 25; Hint := 'Make no changes.'; TabOrder := 0; OnClick := btnCancelClick; Kind := bkCancel; End; btnOK := TBitBtn.Create(AOwner); With btnOK Do Begin Parent := Panel2; Left := 2; Top := 2; Width := 75; Height := 25; Hint := 'Implement changes'; TabOrder := 1; OnClick := btnOKClick; Kind := bkOK; End; CheckListBox := TCheckListBox.Create(AOwner); With CheckListBox Do Begin If IsControl(CheckListBox) Then Begin Parent := Self; End; Left := 0; Top := 0; Width := 210; Height := 423; Hint := 'Check to enable, uncheck to disable.'; Align := alClient; ItemHeight := 18; Style := lbOwnerDrawVariable; TabOrder := 1; OnDrawItem := CheckListBoxDrawItem; End; Except On E : Exception Do RaiseError(UnitName,ProcName,E); End; End; Destructor TfrmUserPreferences.Destroy; Var ProcName: String; Begin ProcName := 'TfrmUserPreferences.Destroy'; Try CheckListBox .Free; btnOK .Free; btnCancel .Free; Panel2 .Free; Panel1 .Free; inherited Destroy; Except On E : Exception Do RaiseError(UnitName,ProcName,E); End; End; //Unit Description UnitIndex Master Index
Function UserPreferencesDlgDetail(var ActionLst: TActionList;Init:Boolean;Reset:Boolean): Boolean; Var Dialog : TForm; Form : TfrmUserPreferences; ProcName: String; Begin Result := False; Dialog := nil; ProcName := 'UserPreferencesDlg'; Try Try Dialog := TForm.Create(nil); Form := TfrmUserPreferences.Create(Dialog); Form.Parent:= Dialog; Form.Align := alClient; With Dialog Do Begin Left := 359; Top := 152; Width := 218; Height := 480; Caption := 'User Preferences'; Color := clBtnFace; Font.Color := clWindowText; Font.Height := -11; Font.Name := 'MS Sans Serif'; Font.Style := []; OldCreateOrder:= False; Position := poScreenCenter; ShowHint := True; OnActivate := Form.FormActivate; OnClose := Form.FormClose; OnCreate := Form.FormCreate; OnDestroy := Form.FormDestroy; PixelsPerInch := 96; End; If Reset Then Begin Form.Reset(ActionLst); Result:=True; Exit; End; Form.UpdateOptionsFromFile(ActionLst); Form.OptionsInit(); If Init Then Begin Result:=True; Exit; End; Form.FormCreate(Dialog); Application.ProcessMessages(); Dialog.ShowModal; Result:=Form.Success; Finally Dialog.Free; End; Except On E : Exception Do RaiseError(UnitName,ProcName,E); End; End; //Unit Description UnitIndex Master Index
Function UserPreferencesEdit(var ActionLst: TActionList): Boolean; Var ProcName: String; Begin Result := False; ProcName := 'UserPreferencesEdit'; Try Result:= UserPreferencesDlgDetail(ActionLst,False,False); Except On E : Exception Do RaiseError(UnitName,ProcName,E); End; End; //Unit Description UnitIndex Master Index
Function UserPreferencesInit(var ActionLst: TActionList): Boolean; Var ProcName: String; Begin Result := False; ProcName := 'UserPreferencesInit'; Try Result:= UserPreferencesDlgDetail(ActionLst,True,False); Except On E : Exception Do RaiseError(UnitName,ProcName,E); End; End; //Unit Description UnitIndex Master Index
Function UserPreferencesReset(var ActionLst: TActionList): Boolean; Var ProcName: String; Begin Result := False; ProcName := 'UserPreferencesReset'; Try Result:= UserPreferencesDlgDetail(ActionLst,False,True); Except On E : Exception Do RaiseError(UnitName,ProcName,E); End; End; { TUserPreferences } class function TUserPreferences.Edit(var a: TActionList): Boolean; Var ProcName: String; Begin Result := False; ProcName := 'TUserPreferences.Edit'; Try Result:= UserPreferencesDlgDetail(a,False,False); Except On E : Exception Do RaiseError(UnitName,ProcName,E); End; End; class function TUserPreferences.Init(var a: TActionList): Boolean; Var ProcName: String; Begin Result := False; ProcName := 'TUserPreferences.Init'; Try Result:= UserPreferencesDlgDetail(a,True,False); Except On E : Exception Do RaiseError(UnitName,ProcName,E); End; End; class function TUserPreferences.Reset(var a: TActionList): Boolean; Var ProcName: String; Begin Result := False; ProcName := 'TUserPreferences.Reset'; Try Result:= UserPreferencesDlgDetail(a,False,True); Except On E : Exception Do RaiseError(UnitName,ProcName,E); End; End; constructor TUserPreferences.Create; begin inherited; end; destructor TUserPreferences.Destroy; begin inherited; end; Initialization UserPreferences:=TUserPreferences.Create; Finalization FreeAndNil(UserPreferences); End. //