Fix typo: Similar Artist -> Similar Artists
[gmpc.git] / src / Plugins / ExternalCommand.vala
blobaee7e560d79d80b514c4188a203fa558e2fd3078
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 /**
21 * Usage:
22 * Create text file: ~/.config/gmpc/external-command.cfg
23 * Add sections for each command, Each section has a cmd and a name entry.
24 * The cmd should be a path to the executable with possible arguments,
25 * the cmd string is parsed by gmpc.
27 * Example:
28 * [1]
29 * cmd="/home/me/test.sh -f test3"
30 * name="Test script"
32 * The paths (relative to MPD directory) are passed to the script as arguments.
34 using GLib;
35 using Gtk;
36 using Gmpc;
37 using Config;
39 private const bool use_transition_externalcommand = Gmpc.use_transition;
40 private const string some_unique_name_externalcommand = Config.VERSION;
41 private const string log_domain_externalcommand = "Gmpc.Plugins.ExternalCommand";
43 namespace Gmpc
45 public class ExternalCommand :
46 Gmpc.Plugin.Base,
47 Gmpc.Plugin.SongListIface,
48 Gmpc.Plugin.PreferencesIface
50 private const int[] version = {0,0,0};
51 private Gmpc.Settings cfg_ec = null;
53 public override unowned int[] get_version() {
54 return this.version;
57 public override unowned string get_name () {
58 return "Call external command";
61 construct {
62 string settings_path = Gmpc.user_path("external-command.cfg");
63 cfg_ec = new Gmpc.Settings.from_file(settings_path);
64 this.plugin_type = 8;
67 ~ExternalCommand() {
68 cfg_ec = null;
71 private void start_command(Gtk.MenuItem item) {
72 // Get the command.
73 string cmd = item.get_data("cmd");
74 // Calculate number of arguments.
75 int args = 0;
76 int index= 0;
77 Gtk.TreeView tree = item.get_data("tree");
78 Gtk.TreeSelection sel = tree.get_selection();
79 args += sel.count_selected_rows();
81 // Parse the command list.
82 string[] argv;
83 try {
84 Shell.parse_argv(cmd, out argv);
85 } catch (Error e) {
86 Gmpc.Messages.show("%s: %s".printf(_("Failed to parse command"), e.message), Gmpc.Messages.Level.WARNING);
87 return;
90 // Resize the list to fit the songs passed.
91 index = argv.length;
92 args += index;
93 // +1 (closing NULL)
94 argv.resize((args+1));
97 // Path.
98 weak string? music_directory = null;
99 var cp = Gmpc.profiles.get_current();
100 if( cp != null )
102 if(Gmpc.profiles.get_music_directory(cp) != null)
104 music_directory = Gmpc.profiles.get_music_directory(cp);
108 // Set song paths as arguments.
109 Gtk.TreeModel model;
110 var rows = sel.get_selected_rows(out model);
111 foreach ( Gtk.TreePath path in rows ){
112 string file;
113 Gtk.TreeIter iter;
114 if(model.get_iter(out iter, path)){
115 model.get(iter,3, out file);
116 if(music_directory != null) {
117 argv[index] = Path.build_filename(music_directory,file);
118 }else{
119 argv[index] = file;
121 index++;
124 // Closing null
125 argv[index] = null;
127 // Execute.
128 try {
129 GLib.Process.spawn_async(null, argv, null, SpawnFlags.SEARCH_PATH, null, null);
130 } catch (Error e) {
131 Gmpc.Messages.show("%s: %s".printf(_("Failed to start external command"), e.message), Gmpc.Messages.Level.WARNING);
132 return;
136 public int song_list (Gtk.Widget tree, Gtk.Menu menu)
138 int retv = 0;
140 SettingsList sl = cfg_ec.get_class_list();
141 weak SettingsList iter = sl;
142 while(iter != null) {
143 string cmd = cfg_ec.get_string(iter.key, "cmd");
144 string name = cfg_ec.get_string(iter.key, "name");
146 // If both values are not valid, continue.
147 if(cmd == null || name == null) continue;
148 var item = new Gtk.ImageMenuItem.with_label("Run external command: "+name);
150 // Attach tree widget to item and the command.
151 item.set_data("tree", tree);
152 item.set_data("cmd", cmd);
153 // Click Signal.
154 item.activate.connect(start_command);
155 // Add to menu
156 menu.append(item);
157 retv++;
158 // Next item.
159 iter = iter.next;
161 return retv;
165 /************************
166 * Preferences
167 ************************/
168 private Gtk.Builder pref_builder = null;
170 private void preferences_pane_combo_changed(Gtk.ComboBox source)
172 Gtk.TreeIter titer;
173 if(source.get_active_iter(out titer)) {
174 Gtk.TreeModel model = source.get_model();
175 string key = null;
176 model.get(titer, 0, out key);
177 string name = cfg_ec.get_string(key, "name");
178 string cmd = cfg_ec.get_string(key, "cmd");
179 if(name != null)
180 (pref_builder.get_object("entry_name") as Gtk.Entry).set_text(name);
181 if(cmd != null)
182 (pref_builder.get_object("entry_cmd") as Gtk.Entry).set_text(cmd);
184 (pref_builder.get_object("entry_cmd") as Gtk.Entry).set_sensitive(true);
185 (pref_builder.get_object("entry_name") as Gtk.Entry).set_sensitive(true);
186 } else {
187 (pref_builder.get_object("entry_cmd") as Gtk.Entry).set_sensitive(false);
188 (pref_builder.get_object("entry_name") as Gtk.Entry).set_sensitive(false);
192 private void preferences_pane_entry_cmd(Gtk.Editable entry)
194 var cb = (pref_builder.get_object("commands_cb") as Gtk.ComboBox);
195 Gtk.TreeIter iter;
196 if(cb.get_active_iter(out iter))
198 string key;
199 cb.get_model().get(iter, 0, out key);
200 cfg_ec.set_string(key, "cmd", (entry as Gtk.Entry).get_text());
203 private void preferences_pane_entry_name(Gtk.Editable entry)
205 var cb = (pref_builder.get_object("commands_cb") as Gtk.ComboBox);
206 Gtk.TreeIter iter;
207 if(cb.get_active_iter(out iter))
209 string key;
210 cb.get_model().get(iter, 0, out key);
211 cfg_ec.set_string(key, "name", (entry as Gtk.Entry).get_text());
212 (cb.get_model() as Gtk.ListStore).set(iter, 1, (entry as Gtk.Entry).get_text());
216 private void preferences_pane_remove_button(Gtk.Button button)
218 Gtk.TreeIter iter;
219 Gtk.ListStore store = pref_builder.get_object("commands_list") as Gtk.ListStore;
220 var cb = (pref_builder.get_object("commands_cb") as Gtk.ComboBox);
222 if(cb.get_active_iter(out iter)) {
223 string key;
224 cb.get_model().get(iter, 0, out key);
225 cfg_ec.remove_class(key);
226 // remove entry.
227 store.remove(iter);
228 preferences_pane_enable_remove_button();
229 (pref_builder.get_object("commands_cb") as Gtk.ComboBox).set_active(0);
232 private void preferences_pane_enable_remove_button()
234 Gtk.ListStore store = pref_builder.get_object("commands_list") as Gtk.ListStore;
235 var cb = (pref_builder.get_object("button_delete") as Gtk.Button);
236 if(store.iter_n_children(null) > 0) {
237 cb.set_sensitive(true);
238 }else{
239 cb.set_sensitive(false);
242 private void preferences_pane_add_button(Gtk.Button button)
244 uint id = 0;
245 stdout.printf("add button\n");
246 while(cfg_ec.get_string("%u".printf(id), "name") != null) id++;
247 cfg_ec.set_string("%u".printf(id), "name", "<Command name>");
248 cfg_ec.set_string("%u".printf(id), "cmd", "<Command cmd>");
250 Gtk.ListStore store = pref_builder.get_object("commands_list") as Gtk.ListStore;
251 var cb = (pref_builder.get_object("commands_cb") as Gtk.ComboBox);
252 Gtk.TreeIter iter;
253 store.append(out iter);
254 store.set(iter, 0, "%u".printf(id), 1, "<Command name>");
255 cb.set_active_iter(iter);
258 /* Destroy preferences construct */
259 public void preferences_pane_construct(Gtk.Container container)
261 if(pref_builder != null) return;
262 pref_builder = new Gtk.Builder();
265 pref_builder.add_from_file(Gmpc.data_path("preferences-external-command.ui"));
267 catch (GLib.Error e)
269 GLib.error("Failed to load GtkBuilder file: %s", e.message);
273 Gtk.ListStore store = pref_builder.get_object("commands_list") as Gtk.ListStore;
275 * Fill in the list.
277 SettingsList sl = cfg_ec.get_class_list();
278 weak SettingsList iter = sl;
279 while(iter != null) {
280 string name = cfg_ec.get_string(iter.key, "name");
281 Gtk.TreeIter titer;
282 store.prepend(out titer);
283 store.set(titer, 0,iter.key, 1, name);
285 // Next item.
286 iter = iter.next;
289 // Signal
290 (pref_builder.get_object("button_add") as Gtk.Button).clicked.connect(
291 preferences_pane_add_button);
292 (pref_builder.get_object("button_delete") as Gtk.Button).clicked.connect(
293 preferences_pane_remove_button);
294 (pref_builder.get_object("entry_cmd") as Gtk.Entry).changed.
295 connect(preferences_pane_entry_cmd);
296 (pref_builder.get_object("entry_name") as Gtk.Entry).changed.
297 connect(preferences_pane_entry_name);
299 // Connect signals.
300 (pref_builder.get_object("commands_cb") as Gtk.ComboBox).
301 changed.connect(preferences_pane_combo_changed);
302 // Add to window.
303 var b = pref_builder.get_object("main_box") as Gtk.Widget;
304 container.add(b);
306 (pref_builder.get_object("commands_cb") as Gtk.ComboBox).set_active(0);
308 preferences_pane_enable_remove_button();
310 /* Destroy preferences pane */
311 public void preferences_pane_destroy(Gtk.Container container)
313 container.remove((container as Gtk.Bin).get_child());
314 pref_builder = null;