/* * This file is a part of Winix * and is distributed under the 2-Clause BSD licence. * Author: Tomasz Sowa */ /* * 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_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 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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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 ; acitem->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(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