rewritten: plugin 'menu'
now we have a cache for the plugin (this limits the number of database requests) added: to plugin 'menu' menu_dir_tab can have a 'current' parameter (first argument) (it uses the last path from the previous menu_dir_tab) changed: updated to the new EZC api added: new message to plugins: WINIX_DIR_ADDED git-svn-id: svn://ttmath.org/publicrep/winix/trunk@808 e52654a7-88a9-db11-a3e9-0013d4bc506e
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
* This file is a part of Winix
|
||||
* and is not publicly distributed
|
||||
*
|
||||
* Copyright (c) 2011, Tomasz Sowa
|
||||
* Copyright (c) 2011-2012, Tomasz Sowa
|
||||
* All rights reserved.
|
||||
*
|
||||
*/
|
||||
@@ -12,113 +12,107 @@
|
||||
#include "core/item.h"
|
||||
#include "core/log.h"
|
||||
#include "core/misc.h"
|
||||
#include "cache.h"
|
||||
|
||||
|
||||
// !! temporarily
|
||||
template<class Key1, class Key2, class Value>
|
||||
class Stack
|
||||
{
|
||||
public:
|
||||
|
||||
typedef Key1 StackKey1;
|
||||
typedef Key2 StackKey2;
|
||||
typedef Value StackValue;
|
||||
|
||||
struct Item
|
||||
{
|
||||
StackKey1 key1;
|
||||
StackKey2 key2;
|
||||
StackValue value;
|
||||
};
|
||||
|
||||
|
||||
Stack()
|
||||
{
|
||||
added_new = false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
StackValue * Get(const StackKey1 & key1, const StackKey2 & key2)
|
||||
{
|
||||
for(size_t i=0 ; i<tab.size() ; ++i)
|
||||
{
|
||||
if( tab[i].key1 == key1 && tab[i].key2 == key2 )
|
||||
{
|
||||
added_new = false;
|
||||
return &tab[i].value;
|
||||
}
|
||||
}
|
||||
|
||||
// there is no such an element in our table
|
||||
// so we add a new item
|
||||
tab.push_back(Item());
|
||||
|
||||
tab.back().key1 = key1;
|
||||
tab.back().key2 = key2;
|
||||
added_new = true;
|
||||
|
||||
return &tab.back().value;
|
||||
}
|
||||
|
||||
/*
|
||||
returning true if Get() method has inserted a new Item
|
||||
*/
|
||||
bool AddedNew()
|
||||
{
|
||||
return added_new;
|
||||
}
|
||||
|
||||
|
||||
void Clear()
|
||||
{
|
||||
tab.clear();
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
|
||||
std::vector<Item> tab;
|
||||
bool added_new;
|
||||
};
|
||||
|
||||
|
||||
|
||||
#define WINIX_PL_MENU_PARAM_NONE 0
|
||||
#define WINIX_PL_MENU_PARAM_IMAGES 1
|
||||
#define WINIX_PL_MENU_PARAM_DIRS 2
|
||||
#define WINIX_PL_MENU_PARAM_FILES 3
|
||||
|
||||
|
||||
namespace Menu
|
||||
{
|
||||
|
||||
using namespace TemplatesFunctions;
|
||||
using TemplatesFunctions::system;
|
||||
|
||||
extern int mount_par_menu_skip;
|
||||
extern Cache cache;
|
||||
|
||||
|
||||
static DbItemQuery iq;
|
||||
static std::vector<Item> item_tab;
|
||||
static MenuItem menu_item;
|
||||
|
||||
struct MenuDir
|
||||
|
||||
struct StackItem : public Ezc::FunData
|
||||
{
|
||||
std::vector<Item> items;
|
||||
size_t index;
|
||||
std::wstring dir;
|
||||
CacheItem * citem;
|
||||
|
||||
MenuDir()
|
||||
StackItem(CacheItem * ci)
|
||||
{
|
||||
index = 0;
|
||||
citem = ci;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
static MenuDir * menu_dir = 0;
|
||||
static DbItemQuery iq;
|
||||
static Stack<std::wstring, std::wstring, MenuDir> menu_dir_stack;
|
||||
static size_t req_id = 0;
|
||||
static std::wstring strempty;
|
||||
|
||||
|
||||
// warning: O(n^2) complexity
|
||||
void menu_dir_skip_items(long parent_id)
|
||||
int string_to_param(const std::wstring & param, bool use_log = true)
|
||||
{
|
||||
Mount * m = system->mounts.CalcMount(parent_id);
|
||||
if( param == L"images" )
|
||||
return WINIX_PL_MENU_PARAM_IMAGES;
|
||||
else
|
||||
if( param == L"dirs" )
|
||||
return WINIX_PL_MENU_PARAM_DIRS;
|
||||
else
|
||||
if( param == L"files" )
|
||||
return WINIX_PL_MENU_PARAM_FILES;
|
||||
else
|
||||
if( !param.empty() )
|
||||
{
|
||||
if( use_log )
|
||||
log << log1 << "Menu: unknown parameter: " << param << logend;
|
||||
}
|
||||
|
||||
return WINIX_PL_MENU_PARAM_NONE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void read_from_db(long dir_id, int param)
|
||||
{
|
||||
iq.SetAll(false, false);
|
||||
iq.sel_subject = true;
|
||||
iq.sel_url = true;
|
||||
iq.sel_sort_index = true;
|
||||
iq.sel_type = true;
|
||||
iq.sel_file = true;
|
||||
iq.WhereParentId(dir_id);
|
||||
|
||||
if( param == WINIX_PL_MENU_PARAM_IMAGES )
|
||||
{
|
||||
iq.WhereType(Item::file);
|
||||
iq.WhereFileType(WINIX_ITEM_FILETYPE_IMAGE);
|
||||
}
|
||||
else
|
||||
if( param == WINIX_PL_MENU_PARAM_DIRS )
|
||||
{
|
||||
iq.WhereType(Item::dir);
|
||||
}
|
||||
else
|
||||
if( param == WINIX_PL_MENU_PARAM_FILES )
|
||||
{
|
||||
iq.WhereType(Item::file);
|
||||
}
|
||||
|
||||
db->GetItems(item_tab, iq);
|
||||
log << log4 << "Menu: loaded directories/files from the database for parent_id: "
|
||||
<< dir_id << logend;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// !! IMPROVE ME
|
||||
// O(n^2) complexity
|
||||
void skip_mount_items(CacheItem & citem)
|
||||
{
|
||||
Mount * m = system->mounts.CalcMount(citem.dir_id);
|
||||
|
||||
if( !m || mount_par_menu_skip==-1 || !m->param[mount_par_menu_skip].defined )
|
||||
return;
|
||||
@@ -127,10 +121,10 @@ void menu_dir_skip_items(long parent_id)
|
||||
|
||||
for(size_t i=0 ; i<arg.size() ; ++i)
|
||||
{
|
||||
for(size_t x=0 ; x<menu_dir->items.size() ; )
|
||||
for(size_t x=0 ; x<citem.menu_items.size() ; )
|
||||
{
|
||||
if( menu_dir->items[x].url == arg[i] )
|
||||
menu_dir->items.erase(menu_dir->items.begin() + x);
|
||||
if( citem.menu_items[x].url == arg[i] )
|
||||
citem.menu_items.erase(citem.menu_items.begin() + x);
|
||||
else
|
||||
x += 1;
|
||||
}
|
||||
@@ -138,141 +132,154 @@ void menu_dir_skip_items(long parent_id)
|
||||
}
|
||||
|
||||
|
||||
void menu_dir_skip_static_files()
|
||||
|
||||
|
||||
void skip_static_files(CacheItem & citem)
|
||||
{
|
||||
for(size_t x=0 ; x<menu_dir->items.size() ; )
|
||||
for(size_t x=0 ; x<citem.menu_items.size() ; )
|
||||
{
|
||||
if( menu_dir->items[x].type == Item::file && menu_dir->items[x].file_type != WINIX_ITEM_FILETYPE_NONE )
|
||||
menu_dir->items.erase(menu_dir->items.begin() + x);
|
||||
if( citem.menu_items[x].type == Item::file && citem.menu_items[x].file_type != WINIX_ITEM_FILETYPE_NONE )
|
||||
citem.menu_items.erase(citem.menu_items.begin() + x);
|
||||
else
|
||||
x += 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void menu_dir_load_menu(long parent_id, const std::wstring & arg)
|
||||
void copy_items(CacheItem & citem)
|
||||
{
|
||||
iq.SetAll(false, false);
|
||||
iq.sel_subject = true;
|
||||
iq.sel_url = true;
|
||||
iq.sel_sort_index = true;
|
||||
iq.sel_type = true;
|
||||
iq.sel_file = true;
|
||||
iq.WhereParentId(parent_id);
|
||||
size_t new_size = citem.menu_items.size() + item_tab.size();
|
||||
|
||||
if( arg == L"images" )
|
||||
{
|
||||
iq.WhereType(Item::file);
|
||||
iq.WhereFileType(WINIX_ITEM_FILETYPE_IMAGE);
|
||||
}
|
||||
else
|
||||
if( arg == L"dirs" )
|
||||
{
|
||||
iq.WhereType(Item::dir);
|
||||
}
|
||||
else
|
||||
if( arg == L"files" )
|
||||
{
|
||||
iq.WhereType(Item::file);
|
||||
}
|
||||
else
|
||||
if( arg == L"" )
|
||||
{
|
||||
}
|
||||
else
|
||||
{
|
||||
log << log1 << "Menu: unknown parameter: " << arg << logend;
|
||||
}
|
||||
if( new_size > citem.menu_items.capacity() )
|
||||
citem.menu_items.reserve(new_size);
|
||||
|
||||
for(size_t i=0 ; i < item_tab.size() ; ++i)
|
||||
{
|
||||
menu_item.id = item_tab[i].id;
|
||||
menu_item.subject = item_tab[i].subject;
|
||||
menu_item.url = item_tab[i].url;
|
||||
menu_item.type = item_tab[i].type;
|
||||
menu_item.file_type = item_tab[i].file_type;
|
||||
|
||||
db->GetItems(menu_dir->items, iq);
|
||||
menu_dir_skip_items(parent_id);
|
||||
|
||||
// !! FIXME: in the future is better to have DbItemQuery with a special option
|
||||
// that skips static files
|
||||
if( arg == L"" )
|
||||
menu_dir_skip_static_files();
|
||||
|
||||
// !! temporarily for debug purposes
|
||||
log << log1 << "Menu: db used" << logend;
|
||||
citem.menu_items.push_back(menu_item);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void menu_dir_init(const std::wstring & path, const std::wstring & arg)
|
||||
{
|
||||
menu_dir = menu_dir_stack.Get(path, arg);
|
||||
|
||||
if( menu_dir_stack.AddedNew() )
|
||||
void menu_dir_init(Info & i, long dir_id, int param)
|
||||
{
|
||||
CacheItem * citem = cache.Get(dir_id, param);
|
||||
|
||||
if( !citem )
|
||||
{
|
||||
if( path.empty() )
|
||||
read_from_db(dir_id, param);
|
||||
citem = cache.Insert(dir_id, param);
|
||||
copy_items(*citem);
|
||||
skip_mount_items(*citem);
|
||||
|
||||
if( param == WINIX_PL_MENU_PARAM_NONE )
|
||||
skip_static_files(*citem);
|
||||
}
|
||||
|
||||
i.fun_data = new StackItem(citem);
|
||||
}
|
||||
|
||||
|
||||
void menu_dir_init(Info & i, const std::wstring & dir, int param)
|
||||
{
|
||||
Item * pdir = system->dirs.GetDir(dir);
|
||||
|
||||
if( pdir )
|
||||
{
|
||||
menu_dir_init(i, pdir->id, param);
|
||||
}
|
||||
else
|
||||
{
|
||||
log << log1 << "Menu: there is not such a directory: " << dir << logend;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void menu_dir_init(Info & i)
|
||||
{
|
||||
int param = WINIX_PL_MENU_PARAM_NONE;
|
||||
|
||||
if( i.params.size() >= 2 )
|
||||
param = string_to_param(i.params[1]);
|
||||
|
||||
if( !i.params.empty() )
|
||||
{
|
||||
if( i.params[0] == L"current" )
|
||||
{
|
||||
// current directory
|
||||
menu_dir_load_menu(cur->request->dir_tab.back()->id, arg);
|
||||
system->dirs.MakePath(cur->request->dir_tab, menu_dir->dir);
|
||||
if( i.last_fun_data )
|
||||
{
|
||||
StackItem * previous_sitem = reinterpret_cast<StackItem*>(i.last_fun_data);
|
||||
|
||||
if( i.last_iter < previous_sitem->citem->menu_items.size() )
|
||||
menu_dir_init(i, previous_sitem->citem->menu_items[i.last_iter].id, param);
|
||||
}
|
||||
}
|
||||
else
|
||||
if( !i.params[0].empty() && i.params[0][0] != '/' )
|
||||
{
|
||||
log << log1 << "Menu: path for a menu should not be relative" << logend;
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
menu_dir->dir = path;
|
||||
Item * pdir = system->dirs.GetDir(path);
|
||||
|
||||
if( pdir )
|
||||
menu_dir_load_menu(pdir->id, arg);
|
||||
else
|
||||
log << log1 << "Menu: I cannot find a directory: " << path << logend;
|
||||
menu_dir_init(i, i.params[0], param);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
menu_dir_init(i, cur->request->dir_tab.back()->id, param);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void menu_dir_init(const std::vector<std::wstring> & params)
|
||||
{
|
||||
if( cur->request->id != req_id )
|
||||
{
|
||||
menu_dir_stack.Clear();
|
||||
menu_dir = 0;
|
||||
req_id = cur->request->id;
|
||||
}
|
||||
|
||||
if( !params.empty() && !params[0].empty() && params[0][0] != '/' )
|
||||
{
|
||||
log << log1 << "Menu: path for a menu should not be relative" << logend;
|
||||
return;
|
||||
}
|
||||
|
||||
strempty.clear(); // for safety
|
||||
|
||||
if( params.empty() )
|
||||
menu_dir_init(strempty, strempty);
|
||||
else
|
||||
if( params.size() == 1 )
|
||||
menu_dir_init(params[0], strempty);
|
||||
else
|
||||
menu_dir_init(params[0], params[1]);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void menu_dir_tab(Info & i)
|
||||
{
|
||||
menu_dir_init(i.params);
|
||||
if( !i.fun_data )
|
||||
menu_dir_init(i);
|
||||
|
||||
menu_dir->index = i.iter;
|
||||
i.res = menu_dir->index < menu_dir->items.size();
|
||||
if( i.fun_data )
|
||||
{
|
||||
StackItem * sitem = reinterpret_cast<StackItem*>(i.fun_data);
|
||||
i.res = (i.iter < sitem->citem->menu_items.size());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void menu_dir_tab_subject(Info & i)
|
||||
{
|
||||
if( menu_dir && menu_dir->index < menu_dir->items.size() )
|
||||
i.out << menu_dir->items[menu_dir->index].subject;
|
||||
if( i.fun_data )
|
||||
{
|
||||
StackItem * sitem = reinterpret_cast<StackItem*>(i.fun_data);
|
||||
|
||||
if( i.last_iter < sitem->citem->menu_items.size() )
|
||||
i.out << sitem->citem->menu_items[i.last_iter].subject;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void menu_dir_tab_url(Info & i)
|
||||
{
|
||||
if( menu_dir && menu_dir->index < menu_dir->items.size() )
|
||||
i.out << menu_dir->items[menu_dir->index].url;
|
||||
if( i.fun_data )
|
||||
{
|
||||
StackItem * sitem = reinterpret_cast<StackItem*>(i.fun_data);
|
||||
|
||||
if( i.last_iter < sitem->citem->menu_items.size() )
|
||||
i.out << sitem->citem->menu_items[i.last_iter].url;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -281,14 +288,25 @@ void menu_dir_tab_url(Info & i)
|
||||
|
||||
void menu_dir_tab_link(Info & i)
|
||||
{
|
||||
if( menu_dir && menu_dir->index < menu_dir->items.size() )
|
||||
if( i.fun_data )
|
||||
{
|
||||
i.out << menu_dir->dir;
|
||||
|
||||
if( !IsLastSlash(menu_dir->dir) )
|
||||
i.out << '/';
|
||||
|
||||
i.out << menu_dir->items[menu_dir->index].url;
|
||||
StackItem * sitem = reinterpret_cast<StackItem*>(i.fun_data);
|
||||
|
||||
if( i.last_iter < sitem->citem->menu_items.size() )
|
||||
i.out << sitem->citem->dir << '/'
|
||||
<< sitem->citem->menu_items[i.last_iter].url;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void menu_dir_tab_is_dir(Info & i)
|
||||
{
|
||||
if( i.fun_data )
|
||||
{
|
||||
StackItem * sitem = reinterpret_cast<StackItem*>(i.fun_data);
|
||||
|
||||
if( i.last_iter < sitem->citem->menu_items.size() )
|
||||
i.res = (sitem->citem->menu_items[i.last_iter].type == Item::dir);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -296,9 +314,12 @@ void menu_dir_tab_link(Info & i)
|
||||
|
||||
void menu_dir_tab_is_current(Info & i)
|
||||
{
|
||||
if( menu_dir && menu_dir->index < menu_dir->items.size() )
|
||||
if( i.fun_data )
|
||||
{
|
||||
i.res = (menu_dir->items[menu_dir->index].id == cur->request->last_item->id);
|
||||
StackItem * sitem = reinterpret_cast<StackItem*>(i.fun_data);
|
||||
|
||||
if( i.last_iter < sitem->citem->menu_items.size() )
|
||||
i.res = (sitem->citem->menu_items[i.last_iter].id == cur->request->last_item->id);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -308,8 +329,13 @@ void menu_dir_tab_is_current(Info & i)
|
||||
// returning true if the dir tab element is a first parent for current item
|
||||
void menu_dir_tab_is_first_parent_for_current_item(Info & i)
|
||||
{
|
||||
if( menu_dir && menu_dir->index < menu_dir->items.size() )
|
||||
i.res = (menu_dir->items[menu_dir->index].id == cur->request->last_item->parent_id);
|
||||
if( i.fun_data )
|
||||
{
|
||||
StackItem * sitem = reinterpret_cast<StackItem*>(i.fun_data);
|
||||
|
||||
if( i.last_iter < sitem->citem->menu_items.size() )
|
||||
i.res = (sitem->citem->menu_items[i.last_iter].id == cur->request->last_item->parent_id);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -317,22 +343,27 @@ void menu_dir_tab_is_first_parent_for_current_item(Info & i)
|
||||
// (it don't have to be the first parent - it can be a descendant)
|
||||
void menu_dir_tab_is_parent_for_current_item(Info & i)
|
||||
{
|
||||
if( menu_dir && menu_dir->index < menu_dir->items.size() )
|
||||
if( i.fun_data )
|
||||
{
|
||||
size_t len = cur->request->dir_tab.size(); // at least one
|
||||
StackItem * sitem = reinterpret_cast<StackItem*>(i.fun_data);
|
||||
|
||||
if( !cur->request->is_item )
|
||||
if( i.last_iter < sitem->citem->menu_items.size() )
|
||||
{
|
||||
// the last item is a directory so we don't get it into account
|
||||
len -= 1;
|
||||
}
|
||||
size_t len = cur->request->dir_tab.size(); // at least one
|
||||
|
||||
for(size_t a=0 ; a<len ; ++a)
|
||||
{
|
||||
if( menu_dir->items[menu_dir->index].id == cur->request->dir_tab[a]->id )
|
||||
if( !cur->request->is_item )
|
||||
{
|
||||
i.res = true;
|
||||
break;
|
||||
// the last item is a directory so we don't get it into account
|
||||
len -= 1;
|
||||
}
|
||||
|
||||
for(size_t a=0 ; a<len ; ++a)
|
||||
{
|
||||
if( sitem->citem->menu_items[i.last_iter].id == cur->request->dir_tab[a]->id )
|
||||
{
|
||||
i.res = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -346,11 +377,12 @@ void AddEzcFunctions(PluginInfo & info)
|
||||
using TemplatesFunctions::EzcFun;
|
||||
EzcFun * fun = reinterpret_cast<EzcFun*>(info.p1);
|
||||
|
||||
fun->Insert("menu_dir_tab", menu_dir_tab);
|
||||
fun->Insert("menu_dir_tab_subject", menu_dir_tab_subject);
|
||||
fun->Insert("menu_dir_tab_url", menu_dir_tab_url);
|
||||
fun->Insert("menu_dir_tab_link", menu_dir_tab_link);
|
||||
fun->Insert("menu_dir_tab_is_current", menu_dir_tab_is_current);
|
||||
fun->Insert("menu_dir_tab", menu_dir_tab);
|
||||
fun->Insert("menu_dir_tab_subject", menu_dir_tab_subject);
|
||||
fun->Insert("menu_dir_tab_url", menu_dir_tab_url);
|
||||
fun->Insert("menu_dir_tab_link", menu_dir_tab_link);
|
||||
fun->Insert("menu_dir_tab_is_dir", menu_dir_tab_is_dir);
|
||||
fun->Insert("menu_dir_tab_is_current", menu_dir_tab_is_current);
|
||||
fun->Insert("menu_dir_tab_is_first_parent_for_current_item", menu_dir_tab_is_first_parent_for_current_item);
|
||||
fun->Insert("menu_dir_tab_is_parent_for_current_item", menu_dir_tab_is_parent_for_current_item);
|
||||
}
|
||||
|
Reference in New Issue
Block a user