1 /*
2 * Copyright (C) 2013-2020 Graeme Gott <graeme@gottcode.org>
3 *
4 * This library is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this library. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18 #include "category.h"
19
20 #include "category-button.h"
21 #include "launcher-view.h"
22 #include "util.h"
23
24 #include <algorithm>
25
26 #include <glib/gi18n-lib.h>
27
28 using namespace WhiskerMenu;
29
30 //-----------------------------------------------------------------------------
31
Category(GarconMenu * menu)32 Category::Category(GarconMenu* menu) :
33 m_button(nullptr),
34 m_model(nullptr),
35 m_has_separators(false),
36 m_has_subcategories(false),
37 m_owns_button(true)
38 {
39 const gchar* icon = nullptr;
40 const gchar* text = nullptr;
41 const gchar* tooltip = nullptr;
42 if (menu)
43 {
44 GarconMenuElement* element = GARCON_MENU_ELEMENT(menu);
45 icon = garcon_menu_element_get_icon_name(element);
46 text = garcon_menu_element_get_name(element);
47 tooltip = garcon_menu_element_get_comment(element);
48 }
49 else
50 {
51 text = _("All Applications");
52 }
53 set_icon(!xfce_str_is_empty(icon) ? icon : "applications-other", true);
54 set_text(text ? text : "");
55 set_tooltip(tooltip ? tooltip : "");
56 }
57
58 //-----------------------------------------------------------------------------
59
~Category()60 Category::~Category()
61 {
62 unset_model();
63
64 if (m_owns_button)
65 {
66 delete m_button;
67 }
68
69 for (auto element : m_items)
70 {
71 if (Category* category = dynamic_cast<Category*>(element))
72 {
73 delete category;
74 }
75 }
76 }
77
78 //-----------------------------------------------------------------------------
79
get_button()80 CategoryButton* Category::get_button()
81 {
82 if (!m_button)
83 {
84 m_button = new CategoryButton(get_icon(), get_text());
85 }
86
87 return m_button;
88 }
89
90 //-----------------------------------------------------------------------------
91
get_model()92 GtkTreeModel* Category::get_model()
93 {
94 if (!m_model)
95 {
96 if (m_has_subcategories)
97 {
98 GtkTreeStore* model = gtk_tree_store_new(
99 LauncherView::N_COLUMNS,
100 G_TYPE_ICON,
101 G_TYPE_STRING,
102 G_TYPE_STRING,
103 G_TYPE_POINTER);
104 insert_items(model, nullptr);
105 m_model = GTK_TREE_MODEL(model);
106 }
107 else
108 {
109 GtkListStore* model = gtk_list_store_new(
110 LauncherView::N_COLUMNS,
111 G_TYPE_ICON,
112 G_TYPE_STRING,
113 G_TYPE_STRING,
114 G_TYPE_POINTER);
115 insert_items(model);
116 m_model = GTK_TREE_MODEL(model);
117 }
118 }
119
120 return m_model;
121 }
122
123 //-----------------------------------------------------------------------------
124
append_separator()125 void Category::append_separator()
126 {
127 if (!m_items.empty() && m_items.back())
128 {
129 unset_model();
130 m_items.push_back(nullptr);
131 m_has_separators = true;
132 }
133 }
134
135 //-----------------------------------------------------------------------------
136
set_button(CategoryButton * button)137 void Category::set_button(CategoryButton* button)
138 {
139 if (m_owns_button)
140 {
141 delete m_button;
142 }
143
144 m_owns_button = false;
145
146 m_button = button;
147 }
148
149 //-----------------------------------------------------------------------------
150
sort()151 void Category::sort()
152 {
153 unset_model();
154 std::sort(m_items.begin(), m_items.end(), &Element::less_than);
155 }
156
157 //-----------------------------------------------------------------------------
158
insert_items(GtkTreeStore * model,GtkTreeIter * parent)159 void Category::insert_items(GtkTreeStore* model, GtkTreeIter* parent)
160 {
161 if (!m_items.empty() && !m_items.back())
162 {
163 m_items.pop_back();
164 }
165
166 for (auto element : m_items)
167 {
168 if (Category* category = dynamic_cast<Category*>(element))
169 {
170 gchar* text = g_markup_escape_text(category->get_text(), -1);
171 const gchar* tooltip = category->get_tooltip();
172
173 GtkTreeIter iter;
174 gtk_tree_store_insert_with_values(model,
175 &iter, parent, G_MAXINT,
176 LauncherView::COLUMN_ICON, category->get_icon(),
177 LauncherView::COLUMN_TEXT, text,
178 LauncherView::COLUMN_TOOLTIP, tooltip,
179 LauncherView::COLUMN_LAUNCHER, nullptr,
180 -1);
181 g_free(text);
182 category->insert_items(model, &iter);
183 }
184 else if (Launcher* launcher = dynamic_cast<Launcher*>(element))
185 {
186 gtk_tree_store_insert_with_values(model,
187 nullptr, parent, G_MAXINT,
188 LauncherView::COLUMN_ICON, launcher->get_icon(),
189 LauncherView::COLUMN_TEXT, launcher->get_text(),
190 LauncherView::COLUMN_TOOLTIP, launcher->get_tooltip(),
191 LauncherView::COLUMN_LAUNCHER, launcher,
192 -1);
193 }
194 else
195 {
196 gtk_tree_store_insert_with_values(model,
197 nullptr, parent, G_MAXINT,
198 LauncherView::COLUMN_ICON, nullptr,
199 LauncherView::COLUMN_TEXT, nullptr,
200 LauncherView::COLUMN_TOOLTIP, nullptr,
201 LauncherView::COLUMN_LAUNCHER, nullptr,
202 -1);
203 }
204 }
205 }
206
207 //-----------------------------------------------------------------------------
208
insert_items(GtkListStore * model)209 void Category::insert_items(GtkListStore* model)
210 {
211 if (!m_items.empty() && !m_items.back())
212 {
213 m_items.pop_back();
214 }
215
216 for (auto element : m_items)
217 {
218 if (Launcher* launcher = dynamic_cast<Launcher*>(element))
219 {
220 gtk_list_store_insert_with_values(model,
221 nullptr, G_MAXINT,
222 LauncherView::COLUMN_ICON, launcher->get_icon(),
223 LauncherView::COLUMN_TEXT, launcher->get_text(),
224 LauncherView::COLUMN_TOOLTIP, launcher->get_tooltip(),
225 LauncherView::COLUMN_LAUNCHER, launcher,
226 -1);
227 }
228 else
229 {
230 gtk_list_store_insert_with_values(model,
231 nullptr, G_MAXINT,
232 LauncherView::COLUMN_ICON, nullptr,
233 LauncherView::COLUMN_TEXT, nullptr,
234 LauncherView::COLUMN_TOOLTIP, nullptr,
235 LauncherView::COLUMN_LAUNCHER, nullptr,
236 -1);
237 }
238 }
239 }
240
241 //-----------------------------------------------------------------------------
242
unset_model()243 void Category::unset_model()
244 {
245 if (m_model)
246 {
247 g_object_unref(m_model);
248 m_model = nullptr;
249 }
250 }
251
252 //-----------------------------------------------------------------------------
253