/* * Copyright (C) 2013 Graeme Gott * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . */ #include "category.h" #include "launcher-view.h" #include "section-button.h" #include #include using namespace WhiskerMenu; //----------------------------------------------------------------------------- static bool is_category(const Element* element) { return element && (element->get_type() == Category::Type); } static bool is_null(const Element* element) { return !element; } //----------------------------------------------------------------------------- Category::Category(GarconMenuDirectory* directory) : m_button(NULL), m_model(NULL), m_has_separators(false), m_has_subcategories(false) { const gchar* icon = NULL; const gchar* text = NULL; if (directory) { icon = garcon_menu_directory_get_icon_name(directory); text = garcon_menu_directory_get_name(directory); } else { icon = "applications-other"; text = _("All"); } set_icon(icon ? icon : ""); set_text(text ? text : ""); } //----------------------------------------------------------------------------- Category::~Category() { unset_model(); delete m_button; for (std::vector::const_iterator i = m_items.begin(), end = m_items.end(); i != end; ++i) { if (is_category(*i)) { delete *i; } } } //----------------------------------------------------------------------------- SectionButton* Category::get_button() { if (!m_button) { m_button = new SectionButton(get_icon(), get_text()); } return m_button; } //----------------------------------------------------------------------------- GtkTreeModel* Category::get_model() { if (!m_model) { if (m_has_subcategories) { GtkTreeStore* model = gtk_tree_store_new( LauncherView::N_COLUMNS, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_POINTER); insert_items(model, NULL, get_icon()); m_model = GTK_TREE_MODEL(model); } else { GtkListStore* model = gtk_list_store_new( LauncherView::N_COLUMNS, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_POINTER); insert_items(model); m_model = GTK_TREE_MODEL(model); } } return m_model; } //----------------------------------------------------------------------------- bool Category::empty() const { for (std::vector::const_iterator i = m_items.begin(), end = m_items.end(); i != end; ++i) { if (*i && (!is_category(*i) || !static_cast(*i)->empty())) { return false; } } return true; } //----------------------------------------------------------------------------- Category* Category::append_menu(GarconMenuDirectory* directory) { m_has_subcategories = true; unset_model(); Category* category = new Category(directory); m_items.push_back(category); return category; } //----------------------------------------------------------------------------- void Category::append_separator() { if (!m_items.empty() && m_items.back()) { unset_model(); m_items.push_back(NULL); m_has_separators = true; } } //----------------------------------------------------------------------------- void Category::sort() { unset_model(); merge(); if (m_has_separators) { m_items.erase(std::remove_if(m_items.begin(), m_items.end(), is_null), m_items.end()); } std::sort(m_items.begin(), m_items.end(), &Element::less_than); } //----------------------------------------------------------------------------- void Category::insert_items(GtkTreeStore* model, GtkTreeIter* parent, const gchar* fallback_icon) { for (std::vector::size_type i = 0, end = m_items.size(); i < end; ++i) { Element* element = m_items.at(i); if (is_category(element)) { Category* category = static_cast(element); if (category->empty()) { continue; } const gchar* icon = category->get_icon(); if (!gtk_icon_theme_has_icon(gtk_icon_theme_get_default(), icon)) { icon = fallback_icon; } gchar* text = g_markup_escape_text(category->get_text(), -1); GtkTreeIter iter; gtk_tree_store_insert_with_values(model, &iter, parent, INT_MAX, LauncherView::COLUMN_ICON, icon, LauncherView::COLUMN_TEXT, text, LauncherView::COLUMN_LAUNCHER, NULL, -1); g_free(text); category->insert_items(model, &iter, icon); } else if (element) { Launcher* launcher = static_cast(element); gtk_tree_store_insert_with_values(model, NULL, parent, INT_MAX, LauncherView::COLUMN_ICON, launcher->get_icon(), LauncherView::COLUMN_TEXT, launcher->get_text(), LauncherView::COLUMN_LAUNCHER, launcher, -1); } else if ((i + 1) < end) { gtk_tree_store_insert_with_values(model, NULL, parent, INT_MAX, LauncherView::COLUMN_ICON, NULL, LauncherView::COLUMN_TEXT, NULL, LauncherView::COLUMN_LAUNCHER, NULL, -1); } } } //----------------------------------------------------------------------------- void Category::insert_items(GtkListStore* model) { for (std::vector::size_type i = 0, end = m_items.size(); i < end; ++i) { Element* element = m_items.at(i); if (element) { Launcher* launcher = static_cast(element); gtk_list_store_insert_with_values(model, NULL, INT_MAX, LauncherView::COLUMN_ICON, launcher->get_icon(), LauncherView::COLUMN_TEXT, launcher->get_text(), LauncherView::COLUMN_LAUNCHER, launcher, -1); } else if ((i + 1) < end) { gtk_list_store_insert_with_values(model, NULL, INT_MAX, LauncherView::COLUMN_ICON, NULL, LauncherView::COLUMN_TEXT, NULL, LauncherView::COLUMN_LAUNCHER, NULL, -1); } } } //----------------------------------------------------------------------------- void Category::merge() { if (!m_has_subcategories) { return; } // Find direct subcategories std::vector categories; for (std::vector::const_iterator i = m_items.begin(), end = m_items.end(); i != end; ++i) { if (is_category(*i)) { categories.push_back(static_cast(*i)); } } std::vector::size_type last_direct = categories.size(); // Recursively find subcategories std::vector::size_type count = m_items.size(); for (std::vector::size_type i = 0; i < categories.size(); ++i) { Category* category = categories.at(i); count += category->m_items.size(); for (std::vector::const_iterator j = category->m_items.begin(), end = category->m_items.end(); j != end; ++j) { if (is_category(*j)) { categories.push_back(static_cast(*j)); } } } // Append items m_items.reserve(count); for (std::vector::const_iterator i = categories.begin(), end = categories.end(); i != end; ++i) { m_items.insert(m_items.end(), (*i)->m_items.begin(), (*i)->m_items.end()); } // Remove subcategories for (std::vector::iterator i = m_items.begin(), end = m_items.end(); i != end; ++i) { if (is_category(*i)) { *i = NULL; } } // Delete direct subcategories; they will recursively delete their subcategories for (std::vector::size_type i = 0; i < last_direct; ++i) { delete categories.at(i); } m_has_subcategories = false; m_has_separators = true; } //----------------------------------------------------------------------------- void Category::unset_model() { if (m_model) { g_object_unref(m_model); m_model = NULL; } } //-----------------------------------------------------------------------------