{ Double Commander ------------------------------------------------------------------------- Content plugin search control Copyright (C) 2014-2023 Alexander Koblov (alexx2000@mail.ru) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . } unit uSearchContent; {$mode objfpc}{$H+} interface uses Classes, SysUtils, Controls, StdCtrls, ExtCtrls, LCLType, uFindFiles, EditBtn, DateTimePicker; type { TCalcEdit } TCalcEdit = class(EditBtn.TCalcEdit) public procedure RunDialog; override; end; { TPluginPanel } TPluginPanel = class(TPanel) private FComboPlugin, FComboField, // <---The text of this combo is filled from localized string. The "objects" pointed from the its list are "TWdxField" type. FComboOperator, FComboValue, FComboUnit: TComboBox; FEditValue: TCalcEdit; FDateTimeValue: TDateTimePicker; FValuePanel: TPanel; private function GetCompare: TPluginOperator; function GetField: String; function GetFieldType: Integer; function GetPlugin: String; function GetUnitName: String; function GetValue: Variant; procedure PluginChange(Sender: TObject); procedure FieldChange(Sender: TObject); procedure SetCompare(AValue: TPluginOperator); procedure SetField(AValue: String); procedure SetPlugin(AValue: String); procedure SetUnitName(AValue: String); procedure SetValue(AValue: Variant); procedure SetComboBox(ComboBox: TComboBox; const Value, Error: String); procedure ValueKeyPress(Sender: TObject; var Key: Char); procedure ValueUTF8KeyPress(Sender: TObject; var UTF8Key: TUTF8Char); procedure ComboValueKeyPress(Sender: TObject; var Key: Char); procedure ComboValueUTF8KeyPress(Sender: TObject; var UTF8Key: TUTF8Char); public constructor Create(TheOwner: TComponent); override; destructor Destroy; override; procedure UpdateSizes(ColumnWidth: Integer); public property Plugin: String read GetPlugin write SetPlugin; property Field: String read GetField write SetField; property UnitName: String read GetUnitName write SetUnitName; property FieldType: Integer read GetFieldType; property Compare: TPluginOperator read GetCompare write SetCompare; property Value: Variant read GetValue write SetValue; end; implementation uses DateUtils, CalcForm, uLng, Variants, WdxPlugin, uGlobs, uWDXModule, Graphics, uShowMsg; { TCalcEdit } procedure TCalcEdit.RunDialog; begin cColorBtnDigits:= ColorToRGB(clBtnText); cColorBtnOthers:= cColorBtnDigits; cColorDisplayText:= clWindowText; cColorDisplayBack:= clWindow; inherited RunDialog; end; { TPluginPanel } function TPluginPanel.GetCompare: TPluginOperator; begin Result:= TPluginOperator(PtrInt(FComboOperator.Items.Objects[FComboOperator.ItemIndex])); end; function TPluginPanel.GetField: String; begin Result := TWdxField(FComboField.Items.Objects[FComboField.ItemIndex]).FName; end; function TPluginPanel.GetFieldType: Integer; begin Result := TWdxField(FComboField.Items.Objects[FComboField.ItemIndex]).FType end; function TPluginPanel.GetPlugin: String; begin Result:= FComboPlugin.Text; end; function TPluginPanel.GetUnitName: String; begin if (FComboField.ItemIndex < 0) or (FComboUnit.ItemIndex < 0) then Result:= FComboUnit.Text else begin Result:= TWdxField(FComboField.Items.Objects[FComboField.ItemIndex]).FUnits[FComboUnit.ItemIndex]; end; end; function TPluginPanel.GetValue: Variant; var WdxField: TWdxField; begin WdxField:= TWdxField(FComboField.Items.Objects[FComboField.ItemIndex]); if (WdxField.FType <> ft_multiplechoice) then case WdxField.FType of FT_NUMERIC_32: result:= FEditValue.AsInteger; FT_NUMERIC_64: result:= round(FEditValue.AsFloat); FT_NUMERIC_FLOATING: result:= FEditValue.AsFloat; FT_DATE: result:= FDateTimeValue.Date; FT_TIME: result:= FDateTimeValue.Time; FT_DATETIME: result:= FDateTimeValue.DateTime; FT_BOOLEAN, FT_STRING, FT_STRINGW, FT_FULLTEXT, FT_FULLTEXTW: Result:= StrToVar(FComboValue.Text, WdxField.FType) end else begin Result:= StrToVar(WdxField.FUnits[FComboValue.ItemIndex], WdxField.FType) end; end; // When a plugin is selected from the plugin combo, we populate the others in cascade. // In the field combo, each element references a corresding "TWdxField" object. // Since this combo is for the user we populate text of it from localized strings. procedure TPluginPanel.PluginChange(Sender: TObject); var I: Integer; Module: TWDXModule; begin if FComboPlugin.ItemIndex < 0 then Exit; FComboField.Clear; Module:= gWdxPlugins.GetWdxModule(FComboPlugin.Text); if Assigned(Module) then for I:= 0 to Module.FieldList.Count - 1 do FComboField.Items.AddObject(TWdxField(Module.FieldList.Objects[I]).LName, TObject(Module.FieldList.Objects[I])); if FComboField.Items.Count > 0 then begin FComboField.ItemIndex:= 0; FieldChange(FComboField); end; end; procedure TPluginPanel.FieldChange(Sender: TObject); var WdxField: TWdxField; begin FComboUnit.Clear; FComboValue.Items.Clear; FComboOperator.Items.Clear; FComboValue.Text:= EmptyStr; FComboValue.Visible:= True; FDateTimeValue.DateTime:= RecodeMilliSecond(Now, 0); FDateTimeValue.Visible:= False; FEditValue.Text:= EmptyStr; FEditValue.Visible:= False; if (FComboField.ItemIndex < 0) then Exit; WdxField:= TWdxField(FComboField.Items.Objects[FComboField.ItemIndex]); if (WdxField.FType <> FT_MULTIPLECHOICE) then begin FComboUnit.Items.AddStrings(WdxField.LUnits); end; FComboUnit.Visible := (WdxField.FType <> FT_MULTIPLECHOICE) and (FComboUnit.Items.Count > 0); if FComboUnit.Visible then FComboUnit.ItemIndex:= 0; case WdxField.FType of FT_NUMERIC_32, FT_NUMERIC_64, FT_NUMERIC_FLOATING, FT_DATE, FT_TIME, FT_DATETIME: begin FComboValue.Visible:= False; if (WdxField.FType > FT_NUMERIC_FLOATING) then begin FDateTimeValue.Visible:= True; if (WdxField.FType = FT_DATETIME) then FDateTimeValue.Kind:= dtkDateTime else if (WdxField.FType = FT_TIME) then FDateTimeValue.Kind:= dtkTime else FDateTimeValue.Kind:= dtkDate end else begin FEditValue.Visible:= True;; end; FComboOperator.Items.AddObject('=', TObject(PtrInt(poEqualCaseSensitive))); FComboOperator.Items.AddObject('!=', TObject(PtrInt(poNotEqualCaseSensitive))); FComboOperator.Items.AddObject('>', TObject(PtrInt(poMore))); FComboOperator.Items.AddObject('<', TObject(PtrInt(poLess))); FComboOperator.Items.AddObject('>=', TObject(PtrInt(poMoreEqual))); FComboOperator.Items.AddObject('<=', TObject(PtrInt(poLessEqual))); end; FT_BOOLEAN: begin FComboValue.Items.Add(rsSimpleWordTrue); FComboValue.Items.Add(rsSimpleWordFalse); FComboValue.ItemIndex:= 0; FComboValue.Style:= csDropDownList; FComboOperator.Items.AddObject('=', TObject(PtrInt(poEqualCaseSensitive))); end; FT_MULTIPLECHOICE: begin begin FComboValue.Style:= csDropDownList; FComboOperator.Items.AddObject('=', TObject(PtrInt(poEqualCaseSensitive))); FComboOperator.Items.AddObject('!=', TObject(PtrInt(poNotEqualCaseSensitive))); FComboValue.Items.AddStrings(WdxField.LUnits); if FComboValue.Items.Count > 0 then FComboValue.ItemIndex:= 0; end; end; FT_STRING, FT_STRINGW: begin FComboValue.Style:= csDropDown; FComboValue.Items := glsSearchHistory; FComboOperator.Items.AddObject(rsPluginSearchEqualNotCase, TObject(PtrInt(poEqualCaseInsensitive))); FComboOperator.Items.AddObject(rsPluginSearchNotEqualNotCase, TObject(PtrInt(poNotEqualCaseInsensitive))); FComboOperator.Items.AddObject(rsPluginSearchEqualCaseSensitive, TObject(PtrInt(poEqualCaseSensitive))); FComboOperator.Items.AddObject(rsPluginSearchNotEquaCaseSensitive, TObject(PtrInt(poNotEqualCaseSensitive))); FComboOperator.Items.AddObject(rsPluginSearchContainsNotCase, TObject(PtrInt(poContainsCaseInsensitive))); FComboOperator.Items.AddObject(rsPluginSearchNotContainsNotCase, TObject(PtrInt(poNotContainsCaseInsensitive))); FComboOperator.Items.AddObject(rsPluginSearchContainsCaseSenstive, TObject(PtrInt(poContainsCaseSensitive))); FComboOperator.Items.AddObject(rsPluginSearchNotContainsCaseSenstive, TObject(PtrInt(poNotContainsCaseSensitive))); FComboOperator.Items.AddObject(rsPluginSearchRegExpr, TObject(PtrInt(poRegExpr))); FComboOperator.Items.AddObject(rsPluginSearchNotRegExpr, TObject(PtrInt(poNotRegExpr))); end; FT_FULLTEXT, FT_FULLTEXTW: begin FComboValue.Style:= csDropDown; FComboValue.Items := glsSearchHistory; FComboOperator.Items.AddObject(rsPluginSearchContainsNotCase, TObject(PtrInt(poContainsCaseInsensitive))); FComboOperator.Items.AddObject(rsPluginSearchNotContainsNotCase, TObject(PtrInt(poNotContainsCaseInsensitive))); FComboOperator.Items.AddObject(rsPluginSearchContainsCaseSenstive, TObject(PtrInt(poContainsCaseSensitive))); FComboOperator.Items.AddObject(rsPluginSearchNotContainsCaseSenstive, TObject(PtrInt(poNotContainsCaseSensitive))); end; end; if FComboOperator.Items.Count > 0 then FComboOperator.ItemIndex:= 0; end; procedure TPluginPanel.SetCompare(AValue: TPluginOperator); var Index: Integer; begin Index:= FComboOperator.Items.IndexOfObject(TObject(PtrInt(AValue))); if Index >= 0 then FComboOperator.ItemIndex:= Index; end; // The "AValue" parameter received here is not localized. // We can't search it in combo box directly so we go by index. procedure TPluginPanel.SetField(AValue: String); var Module: TWDXModule; begin Module := gWdxPlugins.GetWdxModule(FComboPlugin.Text); if Module = nil then exit; FComboField.ItemIndex := Module.GetFieldIndex(AValue); if FComboField.ItemIndex <> -1 then begin if Assigned(FComboField.OnChange) then FComboField.OnChange(FComboField); end else begin msgError(rsPluginSearchFieldNotFound); end; end; procedure TPluginPanel.SetPlugin(AValue: String); begin SetComboBox(FComboPlugin, AValue, Format(rsPluginSearchPluginNotFound, [AValue])); end; procedure TPluginPanel.SetUnitName(AValue: String); var Index: Integer; WdxField: TWdxField; begin if FComboUnit.Visible then begin WdxField:= TWdxField(FComboField.Items.Objects[FComboField.ItemIndex]); Index := WdxField.GetUnitIndex(AValue); if Index >= 0 then AValue:= WdxField.LUnits[Index]; SetComboBox(FComboUnit, AValue, Format(rsPluginSearchUnitNotFoundForField, [AValue, Self.Field])); end; end; procedure TPluginPanel.SetValue(AValue: Variant); var Index: Integer; WdxField: TWdxField; begin if VarIsBool(AValue) then begin if AValue then FComboValue.Text := rsSimpleWordTrue else FComboValue.Text := rsSimpleWordFalse; end else begin WdxField:= TWdxField(FComboField.Items.Objects[FComboField.ItemIndex]); if (WdxField.FType <> FT_MULTIPLECHOICE) then begin if (WdxField.FType < FT_DATE) then FEditValue.Text:= AValue else if (WdxField.FType in [FT_DATE, FT_TIME, FT_DATETIME]) then FDateTimeValue.DateTime:= AValue else FComboValue.Text := AValue; end else begin Index:= WdxField.GetUnitIndex(AValue); if Index < 0 then FComboValue.Text := AValue else FComboValue.Text := WdxField.LUnits[Index]; end; end; end; procedure TPluginPanel.SetComboBox(ComboBox: TComboBox; const Value, Error: String); var Index: Integer; begin Index:= ComboBox.Items.IndexOf(Value); if Index < 0 then msgError(Error) else begin ComboBox.ItemIndex:= Index; if Assigned(ComboBox.OnChange) then ComboBox.OnChange(ComboBox); end; end; procedure TPluginPanel.ValueKeyPress(Sender: TObject; var Key: Char); var WdxField: TWdxField; begin WdxField:= TWdxField(FComboField.Items.Objects[FComboField.ItemIndex]); case WdxField.FType of FT_NUMERIC_32, FT_NUMERIC_64: begin if not (Key in ['0'..'9', Chr(VK_BACK)]) then Key:= #0; end; FT_NUMERIC_FLOATING: begin if not (Key in ['0'..'9', Chr(VK_BACK), DefaultFormatSettings.DecimalSeparator]) then Key:= #0; end; end; end; procedure TPluginPanel.ValueUTF8KeyPress(Sender: TObject; var UTF8Key: TUTF8Char); var WdxField: TWdxField; begin WdxField:= TWdxField(FComboField.Items.Objects[FComboField.ItemIndex]); case WdxField.FType of FT_NUMERIC_32, FT_NUMERIC_64, FT_NUMERIC_FLOATING: begin if (Length(UTF8Key) > 1) then UTF8Key:= #0; end; end; end; procedure TPluginPanel.ComboValueKeyPress(Sender: TObject; var Key: Char); var WdxField: TWdxField; begin if (FComboField.ItemIndex < 0) then Exit; ValueKeyPress(Sender, Key); end; procedure TPluginPanel.ComboValueUTF8KeyPress(Sender: TObject; var UTF8Key: TUTF8Char); var WdxField: TWdxField; begin if (FComboField.ItemIndex < 0) then Exit; ValueUTF8KeyPress(Sender, UTF8Key); end; procedure TPluginPanel.UpdateSizes(ColumnWidth: Integer); begin FComboPlugin.Constraints.MinWidth:= ColumnWidth; FComboPlugin.Constraints.MaxWidth:= ColumnWidth; FComboField.Constraints.MinWidth:= ColumnWidth; FComboField.Constraints.MaxWidth:= ColumnWidth; FComboOperator.Constraints.MinWidth:= ColumnWidth; FComboOperator.Constraints.MaxWidth:= ColumnWidth; FValuePanel.Constraints.MinWidth:= ColumnWidth * 2; FValuePanel.Constraints.MaxWidth:= ColumnWidth * 2; end; constructor TPluginPanel.Create(TheOwner: TComponent); var I, ColumnWidth: Integer; begin inherited Create(TheOwner); AutoSize:= True; BevelOuter:= bvNone; FComboPlugin:= TComboBox.Create(Self); FComboPlugin.Parent:= Self; FComboPlugin.Style:= csDropDownList; FComboPlugin.OnChange:= @PluginChange; FComboField:= TComboBox.Create(Self); FComboField.Parent:= Self; FComboField.Style:= csDropDownList; FComboField.OnChange:= @FieldChange; FComboOperator:= TComboBox.Create(Self); FComboOperator.Parent:= Self; FComboOperator.Style:= csDropDownList; FValuePanel:= TPanel.Create(Self); FValuePanel.Parent:= Self; FValuePanel.AutoSize:= True; FValuePanel.BevelOuter:= bvNone; FValuePanel.ChildSizing.ControlsPerLine:= 2; FValuePanel.ChildSizing.Layout:= cclLeftToRightThenTopToBottom; FValuePanel.ChildSizing.EnlargeHorizontal:= crsScaleChilds; FValuePanel.ChildSizing.EnlargeVertical:= crsScaleChilds; FComboValue:= TComboBox.Create(Self); FComboValue.OnKeyPress:= @ComboValueKeyPress; FComboValue.OnUTF8KeyPress:= @ComboValueUTF8KeyPress; FComboValue.Parent:= FValuePanel; FEditValue:= TCalcEdit.Create(Self); FEditValue.OnKeyPress:= @ValueKeyPress; FEditValue.OnUTF8KeyPress:= @ValueUTF8KeyPress; FEditValue.Parent:= FValuePanel; FDateTimeValue:= TDateTimePicker.Create(Self); FDateTimeValue.Parent:= FValuePanel; FDateTimeValue.BorderSpacing.CellAlignVertical:=ccaCenter; FDateTimeValue.BorderSpacing.CellAlignHorizontal:=ccaCenter; FComboUnit:= TComboBox.Create(Self); FComboUnit.Style:= csDropDownList; FComboUnit.Parent:= FValuePanel; FComboPlugin.AnchorVerticalCenterTo(FValuePanel); FComboField.AnchorVerticalCenterTo(FValuePanel); FComboField.AnchorToNeighbour(akLeft, 0, FComboPlugin); FComboOperator.AnchorVerticalCenterTo(FValuePanel); FComboOperator.AnchorToNeighbour(akLeft, 0, FComboField); FValuePanel.AnchorToNeighbour(akLeft, 0, FComboOperator); ColumnWidth:= TControl(TheOwner).ClientWidth div 5; UpdateSizes(ColumnWidth); for I:= 0 to gWDXPlugins.Count - 1do begin if gWdxPlugins.GetWdxModule(I).IsLoaded or gWdxPlugins.GetWdxModule(I).LoadModule then begin FComboPlugin.Items.Add(gWdxPlugins.GetWdxModule(I).Name); end; end; if FComboPlugin.Items.Count > 0 then begin FComboPlugin.ItemIndex:= 0; PluginChange(FComboPlugin); end; end; destructor TPluginPanel.Destroy; begin FComboPlugin.Free; FComboField.Free; FComboOperator.Free; FValuePanel.Free; FComboValue.Free; FEditValue.Free; FDateTimeValue.Free; FComboUnit.Free; inherited Destroy; end; end.