unit MFMail;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  SRVTabSet, RVScroll, RichView, RVStyle, SRVToolBar, SRVControl, CRVFData,
  SRVListBox, ExtCtrls, SRVPanel, SRVComboBox, ImgList, SRVSkinManager,
  RVTable, ShellAPI;

type
  TFileInfo = record
    FileName : string;
    FileType : string;
    Icon : TIcon;
    FileSize : Integer;
  end;

  TMail = record
    FromEMail : string;
    ToEMail : string;
    Title : string;
    FileBody : string;
    Files : array [0..10] of String;
  end;

  TfrmMail = class(TForm)
    Splitter1: TSplitter;
    RVStyle1: TRVStyle;
    RVStyle2: TRVStyle;
    Panel1: TPanel;
    SRVPanel1: TSRVPanel;
    lstFolders: TSRVListBox;
    cmbUsers: TSRVComboBox;
    Splitter2: TSplitter;
    SRVPanel3: TSRVPanel;
    SRVToolBar1: TSRVToolBar;
    rvEmails: TRichView;
    Panel2: TPanel;
    SRVPanel2: TSRVPanel;
    rvMailInfo: TRichView;
    Panel3: TPanel;
    Splitter3: TSplitter;
    SRVPanel4: TSRVPanel;
    SRVPanel5: TSRVPanel;
    rvMailBody: TRichView;
    rvFiles: TRichView;
    ilGlyphs: TImageList;
    SRVSkinManager1: TSRVSkinManager;
    tsFilter1: TSRVTabSet;
    tsFilter2: TSRVTabSet;
    ilFolders: TImageList;
    ilFileIcons: TImageList;
    ilStatus: TImageList;
    procedure rvEmailsRVMouseUp(Sender: TCustomRichView;
      Button: TMouseButton; Shift: TShiftState; ItemNo, X, Y: Integer);
    procedure rvEmailsMouseMove(Sender: TObject; Shift: TShiftState; X,
      Y: Integer);
    procedure FormCreate(Sender: TObject);
    procedure rvFilesJump(Sender: TObject; id: Integer);
    procedure FormDestroy(Sender: TObject);
    procedure rvEmailsKeyDown(Sender: TObject; var Key: Word;
      Shift: TShiftState);
  private
    { Private declarations }
    Mails : array of TMail;
    HighlightedRow, SelectedRow: Integer;
    EmailListTable: TRVTableItemInfo;
  public
    { Public declarations }
    function  GetFileInfo(FileName : String) : TFileInfo;
    function  AddTitleRow(Title: TStringList; Lengths : array of Integer) : TRVTableItemInfo;
    procedure AddMailRow(table : TRVTableItemInfo; slMailInfo: TStringList);
    procedure PreviewMail(FromEMail, ToEMail, Title, FileBody : String;
      slFiles: TStringList);
    procedure SetRowColor(Row: Integer; Color: TColor);
    procedure HighlightRow(Row: Integer);
    procedure SelectRow(Row: Integer);
  end;

var
  frmMail: TfrmMail;

implementation

{$R *.DFM}

const
  TABLECOLOR = $CCFFFF;
  HEADCOLOR  = $990033;
  HLTCOLOR   = $66CCFF;
  SELCOLOR   = $3399CC;
  PASSCOLOR  = $00FF33;
  FAILCOLOR  = $0033FF;

{------------------------------------------------------------------------------}
// Fills sl with '|'-separated text
procedure FillList(s : string; sl : TStringList);
var
     p : Integer;
begin
  sl.Clear;
  p := Pos('|', s);
  while (p > 0) do begin
    sl.Append(Trim(Copy(s, 1, p-1)));
    Delete(s, 1, p);
    p := Pos('|', s);
  end;
  sl.Append(Trim(s));
end;
// Fills sl with '|'-separated values
procedure FillIntegerArray(s : string; var lst : array of Integer);
var
     p, Index : Integer;
begin
  Index := 0;
  p := Pos('|', s);
  while (p > 0) do begin
    lst[Index] := StrToIntDef(Trim(Copy(s, 1, p-1)), 0);
    Inc(Index);
    Delete(s, 1, p);
    p := Pos('|', s);
  end;
  lst[Index] := StrToIntDef(Trim(s), 0);
end;
{------------------------------------------------------------------------------}
procedure TfrmMail.FormCreate(Sender: TObject);
var
     slMail, sl : TStringList;
     CellSizes : array [0..10] of Integer;
     Index, MailCount, FileCount : Integer;
begin
  cmbUsers.ItemIndex := 0;

  SetLength(Mails, 10);
  slMail := TStringList.Create;
  slMail.LoadFromFile('lstLetter.txt');

  // read
  sl := TStringList.Create;
  FillList(slMail[0], sl);
  FillIntegerArray(slMail[1], CellSizes);
  EmailListTable := AddTitleRow(sl, CellSizes);

  // reading list of mails
  Index := 2;
  MailCount := 0;
  while Index < slMail.Count do begin
    // read letter
    FillList(slMail[index], sl);
    Mails[MailCount].Title := sl[1];
    AddMailRow(EmailListTable, sl);
    Inc(index);

    // read email title
    FillList(slMail[index], sl);
    Mails[MailCount].FromEMail := sl[0];
    Mails[MailCount].ToEMail := sl[1];
    Mails[MailCount].FileBody := sl[2];
    Inc(index);

    // read attached files
    FileCount := 0;
    while (index < slMail.Count) and (slMail[index] <> '') do begin
      Mails[MailCount].Files[FileCount] := slMail[Index];
      Inc(FileCount);
      Inc(Index);
    end;

    Inc(Index);
    Inc(MailCount);
    If MailCount >= Length(Mails) then
      SetLength(Mails, MailCount*2);
  end;

  sl.Free;
  slMail.Free;
  rvEmails.Format;

  SelectedRow := -1;
  HighlightedRow := -1;
end;
{------------------------------------------------------------------------------}
procedure TfrmMail.FormDestroy(Sender: TObject);
begin
  Finalize(Mails);
end;
{------------------------------------------------------------------------------}
// Returns info about the file
function TfrmMail.GetFileInfo(FileName : String) : TFileInfo;
var
     shInfo : TSHFileInfo;
     sFileType : string;
     f: file;
begin
  Result.Icon := TIcon.Create;
  // get details about file type from SHGetFileInfo
  SHGetFileInfo(PChar(FileName), 0, shInfo, SizeOf(shInfo), SHGFI_TYPENAME);
  sFileType := shInfo.szTypeName;

  if shInfo.szTypeName = 'Shortcut' then   // is this a shortcut file ?
    SHGetFileInfo(PChar(FileName), 0, shInfo, SizeOf(shInfo),
      SHGFI_LINKOVERLAY or SHGFI_ICON or SHGFI_SMALLICON or SHGFI_SYSICONINDEX)
  else // ...otherwise treat it as a normal file}
    SHGetFileInfo(PChar(FileName), 0, shInfo, SizeOf(shInfo),
      SHGFI_ICON or SHGFI_LARGEICON or SHGFI_SYSICONINDEX);
    // assign icon
  Result.Icon.Handle := shInfo.hIcon;
  Result.FileName := ExtractFileName(FileName);
  Result.FileType := sFileType;
  if FileExists(FileName) then begin
    AssignFile(f, FileName);
    Reset(f);
    try
      Result.FileSize := FileSize(f);
    finally
      CloseFile(f);
    end
    end
  else
     Result.FileSize := 0;
 end;
{------------------------------------------------------------------------------}
// Changes color for cells in EmailListTable.Rows[Row]
procedure TfrmMail.SetRowColor(Row: Integer; Color: TColor);
var c: Integer;
begin
  for c := 0 to EmailListTable.ColCount-1 do begin
    EmailListTable.Cells[Row, c].Color := Color;
    EmailListTable.Cells[Row, c].Invalidate;
  end;
end;
{------------------------------------------------------------------------------}
// Highlights EmailListTable.Rows[Row]
procedure TfrmMail.HighlightRow(Row: Integer);
begin
  if Row=HighlightedRow then
    exit;
  if HighlightedRow>=0 then begin
    if HighlightedRow<>SelectedRow then
      SetRowColor(HighlightedRow, clNone);
    HighlightedRow := -1;
  end;
  if (Row<1) or (Row=SelectedRow) then
    exit;
  HighlightedRow := Row;
  SetRowColor(HighlightedRow, HLTCOLOR);
end;
{------------------------------------------------------------------------------}
// Selectes EmailListTable.Rows[Row], displays info about the selected email
procedure TfrmMail.SelectRow(Row: Integer);
var i: Integer;
    slFiles : TStringList;
begin
  if (Row=SelectedRow) or (Row<1) then
    exit;
  if SelectedRow>=0 then
    SetRowColor(SelectedRow, clNone);
  SelectedRow := Row;
  if SelectedRow<0 then
    exit;
  SetRowColor(SelectedRow, SELCOLOR);
  // mark as read
  if EmailListTable.Cells[SelectedRow,0].ItemCount>0 then
    EmailListTable.Cells[SelectedRow,0].SetBulletInfo(0, '1', 1, ilStatus, 1);
  // displaying a preview
  slFiles := TStringList.Create;
  try
    for i := 0 to High(Mails[SelectedRow-1].Files) do
      if Mails[SelectedRow-1].Files[i]<>'' then
        slFiles.Append(Mails[SelectedRow-1].Files[i]);
    with Mails[SelectedRow-1] do
      PreviewMail(FromEMail, ToEMail, Title, FileBody, slFiles);
  finally
    slFiles.Free;
  end;
end;

{------------------------------------------------------------------------------}
// Creates and returns EmailListTable, adds a header row
function TfrmMail.AddTitleRow(Title: TStringList; Lengths : array of Integer) : TRVTableItemInfo;
var table: TRVTableItemInfo;
    col: Integer;
begin
  table := TRVTableItemInfo.CreateEx(1, Title.Count, rvEMails.RVData);
  table.ParaNo := 1;
  table.Color := TABLECOLOR;
  for col := 0 to Title.Count-1 do begin
    If Lengths[col] <> 0 then
      table.SetCellBestWidth(Lengths[col], 0, col);
    table.Cells[0, col].Clear;
    table.Cells[0, col].AddNL(Title[col], 0, 0);
    table.Cells[0, col].Color := clSilver;
  end;
  table.CellHPadding := 4;
  table.CellHSpacing := -1;
  table.CellVSpacing := -1;
  table.BorderWidth := 0;
  table.CellBorderWidth := 1;
  table.BorderStyle := rvtbColor;
  table.CellBorderStyle := rvtbColor;
  rvEMails.AddItem('', table);
  Result := table;
end;
{------------------------------------------------------------------------------}
// Adds a row with info about email
procedure TfrmMail.AddMailRow(table : TRVTableItemInfo; slMailInfo: TStringList);
var
    col: Integer;
begin
  table.InsertRows(table.RowCount, 1, -1, False);
  table.Cells[table.RowCount-1, 0].Clear;
  If slMailInfo[0] <> '' then
    table.Cells[table.RowCount-1, 0].AddBulletEx( '', StrToInt(slMailInfo[0]), ilStatus, 0);
  for col := 1 to slMailInfo.Count-1 do begin
    table.Cells[table.RowCount-1, col].Clear;
    table.Cells[table.RowCount-1, col].AddNL(slMailInfo[col], 0, 0);
  end;
end;
{------------------------------------------------------------------------------}
// Previews the email in rvMailInfo, rvMailBody, rvFiles
procedure TfrmMail.PreviewMail(FromEMail, ToEMail, Title, FileBody : String;
   slFiles: TStringList);
var
     table: TRVTableItemInfo;
     i, index : Integer;
     FileInfo: TFileInfo;
     s : String;
begin
  // Displaying info about the selected email
  rvMailInfo.Clear;

  table := TRVTableItemInfo.CreateEx(3, 2, rvMailInfo.RVData);
  table.ParaNo := 1;
  table.Color := TABLECOLOR;
  table.SetCellBestWidth(50, 0, 0);

  table.Cells[0, 0].Clear;
  table.Cells[0, 0].AddNL('From:', 6, 2);
  table.Cells[0, 0].Color := clSilver;

  table.Cells[0, 1].Clear;
  table.Cells[0, 1].AddNL(FromEMail, 6, 0);

  table.Cells[1, 0].Clear;
  table.Cells[1, 0].AddNL('To:', 6, 2);
  table.Cells[1, 0].Color := clSilver;

  table.Cells[1, 1].Clear;
  table.Cells[1, 1].AddNL(ToEMail, 6, 0);

  table.Cells[2, 0].Clear;
  table.Cells[2, 0].AddNL('Title:', 6, 2);
  table.Cells[2, 0].Color := clSilver;

  table.Cells[2, 1].Clear;
  table.Cells[2, 1].AddNL(Title, 6, 0);

  table.CellHPadding := 4;
  table.CellHSpacing := -1;
  table.CellVSpacing := -1;
  table.BorderVSpacing := 0;
  table.BorderHSpacing := 0;
  table.BorderWidth := 0;
  table.CellBorderWidth := 1;
  table.BorderStyle := rvtbColor;
  table.CellBorderStyle := rvtbColor;
  rvMailInfo.Clear;
  rvMailInfo.AddItem('', table);
  rvMailInfo.Format;
  rvMailInfo.VSmallStep := 1;
  rvMailInfo.VScrollVisible := rvMailInfo.Height < rvMailInfo.DocumentHeight;

  // Displaying content of the selected email
  rvMailBody.Clear;
  rvMailBody.LoadText(FileBody, 0, 0, True);
  rvMailBody.Format;

  // Displaying attached files
  ilFileIcons.Clear;
  rvFiles.Clear;
  if Assigned(slFiles) then
    for i := 0 to slFiles.Count-1 do begin
      FileInfo := GetFileInfo(slFiles[i]);
      Index := ilFileIcons.AddIcon(FileInfo.Icon);

      table := TRVTableItemInfo.CreateEx(1, 1, rvFiles.RVData);
      table.ParaNo := 1;
      table.Color := TABLECOLOR;
      table.Cells[0, 0].Clear;

      table.CellHPadding := 4;
      table.CellHSpacing := -1;
      table.CellVSpacing := -1;
      table.BorderVSpacing := 0;
      table.BorderHSpacing := 0;
      table.BorderWidth := 0;
      table.CellBorderWidth := 0;
      table.BorderStyle := rvtbColor;
      table.CellBorderStyle := rvtbColor;

      table.Cells[0, 0].Clear;
      table.Cells[0, 0].AddHotspotExTag(FileInfo.FileName, index, index,
        ilFileIcons, 1, Integer(StrNew(PChar(FileInfo.FileName))));
      table.Cells[0, 0].AddNLTag(FileInfo.FileName, 4, 1, Integer(StrNew(PChar(FileInfo.FileName))));
      If FileInfo.FileSize div 1024 = 0 then
        s := IntToStr(FileInfo.FileSize) + ' bytes'
      else
        s := IntToStr(FileInfo.FileSize div 1024) + ' kb';
      table.Cells[0, 0].AddNL(s, 6, 1);        
      rvFiles.AddItem('', table);
      FileInfo.Icon.Free;
    end;
  rvFiles.Format;
  rvFiles.VScrollVisible := rvFiles.Height < rvFiles.DocumentHeight;
end;
{------------------------------------------------------------------------------}
// Opening the attached file on clicking
procedure TfrmMail.rvFilesJump(Sender: TObject; id: Integer);
var ItemNo: Integer;
    RVData: TCustomRVFormattedData;
    FileName : String;
begin
  rvFiles.GetJumpPointLocation(id, RVData, ItemNo);
  FileName := ExtractFilePath(Application.ExeName) +
    'AttachFile\' + PChar(RVData.GetItemTag(ItemNo));
  if FileExists(FileName) then
    ShellExecute(0, 'Open', PChar(FileName), nil, PChar(ExtractFilePath(FileName)), SW_SHOW);
end;
{------------------------------------------------------------------------------}
// Selecting on click
procedure TfrmMail.rvEmailsRVMouseUp(Sender: TCustomRichView;
  Button: TMouseButton; Shift: TShiftState; ItemNo, X, Y: Integer);
var RVData: TCustomRVFormattedData;
    LItemNo, LOffs, r, c: Integer;
    pt: TPoint;
begin
  pt := rvEmails.ClientToDocument(Point(X,Y));
  rvEmails.GetItemAt(pt.X, pt.Y, RVData, LItemNo, LOffs, False);
  RVData := TCustomRVFormattedData(RVData.GetSourceRVData);
  if RVData is TRVTableCellData then begin
    EmailListTable.GetCellPosition(TRVTableCellData(RVData), r, c);
    SelectRow(r);
  end;
end;
{------------------------------------------------------------------------------}
// Highlighting on click
procedure TfrmMail.rvEmailsMouseMove(Sender: TObject; Shift: TShiftState;
  X, Y: Integer);
var RVData: TCustomRVFormattedData;
    LItemNo, LOffs, r, c: Integer;
    pt: TPoint;
begin
  pt := rvEmails.ClientToDocument(Point(X,Y));
  rvEmails.GetItemAt(pt.X, pt.Y, RVData, LItemNo, LOffs, False);
  RVData := TCustomRVFormattedData(RVData.GetSourceRVData);
  if RVData is TRVTableCellData then begin
    EmailListTable.GetCellPosition(TRVTableCellData(RVData), r, c);
    HighlightRow(r);
    end
  else
    HighlightRow(-1);
end;
{------------------------------------------------------------------------------}
// Selecting email with the keyboard
procedure TfrmMail.rvEmailsKeyDown(Sender: TObject; var Key: Word;
  Shift: TShiftState);
begin
  if Shift<>[] then
    exit;
  case Key of
    VK_HOME:
      begin
        SelectRow(1);
        Key := 0;
      end;
    VK_END:
      begin
        SelectRow(EmailListTable.RowCount-1);
        Key := 0;
      end;
    VK_UP:
      if SelectedRow>1 then begin
        SelectRow(SelectedRow-1);
        Key := 0;
      end;
    VK_DOWN:
      if (SelectedRow>0) and (SelectedRow<EmailListTable.RowCount-1) then begin
        SelectRow(SelectedRow+1);
        Key := 0;
      end;
  end;
end;

end.
