/*------------------------------------------------------------------------------

  Notes:
  1. Making sure that all cells contain one item (and only one)
    - adding rvpaoDoNotWantReturns in Options of all paragraph styles
    - allowing to paste only one line of plain text (see OnPaste)
  2. Protecting autocalculated text
    - the 1st paragraph style ("Read-Only") has rvpaoReadOnly
    - RichView allows to delete read-only paragraphs when they are parts
      of lager selection (for example, multicell selection)
      An event, allowing to avoid this problem, was added in version 1.6.11
      (OnCellEditing)
  3. Table cannot be deleted because it is added in read-only paragraph.
  4. EConvertError exception occurs if Income column contains non numeric data.
    If running in C++Builder IDE, Builder stops on exception. Just click OK and
    press F9 to continue.
  5. AcceptDragDropFormats is set to []

------------------------------------------------------------------------------*/

#include <vcl\vcl.h>
#pragma hdrstop

#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma link "RVEdit"
#pragma link "RichView"
#pragma link "RVScroll"
#pragma link "RVStyle"
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
	: TForm(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormCreate(TObject *Sender)
{
  int r,c;

  table = new TRVTableItemInfo(5,4, rve->RVData);
  table->BorderWidth     = 1;
  table->CellBorderWidth = 1;
  table->CellBorderStyle = rvtbColor;
  table->CellBorderColor = clBtnFace;
  table->BorderStyle     = rvtbColor;

  table->OnCellEditing   = OnCellEditing;

  // Each cell initially contains one empty text item. Deleting it
  for (r=0; r<table->Rows->Count; r++)
    for (c=0; c<table->Rows->Items[r]->Count; c++)
      table->Cells[r][c]->Clear();

  // First Row
  table->Cells[0][0]->AddNLATag("Name",1,1,0);
  table->Cells[0][1]->AddNLATag("Income",1,1,0);
  table->Cells[0][2]->AddNLATag("Tax Rate",1,1,0);
  table->Cells[0][3]->AddNLATag("Tax",1,1,0);

  // Last Row
  r = table->Rows->Count-1;
  table->Cells[r][0]->AddNLATag("TOTAL:",1,1,0);
  table->Cells[r][1]->AddNLATag("",1,1,0);
  table->Cells[r][2]->AddNLATag("",1,1,0);
  table->Cells[r][3]->AddNLATag("",1,1,0);

  // First Column
  table->Cells[1][0]->AddNLATag("John Smith", 0,0,0);
  table->Cells[2][0]->AddNLATag("John Brown", 0,0,0);
  table->Cells[3][0]->AddNLATag("Phil Forest", 0,0,0);

  // Second Column
  table->Cells[1][1]->AddNLATag("2000", 0,0,0);
  table->Cells[2][1]->AddNLATag("2500", 0,0,0);
  table->Cells[3][1]->AddNLATag("1000", 0,0,0);

  for (r=1; r<table->Rows->Count-1; r++)
  {
    table->Cells[r][2]->Color = clSilver;
    table->Cells[r][3]->Color = clSilver;
    table->Cells[r][2]->AddNLATag("0.20",0,1,0);
    table->Cells[r][3]->AddNLATag("",0,1,0);
  }

  for (c=0; c<table->Rows->Items[0]->Count; c++)
  {
    table->Cells[0][c]->Color = clSilver;
    table->Cells[table->Rows->Count-1][c]->Color = clSilver;
  }

  DecimalSeparator = '.';

  Calculate();

  rve->InsertItem("Spreadsheet", table);
  rve->ApplyParaStyle(1); // read-only style;
}
//---------------------------------------------------------------------------
void TForm1::Calculate()
{
  // Last Column
  AnsiString s;
  bool totalOK = true;
  double total   = 0.0;
  double totaltax = 0.0;
  double val, valtax;
  for (int r=1; r<table->Rows->Count-1; r++)
  {
    try
    {
      // val <- income
      val = StrToFloat(table->Cells[r][1]->GetRVData()->GetItemTextA(0));
      // valtax <- income * tax rate
      valtax = val*StrToFloat(table->Cells[r][2]->GetRVData()->GetItemTextA(0));
      s = FloatToStr(valtax);
      total    += val;
      totaltax += valtax;
    }
    catch(...)
    {
      s = "?";
      totalOK = false;
    }
    table->Cells[r][3]->GetRVData()->SetItemTextA(0,s);
  }

  if (totalOK)
  {
    table->Cells[table->Rows->Count-1][3]->GetRVData()->SetItemTextA(0, FloatToStr(totaltax));
    table->Cells[table->Rows->Count-1][1]->GetRVData()->SetItemTextA(0, FloatToStr(total));
  }
  else
  {
    table->Cells[table->Rows->Count-1][3]->GetRVData()->SetItemTextA(0, "?");
    table->Cells[table->Rows->Count-1][1]->GetRVData()->SetItemTextA(0, "?");
  }
  table->Changed();
}
//---------------------------------------------------------------------------
// OnChange: recalculating
void __fastcall TForm1::rveChange(TObject *Sender)
{
  Calculate();
  rve->Reformat();
  if (rve->InplaceEditor)
    rve->InplaceEditor->Invalidate();
  // Some ideas:
  // - you can use table->GetEditedCell() to get a cell which was changed
}
//---------------------------------------------------------------------------
// Adding a new row
void __fastcall TForm1::Button1Click(TObject *Sender)
{
  int Data;
  int ItemNo = rve->GetItemNo(table);
  rve->BeginItemModify(ItemNo, Data);
  int r = table->Rows->Count-1;
  table->InsertRows(r, 1, -1
  #if __BORLANDC__ > 0x530
  , false
  #endif
  );

  for (int c=1; c<table->Rows->Items[r]->Count; c++)
    table->Cells[r][c]->Clear();

  table->Cells[r][1]->AddNLATag("0", 0,0,0);
  table->Cells[r][2]->AddNLATag("0.20", 0,1,0);
  table->Cells[r][3]->AddNLATag("", 0,1,0);
  table->Cells[r][2]->Color = clSilver;
  table->Cells[r][3]->Color = clSilver;

  rve->EndItemModify(ItemNo, Data);
  rve->Change();
}
//---------------------------------------------------------------------------
// Deleting a row with caret
void __fastcall TForm1::Button2Click(TObject *Sender)
{
  int r,c;
  if (table->GetEditedCell(r,c) && r!=0 && r!=table->Rows->Count-1)
  {
    int Data;
    int ItemNo = rve->GetItemNo(table);
    rve->BeginItemModify(ItemNo, Data);
    table->DeleteRows(r,1,false);
    rve->EndItemModify(ItemNo, Data);
    rve->Change();
  }
  else
    MessageBeep(0);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::rvePaste(TCustomRichViewEdit *Sender, bool &DoDefault)
{
  if (Clipboard()->HasFormat(CF_TEXT))
  {
    AnsiString s = Clipboard()->AsText;
    if (!strchr(s.c_str(), '\r') && !strchr(s.c_str(), '\n'))
      rve->InsertText(s, false);
  }
  DoDefault = false;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::OnCellEditing(TRVTableItemInfo* Sender, int Row, int Col,
  bool Automatic, bool &AllowEdit)
{
  if (Automatic)
    AllowEdit = (Row!=0) && (Row!=table->Rows->Count-1) && (Col<2);
}