winix/plugins/menu/templates.cpp

568 lines
13 KiB
C++
Executable File

/*
* This file is a part of Winix
* and is distributed under the 2-Clause BSD licence.
* Author: Tomasz Sowa <t.sowa@ttmath.org>
*/
/*
* Copyright (c) 2011-2014, Tomasz Sowa
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "templates/templates.h"
#include "core/plugin.h"
#include "core/item.h"
#include "core/log.h"
#include "core/misc.h"
#include "cache.h"
#include "templates/miscspace.h"
namespace Winix
{
#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 Ezc::Stack * stack = &empty_stack;
static DbItemQuery iq;
static std::vector<Item> item_tab;
static MenuItem menu_item;
struct StackItem : public Ezc::FunData
{
CacheItem * citem;
StackItem(CacheItem * ci)
{
citem = ci;
}
};
int string_to_param(const std::wstring & param, bool use_log = true)
{
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, bool with_meta)
{
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.sel_meta = with_meta;
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;
const Mount::ParamRow::ParamArg & arg = m->param[mount_par_menu_skip].arg;
for(size_t i=0 ; i<arg.size() ; ++i)
{
for(size_t x=0 ; x<citem.menu_items.size() ; )
{
if( citem.menu_items[x].url == arg[i] )
citem.menu_items.erase(citem.menu_items.begin() + x);
else
x += 1;
}
}
}
void skip_static_files(CacheItem & citem)
{
for(size_t x=0 ; x<citem.menu_items.size() ; )
{
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 copy_items(CacheItem & citem)
{
size_t new_size = citem.menu_items.size() + item_tab.size();
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.meta = item_tab[i].meta;
menu_item.type = item_tab[i].type;
menu_item.file_type = item_tab[i].file_type;
citem.menu_items.push_back(menu_item);
}
}
void menu_dir_init(Info & i, long dir_id, int param, bool with_meta)
{
CacheItem * citem = cache.Get(dir_id, param);
if( !citem )
{
read_from_db(dir_id, param, with_meta);
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.stack.fun_data = new StackItem(citem);
}
void menu_dir_init(Info & i, const std::wstring & dir, int param, bool with_meta)
{
Item * pdir = system->dirs.GetDir(dir);
if( pdir )
{
menu_dir_init(i, pdir->id, param, with_meta);
}
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;
bool with_meta = false;
if( i.params.size() >= 2 )
param = string_to_param(i.params[1]);
if( i.params.size() >=3 && i.params[2] == L"withmeta" )
with_meta = true;
if( i.params.empty() || i.params[0].empty() )
{
menu_dir_init(i, cur->request->dir_tab.back()->id, param, with_meta);
}
else
if( !i.params.empty() )
{
if( i.params[0] == L"current" )
{
if( stack->fun_data )
{
StackItem * previous_sitem = reinterpret_cast<StackItem*>(stack->fun_data);
if( stack->iter < previous_sitem->citem->menu_items.size() )
menu_dir_init(i, previous_sitem->citem->menu_items[stack->iter].id, param, with_meta);
}
}
else
if( i.params[0] == L"this" )
{
menu_dir_init(i, cur->request->dir_tab.back()->id, param, with_meta);
}
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_init(i, i.params[0], param, with_meta);
}
}
}
void menu_dir_tab(Info & i)
{
if( !i.stack.fun_data )
menu_dir_init(i);
if( i.stack.fun_data )
{
StackItem * sitem = reinterpret_cast<StackItem*>(i.stack.fun_data);
i.res = (i.stack.iter < sitem->citem->menu_items.size());
}
//
// we have 'current' items so we should remember the stack only from [for] statements
// this allows:
// [for menu_dir_tab "/path"]
// [if menu_dir_tab "current"] (here do not remember the stack)
// [for menu_dir_tab "current"]
// work correctly
// [end]
// [end]
// [end]
//
if( i.is_for )
stack = &i.stack;
}
void menu_dir_tab_index(Info & i)
{
i.out << stack->iter;
}
void menu_dir_tab_subject(Info & i)
{
if( stack->fun_data )
{
StackItem * sitem = reinterpret_cast<StackItem*>(stack->fun_data);
if( stack->iter < sitem->citem->menu_items.size() )
i.out << sitem->citem->menu_items[stack->iter].subject;
}
}
void menu_dir_tab_url(Info & i)
{
if( stack->fun_data )
{
StackItem * sitem = reinterpret_cast<StackItem*>(stack->fun_data);
if( stack->iter < sitem->citem->menu_items.size() )
i.out << sitem->citem->menu_items[stack->iter].url;
}
}
void menu_dir_tab_link(Info & i)
{
if( stack->fun_data )
{
StackItem * sitem = reinterpret_cast<StackItem*>(stack->fun_data);
if( stack->iter < sitem->citem->menu_items.size() )
i.out << sitem->citem->dir << '/'
<< sitem->citem->menu_items[stack->iter].url;
}
}
void menu_dir_tab_meta_str(Info & i)
{
if( stack->fun_data )
{
StackItem * sitem = reinterpret_cast<StackItem*>(stack->fun_data);
if( stack->iter < sitem->citem->menu_items.size() )
sitem->citem->menu_items[stack->iter].meta.Serialize(i.out, true, false);
}
}
void menu_dir_tab_meta(Info & i)
{
if( stack->fun_data )
{
StackItem * sitem = reinterpret_cast<StackItem*>(stack->fun_data);
if( stack->iter < sitem->citem->menu_items.size() )
space(i, sitem->citem->menu_items[stack->iter].meta);
}
}
void menu_dir_tab_meta_tab(Info & i)
{
if( stack->fun_data )
{
StackItem * sitem = reinterpret_cast<StackItem*>(stack->fun_data);
if( stack->iter < sitem->citem->menu_items.size() )
spaces_tab(i, sitem->citem->menu_items[stack->iter].meta);
}
}
void menu_dir_tab_meta_tab_value(Info & i)
{
if( stack->fun_data )
{
StackItem * sitem = reinterpret_cast<StackItem*>(stack->fun_data);
if( stack->iter < sitem->citem->menu_items.size() )
spaces_tab_value(i, sitem->citem->menu_items[stack->iter].meta);
}
}
void menu_dir_tab_meta_tab_has_next(Info & i)
{
if( stack->fun_data )
{
StackItem * sitem = reinterpret_cast<StackItem*>(stack->fun_data);
if( stack->iter < sitem->citem->menu_items.size() )
spaces_tab_has_next(i, sitem->citem->menu_items[stack->iter].meta);
}
}
void menu_dir_tab_is_dir(Info & i)
{
if( stack->fun_data )
{
StackItem * sitem = reinterpret_cast<StackItem*>(stack->fun_data);
if( stack->iter < sitem->citem->menu_items.size() )
i.res = (sitem->citem->menu_items[stack->iter].type == Item::dir);
}
}
void menu_dir_tab_is_file(Info & i)
{
if( stack->fun_data )
{
StackItem * sitem = reinterpret_cast<StackItem*>(stack->fun_data);
if( stack->iter < sitem->citem->menu_items.size() )
i.res = (sitem->citem->menu_items[stack->iter].type == Item::file);
}
}
void menu_dir_tab_is_symlink(Info & i)
{
if( stack->fun_data )
{
StackItem * sitem = reinterpret_cast<StackItem*>(stack->fun_data);
if( stack->iter < sitem->citem->menu_items.size() )
i.res = (sitem->citem->menu_items[stack->iter].type == Item::symlink);
}
}
void menu_dir_tab_is_current(Info & i)
{
if( stack->fun_data )
{
StackItem * sitem = reinterpret_cast<StackItem*>(stack->fun_data);
if( stack->iter < sitem->citem->menu_items.size() )
i.res = (sitem->citem->menu_items[stack->iter].id == cur->request->last_item->id);
}
}
void menu_dir_tab_is_current_the_same_dir(Info & i)
{
if( stack->fun_data )
{
StackItem * sitem = reinterpret_cast<StackItem*>(stack->fun_data);
if( stack->iter < sitem->citem->menu_items.size() )
i.res = (sitem->citem->menu_items[stack->iter].id == cur->request->dir_tab.back()->id);
}
}
// 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( stack->fun_data )
{
StackItem * sitem = reinterpret_cast<StackItem*>(stack->fun_data);
if( stack->iter < sitem->citem->menu_items.size() )
i.res = (sitem->citem->menu_items[stack->iter].id == cur->request->last_item->parent_id);
}
}
// returning true if the dir tab element is a parent for current item
// (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( stack->fun_data )
{
StackItem * sitem = reinterpret_cast<StackItem*>(stack->fun_data);
if( stack->iter < sitem->citem->menu_items.size() )
{
size_t len = cur->request->dir_tab.size(); // at least one
if( !cur->request->is_item )
{
// 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[stack->iter].id == cur->request->dir_tab[a]->id )
{
i.res = true;
break;
}
}
}
}
}
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_index", menu_dir_tab_index);
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_meta_str", menu_dir_tab_meta_str);
fun->Insert("menu_dir_tab_meta", menu_dir_tab_meta);
fun->Insert("menu_dir_tab_meta_tab", menu_dir_tab_meta_tab);
fun->Insert("menu_dir_tab_meta_tab_value", menu_dir_tab_meta_tab_value);
fun->Insert("menu_dir_tab_meta_tab_has_next", menu_dir_tab_meta_tab_has_next);
fun->Insert("menu_dir_tab_is_dir", menu_dir_tab_is_dir);
fun->Insert("menu_dir_tab_is_file", menu_dir_tab_is_file);
fun->Insert("menu_dir_tab_is_symlink", menu_dir_tab_is_symlink);
fun->Insert("menu_dir_tab_is_current", menu_dir_tab_is_current);
fun->Insert("menu_dir_tab_is_current_the_same_dir", menu_dir_tab_is_current_the_same_dir);
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);
}
} // namespace
} // namespace Winix