2
0
mirror of https://github.com/koreader/koreader synced 2024-10-31 21:20:20 +00:00
koreader/filehistory.lua
Tigran Aivazian 4bc9f37b49 Two trivial optimizations
1. Comment out re-calculation of parameters to adjust for the case when
the user changed screen orientation, because we force portrait mode on
document close. I left a comment explaining this, so we can uncomment
this code if we choose to not force portrait mode on document close in
thefuture.
2. Don't re-sort the list if the file does not exist.
This predicts the most likely scenario, namely that the user
will choose to delete this stale history entry.
And even if he chooses NOT to delete it, placing a stale entry
to the top of the list contradicts our logic because the
non-existent file was never opened.
2012-11-21 10:19:45 +00:00

375 lines
10 KiB
Lua

require "rendertext"
require "keys"
require "graphics"
require "font"
require "inputbox"
require "dialog"
require "filesearcher"
require "settings"
require "dialog"
FileHistory = {
title_H = 40, -- title height
spacing = 36, -- spacing between lines
foot_H = 28, -- foot height
margin_H = 10, -- horisontal margin
-- state buffer
history_files = {},
files = {},
result = {},
items = 0,
page = 0,
current = 1,
oldcurrent = 1,
commands = nil,
}
function FileHistory:init(history_path)
self:setPath("history")
-- to initialize only once
if not self.commands then self:addAllCommands() end
end
function FileHistory:setPath(newPath)
self.path = newPath
self:readDir("-c ")
self.items = #self.files
if self.items == 1 then
return nil
end
self.page = 1
self.current = 1
return true
end
function FileHistory:readDir(order_criteria)
self.history_files = {}
self.files = {}
local p = io.popen("ls "..order_criteria.."-1 "..self.path)
for f in p:lines() do
-- insert history files
table.insert(self.history_files, {dir=self.path, name=f})
-- and corresponding path & file items
table.insert(self.files, {dir=HistoryToPath(f), name=HistoryToName(f)})
end
p:close()
end
function FileHistory:setSearchResult(keywords)
self.result = {}
if keywords == "" or keywords == " " then
-- show all history
self.result = self.files
else
-- select history files with keywords in the filename
for __,f in pairs(self.files) do
if string.find(string.lower(f.name), keywords) then
table.insert(self.result,f)
end
end
end
self.keywords = keywords
self.items = #self.result
self.page = 1
self.current = 1
return self.items
end
function FileHistory:prevItem()
if self.current == 1 then
if self.page > 1 then
self.current = self.perpage
self.page = self.page - 1
self.pagedirty = true
end
else
self.current = self.current - 1
self.markerdirty = true
end
end
function FileHistory:nextItem()
if self.current == self.perpage then
if self.page < (self.items / self.perpage) then
self.current = 1
self.page = self.page + 1
self.pagedirty = true
end
else
if self.page ~= math.floor(self.items / self.perpage) + 1
or self.current + (self.page-1)*self.perpage < self.items then
self.current = self.current + 1
self.markerdirty = true
end
end
end
function FileHistory:addAllCommands()
self.commands = Commands:new{}
self.commands:add(KEY_H, nil, "H",
"show help page",
function(self)
HelpPage:show(0, G_height, self.commands)
self.pagedirty = true
end
)
self.commands:add(KEY_FW_UP, nil, "joypad up",
"previous item",
function(self)
self:prevItem()
end
)
self.commands:add(KEY_FW_DOWN, nil, "joypad down",
"next item",
function(self)
self:nextItem()
end
)
-- NuPogodi, 01.10.12: fast jumps to items at positions 10, 20, .. 90, 0% within the list
local numeric_keydefs, i = {}
for i=1, 10 do numeric_keydefs[i]=Keydef:new(KEY_1+i-1, nil, tostring(i%10)) end
self.commands:addGroup("[1, 2 .. 9, 0]", numeric_keydefs,
"item at position 0%, 10% .. 90%, 100%",
function(self)
local target_item = math.ceil(self.items * (keydef.keycode-KEY_1) / 9)
self.current, self.page, self.markerdirty, self.pagedirty =
gotoTargetItem(target_item, self.items, self.current, self.page, self.perpage)
end
)
self.commands:add({KEY_PGFWD, KEY_LPGFWD}, nil, ">",
"next page",
function(self)
if self.page < (self.items / self.perpage) then
if self.current + self.page*self.perpage > self.items then
self.current = self.items - self.page*self.perpage
end
self.page = self.page + 1
self.pagedirty = true
else
self.current = self.items - (self.page-1)*self.perpage
self.markerdirty = true
end
end
)
self.commands:add({KEY_PGBCK, KEY_LPGBCK}, nil, "<",
"previous page",
function(self)
if self.page > 1 then
self.page = self.page - 1
self.pagedirty = true
else
self.current = 1
self.markerdirty = true
end
end
)
self.commands:add(KEY_G, nil, "G", -- NuPogodi, 01.10.12: goto page No.
"goto page",
function(self)
local n = math.ceil(self.items / self.perpage)
local page = NumInputBox:input(G_height-100, 100, "Page:", "current page "..self.page.." of "..n, true)
if pcall(function () page = math.floor(page) end) -- convert string to number
and page ~= self.page and page > 0 and page <= n then
self.page = page
if self.current + (page-1)*self.perpage > self.items then
self.current = self.items - (page-1)*self.perpage
end
end
self.pagedirty = true
end
)
self.commands:add(KEY_FW_RIGHT, nil, "joypad right",
"document details",
function(self)
local file_entry = self.result[self.perpage*(self.page-1)+self.current]
if file_entry.name == ".." then
warningUnsupportedFunction()
return
end -- do not show details
FileInfo:show(file_entry.dir,file_entry.name)
self.pagedirty = true
end
)
self.commands:add(KEY_S, nil, "S",
"invoke search inputbox",
function(self)
-- NuPogodi, 30.09.12: be sure that something is found
local old_keywords = self.keywords
local old_data = self.result
local old_page, old_current = self.page, self.current
self.keywords = InputBox:input(G_height - 100, 100, "Search:", old_keywords)
if self.keywords then
self:setSearchResult(self.keywords)
else
self.keywords = old_keywords
end
if #self.result < 1 then
InfoMessage:inform("No search hits ", DINFO_DELAY, 1, MSG_WARN)
-- restoring the original data
self.result = old_data
self.items = #self.result
self.keywords = old_keywords
self.page = old_page
self.current = old_current
end
self.pagedirty = true
end
)
self.commands:add({KEY_F, KEY_AA}, nil, "F, Aa",
"change font faces",
function(self)
Font:chooseFonts()
self.pagedirty = true
end
)
self.commands:add({KEY_ENTER, KEY_FW_PRESS}, nil, "Enter",
"open selected document",
function(self)
local file_entry = self.result[self.perpage*(self.page-1)+self.current]
file_full_path = file_entry.dir .. "/" .. file_entry.name
if FileExists(file_full_path) then
openFile(file_full_path)
--[[
-- reset height and item index if screen has been rotated
-- not needed because we force portrait mode on document close
local item_no = self.perpage * (self.page - 1) + self.current
self.perpage = math.floor(G_height / self.spacing) - 2
self.current = item_no % self.perpage
self.page = math.floor(item_no / self.perpage) + 1
--]]
self:init()
self:setSearchResult(self.keywords)
self.pagedirty = true
else
InfoMessage:inform("File does not exist ", DINFO_DELAY, 1, MSG_ERROR)
end
end
)
self.commands:add(KEY_DEL, nil, "Del",
"delete history entry",
function(self)
local file_entry = self.result[self.perpage*(self.page-1)+self.current]
local file_to_del = file_entry.dir .. "/" .. file_entry.name
if InfoMessage.InfoMethod[MSG_CONFIRM] == 0 then -- silent regime
os.remove(DocToHistory(file_to_del))
self:init()
self:setSearchResult(self.keywords)
else
InfoMessage:inform("Press 'Y' to confirm ", DINFO_NODELAY, 0, MSG_CONFIRM)
if ReturnKey() == KEY_Y then
os.remove(DocToHistory(file_to_del))
self:init()
self:setSearchResult(self.keywords)
end
end
self.pagedirty = true
if self.items == 0 then
return "break"
end
end
)
self.commands:add(KEY_SPACE, nil, "Space",
"refresh page manually",
function(self)
self.pagedirty = true
end
)
self.commands:add(KEY_BACK, nil, "Back",
"back",
function(self)
return "break"
end
)
end
function FileHistory:choose(keywords)
self.perpage = math.floor(G_height / self.spacing) - 2
self.pagedirty = true
self.markerdirty = false
-- NuPogodi, 30.09.12: immediate quit (no redraw), if empty
if self:setSearchResult(keywords) < 1 then
InfoMessage:inform("No reading history ", DINFO_DELAY, 1, MSG_WARN)
return nil
end
while true do
local cface = Font:getFace("cfont", 22)
local tface = Font:getFace("tfont", 25)
local fface = Font:getFace("ffont", 16)
if self.pagedirty then
self.markerdirty = true
fb.bb:paintRect(0, 0, G_width, G_height, 0)
-- draw header
local header = "Last Documents ("..tostring(self.items).." items)"
if self.keywords ~= "" and self.keywords ~= " " then
--header = header .. " (filter: \'" .. string.upper(self.keywords) .. "\')"
header = "Search Results for \'"..string.upper(self.keywords).."\'"
end
DrawTitle(header,self.margin_H,0,self.title_H,3,tface)
-- draw found results
for c = 1, self.perpage do
local i = (self.page - 1) * self.perpage + c
if i <= self.items then
y = self.title_H + (self.spacing * c) + 4
local ftype = string.lower(string.match(self.result[i].name, ".+%.([^.]+)") or "")
DrawFileItem(self.result[i].name,self.margin_H,y,ftype)
end
end
-- draw footer
all_page = math.ceil(self.items/self.perpage)
DrawFooter("Page "..self.page.." of "..all_page,fface,self.foot_H)
end
if self.markerdirty then
if not self.pagedirty then
if self.oldcurrent > 0 then
y = self.title_H + (self.spacing * self.oldcurrent) + 12
fb.bb:paintRect(self.margin_H, y, G_width - 2 * self.margin_H, 3, 0)
fb:refresh(1, self.margin_H, y, G_width - 2 * self.margin_H, 3)
end
end
-- draw new marker line
y = self.title_H + (self.spacing * self.current) + 12
fb.bb:paintRect(self.margin_H, y, G_width - 2 * self.margin_H, 3, 15)
if not self.pagedirty then
fb:refresh(1, self.margin_H, y, G_width - 2 * self.margin_H, 3)
end
self.oldcurrent = self.current
self.markerdirty = false
end
if self.pagedirty then
fb:refresh(0)
self.pagedirty = false
end
local ev = input.saveWaitForEvent()
ev.code = adjustKeyEvents(ev)
if ev.type == EV_KEY and ev.value ~= EVENT_VALUE_KEY_RELEASE then
keydef = Keydef:new(ev.code, getKeyModifier())
Debug("key pressed: "..tostring(keydef))
command = self.commands:getByKeydef(keydef)
if command ~= nil then
Debug("command to execute: "..tostring(command))
ret_code = command.func(self, keydef)
else
Debug("command not found: "..tostring(command))
end
if ret_code == "break" then
break
end
if self.selected_item ~= nil then
Debug("# selected "..self.selected_item)
return self.selected_item
end
end -- if
end -- while true
return nil
end