Search Siblings or Parents.fh_lua--[[
@Title: Search Siblings or Parents
@Author: Jane Taubman
@Version: 1.1
@LastUpdated: 29 Nov 2020
@Description: Search for a pair Siblings or a Child and Parent by Christian names. Searches children of all recorded Parents.
1.1 V7 compatibility
]]
require "iuplua"
iup.SetGlobal("CUSTOMQUITMESSAGE","YES")
function main()
local sName1, sSurname,sName2,sRelation = prompt()
if sName1 == nil then return end
local tblResults = createResultTable()
-- Define Columns
tblResults.indi1 = {title='Individual 1',sort=1}
tblResults.life1 = {title='Life Dates', width=60}
tblResults.recordid1 = {title='Id', width=60}
tblResults.indi2 = {title='Individual 2'}
tblResults.life2 = {title='Life Dates',width=60}
tblResults.recordid2 = {title='Id', width=60}
tblResults.father1 = {title='Father 1'}
tblResults.father2 = {title='Father 2'}
local function addRow(pi,ps) -- Defining output here inherits upvalues for the output table
-- Add Row
tblResults:newRow()
-- Set Columns
tblResults.indi1:set(pi:Clone())
tblResults.life1:set(fhCallBuiltInFunction('lifedates',pi))
tblResults.recordid1 :set(fhGetRecordId(pi))
tblResults.indi2:set(ps:Clone())
tblResults.life2:set(fhCallBuiltInFunction('lifedates',ps))
tblResults.recordid2:set(fhGetRecordId(ps))
tblResults.father1:set(fhGetItemPtr(pi,'~.~FATH>'))
tblResults.father2:set(fhGetItemPtr(ps,'~.~FATH>'))
end
for pi in records('INDI') do
local spiname = string.lower(allGivenNames(pi))
local spisurname = string.lower(allSurnames(pi))
if spiname:match(sName1) and spisurname:match(sSurname) then
if sRelation == 0 then -- Sibling Search
local sibList = allSiblings(pi)
for _,ps in pairs(sibList) do
local spsname = string.lower(allGivenNames(ps))
if spsname:match(sName2) then
addRow(pi,ps)
end
end
else -- parent matching
local parList = allParents(pi)
for _,ps in pairs(parList) do
local spsname = string.lower(allGivenNames(ps))
if spsname:match(sName2) then
addRow(pi,ps)
end
end
end
end
end
sTitle = "Siblings Matching "..sName1:titleCase()..' '..sSurname:titleCase()..' and '..sName2:titleCase()
if sRelation == 1 then
sTitle = "Child Matching "..sName1:titleCase()..' '..sSurname:titleCase()..' with Parent matching '..sName2:titleCase()
end
fhOutputResultSetTitles(sTitle, sTitle, "Printed Date: %#x")
tblResults:outputResults()
end
---------------------------------------------------- Prompt
function prompt()
local sPrompt =
[[First Person (leave Surname blank for all) %t
Given Name Contains %s
Surname Contains %s
Second Person %t
Given Name Contains %s
Relationship %l|Sibling|Parent|
]]
local sName1 = ''
local sSurname1 = ''
local sName2 = ''
local sRelation = 0
local ret, sName1, sSurname1, sName2,sRelation =
iup.GetParam("Search Siblings or Parents",nil,
sPrompt,
sName1, sSurname1,sName2,sRelation)
if (ret == 0) or ret == false then
return
else
return sName1:trim():lower(),sSurname1:trim():lower(),sName2:trim():lower(),sRelation
end
end
---------------------------------------------------- Relations
function allSiblings(pi)
local tParents = allParents(pi)
local tSiblings = allChildren(tParents)
tSiblings[fhGetRecordId(pi)] = nil -- Exclude Original Person
return tSiblings
end
function allParents(pi)
local tParents = {}
local ps = fhNewItemPtr()
local pf = fhNewItemPtr()
local pf = fhNewItemPtr()
local pp = fhNewItemPtr()
ps:MoveTo(pi,'~.FAMC')
while ps:IsNotNull() do
pf = fhGetValueAsLink(ps)
pp:MoveTo(pf,'~.HUSB>')
if pp:IsNotNull() then
table.insert(tParents,pp:Clone())
end
pp:MoveTo(pf,'~.WIFE>')
if pp:IsNotNull() then
table.insert(tParents,pp:Clone())
end
ps:MoveNext('SAME_TAG')
end
return tParents
end
function allChildren(tParents)
local tChildren = {}
local pc = fhNewItemPtr()
for _,pi in ipairs(tParents) do
i = 1
pc:MoveTo(pi,'~.~CHIL>') -- INDI.~CHIL[1]>
while pc:IsNotNull() do
if pc:IsNotNull() then
irec = fhGetRecordId(pc)
tChildren[irec] = pc:Clone()
end
i = i + 1
pc:MoveTo(pi,'~.~CHIL['..i..']>')
end
end
return tChildren
end
function allGivenNames(pi)
local tblall = {}
local function addvalue(p,tag)
n = fhGetItemText(p,tag)
if n and n ~= '' then
table.insert(tblall,n)
end
end
local pn = fhNewItemPtr()
pn:MoveTo(pi,'~.NAME')
while pn:IsNotNull() do
addvalue(pn,'~:GIVEN_ALL')
addvalue(pn,'~._USED')
addvalue(pn,'~.GIVN')
addvalue(pn,'~.NICK')
pn:MoveNext('SAME_TAG')
end
return table.concat(tblall,' ')
end
function allSurnames(pi)
local tblall = {}
local function addvalue(p,tag)
n = fhGetItemText(p,tag)
if n and n ~= '' then
table.insert(tblall,n)
end
end
local pn = fhNewItemPtr()
local pf = fhNewItemPtr()
local ph = fhNewItemPtr()
pn:MoveTo(pi,'~.NAME')
while pn:IsNotNull() do
addvalue(pi,'~.NAME:SURNAME')
addvalue(pi,'~.NAME.SURNAME')
pn:MoveNext('SAME_TAG')
end
-- Married Women get Married Surnames
if fhGetItemText(pi,'~.SEX') == 'Female' then
pf:MoveTo(pi,'~.FAMS')
while pf:IsNotNull() do
ph = fhGetValueAsLink(pf)
ph:MoveTo(ph,'~.HUSB>')
if ph:IsNotNull() then
pn:MoveTo(ph,'~.NAME')
while pn:IsNotNull() do
addvalue(pn,'~:SURNAME')
addvalue(pn,'~.SURNAME')
pn:MoveNext('SAME_TAG')
end
end
pf:MoveNext('SAME_TAG')
end
end
return table.concat(tblall,' ')
end
---------------------------------------------------- Standard Functions
function string.titleCase(str)
local function titleCasePart( first, rest )
return first:upper()..rest:lower()
end
return string.gsub(str, "(%a)([%w_']*)", titleCasePart)
end
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
function string.trim(s)
return (s:gsub("^%s*(.-)%s*$", "%1"))
end
function createResultTable()
local tblOutput_mt = {} -- create metatable
local iC = 0 -- Define count of lines
local tblOutput = {} -- Define Columns Table
tblOutput_mt.col = 0
tblOutput_mt.seq = {}
tblOutput_mt.__newindex =
function (t,k,v)
-- Set Values to Defaults if not supplied
if v.content == nil then v.content = {} end
if v.title == nil then v.title = k end
if v.type == nil then v.type = 'notset' end
if v.width == nil then v.width = 140 end
if v.align == nil then v.align = 'align_left' end
if v.sort == nil then v.sort = 0 end
if v.sortAscending == nil then v.sortAscending = true end
if v.sortType == nil then v.sortType = 'default' end
if v.visibility == nil then v. visibility = 'show' end
v.set =
function(self,value)
self.content[iC] = value
if self.type == 'notset' then
if type(value) == 'string' then
self.type = 'text'
elseif type(value) == 'number' then
self.type = 'integer'
self.width = '30'
else
self.type = 'item'
end
end
end
rawset(t,k,v) -- update original table
local m = getmetatable(t)
m.col = m.col + 1
table.insert(m.seq,k)
end
tblOutput_mt.__call =
function (t)
local i = 0
local m = getmetatable(t)
local n = table.getn(m.seq)
return function ()
i = i + 1
if i <= n then
return t[m.seq[i]]
end
end
end
tblOutput.newRow = function(t)
iC = iC + 1
end
tblOutput.rowCount = function(t)
return iC
end
tblOutput.outputResults = function(self)
if iC > 0 then
for l in self() do
fhOutputResultSetColumn(l.title, l.type, l.content, iC, l.width,l.align,l.sort,l.sortAscending,l.sortType,l.visibility )
end
else
fhMessageBox('Sorry, no results found')
end
end
setmetatable(tblOutput, tblOutput_mt)
return tblOutput
end
if not(table.getn) then
function table.getn(t)
local count = 0
for _, __ in pairs(t) do
count = count + 1
end
return count
end
end
main()
--[[
@Title: Search Siblings or Parents
@Author: Jane Taubman
@Version: 1.1
@LastUpdated: 29 Nov 2020
@Description: Search for a pair Siblings or a Child and Parent by Christian names. Searches children of all recorded Parents.
1.1 V7 compatibility
]]
require "iuplua"
iup.SetGlobal("CUSTOMQUITMESSAGE","YES")
function main()
local sName1, sSurname,sName2,sRelation = prompt()
if sName1 == nil then return end
local tblResults = createResultTable()
-- Define Columns
tblResults.indi1 = {title='Individual 1',sort=1}
tblResults.life1 = {title='Life Dates', width=60}
tblResults.recordid1 = {title='Id', width=60}
tblResults.indi2 = {title='Individual 2'}
tblResults.life2 = {title='Life Dates',width=60}
tblResults.recordid2 = {title='Id', width=60}
tblResults.father1 = {title='Father 1'}
tblResults.father2 = {title='Father 2'}
local function addRow(pi,ps) -- Defining output here inherits upvalues for the output table
-- Add Row
tblResults:newRow()
-- Set Columns
tblResults.indi1:set(pi:Clone())
tblResults.life1:set(fhCallBuiltInFunction('lifedates',pi))
tblResults.recordid1 :set(fhGetRecordId(pi))
tblResults.indi2:set(ps:Clone())
tblResults.life2:set(fhCallBuiltInFunction('lifedates',ps))
tblResults.recordid2:set(fhGetRecordId(ps))
tblResults.father1:set(fhGetItemPtr(pi,'~.~FATH>'))
tblResults.father2:set(fhGetItemPtr(ps,'~.~FATH>'))
end
for pi in records('INDI') do
local spiname = string.lower(allGivenNames(pi))
local spisurname = string.lower(allSurnames(pi))
if spiname:match(sName1) and spisurname:match(sSurname) then
if sRelation == 0 then -- Sibling Search
local sibList = allSiblings(pi)
for _,ps in pairs(sibList) do
local spsname = string.lower(allGivenNames(ps))
if spsname:match(sName2) then
addRow(pi,ps)
end
end
else -- parent matching
local parList = allParents(pi)
for _,ps in pairs(parList) do
local spsname = string.lower(allGivenNames(ps))
if spsname:match(sName2) then
addRow(pi,ps)
end
end
end
end
end
sTitle = "Siblings Matching "..sName1:titleCase()..' '..sSurname:titleCase()..' and '..sName2:titleCase()
if sRelation == 1 then
sTitle = "Child Matching "..sName1:titleCase()..' '..sSurname:titleCase()..' with Parent matching '..sName2:titleCase()
end
fhOutputResultSetTitles(sTitle, sTitle, "Printed Date: %#x")
tblResults:outputResults()
end
---------------------------------------------------- Prompt
function prompt()
local sPrompt =
[[First Person (leave Surname blank for all) %t
Given Name Contains %s
Surname Contains %s
Second Person %t
Given Name Contains %s
Relationship %l|Sibling|Parent|
]]
local sName1 = ''
local sSurname1 = ''
local sName2 = ''
local sRelation = 0
local ret, sName1, sSurname1, sName2,sRelation =
iup.GetParam("Search Siblings or Parents",nil,
sPrompt,
sName1, sSurname1,sName2,sRelation)
if (ret == 0) or ret == false then
return
else
return sName1:trim():lower(),sSurname1:trim():lower(),sName2:trim():lower(),sRelation
end
end
---------------------------------------------------- Relations
function allSiblings(pi)
local tParents = allParents(pi)
local tSiblings = allChildren(tParents)
tSiblings[fhGetRecordId(pi)] = nil -- Exclude Original Person
return tSiblings
end
function allParents(pi)
local tParents = {}
local ps = fhNewItemPtr()
local pf = fhNewItemPtr()
local pf = fhNewItemPtr()
local pp = fhNewItemPtr()
ps:MoveTo(pi,'~.FAMC')
while ps:IsNotNull() do
pf = fhGetValueAsLink(ps)
pp:MoveTo(pf,'~.HUSB>')
if pp:IsNotNull() then
table.insert(tParents,pp:Clone())
end
pp:MoveTo(pf,'~.WIFE>')
if pp:IsNotNull() then
table.insert(tParents,pp:Clone())
end
ps:MoveNext('SAME_TAG')
end
return tParents
end
function allChildren(tParents)
local tChildren = {}
local pc = fhNewItemPtr()
for _,pi in ipairs(tParents) do
i = 1
pc:MoveTo(pi,'~.~CHIL>') -- INDI.~CHIL[1]>
while pc:IsNotNull() do
if pc:IsNotNull() then
irec = fhGetRecordId(pc)
tChildren[irec] = pc:Clone()
end
i = i + 1
pc:MoveTo(pi,'~.~CHIL['..i..']>')
end
end
return tChildren
end
function allGivenNames(pi)
local tblall = {}
local function addvalue(p,tag)
n = fhGetItemText(p,tag)
if n and n ~= '' then
table.insert(tblall,n)
end
end
local pn = fhNewItemPtr()
pn:MoveTo(pi,'~.NAME')
while pn:IsNotNull() do
addvalue(pn,'~:GIVEN_ALL')
addvalue(pn,'~._USED')
addvalue(pn,'~.GIVN')
addvalue(pn,'~.NICK')
pn:MoveNext('SAME_TAG')
end
return table.concat(tblall,' ')
end
function allSurnames(pi)
local tblall = {}
local function addvalue(p,tag)
n = fhGetItemText(p,tag)
if n and n ~= '' then
table.insert(tblall,n)
end
end
local pn = fhNewItemPtr()
local pf = fhNewItemPtr()
local ph = fhNewItemPtr()
pn:MoveTo(pi,'~.NAME')
while pn:IsNotNull() do
addvalue(pi,'~.NAME:SURNAME')
addvalue(pi,'~.NAME.SURNAME')
pn:MoveNext('SAME_TAG')
end
-- Married Women get Married Surnames
if fhGetItemText(pi,'~.SEX') == 'Female' then
pf:MoveTo(pi,'~.FAMS')
while pf:IsNotNull() do
ph = fhGetValueAsLink(pf)
ph:MoveTo(ph,'~.HUSB>')
if ph:IsNotNull() then
pn:MoveTo(ph,'~.NAME')
while pn:IsNotNull() do
addvalue(pn,'~:SURNAME')
addvalue(pn,'~.SURNAME')
pn:MoveNext('SAME_TAG')
end
end
pf:MoveNext('SAME_TAG')
end
end
return table.concat(tblall,' ')
end
---------------------------------------------------- Standard Functions
function string.titleCase(str)
local function titleCasePart( first, rest )
return first:upper()..rest:lower()
end
return string.gsub(str, "(%a)([%w_']*)", titleCasePart)
end
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
function string.trim(s)
return (s:gsub("^%s*(.-)%s*$", "%1"))
end
function createResultTable()
local tblOutput_mt = {} -- create metatable
local iC = 0 -- Define count of lines
local tblOutput = {} -- Define Columns Table
tblOutput_mt.col = 0
tblOutput_mt.seq = {}
tblOutput_mt.__newindex =
function (t,k,v)
-- Set Values to Defaults if not supplied
if v.content == nil then v.content = {} end
if v.title == nil then v.title = k end
if v.type == nil then v.type = 'notset' end
if v.width == nil then v.width = 140 end
if v.align == nil then v.align = 'align_left' end
if v.sort == nil then v.sort = 0 end
if v.sortAscending == nil then v.sortAscending = true end
if v.sortType == nil then v.sortType = 'default' end
if v.visibility == nil then v. visibility = 'show' end
v.set =
function(self,value)
self.content[iC] = value
if self.type == 'notset' then
if type(value) == 'string' then
self.type = 'text'
elseif type(value) == 'number' then
self.type = 'integer'
self.width = '30'
else
self.type = 'item'
end
end
end
rawset(t,k,v) -- update original table
local m = getmetatable(t)
m.col = m.col + 1
table.insert(m.seq,k)
end
tblOutput_mt.__call =
function (t)
local i = 0
local m = getmetatable(t)
local n = table.getn(m.seq)
return function ()
i = i + 1
if i <= n then
return t[m.seq[i]]
end
end
end
tblOutput.newRow = function(t)
iC = iC + 1
end
tblOutput.rowCount = function(t)
return iC
end
tblOutput.outputResults = function(self)
if iC > 0 then
for l in self() do
fhOutputResultSetColumn(l.title, l.type, l.content, iC, l.width,l.align,l.sort,l.sortAscending,l.sortType,l.visibility )
end
else
fhMessageBox('Sorry, no results found')
end
end
setmetatable(tblOutput, tblOutput_mt)
return tblOutput
end
if not(table.getn) then
function table.getn(t)
local count = 0
for _, __ in pairs(t) do
count = count + 1
end
return count
end
end
main()Source:Search-Siblings-or-Parents-1.fh_lua