Fix typo: Similar Artist -> Similar Artists
[gmpc.git] / src / GUI / cmd.c
blobb165a4c9f90a2042720b78ca406817cf75380f23
1 /* Gnome Music Player Client (GMPC)
2 * Copyright (C) 2004-2012 Qball Cow <qball@gmpclient.org>
3 * Project homepage: http://gmpclient.org/
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 #include <gtk/gtk.h>
21 #include <glib/gstdio.h>
22 #include "playlist3.h"
23 #include "main.h"
24 #include "cmd.h"
27 #define LOG_DOMAIN "GUI.cmd"
28 /**
29 * Easy command interface
32 /* icon release */
33 void show_command_line_icon_release(
34 GtkWidget *entry,
35 GtkEntryIconPosition pos,
36 GdkEvent *event,
37 gpointer data)
40 /* The clear icon */
41 if ( pos == GTK_ENTRY_ICON_SECONDARY )
43 /* clear and hide */
44 gtk_widget_hide(entry);
45 gtk_entry_set_text(GTK_ENTRY(entry), "");
47 /* Primary */
48 else if ( pos == GTK_ENTRY_ICON_PRIMARY )
50 /* open the help window */
51 gmpc_easy_command_help_window(gmpc_easy_command, NULL);
57 /* List<string> history */
58 static GList *history = NULL;
60 /* weak List<string> current */
61 static GList *current = NULL;
62 static GList *last = NULL;
63 static gint history_length = 0;
64 static gchar *entry_current = NULL;
66 static void show_command_line_history_destroy(void)
68 gchar *path = gmpc_get_user_path("cmd-history.txt");
69 /* Store results */
70 FILE *fp = g_fopen(path,"w");
71 if(fp != NULL)
73 GList *first = g_list_first(history);
74 for(;first != NULL; first = g_list_next(first))
76 fputs(first->data, fp);
77 fputc('\n', fp);
80 fclose(fp);
82 g_free(path);
83 current = NULL;
84 last = NULL;
85 g_list_foreach(history, (GFunc)g_free, NULL);
86 g_list_free(history);
87 history = NULL;
88 g_free(entry_current);
89 entry_current = NULL;
90 g_log(LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "Cleanup Command Line history");
93 /* On activate */
94 void show_command_line_activate(GtkWidget *entry, gpointer data)
96 const char *command = gtk_entry_get_text(GTK_ENTRY(entry));
98 gmpc_easy_command_do_query(GMPC_EASY_COMMAND(gmpc_easy_command),
99 command);
101 if(last == NULL || g_utf8_collate(last->data, command) != 0)
103 history = g_list_prepend(history, g_strdup(command));
104 /* if no last, current is last */
105 if(last == NULL) {
106 last = history;
108 history_length++;
110 /* Clear the current selected entry */
111 current = NULL;
112 if(history_length > 100) {
113 GList *temp;
114 temp = g_list_previous(last);;
115 g_free(last->data);
116 history = g_list_delete_link(history, last);
117 last = temp;
118 history_length--;
121 gtk_widget_hide(entry);
122 /* Clear the entry */
123 gtk_entry_set_text(GTK_ENTRY(entry), "");
127 void show_command_line_entry_changed(
128 GtkWidget *entry,
129 gpointer data)
131 const gchar *text = gtk_entry_get_text(GTK_ENTRY(entry));
133 if(current != NULL && g_utf8_collate(text, current->data) == 0) return;
136 if(entry_current) g_free(entry_current);
137 entry_current = NULL;
138 if(text) entry_current = g_strdup(text);
139 current = NULL;
142 /* On escape close and backspace when empty */
143 gboolean show_command_line_key_press_event(
144 GtkWidget *entry,
145 GdkEventKey *event,
146 gpointer data)
149 /* Go back in history */
150 if(event->keyval == GDK_KEY_Up)
152 if(current == NULL) current = g_list_first(history);
153 else if(current->next != NULL) current = g_list_next(current);
155 if(current != NULL) {
156 gtk_entry_set_text(GTK_ENTRY(entry), (char *)(current->data));
158 return TRUE;
160 /* Go forward in history */
161 else if (event->keyval == GDK_KEY_Down)
163 if(current != NULL) {
164 current = g_list_previous(current);
166 if(current) {
167 gtk_entry_set_text(GTK_ENTRY(entry), (char *)(current->data));
168 }else if (entry_current) {
169 gtk_entry_set_text(GTK_ENTRY(entry), entry_current);
170 }else{
171 /* Fallback */
172 gtk_entry_set_text(GTK_ENTRY(entry),"");
175 return TRUE;
177 else
178 if(event->keyval == GDK_KEY_Escape)
180 gtk_widget_hide(entry);
181 /* Clear the entry */
182 gtk_entry_set_text(GTK_ENTRY(entry), "");
183 return TRUE;
185 if(gtk_entry_get_text_length(GTK_ENTRY(entry)) == 0 &&
186 event->keyval == GDK_KEY_BackSpace)
188 gtk_widget_hide(entry);
189 return TRUE;
192 return FALSE;
195 /* Call from the menu */
196 void show_command_line(void)
198 static int init = 1;
199 GtkWidget *entry = GTK_WIDGET(gtk_builder_get_object(
200 pl3_xml,
201 "special_command_entry"));
203 /* Tell gcc this is not likely to happen (only once) */
204 if(G_UNLIKELY(init == 1))
206 GtkTreeModel *model;
207 GtkCellRenderer *ren;
208 GtkEntryCompletion *comp;
209 FILE *fp;
210 gchar *path;
212 * Setup completion on the entry box.
213 * Completion should match what is done in the Easycommand popup
216 /* steal pointer to model from easycommand */
217 model = (GtkTreeModel *)gmpc_easy_command->store;
219 /* Create completion */
220 comp = gtk_entry_completion_new();
222 /* Attach model to completion */
223 gtk_entry_completion_set_model(comp, model);
224 /* Column 1 holds the 'to match' text */
225 gtk_entry_completion_set_text_column(comp, 1);
226 /* Enable all features that might be usefull to the user */
227 gtk_entry_completion_set_inline_completion(comp, TRUE);
228 gtk_entry_completion_set_inline_selection(comp, TRUE);
229 gtk_entry_completion_set_popup_completion(comp, TRUE);
230 /* Use the match function from GmpcEasyCommand */
231 gtk_entry_completion_set_match_func(comp,
232 (GtkEntryCompletionMatchFunc)gmpc_easy_command_completion_function,
233 g_object_ref(gmpc_easy_command),
234 g_object_unref);
237 /* setup looks */
238 /* Icon */
239 ren = gtk_cell_renderer_pixbuf_new();
240 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(comp), ren, FALSE);
241 gtk_cell_layout_reorder(GTK_CELL_LAYOUT(comp),ren, 0);
242 /* Support both icon-name and stock-id. */
243 gtk_cell_layout_add_attribute(
244 GTK_CELL_LAYOUT(comp),
245 ren,
246 "icon-name", 6);
247 gtk_cell_layout_add_attribute(
248 GTK_CELL_LAYOUT(comp),
249 ren,
250 "stock-id", 7);
251 /* hint */
252 ren = gtk_cell_renderer_text_new();
253 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(comp), ren, FALSE);
254 gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(comp),ren, "text", 5);
255 g_object_set(G_OBJECT(ren), "foreground", "grey", NULL);
257 /* Add completion to the entry */
258 gtk_entry_set_completion(GTK_ENTRY(entry),comp);
260 /* Make sure the history gets cleaned on destroy */
261 g_signal_connect(G_OBJECT(entry),
262 "destroy",
263 G_CALLBACK(show_command_line_history_destroy),
264 NULL);
268 /* Store results */
269 path = gmpc_get_user_path("cmd-history.txt");
270 fp = g_fopen(path,"r");
271 if(fp != NULL)
273 char buffer[512];
274 while(fgets(buffer, 512, fp) != NULL)
276 if(buffer[strlen(buffer)-1] == '\n') buffer[strlen(buffer)-1] = '\0';
277 if(buffer[0] != '\0')
278 history = g_list_prepend(history, g_strdup(buffer));
280 history = g_list_reverse(history);
281 last = history;
282 fclose(fp);
284 g_free(path);
285 /* Only need todo this once */
286 init = 0;
288 /* Show the entry and grab focus */
289 gtk_widget_show(entry);
290 gtk_widget_grab_focus(entry);