Files
koreader/frontend/ui/widget/filechooser.lua
Hans-Werner Hilse 3066c86e38 Refactoring hardware abstraction
This is a major overhaul of the hardware abstraction layer.
A few notes:

General platform distinction happens in
  frontend/device.lua
which will delegate everything else to
  frontend/device/<platform_name>/device.lua
which should extend
  frontend/device/generic/device.lua

Screen handling is implemented in
  frontend/device/screen.lua
which includes the *functionality* to support device specifics.
Actually setting up the device specific functionality, however,
is done in the device specific setup code in the relevant
device.lua file.

The same goes for input handling.
2014-11-02 21:19:04 +01:00

193 lines
5.6 KiB
Lua

local lfs = require("libs/libkoreader-lfs")
local UIManager = require("ui/uimanager")
local Menu = require("ui/widget/menu")
local Screen = require("device").screen
local Device = require("device")
local util = require("ffi/util")
local DEBUG = require("dbg")
local _ = require("gettext")
local ffi = require("ffi")
ffi.cdef[[
int strcoll (char *str1, char *str2);
]]
-- string sort function respecting LC_COLLATE
local function strcoll(str1, str2)
return ffi.C.strcoll(ffi.cast("char*", str1), ffi.cast("char*", str2)) <= 0
end
local FileChooser = Menu:extend{
height = Screen:getHeight(),
width = Screen:getWidth(),
no_title = true,
path = lfs.currentdir(),
parent = nil,
show_hidden = nil,
filter = function(filename) return true end,
exclude_dirs = {"%.sdr$"},
strcoll = strcoll,
collate = "strcoll", -- or collate = "access",
reverse_collate = false,
}
function FileChooser:init()
-- common dir filter
self.dir_filter = function(dirname)
for _, pattern in ipairs(self.exclude_dirs) do
if dirname:match(pattern) then return end
end
return true
end
-- disable string collating in Kobo devices. See issue koreader/koreader#686
if Device:isKobo() then self.strcoll = nil end
self.item_table = self:genItemTableFromPath(self.path)
Menu.init(self) -- call parent's init()
end
function FileChooser:genItemTableFromPath(path)
local dirs = {}
local files = {}
-- lfs.dir directory without permission will give error
local ok, iter, dir_obj = pcall(lfs.dir, self.path)
if ok then
for f in iter, dir_obj do
if self.show_hidden or not string.match(f, "^%.[^.]") then
local filename = self.path.."/"..f
local attributes = lfs.attributes(filename)
if attributes.mode == "directory" and f ~= "." and f~=".." then
if self.dir_filter(filename) then
table.insert(dirs, {name = f, attr = attributes})
end
elseif attributes.mode == "file" then
if self.file_filter(filename) then
table.insert(files, {name = f, attr = attributes})
end
end
end
end
end
local sorting = nil
local reverse = self.reverse_collate
if self.collate == "strcoll" then
sorting = self.strcoll and function(a, b)
return self.strcoll(a.name, b.name) == not reverse
end or function(a, b)
return (a.name < b.name) == not reverse
end
elseif self.collate == "access" then
sorting = function(a, b)
if reverse then
return a.attr.access < b.attr.access
else
return a.attr.access > b.attr.access
end
end
end
table.sort(dirs, sorting)
if path ~= "/" then table.insert(dirs, 1, {name = ".."}) end
table.sort(files, sorting)
local item_table = {}
for i, dir in ipairs(dirs) do
local path = self.path.."/"..dir.name
local items = 0
local ok, iter, dir_obj = pcall(lfs.dir, path)
if ok then
for f in iter, dir_obj do
items = items + 1
end
-- exclude "." and ".."
items = items - 2
end
local istr = items .. (items > 1 and _(" items") or _(" item"))
table.insert(item_table, {
text = dir.name.."/",
mandatory = istr,
path = path
})
end
for _, file in ipairs(files) do
local full_path = self.path.."/"..file.name
local file_size = lfs.attributes(full_path, "size") or 0
local sstr = ""
if file_size > 1024*1024 then
sstr = string.format("%4.1f MB", file_size/1024/1024)
elseif file_size > 1024 then
sstr = string.format("%4.1f KB", file_size/1024)
else
sstr = string.format("%d B", file_size)
end
table.insert(item_table, {
text = file.name,
mandatory = sstr,
path = full_path
})
end
-- lfs.dir iterated node string may be encoded with some weird codepage on Windows
-- we need to encode them to utf-8
if ffi.os == "Windows" then
for k, v in pairs(item_table) do
if v.text then
v.text = util.multiByteToUTF8(v.text) or ""
end
end
end
return item_table
end
function FileChooser:refreshPath()
self:swithItemTable(nil, self:genItemTableFromPath(self.path))
end
function FileChooser:changeToPath(path)
path = util.realpath(path)
self.path = path
self:refreshPath()
end
function FileChooser:toggleHiddenFiles()
self.show_hidden = not self.show_hidden
self:refreshPath()
end
function FileChooser:setCollate(collate)
self.collate = collate
self:refreshPath()
end
function FileChooser:toggleReverseCollate()
self.reverse_collate = not self.reverse_collate
self:refreshPath()
end
function FileChooser:onMenuSelect(item)
-- parent directory of dir without permission get nil mode
-- we need to change to parent path in this case
if lfs.attributes(item.path, "mode") == "file" then
self:onFileSelect(item.path)
else
self:changeToPath(item.path)
end
return true
end
function FileChooser:onMenuHold(item)
self:onFileHold(item.path)
return true
end
function FileChooser:onFileSelect(file)
UIManager:close(self)
return true
end
function FileChooser:onFileHold(file)
return true
end
return FileChooser