Clone Any Record.fh_lua--[[
@Title: Clone Any Record
@Type: Standard
@Author: Peter Richmond
@Contributors: Mike Tate
@Version: 3.0
@LastUpdated: 02Aug2021
@Licence: This plugin is copyright (c) 2021 Peter Richmond & contributors and is licensed under the MIT License which is hereby incorporated by reference (see https://pluginstore.family-historian.co.uk/fh-plugin-licence)
@Description: Creates one or more clones of a selected record.
Useful for creating new records (especially sources) based on a template.
It is best to add this plugin to the Tools menu and run it from there after selecting the
required "Template" record in the Records Window.
A message confirms creation of new record(s) and (if only one) full details are optionally shown as a result set.
You then need to change the name/title of each new record and complete any required non-template fields.
The template record can contain blank fields if wanted, and links to other records.
User is prompted to confirm that an Individual or Family record should be cloned.
Note that if an Individual record is cloned the new record will contain an empty Family-as-Spouse link
which can be either appropriately completed or deleted.
Updated 14 Jan 2021 to work with FH7 as well as FH5 & FH6.
Updated 02 Aug 2021 to v3.0 to also allow multiple (2 to 50) clones; default behaviour same as previous version.
]]
require("iuplua")
function CopyBranch(ptrSource,ptrTarget)
local strTag = fhGetTag(ptrSource)
if strTag == "_FMT" then return end -- Skip rich text format code
if strTag == "_FIELD" then -- Substitute metafield shortcut
strTag = fhGetMetafieldShortcut(ptrSource)
end
local ptrNew = fhCreateItem(strTag,ptrTarget,true)
if ptrNew:IsNull() then return end -- Escape if item not created
fhSetValue_Copy(ptrNew,ptrSource)
CopyChildren(ptrSource,ptrNew)
end -- function CopyBranch cribbed from FHUG KB (with Mike Tate correction)
function CopyChildren(ptrSource,ptrTarget)
local ptrFrom = fhNewItemPtr()
ptrFrom = ptrSource:Clone()
ptrFrom:MoveToFirstChildItem(ptrFrom)
while ptrFrom:IsNotNull() do
CopyBranch(ptrFrom,ptrTarget)
ptrFrom:MoveNext()
end
end -- function CopyChildren cribbed from FHUG KB
function BuildDR(ptr)
local ptrTemp = fhNewItemPtr()
ptrTemp:MoveTo(ptr)
strDR = fhGetTag(ptrTemp)
while fhHasParentItem(ptrTemp) do
ptrTemp:MoveToParentItem(ptrTemp)
strDR = fhGetTag(ptrTemp)..'.'..strDR
end
return strDR
end
------------------------------- Main
tRec = fhGetCurrentRecordSel() -- check that one and only one record has been selected
if #tRec ~= 1 then
fhMessageBox('You must first select one "template" record')
else
pTemplate = tRec[1] -- Pointer for "Template" record
sTag = fhGetTag(pTemplate) -- Type of record being copied
if sTag == 'HEAD' then
fhMessageBox('You cannot clone the Header record','MB_OK','MB_ICONSTOP')
return
end
if sTag == 'SUBN' then
fhMessageBox('You cannot clone the Submission record','MB_OK','MB_ICONSTOP')
return
end
if sTag == 'INDI' or sTag == 'FAM' then
a = fhMessageBox('Are you SURE you want to clone '..sTag..' record "'..fhGetDisplayText(pTemplate)
..'" (Id = '..fhGetRecordId(pTemplate)..')?',"MB_OKCancel","MB_ICONQUESTION")
if a ~= "OK" then return end
end
-- Dialog for user to specify required number of clones.
bOK, iNumber, iOutput = iup.GetParam("Clone Any Record", param_action,
"Please specify number of clones required: %i[1,50]\n" ..
"Show result set (available if only 1 clone)?: %b[No,Yes]\n",1,1)
if bOK then
for i=1,iNumber do
pNewRecord = fhCreateItem(sTag) -- Create new record of same type as template
CopyChildren(pTemplate, pNewRecord) -- Copy all details from template to new record
end
sUndo = "\n\nYou can use FH menu option Edit > Undo Plugin Updates if you don't like the result."
if iNumber == 1 then sMsg = "New "..fhGetTag(pNewRecord)..' record: "'..fhGetDisplayText(pNewRecord)..'" (Id = '..fhGetRecordId(pNewRecord)..')'
else sMsg = iNumber.." clones of "..fhGetDisplayText(pNewRecord)
end
fhMessageBox(sMsg.." created."..sUndo)
if iOutput == 1 and iNumber == 1 then -- Optionally display result set for single clone
tItems = {} -- Define array for Items
tDRs = {} -- Define array for Data References
tValues = {} -- Define array for Values of Items
tClass = {} -- Define array for DataClass of Items
pi = fhNewItemPtr() -- declare pointers
pi2 = pNewRecord
pi1 = pi2:Clone()
pi:MoveTo(pi2)
while pi:IsNotNull() and pi1:IsSame(pi2) do
table.insert(tItems,pi:Clone())
table.insert(tDRs,BuildDR(pi))
table.insert(tValues,fhGetDisplayText(pi,'~','STD'))
table.insert(tClass,fhGetDataClass(pi,'~'))
pi:MoveNextSpecial()
pi1:MoveToRecordItem(pi)
end
sTitle = 'Data List for new '..sMsg
fhOutputResultSetTitles(sTitle, sTitle, " %#c")
fhOutputResultSetColumn('DataRef (w/o Index)', 'text', tDRs, #tDRs, 100)
fhOutputResultSetColumn('DataClass', 'text', tClass, #tClass, 40)
fhOutputResultSetColumn('Item', 'item', tItems, #tItems, 180)
fhOutputResultSetColumn('ValueStd', 'text', tValues, #tValues, 240)
end
end
end
--[[
@Title: Clone Any Record
@Type: Standard
@Author: Peter Richmond
@Contributors: Mike Tate
@Version: 3.0
@LastUpdated: 02Aug2021
@Licence: This plugin is copyright (c) 2021 Peter Richmond & contributors and is licensed under the MIT License which is hereby incorporated by reference (see https://pluginstore.family-historian.co.uk/fh-plugin-licence)
@Description: Creates one or more clones of a selected record.
Useful for creating new records (especially sources) based on a template.
It is best to add this plugin to the Tools menu and run it from there after selecting the
required "Template" record in the Records Window.
A message confirms creation of new record(s) and (if only one) full details are optionally shown as a result set.
You then need to change the name/title of each new record and complete any required non-template fields.
The template record can contain blank fields if wanted, and links to other records.
User is prompted to confirm that an Individual or Family record should be cloned.
Note that if an Individual record is cloned the new record will contain an empty Family-as-Spouse link
which can be either appropriately completed or deleted.
Updated 14 Jan 2021 to work with FH7 as well as FH5 & FH6.
Updated 02 Aug 2021 to v3.0 to also allow multiple (2 to 50) clones; default behaviour same as previous version.
]]
require("iuplua")
function CopyBranch(ptrSource,ptrTarget)
local strTag = fhGetTag(ptrSource)
if strTag == "_FMT" then return end -- Skip rich text format code
if strTag == "_FIELD" then -- Substitute metafield shortcut
strTag = fhGetMetafieldShortcut(ptrSource)
end
local ptrNew = fhCreateItem(strTag,ptrTarget,true)
if ptrNew:IsNull() then return end -- Escape if item not created
fhSetValue_Copy(ptrNew,ptrSource)
CopyChildren(ptrSource,ptrNew)
end -- function CopyBranch cribbed from FHUG KB (with Mike Tate correction)
function CopyChildren(ptrSource,ptrTarget)
local ptrFrom = fhNewItemPtr()
ptrFrom = ptrSource:Clone()
ptrFrom:MoveToFirstChildItem(ptrFrom)
while ptrFrom:IsNotNull() do
CopyBranch(ptrFrom,ptrTarget)
ptrFrom:MoveNext()
end
end -- function CopyChildren cribbed from FHUG KB
function BuildDR(ptr)
local ptrTemp = fhNewItemPtr()
ptrTemp:MoveTo(ptr)
strDR = fhGetTag(ptrTemp)
while fhHasParentItem(ptrTemp) do
ptrTemp:MoveToParentItem(ptrTemp)
strDR = fhGetTag(ptrTemp)..'.'..strDR
end
return strDR
end
------------------------------- Main
tRec = fhGetCurrentRecordSel() -- check that one and only one record has been selected
if #tRec ~= 1 then
fhMessageBox('You must first select one "template" record')
else
pTemplate = tRec[1] -- Pointer for "Template" record
sTag = fhGetTag(pTemplate) -- Type of record being copied
if sTag == 'HEAD' then
fhMessageBox('You cannot clone the Header record','MB_OK','MB_ICONSTOP')
return
end
if sTag == 'SUBN' then
fhMessageBox('You cannot clone the Submission record','MB_OK','MB_ICONSTOP')
return
end
if sTag == 'INDI' or sTag == 'FAM' then
a = fhMessageBox('Are you SURE you want to clone '..sTag..' record "'..fhGetDisplayText(pTemplate)
..'" (Id = '..fhGetRecordId(pTemplate)..')?',"MB_OKCancel","MB_ICONQUESTION")
if a ~= "OK" then return end
end
-- Dialog for user to specify required number of clones.
bOK, iNumber, iOutput = iup.GetParam("Clone Any Record", param_action,
"Please specify number of clones required: %i[1,50]\n" ..
"Show result set (available if only 1 clone)?: %b[No,Yes]\n",1,1)
if bOK then
for i=1,iNumber do
pNewRecord = fhCreateItem(sTag) -- Create new record of same type as template
CopyChildren(pTemplate, pNewRecord) -- Copy all details from template to new record
end
sUndo = "\n\nYou can use FH menu option Edit > Undo Plugin Updates if you don't like the result."
if iNumber == 1 then sMsg = "New "..fhGetTag(pNewRecord)..' record: "'..fhGetDisplayText(pNewRecord)..'" (Id = '..fhGetRecordId(pNewRecord)..')'
else sMsg = iNumber.." clones of "..fhGetDisplayText(pNewRecord)
end
fhMessageBox(sMsg.." created."..sUndo)
if iOutput == 1 and iNumber == 1 then -- Optionally display result set for single clone
tItems = {} -- Define array for Items
tDRs = {} -- Define array for Data References
tValues = {} -- Define array for Values of Items
tClass = {} -- Define array for DataClass of Items
pi = fhNewItemPtr() -- declare pointers
pi2 = pNewRecord
pi1 = pi2:Clone()
pi:MoveTo(pi2)
while pi:IsNotNull() and pi1:IsSame(pi2) do
table.insert(tItems,pi:Clone())
table.insert(tDRs,BuildDR(pi))
table.insert(tValues,fhGetDisplayText(pi,'~','STD'))
table.insert(tClass,fhGetDataClass(pi,'~'))
pi:MoveNextSpecial()
pi1:MoveToRecordItem(pi)
end
sTitle = 'Data List for new '..sMsg
fhOutputResultSetTitles(sTitle, sTitle, " %#c")
fhOutputResultSetColumn('DataRef (w/o Index)', 'text', tDRs, #tDRs, 100)
fhOutputResultSetColumn('DataClass', 'text', tClass, #tClass, 40)
fhOutputResultSetColumn('Item', 'item', tItems, #tItems, 180)
fhOutputResultSetColumn('ValueStd', 'text', tValues, #tValues, 240)
end
end
endSource:Clone-Any-Record-2.fh_lua