unit FMSearchX;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  GradForm, ComCtrls, ExtListView, StdCtrls, Grids, ExtCtrls,
  ComboBoxEx, StatusBarEx, Menus, pmmatcher, EnhListView;


type
  TSearchAdvanced= class(TdfsGradientForm)
    Panel2: TPanel;
    Panel1: TPanel;
    GroupBox1: TGroupBox;
    GroupBox2 : TGroupBox;
    cboStartFolder: TPMComboBoxEx;
    btnStartIn: TButton;
    chkRecurse: TCheckBox;
    rdgMatch: TRadioGroup;
    SearchGrid: TStringGrid;
    cboSearchFields: TComboBox;
    cboSearchActionString: TComboBox;
    Panel3: TPanel;
    btnGo: TButton;
    btnStop: TButton;
    btnClose: TButton;
    lvwSearchResults: TdfsExtListView;
    StatusBarEx1: TStatusBarEx;
    cboDate: TDateTimePicker;
    cboSearchActionNumber: TComboBox;
    cboLabels: TComboBox;
    btnMore: TButton;
    btnFewer: TButton;
    Animate1: TAnimate;
    label1 : TLabel;
    PopupMenu1: TPopupMenu;
    Open1: TMenuItem;
    N1: TMenuItem;
    Copyto1: TMenuItem;
    Moveto1: TMenuItem;
    N2: TMenuItem;
    Delete1 : TMenuItem;
    cboFindText: TComboBox;
    procedure FormCreate(Sender: TObject);
    procedure FormShow(Sender: TObject);
    procedure btnCloseClick(Sender: TObject);
    procedure SearchGridSelectCell(Sender: TObject; ACol, ARow: Integer;
      var CanSelect: Boolean);
    procedure cboSearchFieldsClick(Sender: TObject);
    procedure cboSearchActionStringClick(Sender: TObject);
    procedure dfsGradientFormDestroy(Sender: TObject);
    procedure dfsGradientFormClose(Sender: TObject;
      var Action: TCloseAction);
    procedure btnGoClick(Sender: TObject);
    procedure btnStopClick(Sender: TObject);
    procedure btnStartInClick(Sender: TObject);
    procedure cboDateChange(Sender: TObject);
    procedure cboSearchActionNumberClick(Sender: TObject);
    procedure cboLabelsDrawItem(Control: TWinControl; Index: Integer;
      Rect: TRect; State: TOwnerDrawState);
    procedure cboLabelsClick(Sender: TObject);
    procedure btnMoreClick(Sender: TObject);
    procedure btnFewerClick(Sender: TObject);
    procedure lvwSearchResultsDblClick(Sender: TObject);
    procedure Copyto1Click(Sender: TObject);
    procedure lvwSearchResultsClick(Sender: TObject);
    procedure Delete1Click(Sender: TObject);
    procedure PopupMenu1Popup(Sender: TObject);
    procedure cboFindTextClick(Sender: TObject);
    procedure cboFindTextChange(Sender: TObject);
    procedure cboFindTextExit(Sender: TObject);
  private
    { Private declarations }
    procedure HideCombos;
  protected
    { Protected declarations }
  public
    { Public declarations }
    bStopSearch : Boolean;
    fWorkThread : TThread;
    procedure DoRemoteMove(oldfile, newfile : string);
    procedure SearchMessage;
    procedure StartSearch;
    procedure StopSearch;
  published
    { Published declarations }
  end;

var
  SearchAdvanced : TSearchAdvanced;


implementation

{$R *.DFM}

uses main, pxstuff, ParserSup, DateSup, FMMoveMessage;

/// TSearchThread................
type TSearchThread = class(TThread)
  private
    fMessageFile : TStringList;
    fFileSpecific : TFileSpecific;
    fStartFolder : string;
    fFolder : string;
    fFile : string;
    fStop : Boolean;
    fAndOr : integer;
    procedure FUpdateStatusBar;
    procedure FSearchFolder;
    procedure FRecurseDir(adir : string);
    procedure FAddMessage;
    procedure FDoCompare;
  protected
    procedure Execute; override;
  public
    constructor Create;
    destructor Destroy; override;
    procedure Init;
  end;



procedure TSearchThread.FDoCompare;
 var s, ds : string;
      t1, t2, x : integer;
      bl : boolean;
      da, ti : TDateTime;
begin
  // When doing an OR search, the starting value may be everything. In case
  // of an AND, matching should start with a TRUE value.
  if fAndOr = 0 then
    bl := False
  else
    bl := True;

  for x := 0 to SearchAdvanced.SearchGrid.RowCount - 1 do
  begin
    // Wich field?
    t1 := SearchAdvanced.cboSearchFields.Items.IndexOf(
      SearchAdvanced.SearchGrid.Cells[0, x]);
    if t1 = -1 then
    begin
      fStop := True;
      exit;
    end;
    // The search/compare item as filled in by user of course.
    s := Trim(SearchAdvanced.SearchGrid.Cells[2, x]);

    // String matching only!
    if t1 < 8 then
    begin
      // Get the header field value...
      ds := GetSearchedString(t1, fMessageFile);
      // Check for the action type in the combolist.
      t2 := SearchAdvanced.cboSearchActionString.Items.IndexOf(
        SearchAdvanced.SearchGrid.Cells[1, x]);
      if t2 = -1 then
      begin
        fStop := True;
        exit;
      end;

      // Do appropriate bit math...
      if fAndOr = 0 then
         bl := bl or MatchStrings(s, t2, ds)
      else
         bl := bl and MatchStrings(s, t2, ds);
    end;

    // Date matching only!
    if t1 = 8 then
    begin
      ds := GetSearchedString(t1, fMessageFile);
      t2 := SearchAdvanced.cboSearchActionNumber.Items.IndexOf(
        SearchAdvanced.SearchGrid.Cells[1, x]);
      if t2 = -1 then
      begin
        fStop := True;
        exit;
      end;
      // Convert to Datetime...
      MailTimeToDateTime(ds, da, ti);

      if fAndOr = 0 then
        bl := bl or MatchDouble(StrToDate(s), t2, da)
      else
        bl := bl and MatchDouble(StrToDate(s), t2, da);
    end;

    // Size matching
    if t1 = 9 then
    begin
      t2 := SearchAdvanced.cboSearchActionNumber.Items.IndexOf(
        SearchAdvanced.SearchGrid.Cells[1, x]);

      if t2 = -1 then
      begin
        fStop := True;
        exit;
      end;

      if fAndOr = 0 then
        bl := bl or MatchNumbers(strToIntDef(s, 0), t2, fFileSpecific.fsize)
      else
        bl := bl and MatchNumbers(strToIntDef(s, 0), t2, fFileSpecific.fsize);
    end;

    // Label matching...
    if t1 = 10 then
    begin
      t2 := SearchAdvanced.cboSearchActionNumber.Items.IndexOf(
        SearchAdvanced.SearchGrid.Cells[1, x]);
      if t2 = -1 then
      begin
        fStop := True;
        exit;
      end;

      if fAndOr = 0 then
        bl := bl or MatchNumbers(SearchAdvanced.cboLabels.Items.IndexOf(s), t2,
          fFileSpecific.clabel)
      else
        bl := bl and MatchNumbers(SearchAdvanced.cboLabels.Items.IndexOf(s), t2,
          fFileSpecific.clabel);
    end;

    // Attachment count
    if t1 = 11 then
    begin
      t2 := SearchAdvanced.cboSearchActionNumber.Items.IndexOf(
        SearchAdvanced.SearchGrid.Cells[1, x]);
      if t2 = -1 then
      begin
        fStop := True;
        exit;
      end;

      if fAndOr = 0 then
        bl := bl or MatchAttachments(StrToIntDef(s, 0), t2, fMessageFile.Text)
      else
        bl := bl and MatchAttachments(StrTOIntDef(s, 0), t2, fMessageFile.Text);
    end;
  end;
  if bl then FAddMessage;
end;

procedure TSearchThread.FUpdateStatusBar;
begin
  SearchAdVanced.StatusBarEx1.Panels[1].Text := fFile;
end;

procedure TSearchThread.FSearchFolder;
var
  Found: integer;
  SearchRec: TSearchRec;
begin
  Found := FindFirst(fFolder + '*.msg', faAnyFile, SearchRec);
  while (Found = 0) and (not Terminated) and (not fStop) do
  begin   //AH06
    fMessageFile.LoadFromFile(fFolder + SearchRec.Name);
    fFile := fFolder + searchRec.Name;
    Synchronize(FUpdateStatusBar);
    fFileSpecific.fsize := SearchRec.Size;
    fFileSpecific.clabel := StrToIntDef(SearchRec.Name[1], 0);
    Synchronize(FDoCompare);
    Found := FindNext(SearchRec);
  end;
  FindClose(SearchRec);
end;


procedure TSearchThread.FRecurseDir(adir : string);
var
  SearchRec: TSearchRec;
  Found: Integer;
begin
  Found := FindFirst(adir + '*.*', $37, SearchRec);
  while (Found = 0) and (not Terminated) do begin //AH06
    if (SearchRec.Attr and $10 = $10) and (SearchRec.Name <> '.') and
      (SearchRec.Name <> '..') then
    begin
      fFolder :=  adir + SearchRec.Name + '\';
      FSearchFolder;
      FRecurseDir(fFolder);
    end;
    Found := FindNext(SearchRec);
  end;
  FindClose(SearchRec);
end;


procedure TSearchThread.Init;
begin
  // Actually just sets the folder.
  FStartFolder :=
    MakeValidDirName(
    SearchAdvanced.cboStartFolder.Values[
    SearchAdvanced.cboStartFolder.ItemIndex]);
  fAndOr := SearchAdvanced.rdgMatch.ItemIndex;
end;

procedure TSearchThread.FAddMessage;
var
  li: TListItem;
begin
  if terminated then exit;
  li := SearchAdvanced.lvwSearchResults.Items.Add;
  li.Caption := fFolder;
  li.SubItems.Add(GetSearchedString(7, fMessageFile));
  li.SubItems.Add(GetSearchedString(4, fMessageFile));
  li.SubItems.Add(fFile);
  // AH08
  SearchAdvanced.StatusBarEx1.Panels[0].Text := Format(GetMessageString(111),
    [IntToStr(SearchAdvanced.lvwSearchResults.Items.Count)]);
end;

constructor TSearchThread.Create;
begin
  inherited Create(False); //AH16
  fMessageFile := TStringList.Create;
  fStop := False;
end;

procedure TSearchThread.Execute;
begin
  fFolder := fStartFolder;
  FSearchFolder;
  if Terminated or fStop then
  begin
    SearchAdvanced.StopSearch;
    exit;
  end;

  if SearchAdvanced.chkRecurse.Checked and not terminated and not fStop then
  begin
    FRecurseDir(fStartFolder);
    if Terminated or fStop then
    begin
      SearchAdvanced.StopSearch;
      exit;
    end;
  end;
  SearchAdvanced.StopSearch;
end;

destructor TSearchThread.Destroy;
begin
  fMessageFile.Free;
  inherited Destroy;
end;
/// TSearchThread................


// Members...
procedure TSearchAdvanced.HideCombos;
begin
  // Just hide the combos...
  if cboSearchFields.Visible then    cboSearchFields.Visible := false;
  if cboSearchActionString.Visible then   cboSearchActionString.Visible := false;
  if cboDate.Visible then cboDate.Visible := False;
  if cboSearchActionNumber.visible then cboSearchActionNumber.visible := false;
  if cboLabels.Visible then cboLabels.Visible := False;
  if cboFindText.Visible then cboFindText.Visible := False; //RR33
end;

procedure TSearchAdvanced.StartSearch;
begin
  bStopSearch := False;
  btnGo.Enabled := False;
  btnStop.Enabled := True;
  Animate1.Active := True;
  // AH08
  StatusBarEx1.Panels[0].Text := Format(GetMessageString(111), [IntToStr(0)]); //RR32
  StatusBarEx1.Panels[1].Text := '';
  lvwSearchResults.Items.Clear;
  Panel1.Enabled := False;
end;

procedure TSearchAdvanced.StopSearch;
begin
  bStopSearch := True;
  btnGo.Enabled := True;
  btnStop.Enabled := False;
  Animate1.Active := False;
  Panel1.Enabled := True;
end;


procedure TSearchAdvanced.SearchMessage;
begin
  fWorkThread := TSearchThread.Create;
  TSearchThread(fWorkThread).Init;
  fWorkThread.Resume;
end;


procedure TSearchAdvanced.FormCreate(Sender: TObject);
begin
  // Some resizing...
  SearchGrid.DefaultRowHeight := cboSearchFields.Height;
  SearchGrid.ClientHeight := 4 * SearchGrid.DefaultRowHeight +
                            (5 * SearchGrid.GridLineWidth);
  // Add labels...
  cbolabels.Items.Add('[none]');
  cbolabels.Items.Add(sLabel1);
  cbolabels.Items.Add(sLabel2);
  cbolabels.Items.Add(sLabel3);
  cbolabels.Items.Add(sLabel4);
  cbolabels.Items.Add(sLabel5);
  cbolabels.Items.Add(sLabel6);
  cbolabels.Items.Add(sLabel7);
  cbolabels.Items.Add(sLabel8);
  cbolabels.Items.Add(sLabel9);
end;

procedure TSearchAdvanced.FormShow(Sender: TObject);
var s : TTreeNode;
    abool : boolean;
begin
  SetWindowLong(Handle, GWL_ExStyle, WS_Ex_AppWindow); //RR31
  cboSearchFields.Visible := False;
  cboSearchActionString.Visible := False;
  cboStartFolder.Images := MainForm.ImageList1;
  cboFindText.Visible := False; //RR33 begin

  if FileExists(GetAppPath + 'mfhis.txt') then
    cboFindText.Items.LoadFromFile(GetAppPath + 'mfhis.txt'); //RR33 end

  s := MainForm.TreeView1.Items.GetFirstNode;
  while s <> nil do
  begin
    cboStartFolder.Items.Add(s.Text);
    case s.StateIndex of
    tnThrashBag:  cboStartFolder.Values.Add(sTrashFolder);
    tnAccounts:   cboStartFolder.Values.Add(sAccountRootFolder);
    tnRepository: cboStartFolder.Values.Add(sRepositoryFolder);
    tnStationary:  cboStartFolder.Values.Add(sStationaryFolder);
    end;
    cboStartFolder.ImgIndexes.Add(IntToStr(s.ImageIndex));
    s := s.getNextSibling;
  end;
  cboStartFolder.ItemIndex := 0;
  cboStartFolder.Invalidate;
  // Select first entry of the SearchGrid...
  SearchGrid.OnSelectCell(Self, 0, 0, abool);
  SetForeGroundWindow(SearchAdvanced.Handle);

end;


procedure TSearchAdvanced.btnCloseClick(Sender: TObject);
begin
  if fWorkThread <> nil then
  begin
    fWorkThread.Terminate;
    fWorkThread.WaitFor;
  end;
  Close;
end;

procedure TSearchAdvanced.SearchGridSelectCell(Sender: TObject; ACol,
  ARow: Integer; var CanSelect: Boolean);
var Sel : TRect;
    prevstr : string;
    sind : integer;
begin
  Sel := SearchGrid.CellRect(Acol, Arow);
  prevstr := SearchGrid.Cells[ACol, Arow];
  HideCombos;

  case Acol of
  0 :  begin
         SetWindowPos(cboSearchFields.Handle,
           0,
          Sel.Left+ SearchGrid.left + 1,
          Sel.Top + SearchGrid.top + 1,
          Sel.Right - Sel.Left + 2,
          Sel.Bottom - Sel.top + 2,
          SWP_NOZORDER or SWP_SHOWWINDOW);

          cboSearchFields.ItemIndex := cboSearchFields.Items.IndexOf(prevstr);
          cboSearchFields.Show;
          Exit;
        end;
  1 :  begin
        // If sind = -1 then field will be filled with prevstr...
        sind := cboSearchFields.Items.IndexOf(SearchGrid.Cells[0,ARow]);
        case sind of
        0..7  : begin
                  SetWindowPos(cboSearchActionString.Handle, { handle }
                  0, { change z-order }
                  Sel.Left + SearchGrid.Left + 1,
                  Sel.Top + SearchGrid.top + 1,
                  Sel.Right - Sel.Left + 2,
                  Sel.Bottom - Sel.top + 2,
                  SWP_NOZORDER or SWP_SHOWWINDOW);
                  cboSearchActionString.ItemIndex := cboSearchActionString.Items.IndexOf(prevstr);
                  cboSearchActionString.Show;
                  Exit;
                end;
        8..11 : begin
                  SetWindowPos(cboSearchActionNumber.Handle, { handle }
                  0, { change z-order }
                  Sel.Left + SearchGrid.Left + 1,
                  Sel.Top + SearchGrid.top + 1,
                  Sel.Right - Sel.Left + 2,
                  Sel.Bottom - Sel.top + 2,
                  SWP_NOZORDER or SWP_SHOWWINDOW);
                  cboSearchActionNumber.ItemIndex := cboSearchActionNumber.Items.IndexOf(prevstr);
                  cboSearchActionNumber.Show;
                  Exit;
                end;
        end;
      end;
  2 : begin

        if cboSearchFields.Items.IndexOf(SearchGrid.Cells[0, Arow]) = 8 then  // DATE!
        begin
          // Show Datepicker
          SetWindowPos(cboDate.Handle, { handle }
          0, { change z-order }
          Sel.Left + SearchGrid.Left + 1,
          Sel.Top + SearchGrid.top + 1,
          Sel.Right - Sel.Left + 2,
          Sel.Bottom - Sel.top + 2,
          SWP_NOZORDER or SWP_SHOWWINDOW);

          if prevStr = '' then //RR29
          begin
            cboDate.DateTime := Now;
            btnGo.enabled := false;
            cboDateChange(Sender);
          end //RR29
          else
            cboDate.DateTime := StrToDate(prevStr);
          cboDate.Show;
          Exit;
        end;

        if cboSearchFields.Items.IndexOf(SearchGrid.Cells[0, Arow]) = 10 then //LABEL!
        begin
          // Show Datepicker
          SetWindowPos(cboLabels.Handle, { handle }
          0, { change z-order }
          Sel.Left + SearchGrid.Left + 1,
          Sel.Top + SearchGrid.top + 1,
          Sel.Right - Sel.Left + 2,
          Sel.Bottom - Sel.top + 2,
          SWP_NOZORDER or SWP_SHOWWINDOW);
          cboLabels.ItemIndex := cboLabels.Items.IndexOf(prevstr);
          cboLabels.Show;
          Exit;
        end;

        //RR33 begin Show default cbo for textstrings
        SetWindowPos(cboFindText.Handle, { handle }
          0, { change z-order }
          Sel.Left + SearchGrid.Left + 1,
          Sel.Top + SearchGrid.top + 2, //AH09 Ummmm... a correction?
          Sel.Right - Sel.Left + 2,
          Sel.Bottom - Sel.top + 2,
          SWP_NOZORDER or SWP_SHOWWINDOW);
        cboFindText.ItemIndex := cboFindText.Items.IndexOf(prevstr);
        cboFindText.Show;
        //RR33 end

    end
  end;

  SearchGrid.Cells[ACol, Arow] := prevstr;
end;

procedure TSearchAdvanced.cboSearchFieldsClick(Sender: TObject);
begin
   SearchGrid.Rows[SearchGrid.Row].Clear;  // Clear this line...
   SearchGrid.Cells[SearchGrid.Col,SearchGrid.Row] :=  cboSearchFields.Text;
end;

procedure TSearchAdvanced.cboSearchActionStringClick(Sender: TObject);
begin
  SearchGrid.Cells[SearchGrid.Col,SearchGrid.Row] :=  cboSearchActionString.Text;
end;

procedure TSearchAdvanced.cboSearchActionNumberClick(Sender: TObject);
begin
  SearchGrid.Cells[SearchGrid.Col,SearchGrid.Row] :=  cboSearchActionNumber.Text;
end;

procedure TSearchAdvanced.cboLabelsClick(Sender: TObject);
begin
  SearchGrid.Cells[SearchGrid.Col,SearchGrid.Row] :=  cboLabels.Text;
end;

procedure TSearchAdvanced.dfsGradientFormDestroy(Sender: TObject);
begin
  SearchAdvanced := nil;
  fWorkThread.Free;
end;

procedure TSearchAdvanced.dfsGradientFormClose(Sender: TObject;
  var Action: TCloseAction);
begin
  if fWorkThread <> nil then
  begin
    fWorkThread.Terminate;
    fWorkThread.WaitFor;
  end;
  // RR33
  if cboFindText.Items.Count > 0 then
    cboFindText.Items.SaveToFile(GetAppPath + 'mfhis.txt');

  Action := caFree;
end;

procedure TSearchAdvanced.btnGoClick(Sender: TObject);
begin
  StartSearch;
  SearchMessage;
end;

procedure TSearchAdvanced.btnStopClick(Sender: TObject);
begin
  FWorkThread.Terminate;
  FWorkThread.WaitFor;
  StopSearch;
end;

procedure TSearchAdvanced.btnStartInClick(Sender: TObject);
var
  i: integer;
  dlg :TfrmMoveMessage;
begin
  dlg := frmMoveMessage.Create(Self);
  if Assigned(LangHolder) then
  begin
    if LangHolder.Language <> '' then
      LangHolder.Translate([dlg]);
  end;

  try
    with dlg.TreeView1 do begin
      Items := MainForm.TreeView1.Items;
      FullExpand;
      // AHRK95 AlphaSort;
      // AHRK90
      if MainForm.TreeView1.Selected <> nil then
      begin
        Items[MainForm.TreeView1.Selected.AbsoluteIndex].Selected := True;
      end;      
    end;
    // AH08
    dlg.Caption := GetMessageString(116);
    if dlg.ShowModal = mrOK then begin
      i := cboStartFolder.Items.IndexOf(dlg.GetSearchPathName);
      if i > -1 then begin
        cboStartFolder.Items.Delete(i);
        cboStartFolder.Values.Delete(i);
        cboStartFolder.ImgIndexes.Delete(i);
      end;
      cboStartFolder.Items.Insert(0, dlg.GetSearchPathName);
      cboStartFolder.ItemIndex := 0;
      cboStartFolder.Values.Insert(0, dlg.GetSelectedPath);
      cboStartFolder.ImgIndexes.Insert(0, IntToStr(dlg.TreeView1.Selected.ImageIndex));
      cboStartFolder.Invalidate;
    end;
  finally
    dlg.Free;
  end;
end;



procedure TSearchAdvanced.cboDateChange(Sender: TObject);
begin
  // RR29
  if btnGo.Enabled = false then
  begin
    SearchGrid.Cells[SearchGrid.Col + 1, SearchGrid.Row] := DateToStr(cboDate.DateTime);
  end
  else
  begin
    SearchGrid.Cells[SearchGrid.Col, SearchGrid.Row] := DateToStr(cboDate.DateTime);
  end;
  btnGo.Enabled := true;
  // RR29
end;

procedure TSearchAdvanced.cboLabelsDrawItem(Control: TWinControl;
  Index: Integer; Rect: TRect; State: TOwnerDrawState);
begin
  // Owner draw stuff for those fancy labels (might want to put this
  // part in a unit since it's almost the same as the one in the Menu things...
  case Index of
  0 : begin
        if odSelected in State then
        begin
          cboLabels.Canvas.Brush.Color := clHighLight;
          cboLabels.Canvas.FillRect(Rect);
          cboLabels.Canvas.Font.Color := clHighlighttext;
          Drawtext(cboLabels.Canvas.Handle, PChar('[none]'), -1,  Rect, DT_SINGLELINE or DT_LEFT or DT_VCENTER)
        end
        else
        begin
          cboLabels.Canvas.Brush.Color := clWindow;
          cboLabels.Canvas.FillRect(Rect);
          cboLabels.Canvas.Font.Color := clWindowText;
          Drawtext(cboLabels.Canvas.handle, PChar('[none]'), -1,  Rect, DT_SINGLELINE or DT_LEFT or DT_VCENTER)
       end;
     end;
  1 : begin
        if odSelected in State then
        begin
          cboLabels.Canvas.Brush.Color := $002469FF;
          cboLabels.Canvas.FillRect(Rect);
          cboLabels.Canvas.Font.Color := clHighlighttext;
          Drawtext(cboLabels.Canvas.handle, PChar(sLabel1), -1,  Rect, DT_SINGLELINE or DT_LEFT or DT_VCENTER)
        end
        else
        begin
          cboLabels.Canvas.Brush.Color := clWindow;
          cboLabels.Canvas.FillRect(Rect);
          cboLabels.Canvas.Font.Color := $002469FF;
          Drawtext(cboLabels.Canvas.handle, PChar(slabel1), -1,  Rect, DT_SINGLELINE or DT_LEFT or DT_VCENTER)
       end;
     end;
  2 : begin
        if odSelected in State then
        begin
          cboLabels.Canvas.Brush.Color := clRed;
          cboLabels.Canvas.FillRect(Rect);
          cboLabels.Canvas.Font.Color := clHighlighttext;
          Drawtext(cboLabels.Canvas.handle, PChar(slabel2), -1,  Rect, DT_SINGLELINE or DT_LEFT or DT_VCENTER)
        end
        else
        begin
          cboLabels.Canvas.Brush.Color := clWindow;
          cboLabels.Canvas.FillRect(Rect);
          cboLabels.Canvas.Font.Color := clRed;
          Drawtext(cboLabels.Canvas.handle, PChar(slabel2), -1,  Rect, DT_SINGLELINE or DT_LEFT or DT_VCENTER)
       end;
     end;
  3 : begin
        if odSelected in State then
        begin
          cboLabels.Canvas.Brush.Color := clFuchsia;
          cboLabels.Canvas.FillRect(Rect);
          cboLabels.Canvas.Font.Color := clHighlighttext;
          Drawtext(cboLabels.Canvas.handle, PChar(slabel3), -1,  Rect, DT_SINGLELINE or DT_LEFT or DT_VCENTER)
        end
        else
        begin
          cboLabels.Canvas.Brush.Color := clWindow;
          cboLabels.Canvas.FillRect(Rect);
          cboLabels.Canvas.Font.Color := clFuchsia;
          Drawtext(cboLabels.Canvas.handle, PChar(slabel3), -1,  Rect, DT_SINGLELINE or DT_LEFT or DT_VCENTER)
       end;
     end;
  4 : begin
        if odSelected in State then
        begin
          cboLabels.Canvas.Brush.Color := $00FF8000;
          cboLabels.Canvas.FillRect(Rect);
          cboLabels.Canvas.Font.Color := clHighlighttext;
          Drawtext(cboLabels.Canvas.handle, PChar(slabel4), -1,  Rect, DT_SINGLELINE or DT_LEFT or DT_VCENTER)
        end
        else
        begin
          cboLabels.Canvas.Brush.Color := clWindow;
          cboLabels.Canvas.FillRect(Rect);
          cboLabels.Canvas.Font.Color := $00FF8000;
          Drawtext(cboLabels.Canvas.handle, PChar(slabel4), -1,  Rect, DT_SINGLELINE or DT_LEFT or DT_VCENTER)
       end;
     end;
  5 : begin
        if odSelected in State then
        begin
          cboLabels.Canvas.Brush.Color := clBlue;
          cboLabels.Canvas.FillRect(Rect);
          cboLabels.Canvas.Font.Color := clHighlighttext;
          Drawtext(cboLabels.Canvas.handle, PChar(slabel5), -1,  Rect, DT_SINGLELINE or DT_LEFT or DT_VCENTER)
        end
        else
        begin
          cboLabels.Canvas.Brush.Color := clWindow;
          cboLabels.Canvas.FillRect(Rect);
          cboLabels.Canvas.Font.Color := clBlue;
          Drawtext(cboLabels.Canvas.handle, PChar(slabel5), -1,  Rect, DT_SINGLELINE or DT_LEFT or DT_VCENTER)
       end;
     end;
  6 : begin
        if odSelected in State then
        begin
          cboLabels.Canvas.Brush.Color := clTeal;
          cboLabels.Canvas.FillRect(Rect);
          cboLabels.Canvas.Font.Color := clHighlighttext;
          Drawtext(cboLabels.Canvas.handle, PChar(slabel6), -1,  Rect, DT_SINGLELINE or DT_LEFT or DT_VCENTER)
        end
        else
        begin
          cboLabels.Canvas.Brush.Color := clWindow;
          cboLabels.Canvas.FillRect(Rect);
          cboLabels.Canvas.Font.Color := clTeal;
          Drawtext(cboLabels.Canvas.handle, PChar(slabel6), -1,  Rect, DT_SINGLELINE or DT_LEFT or DT_VCENTER)
       end;
     end;
  7 : begin
        if odSelected in State then
        begin
          cboLabels.Canvas.Brush.Color := clGreen;
          cboLabels.Canvas.FillRect(Rect);
          cboLabels.Canvas.Font.Color := clHighlighttext;
          Drawtext(cboLabels.Canvas.handle, PChar(slabel7), -1,  Rect, DT_SINGLELINE or DT_LEFT or DT_VCENTER)
        end
        else
        begin
          cboLabels.Canvas.Brush.Color := clWindow;
          cboLabels.Canvas.FillRect(Rect);
          cboLabels.Canvas.Font.Color := clGreen;
          Drawtext(cboLabels.Canvas.handle, PChar(slabel7), -1,  Rect, DT_SINGLELINE or DT_LEFT or DT_VCENTER)
       end;
     end;
  8 : begin
        if odSelected in State then
        begin
          cboLabels.Canvas.Brush.Color := clHighLight;
          cboLabels.Canvas.FillRect(Rect);
          cboLabels.Canvas.Font.Color := clHighlighttext;
          Drawtext(cboLabels.Canvas.handle, PChar(slabel8), -1,  Rect, DT_SINGLELINE or DT_LEFT or DT_VCENTER)
        end
        else
        begin
          cboLabels.Canvas.Brush.Color := clWindow;
          cboLabels.Canvas.FillRect(Rect);
          cboLabels.Canvas.Font.Color := clWindowText;
          Drawtext(cboLabels.Canvas.handle, PChar(slabel8), -1,  Rect, DT_SINGLELINE or DT_LEFT or DT_VCENTER)
       end;
     end;
  9 : begin
        if odSelected in State then
        begin
          cboLabels.Canvas.Brush.Color := clHighLight;
          cboLabels.Canvas.FillRect(Rect);
          cboLabels.Canvas.Font.Color := clHighlighttext;
          Drawtext(cboLabels.Canvas.handle, PChar(slabel9), -1,  Rect, DT_SINGLELINE or DT_LEFT or DT_VCENTER)
        end
        else
        begin
          cboLabels.Canvas.Brush.Color := clWindow;
          cboLabels.Canvas.FillRect(Rect);
          cboLabels.Canvas.Font.Color := clWindowText;
          Drawtext(cboLabels.Canvas.handle, PChar(slabel9), -1,  Rect, DT_SINGLELINE or DT_LEFT or DT_VCENTER)
       end;
     end;
  end;
end;

procedure TSearchAdvanced.btnMoreClick(Sender: TObject);
begin
  SearchGrid.RowCount := SearchGrid.RowCount + 1;
  HideCombos;
  btnMore.Enabled := (SearchGrid.RowCount < 4);
  btnFewer.Enabled := (SearchGrid.RowCount > 1);
end;

procedure TSearchAdvanced.btnFewerClick(Sender: TObject);
begin
  HideCombos;
  SearchGrid.RowCount := SearchGrid.RowCount -1;
  SearchGrid.Rows[SearchGrid.RowCount].Clear;

  btnFewer.Enabled := (SearchGrid.RowCount > 1);
  btnMore.Enabled := (SearchGrid.RowCount < 4);
end;

procedure TSearchAdvanced.lvwSearchResultsDblClick(Sender: TObject);
var
  i, j: integer;
  s: boolean;
begin
  if (lvwSearchResults.Selected = nil) and (lvwSearchResults.SelCount > 1) then Exit; // AH06
    s := false;
    with MainForm.TreeView1 do begin
      for i := 1 to Items.Count - 1 do begin
        if CompareText(lvwSearchResults.Selected.Caption, sRepositoryFolder) = 0
        then
        begin
          RepositoryNode.Selected := true;
          s := true;
        end
        else
         if CompareText(lvwSearchResults.Selected.Caption,
                                sTrashFolder) = 0 then
         begin
          TrashNode.Selected := true;
          s := true;
          end
          else if CompareText(lvwSearchResults.Selected.Caption, sStationaryFolder) = 0 then begin // AH03
            StationaryNode.Selected := true;
            s := true;
        end
        else if Items[i].StateIndex = tnFolder then begin
          if CompareText(PFolderData(Items[i].Data)^.Path,
            lvwSearchResults.Selected.Caption) = 0 then begin
            Items[i].Selected := true;
            s := true;
            Break;
          end;
        end;
        Application.ProcessMessages;
      end;
    end;

    if s then begin
      with MainForm.ListView1 do begin
        Items.BeginUpdate;
        for i := 0 to Items.Count - 1 do begin
          if CompareText(Items[i].Subitems[ciFileName],   // AH06 Removed ExtractFileName...
            lvwSearchResults.Selected.Subitems[2])
          = 0 then Break;
        end;

        if i = Items.Count then  // AH06... Error..
        begin
          Items.EndUpdate;
          Invalidate;
          exit;
        end;

        for j := 0 to Items.Count - 1 do
        begin
          Items[j].Selected := false;
        end;
        Items[i].Selected := true;
        Items[i].MakeVisible(false);
        Items.EndUpdate;
        Invalidate;
      end;
      MainForm.UpdateListView;
    end
end;

procedure TSearchAdvanced.Copyto1Click(Sender: TObject);
var
  dlg: TfrmMoveMessage;
  CopyTo: string;
  OldFileName, NewFileName: string;
  i : integer;
  Moving : boolean;
begin
  if lvwSearchResults.Selected = nil then exit;
  Moving := True;
  if Sender = CopyTo1 then Moving := False;

  dlg := TfrmMoveMessage.Create(Self);
  if Assigned(LangHolder) then
  begin
    if LangHolder.Language <> '' then
      LangHolder.Translate([dlg]);
  end;

  try
    with dlg.TreeView1 do
    begin
      Items := MainForm.TreeView1.Items;
      FullExpand;
      AlphaSort;
    end;

    if not Moving then
      // AH08
      dlg.Caption := GetMessageString(117)
    else
      dlg.Caption := GetMessageString(118);

    if dlg.ShowModal = mrOK then
    begin
      CopyTo := dlg.GetSelectedPath;
      for i := 0 to lvwSearchResults.Items.Count - 1 do
      begin
        if lvwSearchResults.Items[i].Selected then
        begin
          OldFileName := lvwSearchResults.Items[i].SubItems[2];
          // AH11 Always create a new unique filename
          NewFileName := CopyTo + GetUniqueMailName + '.msg';
          //          NewFileName := CopyTo + ExtractFileName(OldFileName);
          // AH06 starts here...
          if CompareText(OldFileName, NewFileName) <> 0 then // AH06--Not similar files/dirs:
          begin
            FileCopy(nil, OldFileName, NewFileName);
            if Moving then
            begin
              lvwSearchResults.Items[i].Caption := CopyTo;
              lvwSearchResults.Items[i].SubItems[2] := NewFileName;
              //  AH08             StatusBarEx1.Panels[1].Text := 'Moving ' + IntToStr(i + 1) + ' of '
              //                + IntToStr(lvwSearchResults.Items.Count);
              StatusBarEx1.Panels[1].Text := Format(GetMessageString(119), [IntToStr(i+1),
              IntToStr(lvwSearchResults.Items.Count)]);

              DeleteFile(OldFileName);
              SetPXTreeNodeName(GetTreeByDirName(MainForm.TreeView1.Items[0],
                                                 ExtractFilePath(OldFileName),
                                                 [tnAccount, tnFolder,
                                                 tnThrashbag, tnRepository])); //AH06//RR31
            end
            else
            begin
              //StatusBarEx1.Panels[1].Text := 'Copying ' + IntToStr(i + 1) + ' of '
              //  + IntToStr(lvwSearchResults.Items.Count);
              StatusBarEx1.Panels[1].Text := Format(GetMessageString(120), [IntToStr(i+1),
              IntToStr(lvwSearchResults.Items.Count)]);
            end;
            // AH06 For copying and moving... update target directory...
            SetPXTreeNodeName(GetTreeByDirName(MainForm.TreeView1.Items[0], ExtractFilePath(NewFileName),
                                               [tnAccount, tnFolder, tnThrashbag, tnRepository])); // AH06
            application.ProcessMessages;  // AH06
          end;
        end;
      end;
    end;
  finally
    dlg.Free;
  end;
end;

procedure TSearchAdvanced.lvwSearchResultsClick(Sender: TObject);
begin
  StatusBarEx1.Panels[1].Text := lvwSearchResults.Selected.SubItems[2];
end;

procedure TSearchAdvanced.Delete1Click(Sender: TObject);
var res, i, counter : integer;
begin
  i := 0;

  res := Application.MessageBox(PChar(GetMessageString(121)),
    PChar(GetMessageString(122)), MB_YESNO + MB_ICONQUESTION);
  if res = ID_YES then
  begin
    counter := 0; //RR31
    if lvwSearchResults.SelCount > 0 then
    begin
      while i < lvwSearchResults.Items.Count do
      begin
        if lvwSearchResults.Items[i].Selected then
        begin
          // AH06 Update source directories...
          DeleteFile(lvwSearchResults.Items[i].SubItems[2]);
          SetPXTreeNodeName(GetTreeByDirName(MainForm.TreeView1.Items[0],
            ExtractFilePath(lvwSearchResults.Items[i].SubItems[2]),
            [tnAccount, tnFolder, tnThrashbag, tnRepository])); // AH06
          lvwSearchResults.Items.Delete(i);
          inc(counter); //RR31
          application.ProcessMessages;  // AH06
         end
        else
          inc(i);
      end;
      // AH08
      StatusBarEx1.Panels[0].Text := Format(GetMessageString(111), [IntToStr(lvwSearchResults.Items.Count)]);
      StatusBarEx1.Panels[1].Text := Format(GetMessageString(123) + GetMessageString(111), [IntToStr(counter)]);
    end
  end
end;

procedure TSearchAdvanced.PopupMenu1Popup(Sender: TObject);
begin
  // Update those items...
  Open1.Enabled := (lvwSearchResults.SelCount = 1);
  CopyTo1.Enabled := (lvwSearchResults.Selcount > 0);
  MoveTo1.Enabled := CopyTo1.Enabled;
  Delete1.Enabled := CopyTo1.Enabled;
end;



procedure TSearchAdvanced.cboFindTextClick(Sender: TObject);
begin
  SearchGrid.Cells[SearchGrid.Col, SearchGrid.Row] := cboFindText.Text;
end;


procedure TSearchAdvanced.cboFindTextChange(Sender: TObject);
begin
  SearchGrid.Cells[SearchGrid.Col, SearchGrid.Row] := cboFindText.Text;
  btnGo.Enabled := Length(cboFindText.Text) > 0;
end;

procedure TSearchAdvanced.cboFindTextExit(Sender: TObject);
var sFindText: string;
  i: Integer;
begin
  SearchGrid.Cells[SearchGrid.Col, SearchGrid.Row] := cboFindText.Text;
  sFindText := cboFindText.Text;
  i := cboFindText.Items.IndexOf(sFindText);
  if cboFindText.Text <> '' then
  begin
    if i > -1 then
      cboFindText.Items.Delete(i);
    cboFindText.Items.Insert(0, sFindText);
  end;
  cboFindText.ItemIndex := 0;
end;

procedure TSearchAdvanced.DoRemoteMove(oldfile, newfile : string);
var x : integer;
begin
  if lvwSearchResults.Items.Count > 0 then
  begin
    x := 0;
    while x < lvwSearchResults.Items.Count do
    begin
      if pos(lvwSearchResults.Items[x].SubItems[2], oldfile) = 1 then
      begin
        if newfile = '' then
          lvwSearchResults.Items[x].Delete
        else
          lvwSearchResults.Items[x].SubItems[2] := newfile;
      end;
      inc(x);
    end;
  end;
end;

initialization
   PMRegistry.AddCustomClass(TSearchAdvanced, 'TSearchAdvanced');

end.
