home *** CD-ROM | disk | FTP | other *** search
/ Magazyn Internet 2000 May / MICD_2000_05.iso / CBuilder5 / INSTALL / DATA1.CAB / Program_Built_Files / ObjRepos / recerror.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2000-02-01  |  11.0 KB  |  365 lines

  1. //---------------------------------------------------------------------------
  2. //
  3. //  C++Builder Visual Component Library
  4. //  ClientDataSet Standard Reconcile Error Dialog
  5. //
  6. //  Copyright (c) 1999 Borland International
  7. //
  8. //---------------------------------------------------------------------------
  9. // To use this dialog you should add a call to HandleReconcileError in
  10. // the OnReconcileError event handler of TClientDataSet.  Cut and paste the
  11. // following line into the event handler:
  12. //
  13. // Action = HandleReconcileError(Owner, DataSet, UpdateKind, E);
  14. //
  15.  
  16. #include <stdio.h>
  17. #include <vcl.h>
  18. #pragma hdrstop
  19.  
  20. #include "recerror.h"
  21.  
  22. //---------------------------------------------------------------------------
  23.  
  24. #pragma resource "*.dfm"
  25.  
  26. char *ActionStr[] = {"Skip", "Abort", "Merge",
  27.              "Correct", "Cancel", "Refresh"};
  28. char *UpdateKindStr[] = {"Modified", "Inserted", "Deleted"};
  29. char *SCaption = "Update Error - ";
  30. char *SUnchanged = "<Unchanged>";
  31. char *SBinary = "(Binary)";
  32. char *SFieldName = "Field Name";
  33. char *SOriginal = "Original Value";
  34. char *SConflict = "Conflicting Value";
  35. char *SValue = " Value";
  36. char *SNoData = "<No Records>";
  37. char *SNew = "New";
  38.  
  39. //---------------------------------------------------------------------------
  40. TReconcileErrorForm *ReconcileErrorForm;
  41. TFieldData *PFieldData;
  42.  
  43. //---------------------------------------------------------------------------
  44. // Public and Private Methods
  45. //---------------------------------------------------------------------------
  46.  
  47. TReconcileAction HandleReconcileError(TComponent* Owner, TDataSet *DataSet,
  48.   TUpdateKind UpdateKind, EReconcileError *ReconcileError) {
  49.  
  50.   TReconcileAction      retVal;
  51.   TReconcileErrorForm  *UpdateForm;
  52.  
  53.   UpdateForm = new TReconcileErrorForm (Owner, DataSet, UpdateKind, ReconcileError);
  54.   try {
  55.     if (UpdateForm->ShowModal() == mrOk) {
  56.       retVal = (TReconcileAction) (UpdateForm->ActionGroup->Items->Objects[UpdateForm->ActionGroup->ItemIndex]);
  57.       if (retVal == raCorrect)
  58.     UpdateForm->SetFieldValues(DataSet);
  59.     } else
  60.       retVal = raAbort;
  61.   } __finally {
  62.     delete UpdateForm;
  63.   }
  64.   return retVal;
  65. }
  66.  
  67. //---------------------------------------------------------------------------
  68.  
  69. // Routine to convert a variant value into a string.
  70. // Handles binary field types and "empty" (Unchanged) field values specially
  71.  
  72. AnsiString VarToAnsiStr (Variant &V, TFieldType DataType) {
  73.   try {
  74.     if (VarIsEmpty(V))
  75.       return SUnchanged;
  76.     else {
  77.       switch (DataType) {
  78.     case ftBytes:
  79.     case ftVarBytes:
  80.     case ftBlob:
  81.     // ftGraphic .. ftCursor
  82.     case ftGraphic:
  83.     case ftFmtMemo:
  84.     case ftParadoxOle:
  85.     case ftDBaseOle:
  86.     case ftTypedBinary:
  87.     case ftCursor:
  88.       return SBinary;
  89.     default:
  90.       return VarToStr(V);
  91.       }
  92.     }
  93.   } catch (Exception &e) {
  94.     return e.Message;
  95.   }
  96. }
  97.  
  98. //---------------------------------------------------------------------------
  99.  
  100. __fastcall TReconcileErrorForm::TReconcileErrorForm(TComponent* Owner) :
  101.   TForm(Owner) {
  102.   FDataSet = NULL;
  103.   FDataFields = NULL;
  104. }
  105.  
  106. //---------------------------------------------------------------------------
  107.  
  108. __fastcall TReconcileErrorForm::TReconcileErrorForm(TComponent* Owner,
  109.   TDataSet *DataSet, TUpdateKind UpdateKind, EReconcileError *Error) : TForm(Owner) {
  110.   FDataFields = NULL;
  111.   FDataSet = DataSet;
  112.   FUpdateKind = UpdateKind;
  113.   FError = Error;
  114. }
  115.  
  116. //---------------------------------------------------------------------------
  117.  
  118. //__fastcall ~TReconcileErrorForm(TComponent* Owner) {
  119. //}
  120.  
  121. //---------------------------------------------------------------------------
  122.  
  123. // Create a list of the data fields in the dataset, and store string values
  124. // associated with NewValue, OldValue, and Curvalue in string variables
  125. // to make display switching faster
  126.  
  127. void __fastcall TReconcileErrorForm::InitDataFields() {
  128.  
  129.   int         i;
  130.   bool        HasCurValues;
  131.   TFieldData *FD;
  132.   TField     *ds;
  133.  
  134.   HasCurValues = false;
  135.   for(i = 0; i < FDataSet->FieldCount; i++) {
  136.     ds = FDataSet->Fields->Fields[i];
  137.     if (ds->FieldKind != fkData)
  138.       continue;
  139.     FD = new TFieldData;
  140.     try {
  141.       FD->Field = ds;
  142.       FD->Edited = false;
  143.       if (FUpdateKind != ukDelete)
  144.     FD->NewValue = VarToAnsiStr(ds->NewValue, ds->DataType);
  145.       if (!VarIsEmpty(ds->CurValue))
  146.         HasCurValues = true;
  147.       FD->CurValue = VarToAnsiStr(ds->CurValue, ds->DataType);
  148.       if (FUpdateKind != ukInsert)
  149.     FD->OldValue = VarToAnsiStr(ds->OldValue, ds->DataType);
  150.       FDataFields->Add(FD);
  151.     } catch (Exception &e) {
  152.       delete FD;
  153.       throw;
  154.     }
  155.   }
  156.   InitUpdateData (HasCurValues);
  157. }
  158.  
  159. //---------------------------------------------------------------------------
  160.  
  161. // Initalize the column indexes and grid titles
  162.  
  163. void __fastcall TReconcileErrorForm::InitUpdateData(bool HasCurValues) {
  164.   int FColCount;
  165.  
  166.   FColCount = 1;
  167.   UpdateData->ColCount = 4;
  168.   UpdateData->Cells[0][0] = SFieldName;
  169.   if (FUpdateKind != ukDelete) {
  170.     FNewColIdx = FColCount;
  171.     FColCount++;
  172.     UpdateData->Cells[FNewColIdx][0] = UpdateKindStr[FUpdateKind] + String(SValue);
  173.   } else {
  174.     FOldColIdx = FColCount;
  175.     FColCount++;
  176.     UpdateData->Cells[FOldColIdx][0] = SOriginal;
  177.   }
  178.   if (HasCurValues) {
  179.     FCurColIdx = FColCount;
  180.     FColCount++;
  181.     UpdateData->Cells[FCurColIdx][0] = SConflict;
  182.   }
  183.   if (FUpdateKind == ukModify) {
  184.     FOldColIdx = FColCount;
  185.     FColCount++;
  186.     UpdateData->Cells[FOldColIdx][0] = SOriginal;
  187.   }
  188.   UpdateData->ColCount = FColCount;
  189. }
  190.  
  191. //---------------------------------------------------------------------------
  192.  
  193. // Update the reconcile action radio group based on the valid reconcile actions
  194.  
  195. void __fastcall TReconcileErrorForm::AddAction(TReconcileAction Action) {
  196.   ActionGroup->Items->AddObject(ActionStr[Action], (TObject *) Action);
  197. }
  198.  
  199. void __fastcall TReconcileErrorForm::InitReconcileActions() {
  200.   AddAction(raSkip);
  201.   AddAction(raCancel);
  202.   AddAction(raCorrect);
  203.   if (FCurColIdx > 0) {
  204.     AddAction(raRefresh);
  205.     AddAction(raMerge);
  206.   }
  207.   ActionGroup->ItemIndex = 0;
  208. }
  209.  
  210. //---------------------------------------------------------------------------
  211.  
  212. // Update the grid based on the current display options
  213.  
  214. void __fastcall TReconcileErrorForm::DisplayFieldValues(TObject *Sender) {
  215.  
  216.   int               i, CurRow;
  217.   TFieldData       *fd;
  218.   TReconcileAction  Action;
  219.  
  220.   if (!Visible)
  221.     return;
  222.   Action = (TReconcileAction) ActionGroup->Items->Objects[ActionGroup->ItemIndex];
  223.   UpdateData->Col = 1;
  224.   UpdateData->Row = 1;
  225.   CurRow = 1;
  226.   UpdateData->RowCount = 2;
  227.   UpdateData->Cells[0][CurRow] = SNoData;
  228.   for (i = 1; i < UpdateData->ColCount; i++)
  229.     UpdateData->Cells[i][CurRow] = "";
  230.   for (i = 0; i < FDataFields->Count; i++) {
  231.     fd = (TFieldData *) FDataFields->Items[i];
  232.     if (ConflictsOnly->Checked && (fd->CurValue == SUnchanged))
  233.       continue;
  234.     if (ChangedOnly->Checked && (fd->NewValue == SUnchanged))
  235.       continue;
  236.     UpdateData->RowCount = CurRow + 1;
  237.     UpdateData->Cells[0][CurRow] = fd->Field->DisplayName;
  238.     if (FNewColIdx > 0) {
  239.       switch (Action) {
  240.     case raCancel, raRefresh:
  241.       UpdateData->Cells[FNewColIdx][CurRow] = SUnchanged;
  242.       break;
  243.     case raCorrect:
  244.       if (fd->Edited)
  245.         UpdateData->Cells[FNewColIdx][CurRow] = fd->EditValue;
  246.       else
  247.         UpdateData->Cells[FNewColIdx][CurRow] = fd->NewValue;
  248.       break;
  249.     default:
  250.       UpdateData->Cells[FNewColIdx][CurRow] = fd->NewValue;
  251.       }
  252.       UpdateData->Objects[FNewColIdx][CurRow] = (TObject *) FDataFields->Items[i];
  253.     }
  254.     if (FCurColIdx > 0)
  255.       UpdateData->Cells[FCurColIdx][CurRow] = fd->CurValue;
  256.     if (FOldColIdx > 0)
  257.       if (((Action == raMerge) || (Action == raRefresh)) && (fd->CurValue != SUnchanged))
  258.     UpdateData->Cells[FOldColIdx][CurRow] = fd->CurValue;
  259.       else
  260.     UpdateData->Cells[FOldColIdx][CurRow] = fd->OldValue;
  261.     CurRow++;
  262.   }
  263.   AdjustColumnWidths();
  264. }
  265.  
  266. //---------------------------------------------------------------------------
  267.  
  268. // For fields that the user has edited, copy the changes back into the
  269. // NewValue property of the associated field
  270.  
  271. void __fastcall TReconcileErrorForm::SetFieldValues(TDataSet *DataSet) {
  272.  
  273.   int i;
  274.   TFieldData *fd;
  275.  
  276.   for (i = 0; i < FDataFields->Count; i++) {
  277.     fd = (TFieldData *) FDataFields->Items[i];
  278.     if (fd->Edited)
  279.       fd->Field->NewValue = fd->EditValue;
  280.   }
  281. }
  282.  
  283. //---------------------------------------------------------------------------
  284.  
  285. void __fastcall TReconcileErrorForm::AdjustColumnWidths() {
  286.  
  287.   int NewWidth, i;
  288.   NewWidth = (UpdateData->ClientWidth - UpdateData->ColWidths[0]) /
  289.     (UpdateData->ColCount - 1);
  290.   for (i = 1; i < UpdateData->ColCount; i++)
  291.     UpdateData->ColWidths[i] = NewWidth - 1;
  292. }
  293.  
  294. //---------------------------------------------------------------------------
  295. // Event Handlers
  296. //---------------------------------------------------------------------------
  297.  
  298. // Set the Edited flag in the DataField list and save the value
  299.  
  300. void __fastcall TReconcileErrorForm::UpdateDataSetEditText (TObject *Sender,
  301.   int ACol, int ARow, const AnsiString Value) {
  302.   ((TFieldData *) UpdateData->Objects[ACol][ARow])->EditValue = Value;
  303.   ((TFieldData *) UpdateData->Objects[ACol][ARow])->Edited = true;
  304. }
  305.  
  306. //---------------------------------------------------------------------------
  307.  
  308. // Enable the editing in the grid if we are on the NewValue column and the
  309. // current reconcile action is raCorrect
  310.  
  311.  
  312. void __fastcall TReconcileErrorForm::UpdateDataSelectCell(TObject *Sender, int Col, int Row,
  313.   bool &CanSelect) {
  314.  
  315.   TReconcileAction  Action;
  316.  
  317.   Action = (TReconcileAction) ActionGroup->Items->Objects[ActionGroup->ItemIndex];
  318.   if ((Col == FNewColIdx) && (Action == raCorrect))
  319.     UpdateData->Options = UpdateData->Options << goEditing;
  320.   else
  321.     UpdateData->Options = UpdateData->Options >> goEditing;
  322. }
  323.  
  324.  
  325. /*
  326. void __fastcall TReconcileErrorForm::FormShow(TObject *Sender) {
  327.   // display value fields procedure
  328. }
  329. */
  330.  
  331. //---------------------------------------------------------------------------
  332.  
  333. void __fastcall TReconcileErrorForm::FormDestroy(TObject *Sender) {
  334.  
  335.   int i;
  336.   if (FDataFields != NULL) {
  337.     for (i = 0; i < FDataFields->Count; i++)
  338.       delete ((TFieldData *) FDataFields->Items[i]);
  339.     delete FDataFields;
  340.   } // if
  341. }
  342.  
  343. //---------------------------------------------------------------------------
  344.  
  345. void __fastcall TReconcileErrorForm::FormCreate(TObject *Sender) {
  346.  
  347.   if (FDataSet == NULL)
  348.    return;
  349.   FDataFields = new TList;
  350.   InitDataFields();
  351.   Caption = SCaption + FDataSet->Name;
  352.   UpdateType->Caption = UpdateKindStr[FUpdateKind];
  353.   ErrorMsg->Text = FError->Message;
  354.   if (FError->Context != "")
  355.     ErrorMsg->Lines->Add(FError->Context);
  356.   ConflictsOnly->Enabled = (FCurColIdx > 0);
  357.   ConflictsOnly->Checked = ConflictsOnly->Enabled;
  358.   ChangedOnly->Enabled = (FNewColIdx > 0);
  359.   InitReconcileActions();
  360.   UpdateData->DefaultRowHeight = UpdateData->Canvas->TextHeight("SQgjp") + 7;   // do not localize
  361. }
  362.  
  363. //---------------------------------------------------------------------------
  364.  
  365.