--[[ @Title: Record Civil Registration Data (UK) @Type: Source-driven data entry @Subtype: "Civil Registration Index" @Author: Calico Pie @Version: 1.7 @Keywords: @LastUpdated: September 2022 @GH: #47 #48 #51 #76 #112 #119 #127 #130 @Description: Designed to work with the "Civil Registration Index" source template from the Essentials collection, this will add the related facts for birth, death or marriage to an existing fact. The required minimum Source information is Type, Region, Name and Date. Supports the following regions: England and Wales, Scotland, Ireland, Northern Ireland (if you've created the region), Isle of Man (if you've created the region), and the Channel Islands (if you've created the region). Note: The data in the indices varies with time, so the DEA prompts for everything that was ever recorded in an index in the particular region; if you don't have a value for a particular field, leave it blank and it will be set to N/A. ]] fhInitialise(7) fh = require("fhUtils") fh.setIupDefaults() local ptrHead = fhNewItemPtr() local sPluginName = stringx.strip(fhGetContextInfo("CI_PLUGIN_NAME")) local pForms, pCite, ptrHead local buttons = { "OK", "Cancel" } local buttons2 = { "OK", "Skip" } function main() pCite = fh.loadPreparedCitation() pForms = loadForms() if not pCite.result then fh.getParam(sPluginName, pCite.err) return end -- Ensure all needed fields have been completed if not (pCite:checkRequired("EN-REGION", "EN-TYPE", "NM-NAME_RECORDED", "DT-DATE")) then fh.getParam( sPluginName, "Not all required fields set, please ensure you have entered Region, Type, Name and Date" ) return end -- Validate the Type field is supported sType = pCite:getValue("EN-TYPE") sCountry = pCite:getValue("EN-REGION") if not pForms[sCountry] then fh.getParam(sPluginName, "Sorry " .. sCountry .. " not supported.") return end if not pForms[sCountry][sType] then fh.getParam(sPluginName, "Sorry " .. sType .. " not supported for " .. sCountry .. ".") return end pForms[sCountry][sType]["function"]() end function englandBirth(ptr) local fields = pForms[sCountry][sType]["fields"] local r = fh.getParam("Record Civil Registration Data", "", fields, buttons) local tUpdates = {} if r.ok then local ptrRecord = r.results["RECORD"]:Clone() sText = formatTextFromSource( pForms[sCountry][sType]["template_name"], pForms[sCountry][sType]["template_default"], pCite, r.results ) createTextFromSource(pCite, sText, "citation") if r.results["ACTION"] == "create" then ptrRecord = createIndi(r.results["NAME"]) local b = selectSex() local sSex = "U" if b.button_pressed == "Male" then sSex = "M" end if b.button_pressed == "Female" then sSex = "F" end local ptrSex = fhCreateItem("SEX", ptrRecord, true) fhSetValueAsText(ptrSex, sSex) table.insert(tUpdates, { ptrRecord:Clone(), "Created" }) table.insert(tUpdates, { ptrSex:Clone(), "Added" }) end local sAction = "" ptrBirth, sAction = fh.createUpdateFact( ptrRecord, "BIRT", "Birth", pCite:getValue("TX-REGISTRATION_DISTRICT"), pCite:getValue("DT-DATE") ) if ptrBirth and ptrBirth:IsNotNull() then pCite:appendCitation(ptrBirth) table.insert(tUpdates, { ptrBirth:Clone(), sAction }) end if r.results["CITE.INDI"] then pCite:appendCitation(ptrRecord) table.insert(tUpdates, { ptrRecord:Clone(), "Cited" }) end fh.outputUpdatedFields(tUpdates, pCite) end end function englandDeath(ptr) local tUpdates = {} local fields = pForms[sCountry][sType]["fields"] r = fh.getParam("Record Civil Registration Death Data", "", fields, buttons) if r.ok then sText = formatTextFromSource( pForms[sCountry][sType]["template_name"], pForms[sCountry][sType]["template_default"], pCite, r.results ) createTextFromSource(pCite, sText, "citation") local ptrRecord local sAction local ptrDeath, ptrBirth ptrRecord = r.results["RECORD"]:Clone() if r.results["ACTION"] == "create" then ptrRecord = createIndi(r.results["NAME"]) local b = selectSex() local sSex = "U" if b.button_pressed == "Male" then sSex = "M" end if b.button_pressed == "Female" then sSex = "F" end local ptrSex = fhCreateItem("SEX", ptrRecord, true) fhSetValueAsText(ptrSex, sSex) table.insert(tUpdates, { fhGetItemPtr(ptrRecord, "~.NAME"), "Created" }) table.insert(tUpdates, { ptrSex:Clone(), "Added" }) end ptrDeath, sAction = fh.createUpdateFact( ptrRecord, "DEAT", "Death", pCite:getValue("TX-REGISTRATION_DISTRICT"), pCite:getValue("DT-DATE") ) if ptrDeath and ptrDeath:IsNotNull() then pCite:appendCitation(ptrDeath) table.insert(tUpdates, { ptrDeath:Clone(), sAction }) end local dtBirth = fhNewDate() if r.results["AGE"] then if ptrDeath and ptrDeath:IsNotNull() then -- Add Age to Death local ptrAge = fhCreateItem("AGE", ptrDeath, true) fhSetValueAsText(ptrAge, r.results["AGE"]) dtBirth = fh.calcBirth(pCite:getValue("DT-DATE"), r.results["AGE"]) table.insert(tUpdates, { ptrAge:Clone(), "Updated" }) end end if fh.isSet(r.results["BIRT.DATE"]) then dtBirth = r.results["BIRT.DATE"]:Clone() end if r.results["CITE.INDI"] then pCite:appendCitation(ptrRecord) table.insert(tUpdates, { ptrRecord:Clone(), "Cited" }) end ptrBirth, sAction = fh.createUpdateFact(ptrRecord, "BIRT", "Birth", "", dtBirth) if ptrBirth and ptrBirth:IsNotNull() then pCite:appendCitation(ptrBirth) table.insert(tUpdates, { ptrBirth:Clone(), sAction }) end fh.outputUpdatedFields(tUpdates, pCite) end end function englandMarriage(ptr) local tUpdates = {} local ptrFam, ptrRecord, ptrSpouse, ptrH, ptrW = nil, nil, nil, nil, nil local r, r2, r3 = nil, nil, nil --for results of prompts local fields = pForms[sCountry][sType]["fields"] -- Set up child values if fields[3].value and fields[3].value:IsNotNull() then -- Set Family Values from Record fields[4].values, fields[4].prompts = updateFamList(fields[3].value) fields[4].value = fields[4].values[1] end r = fh.getParam("Record Civil Registration Marriage Data", "", fields, buttons) if r.ok then if r.results["ACTION"] == "create" then --set Individual record ptrRecord = fhNewItemPtr() else ptrRecord = r.results["RECORD"]:Clone() end if r.results["FAMILY"] then --set family record ptrFam = r.results["FAMILY"]:Clone() else ptrFam = fhNewItemPtr() end --Get any missing information about the spouse if ptrFam:IsNull() then --a new family, so prompt for spouse information r2 = fh.getParam("Add Spouse Information", "", spousePromptForm(r.results["SPOUSE.NAME"]), buttons2) if r2.ok then r.results["SPOUSE.NAME"] = r2.results["SPOUSE.NAME"] --needed for Text from Source end else --existing family ptrH = fhGetItemPtr(ptrFam, "~.~SPOU[1]>") ptrW = fhGetItemPtr(ptrFam, "~.~SPOU[2]>") --is there a missing spouse? if ptrH:IsNull() or ptrW:IsNull() then --prompt for missing spouse information r2 = fh.getParam("Add Spouse Information", "", spousePromptForm(r.results["SPOUSE.NAME"]), buttons2) if r2.ok then r.results["SPOUSE.NAME"] = r2.results["SPOUSE.NAME"] --needed for Text from Source end else --existing couple; need to check what index has for spouse name local sname = utils.choose(ptrRecord == ptrH, fhGetDisplayText(ptrW), fhGetDisplayText(ptrH)) --first get the name of the Spouse of the principal r3 = fh.getParam("Spouse name as entered", "", spousenamePromptForm(sname), buttons2) if r3.ok then r.results["SPOUSE.NAME"] = r3.results["SPOUSE.NAME"] --needed for Text from Source else r.results["SPOUSE.NAME"] = sname --needed for Text from Source end end end sText = formatTextFromSource( pForms[sCountry][sType]["template_name"], pForms[sCountry][sType]["template_default"], pCite, r.results ) createTextFromSource(pCite, sText, "citation") --should not change or add any data until this is done if ptrRecord:IsNull() then --create new Individual ptrRecord = createIndi(r.results["NAME"]) local b = selectSex() local sSex = "U" if b.button_pressed == "Male" then sSex = "M" end if b.button_pressed == "Female" then sSex = "F" end local ptrSex = fhCreateItem("SEX", ptrRecord, true) fhSetValueAsText(ptrSex, sSex) table.insert(tUpdates, { ptrRecord:Clone(), "Created" }) table.insert(tUpdates, { ptrSex, "Added" }) end if r.results["CITE.INDI"] then pCite:appendCitation(ptrRecord) end if ptrFam:IsNull() then --create new Family ptrFam = createFamilyAsSpouse(ptrRecord) table.insert(tUpdates, { ptrFam:Clone(), "Created" }) end if r.results["CITE.FAM"] then pCite:appendCitation(ptrFam) end -- Add Marriage local ptrMarriage, sAction = fh.createUpdateFact( ptrFam, "MARR", "Marriage", pCite:getValue("TX-REGISTRATION_DISTRICT"), pCite:getValue("DT-DATE") ) if ptrMarriage and ptrMarriage:IsNotNull() then pCite:appendCitation(ptrMarriage) table.insert(tUpdates, { ptrMarriage:Clone(), sAction }) end if r2 and r2.ok then --missing spouse has been specified if ptrFam:IsNotNull() then if r2.results["SPOUSE.ACTION"] == "create" then ptrSpouse = createIndi(r2.results["SPOUSE.NAME"]) local sSex = fhGetItemText(ptrRecord, "~.SEX") if sSex == "Male" then sSex = "F" else sSex = "M" end local ptrSex = fhCreateItem("SEX", ptrSpouse, true) fhSetValueAsText(ptrSex, sSex) table.insert(tUpdates, { ptrSpouse:Clone(), "Created" }) table.insert(tUpdates, { ptrSex:Clone(), "Added" }) else ptrSpouse = r2.results["SPOUSE.RECORD"]:Clone() end if r2.results["SPOUSE.CITE"] then pCite:appendCitation(ptrSpouse) end -- Add Spouse to Family Record addFamilyAsSpouse(ptrSpouse, ptrFam) table.insert(tUpdates, { ptrFam:Clone(), "Updated" }) end end end fh.outputUpdatedFields(tUpdates, pCite) end ----------------------------------------------------------------- updateFamList (for Marriage) function updateFamList(ptrRecord) if not ptrRecord or ptrRecord:IsNull() then return {}, {} end local famList = fh.familyList(ptrRecord, "FamilyAsSpouse") local prompts = {} local values = {} for i, f in ipairs(famList) do prompts[i] = f.label values[i] = f.ptr end return values, prompts end function createIndi(sName, bCite) local ptrRecord = fhCreateItem("INDI") local ptrName = fhCreateItem("NAME", ptrRecord) fhSetValueAsText(ptrName, sName) pCite:appendCitation(ptrName) return ptrRecord end function createFamilyAsChild(ptrIndi) -- Create Family As Child local ptrFam = fhCreateItem("FAM") local ptrFams = fhCreateItem("FAMC", ptrIndi) fhSetValueAsLink(ptrFams, ptrFam) pCite:appendCitation(ptrFams) return ptrFam end function createFamilyAsSpouse(ptrIndi) -- Create Family As Spouse local ptrFam = fhCreateItem("FAM") -- pCite:appendCitation(ptrFam) local ptrFams = fhCreateItem("FAMS", ptrIndi) fhSetValueAsLink(ptrFams, ptrFam) pCite:appendCitation(ptrFams) return ptrFam end function addFamilyAsChild(ptrIndi, ptrFam) -- Add Family As Child local ptrFamc = fhCreateItem("FAMC", ptrIndi) fhSetValueAsLink(ptrFamc, ptrFam) pCite:appendCitation(ptrFamc) return ptrFam end function addFamilyAsSpouse(ptrIndi, ptrFam) -- Add Family As Spouse local ptrFams = fhCreateItem("FAMS", ptrIndi) local bOK = fhSetValueAsLink(ptrFams, ptrFam) pCite:appendCitation(ptrFams) return ptrFam end --- ChildUpdate handler -- @param value string - value of list box -- @return boolean - true if value select function selectOrCreate(value) if value == "select" then return false, 1 else return true, 0 end end function selectSex() local r = fh.getParam("Select Sex", "Select the Sex for the Principal", {}, { "Male", "Female" }) return r end function createTextFromSource(pCite, sText, sType) local ptrParent, ptrTextFromSource local rt = fhNewRichText() local ptrParent = pCite.source rt:SetText(sText) if sType == "source" then ptrParent = pCite.source else ptrParent = fhGetItemPtr(pCite.ptr, "~.SOUR.DATA") if ptrParent:IsNull() then ptrParent = fhGetItemPtr(pCite.ptr, "~.SOUR") ptrParent = fhCreateItem("DATA", ptrParent) end end local ptrTextFromSource = fhGetItemPtr(ptrParent, "~.TEXT") if ptrTextFromSource:IsNull() then ptrTextFromSource = fhCreateItem("TEXT", ptrParent) end fhSetValueAsRichText(ptrTextFromSource, rt) end function formatTextFromSource(templatename, templateDefault, pCite, tOtherValues) -- Takes a template name for file, template default if no file found and two tables of fields to replace richTextReplace = fh.richTextReplace local tFields = tFields or {} local tOthervalues = tOtherValues or {} local sPlugin = stringx.strip(fhGetContextInfo("CI_PLUGIN_NAME")) local function mkdir(path) local sep = "\\" local pStr = "" for dir in path:gmatch("[^" .. sep .. "]+") do pStr = pStr .. dir .. sep lfs.mkdir(pStr) end end local sFolder = fhGetContextInfo("CI_APP_DATA_FOLDER") .. "\\AutoText for Plugins\\" .. sPlugin .. "\\" -- Check folder exists and create if not mkdir(sFolder) local f = sFolder .. templatename local d, e = file.read(f) if e then -- Create File from default d = templateDefault file.write(f, templateDefault) end -- Replace all citation fields in AutoText for k, v in pairs(pCite.fields) do local n = pCite:getDisplayValue(k) or "" d = richTextReplace(d, "{" .. k .. "}", n) end -- Replace all other fields in AutoText for k, v in pairs(tOtherValues) do local n if k == "BIRT.DATE" then n = v:GetDisplayText() if n == "" then n = "N/A" end else n = tostring(v) or "" end d = richTextReplace(d, "{" .. k .. "}", n) end d = d:gsub("{.-}", "") return d end function loadForms() local forms = {} local ptrDefault = fhGetCurrentPropertyBoxRecord() if ptrDefault:IsNotNull() and fhGetTag(ptrDefault) ~= "INDI" then ptrDefault:SetNull() end if fh.isSet(ptrDefault) then local ptrFamily = fhGetItemPtr(ptrDefault, "~.FAMS") end forms["England and Wales"] = { ["Birth"] = { fields = { { tag = "NAME", label = "Name", type = "STRING", dr = "NAME", value = pCite:getDisplayValue("NM-NAME_RECORDED"), protect = true, }, { tag = "ACTION", label = "Add principal as", type = "LIST", value = "select", values = { "create", "select" }, prompts = { "Create New Record", "Use Existing Record" }, child = "RECORD", childUpdate = function(...) return selectOrCreate(...) end, }, { tag = "RECORD", label = "Record", type = "RECORD", dr = "PTR", value = ptrDefault:Clone(), minlength = 1, }, { tag = "MAIDEN-NAME", label = "Mothers Maiden Name", type = "STRING", dr = "MAIDEN-NAME", value = "", }, { tag = "CITE.INDI", label = "Add Citation to Individual Record", type = "BOOLEAN", value = true, }, }, ["function"] = function(ptr) return englandBirth(ptr) end, ["template_default"] = "{EN-REGION} Civil Index of {EN-TYPE}s\nDate: {DT-DATE} Name: {NM-NAME_RECORDED} Reference: {TX-REFERENCE} Registration District: {TX-REGISTRATION_DISTRICT} Mother's Maiden Name: {MAIDEN-NAME}", ["template_name"] = "UK Birth Index.ftf", }, ["Marriage"] = { fields = { { tag = "NAME", label = "Name", type = "STRING", dr = "NAME", value = pCite:getDisplayValue("NM-NAME_RECORDED"), protect = true, }, { tag = "ACTION", label = "Add principal as", type = "LIST", value = "select", values = { "create", "select" }, prompts = { "Create New Record", "Use Existing Record" }, child = "RECORD", childUpdate = function(...) return selectOrCreate(...) end, }, { tag = "RECORD", label = "Record", type = "RECORD", dr = "PTR", value = ptrDefault:Clone(), minlength = 1, child = "FAMILY", childUpdate = function(...) return updateFamList(...) end, }, { tag = "FAMILY", label = "Family", type = "LIST", values = {}, prompts = {}, }, { tag = "CITE.INDI", label = "Add Citation to Individual Record", type = "BOOLEAN", value = true, }, { tag = "CITE.FAM", label = "Add Citation to Family Record", type = "BOOLEAN", value = true, }, }, ["function"] = function(ptr) return englandMarriage(ptr) end, ["template_default"] = "{EN-REGION} Civil Index of {EN-TYPE}s\nDate: {DT-DATE} Name: {NM-NAME_RECORDED} Reference: {TX-REFERENCE} Registration District: {TX-REGISTRATION_DISTRICT} Spouse Name: {SPOUSE.NAME}", ["template_name"] = "UK Marriage Index.ftf", }, ["Death"] = { fields = { { tag = "NAME", label = "Name", type = "STRING", dr = "NAME", value = pCite:getDisplayValue("NM-NAME_RECORDED"), protect = true, }, { tag = "ACTION", label = "Add principal as", type = "LIST", value = "select", values = { "create", "select" }, prompts = { "Create New Record", "Use Existing Record" }, child = "RECORD", childUpdate = function(...) return selectOrCreate(...) end, }, { tag = "RECORD", label = "Record", type = "RECORD", dr = "PTR", value = ptrDefault:Clone(), minlength = 1, }, { tag = "AGE", label = "Age", type = "STRING", dr = "AGE", value = "", mask = "/d+[dwmy]", }, { tag = "BIRT.DATE", label = "Birth Date", type = "DATE", dr = "BIRT.DATE", value = fhNewDate(), }, { tag = "CITE.INDI", label = "Add Citation to Individual Record", type = "BOOLEAN", value = true, }, }, ["function"] = function(ptr) return englandDeath(ptr) end, ["template_default"] = "{EN-REGION} Civil Index of {EN-TYPE}s\nDate: {DT-DATE} Name: {NM-NAME_RECORDED} Reference: {TX-REFERENCE} Registration District: {TX-REGISTRATION_DISTRICT} Age: {AGE} Date of Birth: {BIRT.DATE}", ["template_name"] = "UK Death Index.ftf", }, } forms["Scotland"] = tablex.deepcopy(forms["England and Wales"]) forms["Scotland"]["Death"]["template_name"] = "Scottish Death Index.ftf" forms["Scotland"]["Death"]["template_default"] = "{EN-REGION} Civil Index of {EN-TYPE}s\nDate: {DT-DATE} Name: {NM-NAME_RECORDED} Reference: {TX-REFERENCE} Registration District: {TX-REGISTRATION_DISTRICT} Age: {AGE} Date of Birth: {BIRT.DATE} Mother's Maiden Name: {MAIDEN-NAME}" table.insert(forms["Scotland"]["Death"]["fields"], 6, { tag = "MAIDEN-NAME", label = "Mothers Maiden Name", type = "STRING", dr = "MAIDEN-NAME", value = "", }) forms["Ireland"] = tablex.deepcopy(forms["England and Wales"]) forms["Northern Ireland"] = tablex.deepcopy(forms["England and Wales"]) forms["Isle of Man"] = tablex.deepcopy(forms["England and Wales"]) forms["Channel Islands"] = tablex.deepcopy(forms["England and Wales"]) function forms.getIndex(fields, tag) for i, field in ipairs(fields) do if field.tag == tag then return i end end return false end return forms end function spousePromptForm(name) return { { tag = "SPOUSE.NAME", label = "Spouse Name", type = "STRING", value = "", minlength = 1, }, { tag = "SPOUSE.ACTION", label = "Add Spouse as", type = "LIST", value = "select", values = { "create", "select" }, prompts = { "Create New Record", "Use Existing Record" }, child = "SPOUSE.RECORD", childUpdate = function(...) return selectOrCreate(...) end, }, { tag = "SPOUSE.RECORD", label = "Spouse Record", type = "RECORD", dr = "PTR", value = fhNewItemPtr(), minlength = 1, }, { tag = "SPOUSE.CITE", label = "Add Citation to Spouse Record", type = "BOOLEAN", value = true, }, } end function spousenamePromptForm(name) return { { tag = "SPOUSE.NAME", label = "Spouse Name", type = "STRING", value = name, minlength = 1, }, } end ----------------------------------------------------- Call Main main()