Hello all,
I have no more idea what to do further. I analyzed all forum topics and samples and now hope for your help.
In a database application in a table there are blob fields that hold richview text (edited by TDBRichViewEdit). The user can freely design these
richview texts and can especially insert field variables that will later be filled with data from the database (for example name and address of a
customer). These contents serve as different templates/layout records for offers, bills and other documents that can be created for customers. The
insertion of variables is done by:
Self.BodyPrintHeader.InsertStringWTag(VarName, TagName);
Self.BodyPrintHeader.SetFocus;
where VarName is a string like "@Firstname@" and TagName is a string "Name1" (that corresponds to the field name of a customer table from which on
printing the data will be filled).
Before printing the offers, bills and others, the desired layout is loaded from the templates table, the variables/tags are filled with real data
from the customer table, and the so modified RichView text is saved as blob to a temporary table (with other temp. data) for printing. On printing
most of the replaced variables are shown correctly, but others not. This means:
- If in the TRichView template the text holds variables and is edited/modified after the insertion of the variables, e.g. inserted a new line or
some text before or after a variable, the replaced variable text (=field value) shows up several times, for example 4 x the customer name, each in a
new line (unpredictable result)
- If in the TRichView template the text holds more than 1 variables in one line, the result will be without the "non variable"-text. The text around
the variables is completely lost.
Example:
"...will be send to: @Title@ @Firstname@ @Lastname@"
replaced result should be:
"...will be send to: Professor Peter Hawk"
but result is:
"ProfessorPeterHawk"
This is my code:
// rsVg: the record with the real customer data to read field values
// Idx: the primary key for the record with the template data
function VgLayoutReplaceItemText(rsVg : TADOQuery; const Idx : string) : boolean;
var
rsTmp : TADOStoredProcedure;
rsVgLyt : TADOStoredProcedure;
mStream : TMemoryStream;
trv : TRichViewEdit;
i : integer;
RVStyle : TRVStyle;
fldName : string;
begin
// Memory Stream for working on the richview layout
mStream := TMemoryStream.Create();
// RichView Element
RVStyle := TRVStyle.Create(Nil);
trv := TRichViewEdit.Create(Nil);
trv.Style := RVStyle;
trv.RTFReadProperties.TextStyleMode := rvrsAddifNeeded;
trv.RTFReadProperties.ParaStyleMode := rvrsAddifNeeded;
trv.RVFOptions := trv.RVFOptions + [rvfoSaveTextStyles, rvfoSaveParaStyles];
trv.Options := trv.Options + [rvoTagsArePChars];
// Load template record. DONT WASTE TIME ON THIS - THIS WORKS RELIABLY!
rsVgLyt := TADOStoredProcedure.Create(Nil);
sqlGetRecordset(gActDB, rsVgLyt, jmsSGRGetVgTypLayoutRecord,
rsVg.Fields.FieldByName('VgTyp').AsInteger, Idx, Null, Null);
// Load record in temp. table for saving the replaced data DONT WASTE TIME ON THIS - THIS WORKS RELIABLY!
rsTmp := TADOStoredProcedure.Create(Nil);
sqlGetRecordset(gActDB, rsTmp, jmsSGRGetTmpVgLayoutRecord,
rsVg.Fields.FieldByName('VgCode').AsString,
getCPrsCode(), Null, Null);
// Do 2 turns, one for the header layout, one for the footer layout
// The problem has nothing to do with the loop - appears also when the the loop is taken away
for i := 1 to 2 do
begin
if(i = 1) then
fldName := 'BodyPrintHeader'
else
fldName := 'BodyPrintFooter';
mStream.Clear;
mStream.Position := 0;
TBlobField(rsVgLyt.Fields.FieldByName(fldName)).SaveToStream(mStream);
mStream.Position := 0;
trv.LoadRVFFromStream(mStream);
//trv.Format; // Only possible if trv is located in a window
//trv.Change; // informs the linked dataset that data were modified
// == Replace variables ==================================================
VgLayoutFillFields(trv.RVData, rsVg);
//trv.Format; // Only possible if trv is located in a window
// Load RichView back to stream for saving
mStream.Clear;
mStream.Position := 0;
trv.SaveRVFToStream(mStream, false);
// Save modified rich view to temp. table
rsTmp.Edit;
rsTmp.Fields.FieldByName(fldName).Clear;
TBlobField(rsTmp.Fields.FieldByName(fldName)).LoadFromStream(mStream);
rsTmp.Post;
end;
rsTmp.Close;
rsTmp.Free;
rsVgLyt.Close;
rsVgLyt.Free;
trv.Free;
RVStyle.Free;
mStream.Free;
mStream := Nil;
result := True;
end;
{------------------------------------------------------------------------------}
// Taken originally from Sergey Tkachenko, only widened to work with other data than string
{
This function iterates through all items in RVData, and if a tag of
some text contains a non-empty text, it calls GetFieldValueFromDatabase(tag) and
replaces this text with the returned value.
You can move this function to your application unchanged.
Initial call: FillFields(RichView.RVData);
}
procedure VgLayoutFillFields(RVData: TCustomRVData; rs : TADOQuery);
var
i,r,c: Integer;
table: TRVTableItemInfo;
FieldName: String;
vTmp : variant;
sTmp : string;
begin
for i := 0 to RVData.ItemCount-1 do
begin
if(RVData.GetItemStyle(i) = rvsTable) then
begin
table := TRVTableItemInfo(RVData.GetItem(i));
for r := 0 to table.Rows.Count-1 do
for c := 0 to table.Rows[r].Count-1 do
if(table.Cells[r,c] <> Nil) then
VgLayoutFillFields(table.Cells[r,c].GetRVData, rs);
table.Changed;
end
else if(RVData.GetItemStyle(i) >= 0) then
begin
FieldName := RVData.GetItemTag(i);
if(FieldName <> STRNOTHING) then
begin
vTmp := rs.Fields.FieldByName(FieldName).value;
// Original by Sergey
//RVData.SetItemText(i, GetFieldValueFromDatabase(FieldName));
// Modified by JM, also for numeric values
case TField(rs.Fields.FieldByName(FieldName)).DataType of
{ -- Perhaps for future use
ftWideMemo: // In Access Datentyp 'Memo'
begin
// ??
end;
ftBlob, ftGraphic: // BLOB oder in Access OLE Objekt
begin
// ??
end;
------------------}
ftDate:
begin
if(vTmp = Null) then
sTmp := STRNOTHING
else
sTmp := System.SysUtils.DateToStr(vTmp);
end;
ftSmallint, ftInteger, ftWord, ftBoolean:
begin
if(vTmp = Null) then
sTmp := STRNOTHING
else
sTmp := System.SysUtils.IntToStr(vTmp);
end;
ftFloat, ftCurrency:
begin
if(vTmp = Null) then
sTmp := STRNOTHING
else
sTmp := System.SysUtils.FloatToStr(vTmp);
end;
else
sTmp := stdNZ(rs.Fields.FieldByName(FieldName).value, STRNOTHING);
end;
RVData.SetItemTextW(i, sTmp);
end;
end;
end;
end;
{------------------------------------------------------------------------------}
My environment:
TrichView 14.0.3
Delphi XE2
Additional information:
I do not necessarily need the handling with the 'tag's. The only thing I need is to hold a variable that will be replaced by other text. I also
tried this:
if(trv.SearchTextW('@CustName@', [rvseoDown, rvseoWholeWord])) then
begin
trv.InsertTextW('Here should be the customer name', false);
end;
but in the first line if(trv.SearchTextW(.... I get an "index out of..." error (Puuuuhhh....).
I hope for any help...
Joe
Problem replacing variables / merge text
-
- Site Admin
- Posts: 17604
- Joined: Sat Aug 27, 2005 10:28 am
- Contact:
Is it possible to create a simple project (preferably using files instead of DB) and send it to me to richviewgmailcom?
Some guesses
1. Probably, when you press Enter before a field, a new empty line is created using properties of the current text (field), so it inherits its tag, and now you have two fields in your document. It may be solved by protecting the field's text style (for example, rvprDoNotAutoSwitch must work).
2. As for disappearing normal text. Two possible reasons
- a bug in field replacement procedure (but it's hard to find bugs in browser, so I need a test project)
- this normal text is not really a normal text but it has the same Tag as a field so it it treated as a field.
Some guesses
1. Probably, when you press Enter before a field, a new empty line is created using properties of the current text (field), so it inherits its tag, and now you have two fields in your document. It may be solved by protecting the field's text style (for example, rvprDoNotAutoSwitch must work).
2. As for disappearing normal text. Two possible reasons
- a bug in field replacement procedure (but it's hard to find bugs in browser, so I need a test project)
- this normal text is not really a normal text but it has the same Tag as a field so it it treated as a field.