Before Xmas I started implementing code checks and metrics in my Browse and Doc It plug-in to help me write better code and where I’m maintaining legacy code, tell me where I need to refactor the code. So there are many files I have which are littered with hard coded integers, numbers and string which later on, may cause issues If I don’t update all the references at the same time.
Today I’ve been working on my Integrated Testing Helper plug-in as its long over due for some TLC. In one of the forms I’m using a
TListView to display information about processes to run before or after the main application has compiled and these were indexed using hard coded integers. So I thought to replace them with an enumerate as below:
Type TITHColumn = (coTitle, coEXE, coParams, coDir);
However to use these enumerates I have to cast them to integers. Also the
SubItems where the index is out by one so I was writing code as follows:
strProgramme := Item.SubItems[Pred(Integer(coEXE))];
LV.Columns[Integer(coExe)].Width := Trunc(i * dblEXEPctWidth);
While walking to the local shops, I thought there must be a better way of doing this! Can I write a (record) helper to do all of this for me and also make it more readable for maintenance. So once I was back, I found I could write a record helper for my enumerate as follows:
Type TITHColumnHelper = Record Helper For TITHColumn Function ColumnIndex : Integer; Function SubItemIndex : Integer; End;
The implementations for the two functions are as follows:
Function TITHColumnHelper.ColumnIndex: Integer; Begin Result := Integer(Self); End; Function TITHColumnHelper.SubItemIndex: Integer; Begin Result := Pred(Integer(Self)); End;
This then allows me to simplify the coding in the form as shown in the following 2 examples:
Procedure TfrmITHConfigureDlg.btnEditClick(Sender: TObject); Var iIndex: Integer; strTitle, strProgramme, strParameters, strWorkingDirectory: String; Item : TListItem; Begin iIndex := lvCompile.ItemIndex; If iIndex > -1 Then Begin Item := lvCompile.Items[iIndex]; strTitle := Item.Caption; strProgramme := Item.SubItems[coEXE.SubItemIndex]; strParameters := Item.SubItems[coParams.SubItemIndex]; strWorkingDirectory := Item.SubItems[coDir.SubItemIndex]; If TfrmITHProgrammeInfo.Execute(strTitle, strProgramme, strParameters, strWorkingDirectory, FGlobalOps.INIFileName) Then Begin Item.Caption := strTitle; Item.SubItems[coEXE.SubItemIndex] := strProgramme; Item.SubItems[coParams.SubItemIndex] := strParameters; Item.SubItems[coDir.SubItemIndex] := strWorkingDirectory; End; End; End; Procedure TfrmITHConfigureDlg.lvResize(Sender: TObject); Const dblTitlePctWidth = 0.15; dblEXEPctWidth = 0.35; dblParamsPctWidth = 0.20; dblDirPctWidth = 0.30; Var i: Integer; LV: TListView; Begin LV := Sender As TListView; i := LV.ClientWidth; LV.Columns[coTitle.ColumnIndex].Width := Trunc(i * dblTitlePctWidth); LV.Columns[coExe.ColumnIndex].Width := Trunc(i * dblEXEPctWidth); LV.Columns[coParams.ColumnIndex].Width := Trunc(i * dblParamsPctWidth); LV.Columns[coDir.ColumnIndex].Width := Trunc(i * dblDirPctWidth); End;
Now I know I can do this, it opens up a number of options for simplifying column layouts in Virtual String Trees and the like.