Improve ListFilterEdit and apply it to compiler message dialog.

git-svn-id: trunk@33774 -
This commit is contained in:
juha 2011-11-25 09:40:15 +00:00
parent 3c6ed01b68
commit bcb7030b54
5 changed files with 136 additions and 164 deletions

View File

@ -17,7 +17,7 @@ type
TListFilterEdit = class(TCustomControlFilterEdit) TListFilterEdit = class(TCustomControlFilterEdit)
private private
fFilteredListbox: TListbox; // A control showing the (filtered) data. fFilteredListbox: TCustomListbox; // A control showing the (filtered) data.
fSelectionList: TStringList; // Store/restore the old selections here. fSelectionList: TStringList; // Store/restore the old selections here.
// Data supplied by caller through Data property. // Data supplied by caller through Data property.
fOriginalData: TStringList; fOriginalData: TStringList;
@ -25,7 +25,7 @@ type
fSortedData: TStringList; fSortedData: TStringList;
function CompareFNs(AFilename1,AFilename2: string): integer; function CompareFNs(AFilename1,AFilename2: string): integer;
function GetFirstSelected: Integer; function GetFirstSelected: Integer;
procedure SetFilteredListbox(const AValue: TListBox); procedure SetFilteredListbox(const AValue: TCustomListBox);
procedure UnselectAll; procedure UnselectAll;
protected protected
procedure MoveNext; override; procedure MoveNext; override;
@ -42,7 +42,7 @@ type
property SelectionList: TStringList read fSelectionList; property SelectionList: TStringList read fSelectionList;
property Data: TStringList read fOriginalData; property Data: TStringList read fOriginalData;
published published
property FilteredListbox: TListBox read fFilteredListbox write SetFilteredListbox; property FilteredListbox: TCustomListBox read fFilteredListbox write SetFilteredListbox;
end; end;
var var
@ -52,6 +52,8 @@ procedure Register;
implementation implementation
uses CheckLst;
procedure Register; procedure Register;
begin begin
{$I listfilteredit_icon.lrs} {$I listfilteredit_icon.lrs}
@ -81,7 +83,7 @@ begin
Result := ListFilterGlyph; Result := ListFilterGlyph;
end; end;
procedure TListFilterEdit.SetFilteredListbox(const AValue: TListBox); procedure TListFilterEdit.SetFilteredListbox(const AValue: TCustomListBox);
begin begin
if fFilteredListbox = AValue then Exit; if fFilteredListbox = AValue then Exit;
fFilteredListbox:=AValue; fFilteredListbox:=AValue;
@ -91,18 +93,33 @@ end;
procedure TListFilterEdit.ApplyFilterCore; procedure TListFilterEdit.ApplyFilterCore;
var var
i: Integer; i, j: Integer;
FileN: string; s: string;
clb: TCustomCheckListBox;
TempOnItemClick: TCheckListClicked;
begin begin
clb:=Nil;
TempOnItemClick:=Nil;
if fFilteredListbox is TCustomCheckListBox then begin
clb:=TCustomCheckListBox(fFilteredListbox);
if Assigned(clb.OnItemClick) then begin
TempOnItemClick:=clb.OnItemClick;
clb.OnItemClick:=Nil; // Disable OnItemClick temporarily.
end;
end;
fFilteredListbox.Clear; fFilteredListbox.Clear;
fFilteredListbox.Items.BeginUpdate; fFilteredListbox.Items.BeginUpdate;
for i:=0 to fSortedData.Count-1 do begin for i:=0 to fSortedData.Count-1 do begin
FileN:=fSortedData[i]; s:=fSortedData[i];
fFilteredListbox.Items.AddObject(FileN, fSortedData.Objects[i]); j:=fFilteredListbox.Items.AddObject(s, fSortedData.Objects[i]);
if Assigned(fSelectedPart) then if Assigned(fSelectedPart) then
fFilteredListbox.Selected[i]:=fSelectedPart=fSortedData.Objects[i]; fFilteredListbox.Selected[i]:=fSelectedPart=fSortedData.Objects[i];
if Assigned(clb) and Assigned(OnCheckItem) then
clb.Checked[j]:=OnCheckItem(fSortedData.Objects[i]);
end; end;
fFilteredListbox.Items.EndUpdate; fFilteredListbox.Items.EndUpdate;
if Assigned(TempOnItemClick) then
clb.OnItemClick:=TempOnItemClick; // Restore OnItemClick.
end; end;
function TListFilterEdit.CompareFNs(AFilename1,AFilename2: string): integer; function TListFilterEdit.CompareFNs(AFilename1,AFilename2: string): integer;
@ -117,18 +134,27 @@ procedure TListFilterEdit.SortAndFilter;
// Copy data from fOriginalData to fSortedData in sorted order // Copy data from fOriginalData to fSortedData in sorted order
var var
Origi, i: Integer; Origi, i: Integer;
FileN: string; s: string;
Pass, Done, Checked: Boolean;
begin begin
Done:=False;
fSortedData.Clear; fSortedData.Clear;
for Origi:=0 to fOriginalData.Count-1 do begin for Origi:=0 to fOriginalData.Count-1 do begin
FileN:=fOriginalData[Origi]; s:=fOriginalData[Origi];
if (Filter='') or (Pos(Filter,lowercase(FileN))>0) then begin // Filter with event handler if there is one.
Pass:=False;
if Assigned(OnFilterItem) then
Pass:=OnFilterItem(fOriginalData.Objects[Origi], Done);
// Filter by item's title text if needed.
if not (Pass or Done) then
Pass:=(Filter='') or (Pos(Filter,lowercase(s))>0);
if Pass then begin
i:=fSortedData.Count-1; i:=fSortedData.Count-1;
while i>=0 do begin while i>=0 do begin
if CompareFNs(FileN,fSortedData[i])>=0 then break; if CompareFNs(s,fSortedData[i])>=0 then break;
dec(i); dec(i);
end; end;
fSortedData.InsertObject(i+1,FileN, fOriginalData.Objects[Origi]); fSortedData.InsertObject(i+1, s, fOriginalData.Objects[Origi]);
end; end;
end; end;
end; end;
@ -138,21 +164,19 @@ var
i: Integer; i: Integer;
begin begin
fSelectionList.Clear; fSelectionList.Clear;
for i := 0 to fFilteredListbox.Count-1 do begin for i := 0 to fFilteredListbox.Count-1 do
if fFilteredListbox.Selected[i] then if fFilteredListbox.Selected[i] then
fSelectionList.Add(fFilteredListbox.Items[i]); fSelectionList.Add(fFilteredListbox.Items[i]);
end; end;
end;
procedure TListFilterEdit.RestoreSelection; procedure TListFilterEdit.RestoreSelection;
var var
i: Integer; i: Integer;
begin begin
for i := 0 to fFilteredListbox.Count-1 do begin for i := 0 to fFilteredListbox.Count-1 do
if fSelectionList.IndexOf(fFilteredListbox.Items[i])>0 then if fSelectionList.IndexOf(fFilteredListbox.Items[i])>0 then
fFilteredListbox.Selected[i]:=True; fFilteredListbox.Selected[i]:=True;
end; end;
end;
function TListFilterEdit.GetFirstSelected: Integer; function TListFilterEdit.GetFirstSelected: Integer;
var var

View File

@ -1,63 +1,67 @@
inherited CompilerMessagesOptionsFrame: TCompilerMessagesOptionsFrame inherited CompilerMessagesOptionsFrame: TCompilerMessagesOptionsFrame
Height = 455 Height = 455
Width = 626 Width = 631
ClientHeight = 455 ClientHeight = 455
ClientWidth = 626 ClientWidth = 631
TabOrder = 0 DesignLeft = 239
DesignLeft = 287 DesignTop = 167
DesignTop = 181
object grpCompilerMessages: TGroupBox[0] object grpCompilerMessages: TGroupBox[0]
Left = 0 Left = 0
Height = 455 Height = 455
Top = 0 Top = 0
Width = 626 Width = 631
Align = alClient Align = alClient
Caption = 'grpCompilerMessages' Caption = 'grpCompilerMessages'
ClientHeight = 436 ClientHeight = 437
ClientWidth = 622 ClientWidth = 627
TabOrder = 0 TabOrder = 0
object editMsgFilter: TEdit
AnchorSideLeft.Control = lblFilter
AnchorSideLeft.Side = asrBottom
AnchorSideTop.Control = grpCompilerMessages
Left = 56
Height = 21
Top = 6
Width = 558
Anchors = [akTop, akLeft, akRight]
BorderSpacing.Left = 6
BorderSpacing.Top = 6
BorderSpacing.Right = 6
OnChange = editMsgFilterChange
TabOrder = 0
Text = 'editMsgFilter'
end
object chklistCompMsg: TCheckListBox object chklistCompMsg: TCheckListBox
AnchorSideLeft.Control = grpCompilerMessages AnchorSideLeft.Control = grpCompilerMessages
AnchorSideTop.Control = editMsgFilter
AnchorSideTop.Side = asrBottom AnchorSideTop.Side = asrBottom
AnchorSideRight.Control = grpCompilerMessages AnchorSideRight.Control = grpCompilerMessages
AnchorSideRight.Side = asrBottom AnchorSideRight.Side = asrBottom
AnchorSideBottom.Control = grpCompilerMessages AnchorSideBottom.Control = grpCompilerMessages
AnchorSideBottom.Side = asrBottom AnchorSideBottom.Side = asrBottom
Left = 6 Left = 6
Height = 397 Height = 399
Top = 33 Top = 32
Width = 610 Width = 615
Anchors = [akTop, akLeft, akRight, akBottom] Anchors = [akTop, akLeft, akRight, akBottom]
BorderSpacing.Around = 6 BorderSpacing.Around = 6
ItemHeight = 0 ItemHeight = 0
OnItemClick = chklistCompMsgItemClick OnItemClick = chklistCompMsgItemClick
Sorted = True Sorted = True
TabOrder = 1 TabOrder = 0
end end
object lblFilter: TLabel object lblFilter: TLabel
AnchorSideTop.Control = editMsgFilter
AnchorSideTop.Side = asrCenter
Left = 6 Left = 6
Height = 16 Height = 15
Top = 8 Top = 9
Width = 44 Width = 41
Caption = 'lblFilter' Caption = 'lblFilter'
ParentColor = False ParentColor = False
end end
object editMsgFilter: TListFilterEdit
AnchorSideLeft.Control = lblFilter
AnchorSideLeft.Side = asrBottom
AnchorSideTop.Control = grpCompilerMessages
Left = 53
Height = 20
Top = 6
Width = 534
OnCheckItem = CheckItem
ButtonWidth = 23
NumGlyphs = 0
Anchors = [akTop, akLeft, akRight]
BorderSpacing.Left = 6
BorderSpacing.Top = 6
BorderSpacing.Right = 6
MaxLength = 0
ParentFont = False
TabOrder = 1
FilteredListbox = chklistCompMsg
end
end end
end end

View File

@ -5,11 +5,9 @@ unit compiler_messages_options;
interface interface
uses uses
Classes, SysUtils, FileUtil, Forms, StdCtrls, CheckLst, LCLProc, Classes, SysUtils, FileUtil, ListFilterEdit, Forms, StdCtrls, CheckLst,
Dialogs, LCLProc, Dialogs, IDEOptionsIntf, Project, LazarusIDEStrConsts,
IDEOptionsIntf, Project, EnvironmentOpts, CompilerOptions, IDEMsgIntf, EditBtn;
LazarusIDEStrConsts,
EnvironmentOpts, CompilerOptions, IDEMsgIntf;
type type
@ -17,22 +15,16 @@ type
TCompilerMessagesOptionsFrame = class(TAbstractIDEOptionsEditor) TCompilerMessagesOptionsFrame = class(TAbstractIDEOptionsEditor)
chklistCompMsg: TCheckListBox; chklistCompMsg: TCheckListBox;
editMsgFilter: TEdit; editMsgFilter: TListFilterEdit;
grpCompilerMessages: TGroupBox; grpCompilerMessages: TGroupBox;
lblFilter: TLabel; lblFilter: TLabel;
procedure btnBrowseMsgClick(Sender: TObject);
procedure chklistCompMsgItemClick(Sender: TObject; Index: integer); procedure chklistCompMsgItemClick(Sender: TObject; Index: integer);
procedure chkUseMsgFileChange(Sender: TObject); function CheckItem(Item: TObject): Boolean;
procedure editMsgFilterChange(Sender: TObject);
private private
fLoaded: Boolean; fLoaded: Boolean;
FSaved: Boolean; FSaved: Boolean;
{ private declarations }
TempMessages: TCompilerMessagesList; TempMessages: TCompilerMessagesList;
procedure UpdateMessages;
procedure UpdateFilter;
public public
{ public declarations }
constructor Create(TheOwner: TComponent); override; constructor Create(TheOwner: TComponent); override;
destructor Destroy; override; destructor Destroy; override;
@ -49,16 +41,6 @@ implementation
{ TCompilerMessagesOptionsFrame } { TCompilerMessagesOptionsFrame }
procedure TCompilerMessagesOptionsFrame.chkUseMsgFileChange(Sender: TObject);
begin
UpdateMessages;
end;
procedure TCompilerMessagesOptionsFrame.editMsgFilterChange(Sender: TObject);
begin
UpdateFilter;
end;
procedure TCompilerMessagesOptionsFrame.chklistCompMsgItemClick(Sender: TObject; Index: integer); procedure TCompilerMessagesOptionsFrame.chklistCompMsgItemClick(Sender: TObject; Index: integer);
const const
BoolToMessageState: array[Boolean] of TCompilerMessageState = (msOff, msOn); BoolToMessageState: array[Boolean] of TCompilerMessageState = (msOff, msOn);
@ -74,87 +56,15 @@ begin
end; end;
end; end;
procedure TCompilerMessagesOptionsFrame.btnBrowseMsgClick(Sender: TObject); function TCompilerMessagesOptionsFrame.CheckItem(Item: TObject): Boolean;
var var
dlg : TOpenDialog;
begin
dlg := TOpenDialog.Create(Self);
try
dlg.Filter := dlgBrowseMsgFilter;
if not dlg.Execute then Exit;
editMsgFilter.Caption := dlg.FileName;
UpdateMessages;
finally
dlg.Free
end;
end;
procedure TCompilerMessagesOptionsFrame.UpdateMessages;
const
MaxIndexLen = 5;
var
topidx : Integer;
begin
topidx := chklistCompMsg.TopIndex;
chklistCompMsg.Items.BeginUpdate;
try
//debugln(['TCompilerMessagesOptionsFrame.UpdateMessages ',EnvironmentOptions.CompilerMessagesFilename]);
if FileExistsUTF8(EnvironmentOptions.CompilerMessagesFilename) then begin
try
// FPC messages file is expected to be UTF8 encoded, no matter for the current code page is
TempMessages.LoadMsgFile(EnvironmentOptions.CompilerMessagesFilename);
except
TempMessages.SetDefault;
end;
end else
TempMessages.SetDefault;
chklistCompMsg.Clear;
chklistCompMsg.Items.Clear;
UpdateFilter;
finally
chklistCompMsg.Items.EndUpdate;
chkListCompMsg.TopIndex := topidx;
end;
end;
procedure TCompilerMessagesOptionsFrame.UpdateFilter;
var
i : Integer;
j : Integer;
m: TCompilerMessageConfig; m: TCompilerMessageConfig;
add : Boolean;
srch : AnsiString;
const
//todo: should be translated
MsgTypeStr : array [TFPCErrorType] of String = ('-','H','N','W','E','F','P');
begin begin
chklistCompMsg.Items.BeginUpdate; m := Item as TCompilerMessageConfig;
try
chklistCompMsg.Clear;
srch:=UTF8UpperCase(editMsgFilter.Text);
for i := 0 to TempMessages.Count - 1 do
begin
m := TempMessages.Msg[i];
add:=m.MsgType in [etNote, etHint, etWarning];
if add and (srch<>'') then
add:=System.Pos(srch, UTF8UpperCase(m.GetUserText))>0;
if add then
begin
j := chklistCompMsg.Items.AddObject( Format('(%s) %s', [MsgTypeStr[m.MsgType], m.GetUserText([])]), m);
if m.State = msDefault then if m.State = msDefault then
chklistCompMsg.Checked[j] := not m.DefIgnored Result := not m.DefIgnored
else else
chklistCompMsg.Checked[j] := m.State = msOn; Result := m.State = msOn;
end;
end;
finally
chklistCompMsg.Items.EndUpdate;
end;
end; end;
constructor TCompilerMessagesOptionsFrame.Create(TheOwner: TComponent); constructor TCompilerMessagesOptionsFrame.Create(TheOwner: TComponent);
@ -165,6 +75,9 @@ end;
destructor TCompilerMessagesOptionsFrame.Destroy; destructor TCompilerMessagesOptionsFrame.Destroy;
begin begin
editMsgFilter.Data.Clear;
chklistCompMsg.Clear;
chklistCompMsg.Items.Clear;
TempMessages.Free; TempMessages.Free;
inherited Destroy; inherited Destroy;
end; end;
@ -176,20 +89,45 @@ end;
procedure TCompilerMessagesOptionsFrame.Setup(ADialog: TAbstractOptionsEditorDialog); procedure TCompilerMessagesOptionsFrame.Setup(ADialog: TAbstractOptionsEditorDialog);
begin begin
editMsgFilter.Caption := '';
grpCompilerMessages.Caption:=dlgCompilerMessage; grpCompilerMessages.Caption:=dlgCompilerMessage;
lblFilter.Caption:=lisFilter; lblFilter.Caption:=lisFilter;
end; end;
procedure TCompilerMessagesOptionsFrame.ReadSettings(AOptions: TAbstractIDEOptions); procedure TCompilerMessagesOptionsFrame.ReadSettings(AOptions: TAbstractIDEOptions);
const // todo: should be translated
MsgTypeStr: array [TFPCErrorType] of String = ('-','H','N','W','E','F','P');
var
topidx, i: Integer;
m: TCompilerMessageConfig;
s: String;
begin begin
if fLoaded then exit; if fLoaded then exit;
fLoaded:=true; fLoaded:=true;
with AOptions as TBaseCompilerOptions do TempMessages.Assign((AOptions as TBaseCompilerOptions).CompilerMessages);
begin topidx := chklistCompMsg.TopIndex;
TempMessages.Assign(CompilerMessages); if FileExistsUTF8(EnvironmentOptions.CompilerMessagesFilename) then begin
UpdateMessages; try
// FPC messages file is expected to be UTF8 encoded, no matter for the current code page is
TempMessages.LoadMsgFile(EnvironmentOptions.CompilerMessagesFilename);
except
TempMessages.SetDefault;
end; end;
end else
TempMessages.SetDefault;
// Copy data to filter component
editMsgFilter.Data.Clear;
for i := 0 to TempMessages.Count - 1 do
begin
m := TempMessages.Msg[i];
if m.MsgType in [etNote, etHint, etWarning] then
begin
s := Format('(%s) %s', [MsgTypeStr[m.MsgType], m.GetUserText([])]);
editMsgFilter.Data.AddObject(s, m);
end;
end;
editMsgFilter.InvalidateFilter;
chkListCompMsg.TopIndex := topidx;
end; end;
procedure TCompilerMessagesOptionsFrame.WriteSettings(AOptions: TAbstractIDEOptions); procedure TCompilerMessagesOptionsFrame.WriteSettings(AOptions: TAbstractIDEOptions);

View File

@ -651,7 +651,7 @@
</Units> </Units>
</ProjectOptions> </ProjectOptions>
<CompilerOptions> <CompilerOptions>
<Version Value="10"/> <Version Value="11"/>
<Target> <Target>
<Filename Value="../lazarus"/> <Filename Value="../lazarus"/>
</Target> </Target>
@ -665,12 +665,6 @@
<CStyleOperator Value="False"/> <CStyleOperator Value="False"/>
</SyntaxOptions> </SyntaxOptions>
</Parsing> </Parsing>
<Linking>
<Debugging>
<GenerateDebugInfo Value="True"/>
<DebugInfoType Value="dsAuto"/>
</Debugging>
</Linking>
<Other> <Other>
<CompilerMessages> <CompilerMessages>
<UseMsgFile Value="True"/> <UseMsgFile Value="True"/>

View File

@ -151,6 +151,14 @@ type
property Visible; property Visible;
end; end;
// Called when an item is filtered. Returns true if the item passes the filter.
// Done=False means the data should also be filtered by its title string.
// Done=True means no other filtering is needed.
TFilterItemEvent = function (Item: TObject; out Done: Boolean): Boolean of object;
// Can be used only for items that have a checkbox. Returns true if checked.
TCheckItemEvent = function (Item: TObject): Boolean of object;
{ TCustomControlFilterEdit } { TCustomControlFilterEdit }
// An abstract base class for edit controls which filter data in // An abstract base class for edit controls which filter data in
@ -167,6 +175,8 @@ type
fNeedUpdate: Boolean; fNeedUpdate: Boolean;
fIsFirstUpdate: Boolean; fIsFirstUpdate: Boolean;
fSelectedPart: TObject; // Select this node on next update fSelectedPart: TObject; // Select this node on next update
fOnFilterItem: TFilterItemEvent;
fOnCheckItem: TCheckItemEvent;
procedure KeyDown(var Key: Word; Shift: TShiftState); override; procedure KeyDown(var Key: Word; Shift: TShiftState); override;
procedure Change; override; procedure Change; override;
procedure DoEnter; override; procedure DoEnter; override;
@ -190,6 +200,8 @@ type
property SortData: Boolean read fSortData write fSortData; property SortData: Boolean read fSortData write fSortData;
property SelectedPart: TObject read fSelectedPart write fSelectedPart; property SelectedPart: TObject read fSelectedPart write fSelectedPart;
published published
property OnFilterItem: TFilterItemEvent read fOnFilterItem write fOnFilterItem;
property OnCheckItem: TCheckItemEvent read fOnCheckItem write fOnCheckItem;
// TEditButton properties. // TEditButton properties.
property ButtonWidth; property ButtonWidth;
property DirectInput; property DirectInput;