--[[ @Title: Possible Problem Manager @Author: Jane Taubman @LastUpdated: July 2011 @Version: 1.0 @Description: Lists all Possible Date Problems, similar the standard Fact Date Warning Query, but ignores those facts marked using Possible Problem Marker Plugin. ]] require "iuplua" -- require "_tableloadsave" --[[ Save Table to File/Stringtable Load Table from File/Stringtable v 0.94 Lua 5.1 compatible Userdata and indices of these are not saved Functions are saved via string.dump, so make sure it has no upvalues References are saved ---------------------------------------------------- table.save( table [, filename] ) Saves a table so it can be called via the table.load function again table must a object of type 'table' filename is optional, and may be a string representing a filename or true/1 table.save( table ) on success: returns a string representing the table (stringtable) (uses a string as buffer, ideal for smaller tables) table.save( table, true or 1 ) on success: returns a string representing the table (stringtable) (uses io.tmpfile() as buffer, ideal for bigger tables) table.save( table, "filename" ) on success: returns 1 (saves the table to file "filename") on failure: returns as second argument an error msg ---------------------------------------------------- table.load( filename or stringtable ) Loads a table that has been saved via the table.save function on success: returns a previously saved table on failure: returns as second argument an error msg ---------------------------------------------------- chillcode, http://lua-users.org/wiki/SaveTableToFile Licensed under the same terms as Lua itself. ]]-- do -- declare local variables --// exportstring( string ) --// returns a "Lua" portable version of the string local function exportstring( s ) s = string.format( "%q",s ) -- to replace s = string.gsub( s,"\\\n","\\n" ) s = string.gsub( s,"\r","\\r" ) s = string.gsub( s,string.char(26),"\"..string.char(26)..\"" ) return s end --// The Save Function function table.save( tbl,filename ) local charS,charE = " ","\n" local file,err -- create a pseudo file that writes to a string and return the string if not filename then file = { write = function( self,newstr ) self.str = self.str..newstr end, str = "" } charS,charE = "","" -- write table to tmpfile elseif filename == true or filename == 1 then charS,charE,file = "","",io.tmpfile() -- write table to file -- use io.open here rather than io.output, since in windows when clicking on a file opened with io.output will create an error else file,err = io.open( filename, "w" ) if err then return _,err end end -- initiate variables for save procedure local tables,lookup = { tbl },{ [tbl] = 1 } file:write( "return {"..charE ) for idx,t in ipairs( tables ) do if filename and filename ~= true and filename ~= 1 then file:write( "-- Table: {"..idx.."}"..charE ) end file:write( "{"..charE ) local thandled = {} for i,v in ipairs( t ) do thandled[i] = true -- escape functions and userdata if type( v ) ~= "userdata" then -- only handle value if type( v ) == "table" then if not lookup[v] then table.insert( tables, v ) lookup[v] = #tables end file:write( charS.."{"..lookup[v].."},"..charE ) elseif type( v ) == "function" then file:write( charS.."loadstring("..exportstring(string.dump( v )).."),"..charE ) else local value = ( type( v ) == "string" and exportstring( v ) ) or tostring( v ) file:write( charS..value..","..charE ) end end end for i,v in pairs( t ) do -- escape functions and userdata if (not thandled[i]) and type( v ) ~= "userdata" then -- handle index if type( i ) == "table" then if not lookup[i] then table.insert( tables,i ) lookup[i] = #tables end file:write( charS.."[{"..lookup[i].."}]=" ) else local index = ( type( i ) == "string" and "["..exportstring( i ).."]" ) or string.format( "[%d]",i ) file:write( charS..index.."=" ) end -- handle value if type( v ) == "table" then if not lookup[v] then table.insert( tables,v ) lookup[v] = #tables end file:write( "{"..lookup[v].."},"..charE ) elseif type( v ) == "function" then file:write( "loadstring("..exportstring(string.dump( v )).."),"..charE ) else local value = ( type( v ) == "string" and exportstring( v ) ) or tostring( v ) file:write( value..","..charE ) end end end file:write( "},"..charE ) end file:write( "}" ) -- Return Values -- return stringtable from string if not filename then -- set marker for stringtable return file.str.."--|" -- return stringttable from file elseif filename == true or filename == 1 then file:seek ( "set" ) -- no need to close file, it gets closed and removed automatically -- set marker for stringtable return file:read( "*a" ).."--|" -- close file and return 1 else file:close() return 1 end end --// The Load Function function table.load( sfile ) -- catch marker for stringtable if string.sub( sfile,-3,-1 ) == "--|" then tables,err = loadstring( sfile ) else tables,err = loadfile( sfile ) end if err then return _,err end tables = tables() for idx = 1,#tables do local tolinkv,tolinki = {},{} for i,v in pairs( tables[idx] ) do if type( v ) == "table" and tables[v[1]] then table.insert( tolinkv,{ i,tables[v[1]] } ) end if type( i ) == "table" and tables[i[1]] then table.insert( tolinki,{ i,tables[i[1]] } ) end end -- link values, first due to possible changes of indices for _,v in ipairs( tolinkv ) do tables[idx][v[1]] = v[2] end -- link indices for _,v in ipairs( tolinki ) do tables[idx][v[2]],tables[idx][v[1]] = tables[idx][v[1]],nil end end return tables[1] end -- close do end function getFactId(ptr,ptrEvent) local tblRecord = {recordid=fhGetRecordId(ptr), type=fhGetTag(ptr), date=fhGetItemText(ptrEvent,'~.DATE'), plac=fhGetItemText(ptrEvent,'~.PLAC'), tag=fhGetTag(ptrEvent), value=fhGetItemText(ptrEvent,'~')} return buildIndex(tblRecord) end function buildIndex(record) return (record.type..'|'..record.recordid..'|'..record.tag..'|'..record.date..'|'..record.plac..'|'..record.value) end function checkMark(record) local mark = 0 if Settings[buildIndex(record)] ~= nil then mark = 1 end return mark end --------------------------------------------------------------Main Code -- Create Result Tables tblIndi = {} tblSpouse = {} tblFact = {} tblFather = {} tblMother = {} tblReason = {} tblMarks = {} -- Load Settings strSettings = fhGetPluginDataFileName() -- Fix File name strSettings =strSettings:gsub('Data\\.-\.dat','Data\\Possible Problem Manager.dat') Settings = table.load(strSettings) if Settings == nil then Settings = {} end -- First Run set empty Settings File -- Prompt User strReportTitle = "Fact Problem Report" btnNo = iup.Alarm(strReportTitle, "Include Facts marked 'Ignore' on the Report?" , "All Problem Facts" ,"Un-Ignored Facts Only" ,"Ignored Facts Only") -- Shows a message for each selected button if btnNo == 1 then bIncludeMarks = true bExcludeUnMarked = false strReportSubTitle = "All Problem Facts" elseif btnNo == 2 then bIncludeMarks = false bExcludeUnMarked = false strReportSubTitle = "Un-Ignored Facts Only" elseif btnNo == 3 then bIncludeMarks = true bExcludeUnMarked = true strReportSubTitle = "Ignored Facts Only" else return end -- Process All Individuals and Family Events recordTypes = {'INDI','FAM'} ptr = fhNewItemPtr() ptrEvent = fhNewItemPtr() ptrDate = fhNewItemPtr() ptrWork = fhNewItemPtr() for k,recordType in pairs(recordTypes) do ptr:MoveToFirstRecord(recordType) while ptr:IsNotNull() do ptrEvent:MoveToFirstChildItem(ptr) while ptrEvent:IsNotNull() do if fhIsFact(ptrEvent) then ptrDate:MoveTo(ptrEvent,'~.DATE') if ptrDate:IsNotNull() then i = 1 warning = fhCallBuiltInFunction('GetDataWarning',ptrDate,i) while warning ~= "" do idx = getFactId(ptr,ptrEvent) bMarked = (Settings[idx] ~= nil) if (not(bMarked) or bIncludeMarks) then if (not(bMarked) and not(bExcludeUnMarked)) or bMarked then table.insert(tblFact,ptrEvent:Clone()) table.insert(tblReason,warning) if Settings[idx] ~= nil then table.insert(tblMarks,'X') else table.insert(tblMarks,' ') end if recordType == 'INDI' then table.insert(tblIndi,ptr:Clone()) table.insert(tblSpouse,' ') ptrWork:MoveTo(ptr,'~.~FATH[1]>') table.insert(tblFather,ptrWork:Clone()) ptrWork:MoveTo(ptr,'~.~MOTH[1]>') table.insert(tblMother,ptrWork:Clone()) else ptrWork:MoveTo(ptr,'~.HUSB>') table.insert(tblIndi,ptrWork:Clone()) ptrWork:MoveTo(ptr,'~.WIFE>') table.insert(tblSpouse,ptrWork:Clone()) table.insert(tblFather,' ') table.insert(tblMother,' ') end end end i = i + 1 warning = fhCallBuiltInFunction('GetDataWarning',ptrDate,i) end end end ptrEvent:MoveNext('ANY') end ptr:MoveNext("SAME_TAG") end end -- Output Results if #tblFact == 0 then fhMessageBox('No Unmarked Facts with Warnings Found') else fhOutputResultSetTitles(strReportTitle.." - "..strReportSubTitle, strReportTitle, strReportSubTitle.." Date: %#x") if bIncludeMarks then fhOutputResultSetColumn("Marked", "text", tblMarks, #tblFact, 30, "align_mid") else end fhOutputResultSetColumn("Fact", "item", tblFact, #tblFact, 120, "align_left") fhOutputResultSetColumn("Warning", "text", tblReason, #tblFact, 200, "align_left") fhOutputResultSetColumn("Individual", "item", tblIndi, #tblFact, 120, "align_left") fhOutputResultSetColumn("Spouse", "item", tblSpouse, #tblFact, 120, "align_left") fhOutputResultSetColumn("Father", "item", tblFather, #tblFact, 120, "align_left") fhOutputResultSetColumn("Mother", "item", tblMother, #tblFact, 120, "align_left") end