filterlist.lua 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301
  1. --Minetest
  2. --Copyright (C) 2013 sapier
  3. --
  4. --This program is free software; you can redistribute it and/or modify
  5. --it under the terms of the GNU Lesser General Public License as published by
  6. --the Free Software Foundation; either version 2.1 of the License, or
  7. --(at your option) any later version.
  8. --
  9. --This program is distributed in the hope that it will be useful,
  10. --but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. --MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. --GNU Lesser General Public License for more details.
  13. --
  14. --You should have received a copy of the GNU Lesser General Public License along
  15. --with this program; if not, write to the Free Software Foundation, Inc.,
  16. --51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  17. --------------------------------------------------------------------------------
  18. -- Generic implementation of a filter/sortable list --
  19. -- Usage: --
  20. -- Filterlist needs to be initialized on creation. To achieve this you need to --
  21. -- pass following functions: --
  22. -- raw_fct() (mandatory): --
  23. -- function returning a table containing the elements to be filtered --
  24. -- compare_fct(element1,element2) (mandatory): --
  25. -- function returning true/false if element1 is same element as element2 --
  26. -- uid_match_fct(element1,uid) (optional) --
  27. -- function telling if uid is attached to element1 --
  28. -- filter_fct(element,filtercriteria) (optional) --
  29. -- function returning true/false if filtercriteria met to element --
  30. -- fetch_param (optional) --
  31. -- parameter passed to raw_fct to aquire correct raw data --
  32. -- --
  33. --------------------------------------------------------------------------------
  34. filterlist = {}
  35. --------------------------------------------------------------------------------
  36. function filterlist.refresh(this)
  37. this.m_raw_list = this.m_raw_list_fct(this.m_fetch_param)
  38. filterlist.process(this)
  39. end
  40. --------------------------------------------------------------------------------
  41. function filterlist.create(raw_fct,compare_fct,uid_match_fct,filter_fct,fetch_param)
  42. assert((raw_fct ~= nil) and (type(raw_fct) == "function"))
  43. assert((compare_fct ~= nil) and (type(compare_fct) == "function"))
  44. local this = {}
  45. this.m_raw_list_fct = raw_fct
  46. this.m_compare_fct = compare_fct
  47. this.m_filter_fct = filter_fct
  48. this.m_uid_match_fct = uid_match_fct
  49. this.m_filtercriteria = nil
  50. this.m_fetch_param = fetch_param
  51. this.m_sortmode = "none"
  52. this.m_sort_list = {}
  53. this.m_processed_list = nil
  54. this.m_raw_list = this.m_raw_list_fct(this.m_fetch_param)
  55. filterlist.process(this)
  56. return this
  57. end
  58. --------------------------------------------------------------------------------
  59. function filterlist.add_sort_mechanism(this,name,fct)
  60. this.m_sort_list[name] = fct
  61. end
  62. --------------------------------------------------------------------------------
  63. function filterlist.set_filtercriteria(this,criteria)
  64. if criteria == this.m_filtercriteria and
  65. type(criteria) ~= "table" then
  66. return
  67. end
  68. this.m_filtercriteria = criteria
  69. filterlist.process(this)
  70. end
  71. --------------------------------------------------------------------------------
  72. function filterlist.get_filtercriteria(this)
  73. return this.m_filtercriteria
  74. end
  75. --------------------------------------------------------------------------------
  76. --supported sort mode "alphabetic|none"
  77. function filterlist.set_sortmode(this,mode)
  78. if (mode == this.m_sortmode) then
  79. return
  80. end
  81. this.m_sortmode = mode
  82. filterlist.process(this)
  83. end
  84. --------------------------------------------------------------------------------
  85. function filterlist.get_list(this)
  86. return this.m_processed_list
  87. end
  88. --------------------------------------------------------------------------------
  89. function filterlist.get_raw_list(this)
  90. return this.m_raw_list
  91. end
  92. --------------------------------------------------------------------------------
  93. function filterlist.get_raw_element(this,idx)
  94. if type(idx) ~= "number" then
  95. idx = tonumber(idx)
  96. end
  97. if idx ~= nil and idx > 0 and idx < #this.m_raw_list then
  98. return this.m_raw_list[idx]
  99. end
  100. return nil
  101. end
  102. --------------------------------------------------------------------------------
  103. function filterlist.get_raw_index(this,listindex)
  104. assert(this.m_processed_list ~= nil)
  105. if listindex ~= nil and listindex > 0 and
  106. listindex <= #this.m_processed_list then
  107. local entry = this.m_processed_list[listindex]
  108. for i,v in ipairs(this.m_raw_list) do
  109. if this.m_compare_fct(v,entry) then
  110. return i
  111. end
  112. end
  113. end
  114. return 0
  115. end
  116. --------------------------------------------------------------------------------
  117. function filterlist.get_current_index(this,listindex)
  118. assert(this.m_processed_list ~= nil)
  119. if listindex ~= nil and listindex > 0 and
  120. listindex <= #this.m_raw_list then
  121. local entry = this.m_raw_list[listindex]
  122. for i,v in ipairs(this.m_processed_list) do
  123. if this.m_compare_fct(v,entry) then
  124. return i
  125. end
  126. end
  127. end
  128. return 0
  129. end
  130. --------------------------------------------------------------------------------
  131. function filterlist.process(this)
  132. assert(this.m_raw_list ~= nil)
  133. if this.m_sortmode == "none" and
  134. this.m_filtercriteria == nil then
  135. this.m_processed_list = this.m_raw_list
  136. return
  137. end
  138. this.m_processed_list = {}
  139. for k,v in pairs(this.m_raw_list) do
  140. if this.m_filtercriteria == nil or
  141. this.m_filter_fct(v,this.m_filtercriteria) then
  142. table.insert(this.m_processed_list,v)
  143. end
  144. end
  145. if this.m_sortmode == "none" then
  146. return
  147. end
  148. if this.m_sort_list[this.m_sortmode] ~= nil and
  149. type(this.m_sort_list[this.m_sortmode]) == "function" then
  150. this.m_sort_list[this.m_sortmode](this)
  151. end
  152. end
  153. --------------------------------------------------------------------------------
  154. function filterlist.size(this)
  155. if this.m_processed_list == nil then
  156. return 0
  157. end
  158. return #this.m_processed_list
  159. end
  160. --------------------------------------------------------------------------------
  161. function filterlist.uid_exists_raw(this,uid)
  162. for i,v in ipairs(this.m_raw_list) do
  163. if this.m_uid_match_fct(v,uid) then
  164. return true
  165. end
  166. end
  167. return false
  168. end
  169. --------------------------------------------------------------------------------
  170. function filterlist.raw_index_by_uid(this, uid)
  171. local elementcount = 0
  172. local elementidx = 0
  173. for i,v in ipairs(this.m_raw_list) do
  174. if this.m_uid_match_fct(v,uid) then
  175. elementcount = elementcount +1
  176. elementidx = i
  177. end
  178. end
  179. -- If there are more elements than one with same name uid can't decide which
  180. -- one is meant. This shouldn't be possible but just for sure.
  181. if elementcount > 1 then
  182. elementidx=0
  183. end
  184. return elementidx
  185. end
  186. --------------------------------------------------------------------------------
  187. -- COMMON helper functions --
  188. --------------------------------------------------------------------------------
  189. --------------------------------------------------------------------------------
  190. function compare_worlds(world1,world2)
  191. if world1.path ~= world2.path then
  192. return false
  193. end
  194. if world1.name ~= world2.name then
  195. return false
  196. end
  197. if world1.gameid ~= world2.gameid then
  198. return false
  199. end
  200. return true
  201. end
  202. --------------------------------------------------------------------------------
  203. function sort_worlds_alphabetic(this)
  204. table.sort(this.m_processed_list, function(a, b)
  205. --fixes issue #857 (crash due to sorting nil in worldlist)
  206. if a == nil or b == nil then
  207. if a == nil and b ~= nil then return false end
  208. if b == nil and a ~= nil then return true end
  209. return false
  210. end
  211. if a.name:lower() == b.name:lower() then
  212. return a.name < b.name
  213. end
  214. return a.name:lower() < b.name:lower()
  215. end)
  216. end
  217. --------------------------------------------------------------------------------
  218. function sort_mod_list(this)
  219. table.sort(this.m_processed_list, function(a, b)
  220. -- Show game mods at bottom
  221. if a.typ ~= b.typ then
  222. return b.typ == "game_mod"
  223. end
  224. -- If in same or no modpack, sort by name
  225. if a.modpack == b.modpack then
  226. if a.name:lower() == b.name:lower() then
  227. return a.name < b.name
  228. end
  229. return a.name:lower() < b.name:lower()
  230. -- Else compare name to modpack name
  231. else
  232. -- Always show modpack pseudo-mod on top of modpack mod list
  233. if a.name == b.modpack then
  234. return true
  235. elseif b.name == a.modpack then
  236. return false
  237. end
  238. local name_a = a.modpack or a.name
  239. local name_b = b.modpack or b.name
  240. if name_a:lower() == name_b:lower() then
  241. return name_a < name_b
  242. end
  243. return name_a:lower() < name_b:lower()
  244. end
  245. end)
  246. end