For users to report plugin bugs and request plugin enhancements; and for authors to test new/new versions of plugins, and to discuss plugin development (in the Programming Technicalities sub-forum). If you want advice on choosing or using a plugin, please ask in General Usage or an appropriate sub-forum.
I would welcome a little guidance with my first plugin. I am trying to move & copy some data within a particular fact. The move I have achieved but the copy bit I am finding a little harder.
My starting point is the code snippet AllItems.fh_Lua
The Fact in question is Marriage Witness and I wanted to move the text from the note field to the main field. This I have achieved OK using this code.
for ptr in allItems('_ATTR-MARRIAGE_WITNESS.NOTE2','FAM') do
strVal=fhGetItemText(ptr,'_ATTR-MARRIAGE_WITNESS.NOTE2')
if strVal ~= '' then
thisptr = fhGetItemPtr(ptr,'_ATTR-MARRIAGE_WITNESS')
fhSetValueAsText(thisptr,strVal)
thisptr = fhGetItemPtr(ptr,'_ATTR-MARRIAGE_WITNESS.NOTE2')
fhSetValueAsText(thisptr,'')
end
end
Th other thing I would like to do is copy the Marriage Date (%FAM.MARR.DATE%) to (%FAM._ATTR-MARRIAGE_WITNESS.DATE%)
I am guessing dates are handled a little different to text fields so I am struggling.
Assuming you want to learn I'll just give you some hints for now.
A few things leap out, your original code does not handle if the field you are moving to does not exist so you need to test for thisptr being null and then use fhCreateItem to add one.
To move dates around you need to use a Date Object and fhGetValueAsDate.
Jane My Family History : My Photography "Knowledge is knowing that a tomato is a fruit. Wisdom is not putting it in a fruit salad."
I took a little break and realised my first part that was doing the move was doing so within a fact, from one field to another. That bit I managed OK, and have just realised the second part will be copying a field from one fact to another, so slightly different.
I was trying to use the same code snippet AllItems.fh_Lua and am now wondering if it might not work copying between facts.
This is what I have so far. The code completes without error but doesn't make the copy. I think I may be getting my pointers mixed up!
for ptr in allItems('_ATTR-MARRIAGE_WITNESS','FAM') do
dtptr = fhGetItemPtr(ptr,'FAM.MARR.DATE')
strDat = fhGetValueAsDate(dtptr)
if strDat ~= '' then
thisptr = fhGetItemPtr(ptr,'_ATTR-MARRIAGE_WITNESS.DATE')
fhSetValueAsDate(thisptr, strDat)
end
end
If there is no _ATTR-MARRIAGE_WITNESS.DATE field already in existence it will not return a pointer.
You need to check there is a FAM.MARR.DATE exists for the Family
To check if there is a date field to update you need to check you got a dtptr back and that strDat:IsNotNull()
It's best to use a table to build a list of all the items you want to add when looping through and then apply them at the end or the loop through can "get lost". It's normally find for copy and add but deletes can cause problems.
Jane My Family History : My Photography "Knowledge is knowing that a tomato is a fruit. Wisdom is not putting it in a fruit salad."
May I briefly interject with a couple of observations.
Firstly, the allItems(...) function only accepts Record types such as INDI, FAM, SOUR, OBJE, etc.
i.e. Those that can appear at the root of a Data Reference and have a tab in the Records Window. _ATTR-MARRIAGE_WITNESS is not a Record Type and the defensive checks within the function just ignore it.
It is a subsidiary field within Family (FAM) records with the special type of Fact and sub-type Attribute.
Secondly, in your original posting, it is setting the Note field to an empty text string rather than delete it. FH will automatically clean up and delete that empty Note field eventually.
The Plugin could use fhDeleteItem(ptr) but take note of Jane's advice about delaying those operations.
Mike Tate ~ researching the Tate and Scott family history ~ tatewise ancestry
To save confusing myself I have made this into two separate little plugins. I have saved the first one that does the moving of the text fields. This second one for copying the dates will be completely separate.
Am I right in thinking blank fields such as these marriage witness dates don't exist empty and are only created when data is saved to them from the user interface. So from a programming point of view do I need to detect if it is first present, then if not, create it then do the copy.
This is what I have. It completes without error but does not copy the dates. (mptr is the pointer to the marriage date, mDat is the marriage date value, and wptr is the witness date pointer)
for ptr in allItems('_ATTR-MARRIAGE_WITNESS','FAM') do
mptr = fhGetItemPtr(ptr,'FAM.MARR.DATE')
if mptr:IsNotNull() then
mDat = fhGetValueAsDate(mptr)
wptr = fhGetItemPtr(ptr,'_ATTR-MARRIAGE_WITNESS.DATE')
if wptr:IsNull() then
wptr = fhCreateItem('_ATTR-MARRIAGE_WITNESS.DATE', ptr )
else
wptr = fhGetItemPtr(ptr,'_ATTR-MARRIAGE_WITNESS.DATE')
fhSetValueAsDate(wptr,mDat)
end
end
end
Yes, I was concentrating so much on detecting and creating the object I forgot to set its value. However It still doesn't work.
I have altered the parameter sent to AllItems to be ('MARR','FAM'). Not sure if this is appropriate.
I have tried to follow the progress using the debugger. I can see ptr pointing to a marriage record, then mptr points to a marriage date and mDat is set with the date string. So far, so good.
It doesn't seem to be setting the date value and bOK always returns false.
for ptr in allItems('MARR','FAM') do
mptr = fhGetItemPtr(ptr,'FAM.MARR.DATE')
if mptr:IsNotNull() then
mDat = fhGetValueAsDate(mptr)
wptr = fhGetItemPtr(ptr,'_ATTR-MARRIAGE_WITNESS.DATE')
if wptr:IsNull() then
ptrFam = fhCreateItem("FAM")
wptr = fhCreateItem('_ATTR-MARRIAGE_WITNESS.DATE', ptrFam )
bOK = fhSetValueAsDate(wptr,mDat)
else
wptr = fhGetItemPtr(ptrFam,'_ATTR-MARRIAGE_WITNESS.DATE')
bOK = fhSetValueAsDate(wptr,mDat)
end
end
end
OK, you are digging deeper into trouble due to your understandable inexperience.
Firstly, in allItems('MARR','FAM') the MARR tag is invalid, as it is NOT a record type.
Secondly, that is an inappropriate looping iterator.
See plugins:code_snippets:loop_through_records|> Loop Through Records (code snippet) and its Using an Iterator Function.
Use iterator function records('FAM') instead, so ptr refers to each Family record in turn.
ptrFam = fhCreateItem("FAM") creates a brand NEW empty Family record, which you do NOT need.
The very first thing to do is discover if the Family record has a Marriage Witness attribute.
Only if that attribute fact exists, does the Marriage Date need copying. local factptr = fhGetItemPtr(ptr,'_ATTR-MARRIAGE_WITNESS') if factptr:IsNotNull() then
You also need to ensure that fact attribute has a Date field. local dateptr = fhGetItemPtr(factptr,'_ATTR-MARRIAGE_WITNESS.DATE')
if dateptr:IsNull() then
dateptr = fhCreateItem('DATE', factptr )
end
Now you can obtain the Marriage Date value and set it into the Marriage Witness Date.
BTW: Notice the use of local variables which is a good habit to get into for later more complex Plugins.
Mike Tate ~ researching the Tate and Scott family history ~ tatewise ancestry
Strangely it didn't work with
local dateptr = fhGetItemPtr(factptr,'_ATTR-MARRIAGE_WITNESS.DATE') until I changed it to
local dateptr = fhGetItemPtr(factptr,'FAM._ATTR-MARRIAGE_WITNESS.DATE') adding the "FAM." to make the full fact/attribute name.
function records(type)
local pi = fhNewItemPtr()
local p2 = fhNewItemPtr()
pi:MoveToFirstRecord(type)
return function ()
p2:MoveTo(pi)
pi:MoveNext()
if p2:IsNotNull() then return p2 end
end
end
for ptr in records('FAM') do
local factptr = fhGetItemPtr(ptr,'FAM._ATTR-MARRIAGE_WITNESS')
if factptr:IsNotNull() then
local dateptr = fhGetItemPtr(factptr,'FAM._ATTR-MARRIAGE_WITNESS.DATE')
if dateptr:IsNull() then
dateptr = fhCreateItem('DATE', factptr )
end
local mptr = fhGetItemPtr(ptr,'FAM.MARR.DATE')
if mptr:IsNotNull() then
local mDat = fhGetValueAsDate(mptr)
bOK = fhSetValueAsDate(dateptr,mDat)
end
end
end
I can assure you the script works as shown. It was a direct copy and paste from the plugin editor.
I previously created a query to find the marriage records in question with the result set showing the relevant fields. Each time I run the plugin I had the editor sat above the result set and saw the date column copy over as intended.
I have just tried the plugin again with a fresh gedcom export from Legacy. It still works as shown and will only work if I use the "FAM." prefix in the line
local factptr = fhGetItemPtr(ptr,'FAM._ATTR-MARRIAGE_WITNESS')
and it will work with or without the prefix in the line
local dateptr = fhGetItemPtr(factptr,'_ATTR-MARRIAGE_WITNESS.DATE')
Thanks for the alternative copy method. I will add that to my collection of code snippets.
Sorry, but look again. The full Plugin script as posted earlier contains: local dateptr = fhGetItemPtr(factptr,'FAM._ATTR-MARRIAGE_WITNESS.DATE') that won't work.
You cannot use the factptr with a FAM rooted data reference.
I don't doubt the Plugin works, but NOT with the code shown earlier.
Try copy & pasting it back and it won't work.
You have just posted two lines that work:
local factptr = fhGetItemPtr(ptr,'FAM._ATTR-MARRIAGE_WITNESS') this gets the factptr and needs FAM.
It works because the ptr refers to a FAM record.
local dateptr = fhGetItemPtr(factptr,'_ATTR-MARRIAGE_WITNESS.DATE') this gets dateptr and must NOT use FAM.
It works because the factptr refers to _ATTR-MARRIAGE_WITNESS fact.
You have to look closely at the reference pointer and the associated data reference.
Mike Tate ~ researching the Tate and Scott family history ~ tatewise ancestry
You are correct it does work, but only by luck in some circumstances.
I bet none of your Marriage Witness attributes have a Date initially.
If you add a Date to one or two of them you will find they won't get updated.
Even if you delete the Date values they still won't get updated.
local dateptr = fhGetItemPtr(factptr,'FAM._ATTR-MARRIAGE_WITNESS.DATE') ALWAYS gives a NULL pointer as it's invalid.
You could delete that line, and the if dateptr:IsNull() then and the end and the Plugin would still work as long as your Marriage Witness facts have no Date values.
local dateptr = fhGetItemPtr(factptr,'ATTR-MARRIAGE_WITNESS.DATE') is what works
Mike Tate ~ researching the Tate and Scott family history ~ tatewise ancestry
I am not new to programming but I am new to Lua and the FH API. I don't have that detailed knowledge of the data structures within FH to comment further so am just pleased from a users point of view that my dates were moved as intended.
My thanks to Jane & Mike for guiding me to a solution.