removed factory registration code from ApplicationItemFactory (it was moved to BasicI...
[simple-launcher] / settings-page-items.cc
1 // This file is a part of Simple Launcher
2 //
3 // Copyright (C) 2006, 2007, Mikhail Sobolev
4 //
5 // Simple Launcher is free software; you can redistribute it and/or modify it
6 // under the terms of the GNU General Public License version 2 as published by
7 // the Free Software Foundation.
8 //
9 // This program is distributed in the hope that it will be useful, but WITHOUT
10 // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
12 // more details.
13 //
14 // You should have received a copy of the GNU General Public License along with
15 // this program; if not, write to the Free Software Foundation, Inc., 51
16 // Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
17
18 #include <gtk/gtkscrolledwindow.h>
19 #include <gtk/gtkcellrendererpixbuf.h>
20 #include <gtk/gtkcellrenderertext.h>
21 #include <gtk/gtkcellrenderertoggle.h>
22 #include <gtk/gtktable.h>
23 #include <gtk/gtkbutton.h>
24 #include <gtk/gtktreeselection.h>
25 #include <gtk/gtkhbox.h>
26 #include <gtk/gtkstock.h>
27
28 #include "settings-page-items.h"
29
30 enum {
31   SLA_STORE_COLUMN_ICON = 0,
32   SLA_STORE_COLUMN_INDEX,
33   SLA_STORE_COLUMN_LAST
34 };
35
36 static GtkWidget *gtk_button_new_stock_image_only(const gchar *stock_id) {
37   GtkWidget *button = gtk_button_new();
38   GtkWidget *image = gtk_image_new_from_stock(stock_id, GTK_ICON_SIZE_BUTTON);
39
40   gtk_container_add(GTK_CONTAINER(button), image);
41
42   return button;
43 }
44
45 SettingsPageWithItems::SettingsPageWithItems(int icon_size, LauncherItems& items): myWidget(NULL), myStore(NULL), myView(NULL), mySelection(NULL), myLastSelection(NULL), myItems(items) {
46   GtkTreeViewColumn *column;
47   GtkCellRenderer *renderer;
48
49   myStore = gtk_list_store_new(2, GDK_TYPE_PIXBUF, G_TYPE_INT);
50
51   myView = GTK_TREE_VIEW(gtk_tree_view_new_with_model(GTK_TREE_MODEL(myStore)));
52   gtk_tree_view_set_headers_visible(myView, FALSE);
53   g_object_set(myView, "allow-checkbox-mode", FALSE, NULL);
54
55   mySelection = gtk_tree_view_get_selection(myView);
56   gtk_tree_selection_set_mode(mySelection, GTK_SELECTION_SINGLE);
57
58   g_signal_connect(G_OBJECT(mySelection), "changed", G_CALLBACK(_selectionChanged), this);
59
60   renderer = gtk_cell_renderer_pixbuf_new();
61   g_object_set(renderer, "yalign", 0.0, NULL);
62   gtk_cell_renderer_set_fixed_size(renderer, icon_size+4, -1);
63   column = GTK_TREE_VIEW_COLUMN(gtk_tree_view_column_new_with_attributes("", renderer, "pixbuf", 0, NULL));
64
65   gtk_tree_view_insert_column(myView, column, -1);
66
67   renderer = gtk_cell_renderer_text_new();
68   g_object_set(renderer, "yalign", 0.0, NULL);
69   column = gtk_tree_view_column_new();
70   gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
71   gtk_tree_view_column_set_expand(column, TRUE);
72   gtk_tree_view_column_pack_start(column, renderer, TRUE);
73   gtk_tree_view_column_set_cell_data_func(column, renderer, _renderText, this, NULL);
74
75   gtk_tree_view_insert_column(myView, column, -1);
76
77   renderer = gtk_cell_renderer_toggle_new();
78   g_object_set(renderer, "activatable", TRUE, NULL);
79   g_signal_connect(renderer, "toggled", G_CALLBACK(_toggleBool), this);
80   column = gtk_tree_view_column_new();
81   gtk_tree_view_column_pack_start(column, renderer, TRUE);
82   gtk_tree_view_column_set_cell_data_func(column, renderer, _renderBool, this, NULL);
83
84   gtk_tree_view_insert_column(myView, column, -1);
85
86   GtkWidget *swindow = gtk_scrolled_window_new(NULL, NULL);
87
88   gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(swindow), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
89   gtk_container_add(GTK_CONTAINER(swindow), GTK_WIDGET(myView));
90
91   GtkWidget *move_up = gtk_button_new_stock_image_only(GTK_STOCK_GO_UP),
92             *move_down = gtk_button_new_stock_image_only(GTK_STOCK_GO_DOWN);
93   GtkTable *table = GTK_TABLE(gtk_table_new(4, 1, FALSE));
94   gtk_table_attach(table, move_up, 0, 1, 1, 2, (GtkAttachOptions)(GTK_EXPAND|GTK_FILL), GTK_EXPAND, 0, 0);
95   gtk_table_attach(table, move_down, 0, 1, 2, 3, (GtkAttachOptions)(GTK_EXPAND|GTK_FILL), GTK_EXPAND, 0, 0);
96
97   g_signal_connect(move_up, "clicked", G_CALLBACK(_moveUp), this);
98   g_signal_connect(move_down, "clicked", G_CALLBACK(_moveDown), this);
99
100   myWidget = gtk_hbox_new(FALSE, 0);
101   gtk_box_pack_start(GTK_BOX(myWidget), swindow, TRUE, TRUE, 0);
102   gtk_box_pack_start(GTK_BOX(myWidget), GTK_WIDGET(table), FALSE, FALSE, 0);
103
104   gtk_widget_show_all(myWidget);
105
106   for (LauncherItems::Names::const_iterator it = myItems.myNames.begin(); it != myItems.myNames.end(); ++it) {
107     LauncherItem *item = myItems.myItems[*it];
108
109     if (item->checkSanity()) {
110       GtkTreeIter iter;
111
112       gtk_list_store_append(myStore, &iter);
113       {
114         GdkPixbuf *icon = item->getIcon(icon_size);
115         gtk_list_store_set(myStore, &iter, SLA_STORE_COLUMN_ICON, icon, SLA_STORE_COLUMN_INDEX, it-myItems.myNames.begin(), -1);
116         g_object_unref(G_OBJECT(icon));
117       }
118     }
119   }
120 }
121
122 SettingsPageWithItems::~SettingsPageWithItems() {
123   if (myLastSelection != NULL) {
124     gtk_tree_iter_free(myLastSelection);
125     myLastSelection = NULL;
126   }
127
128   g_object_unref(G_OBJECT(myStore));
129 }
130
131 void SettingsPageWithItems::_selectionChanged(GtkTreeSelection *selection, void *self) {
132   ((SettingsPageWithItems *)self)->selectionChanged(selection);
133 }
134
135 void SettingsPageWithItems::selectionChanged(GtkTreeSelection *) {
136   if (myLastSelection != NULL) {
137     kickIt(myLastSelection);
138     gtk_tree_iter_free(myLastSelection);
139     myLastSelection = NULL;
140   }
141
142   GtkTreeIter iter;
143   GtkTreeModel *dummy;
144
145   if (gtk_tree_selection_get_selected(mySelection, &dummy, &iter)) {
146     kickIt(&iter);
147     myLastSelection = gtk_tree_iter_copy(&iter);
148   }
149 }
150
151 void SettingsPageWithItems::kickIt(GtkTreeIter *iter) {
152   GtkTreePath *path = gtk_tree_model_get_path(GTK_TREE_MODEL(myStore), iter);
153
154   if (path != NULL) {
155     g_signal_emit_by_name(myStore, "row-changed", path, iter);
156     gtk_tree_path_free(path);
157   }
158 }
159
160 void SettingsPageWithItems::_renderText(GtkTreeViewColumn *column, GtkCellRenderer *cell, GtkTreeModel *model, GtkTreeIter *iter, gpointer self) {
161   ((SettingsPageWithItems *)self)->renderText(column, cell, model, iter);
162 }
163
164 void SettingsPageWithItems::_renderBool(GtkTreeViewColumn *column, GtkCellRenderer *cell, GtkTreeModel *model, GtkTreeIter *iter, gpointer self) {
165   ((SettingsPageWithItems *)self)->renderBool(column, cell, model, iter);
166 }
167
168 void SettingsPageWithItems::_toggleBool(GtkCellRendererToggle *renderer, const gchar *path, void *self) {
169   ((SettingsPageWithItems *)self)->toggleBool(renderer, path);
170 }
171
172 void SettingsPageWithItems::_moveUp(GtkButton *button, void *self) {
173   ((SettingsPageWithItems *)self)->moveUp(button);
174 }
175
176 void SettingsPageWithItems::_moveDown(GtkButton *button, void *self) {
177   ((SettingsPageWithItems *)self)->moveDown(button);
178 }
179
180 void SettingsPageWithItems::renderText(GtkTreeViewColumn *, GtkCellRenderer *cell, GtkTreeModel *model, GtkTreeIter *iter) {
181   int index;
182
183   gtk_tree_model_get(GTK_TREE_MODEL(myStore), iter, SLA_STORE_COLUMN_INDEX, &index, -1);
184
185   LauncherItem *item = myItems[index];
186
187   if (gtk_tree_selection_iter_is_selected(mySelection, iter)) {
188     gchar *text = g_markup_printf_escaped("%s\n<small>%s</small>", item->getName().c_str(), item->getComment().c_str());
189     g_object_set(cell, "markup", text, NULL);
190     g_free(text);
191   } else {
192     g_object_set(cell, "text", item->getName().c_str(), NULL);
193   }
194 }
195
196 void SettingsPageWithItems::renderBool(GtkTreeViewColumn *, GtkCellRenderer *cell, GtkTreeModel *model, GtkTreeIter *iter) {
197   int index;
198
199   gtk_tree_model_get(GTK_TREE_MODEL(myStore), iter, SLA_STORE_COLUMN_INDEX, &index, -1);
200
201   g_object_set(cell, "active", myItems[index]->isEnabled(), NULL);
202 }
203
204 void SettingsPageWithItems::toggleBool(GtkCellRendererToggle *renderer, const gchar *spath) {
205   GtkTreeIter iter;
206
207   if (gtk_tree_model_get_iter_from_string(GTK_TREE_MODEL(myStore), &iter, spath)) {
208     int index;
209
210     gtk_tree_model_get(GTK_TREE_MODEL(myStore), &iter, SLA_STORE_COLUMN_INDEX, &index, -1);
211     myItems[index]->toggle();
212   }
213 }
214
215 void SettingsPageWithItems::moveUp(GtkButton *) {
216   GtkTreeModel *dummy;
217   GtkTreeIter current;
218
219   if (gtk_tree_selection_get_selected(mySelection, &dummy, &current)) {
220     GtkTreePath *path = gtk_tree_model_get_path(GTK_TREE_MODEL(myStore), &current);
221
222     // FIXME: we kinda expexted path to be non-NULL here :)
223     if (gtk_tree_path_prev(path)) {
224       GtkTreeIter next;
225
226       if (gtk_tree_model_get_iter(GTK_TREE_MODEL(myStore), &next, path)) {
227         swap(current, next);
228       }
229     }
230
231     gtk_tree_path_free(path);
232   }
233 }
234
235 void SettingsPageWithItems::moveDown(GtkButton *) {
236   GtkTreeModel *dummy;
237   GtkTreeIter current;
238
239   if (gtk_tree_selection_get_selected(mySelection, &dummy, &current)) {
240     GtkTreePath *path = gtk_tree_model_get_path(GTK_TREE_MODEL(myStore), &current);
241     GtkTreeIter next;
242
243     // FIXME: we kinda expexted path to be non-NULL here :)
244     gtk_tree_path_next(path);
245
246     if (gtk_tree_model_get_iter(GTK_TREE_MODEL(myStore), &next, path)) {
247       swap(current, next);
248     }
249
250     gtk_tree_path_free(path);
251   }
252 }
253
254 void SettingsPageWithItems::swap(GtkTreeIter& a, GtkTreeIter& b) {
255   int i1, i2;
256
257   gtk_tree_model_get(GTK_TREE_MODEL(myStore), &a, SLA_STORE_COLUMN_INDEX, &i1, -1);
258   gtk_tree_model_get(GTK_TREE_MODEL(myStore), &b, SLA_STORE_COLUMN_INDEX, &i2, -1);
259
260   myItems.swap(i1, i2);
261
262   gtk_list_store_set(myStore, &a, SLA_STORE_COLUMN_INDEX, i2, -1);
263   gtk_list_store_set(myStore, &b, SLA_STORE_COLUMN_INDEX, i1, -1);
264
265   gtk_list_store_swap(myStore, &a, &b);
266 }
267
268 // vim:ts=2:sw=2:et