1/* 2Copyright (c) 2011 by Simon Schneegans 3 4This program is free software: you can redistribute it and/or modify it 5under the terms of the GNU General Public License as published by the Free 6Software Foundation, either version 3 of the License, or (at your option) 7any later version. 8 9This program is distributed in the hope that it will be useful, but WITHOUT 10ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 12more details. 13 14You should have received a copy of the GNU General Public License along with 15this program. If not, see <http://www.gnu.org/licenses/>. 16*/ 17 18namespace GnomePie { 19 20///////////////////////////////////////////////////////////////////////// 21/// A window which allows selection of a new Slice which is about to be 22/// added to a Pie. It can be also used to edit an existing Slice 23///////////////////////////////////////////////////////////////////////// 24 25public class NewSliceWindow : GLib.Object { 26 27 ///////////////////////////////////////////////////////////////////// 28 /// This signal gets emitted when the user confirms his selection. 29 ///////////////////////////////////////////////////////////////////// 30 31 public signal void on_select(ActionGroup action, bool as_new_slice, int at_position); 32 33 ///////////////////////////////////////////////////////////////////// 34 /// The contained list of slice types. It contains both: Groups and 35 /// single actions. 36 ///////////////////////////////////////////////////////////////////// 37 38 private SliceTypeList slice_type_list = null; 39 40 ///////////////////////////////////////////////////////////////////// 41 /// The IconSelectWindow used for icon selection for a Slice. 42 ///////////////////////////////////////////////////////////////////// 43 44 private IconSelectWindow? icon_window = null; 45 46 ///////////////////////////////////////////////////////////////////// 47 /// Some widgets of this window. Loaded by a ui-builder and stored 48 /// for later access. 49 ///////////////////////////////////////////////////////////////////// 50 51 private Gtk.Dialog window = null; 52 private Gtk.Box name_box = null; 53 private Gtk.Box command_box = null; 54 private Gtk.Button icon_button = null; 55 private Gtk.Box no_options_box = null; 56 private Gtk.Box pie_box = null; 57 private Gtk.Box hotkey_box = null; 58 private Gtk.Box uri_box = null; 59 private Gtk.Box quickaction_box = null; 60 private Gtk.Image icon = null; 61 private Gtk.Entry name_entry = null; 62 private Gtk.Entry command_entry = null; 63 private Gtk.Entry uri_entry = null; 64 private Gtk.CheckButton quickaction_checkbutton = null; 65 66 ///////////////////////////////////////////////////////////////////// 67 /// Two custom widgets. For Pie and hotkey selection respectively. 68 ///////////////////////////////////////////////////////////////////// 69 70 private PieComboList pie_select = null; 71 private TriggerSelectButton key_select = null; 72 73 ///////////////////////////////////////////////////////////////////// 74 /// These members store information on the currently selected Slice. 75 ///////////////////////////////////////////////////////////////////// 76 77 private string current_type = ""; 78 private string current_icon = ""; 79 private string current_id = ""; 80 private string current_custom_icon = ""; 81 private string current_hotkey = ""; 82 private string current_pie_to_open = ""; 83 84 ///////////////////////////////////////////////////////////////////// 85 /// The position of the edited Slice in its parent Pie. 86 ///////////////////////////////////////////////////////////////////// 87 88 private int slice_position = 0; 89 90 ///////////////////////////////////////////////////////////////////// 91 /// True, if the Slice i going to be added as a new Slice. Else it 92 /// will edit the Slice at slice_position in its parent Pie. 93 ///////////////////////////////////////////////////////////////////// 94 95 private bool add_as_new_slice = true; 96 97 ///////////////////////////////////////////////////////////////////// 98 /// C'tor creates a new window. 99 ///////////////////////////////////////////////////////////////////// 100 101 public NewSliceWindow() { 102 try { 103 104 Gtk.Builder builder = new Gtk.Builder(); 105 106 builder.add_from_file (Paths.ui_files + "/slice_select.ui"); 107 108 this.slice_type_list = new SliceTypeList(); 109 this.slice_type_list.on_select.connect((type, icon) => { 110 111 this.name_box.hide(); 112 this.command_box.hide(); 113 this.icon_button.sensitive = false; 114 this.no_options_box.hide(); 115 this.pie_box.hide(); 116 this.hotkey_box.hide(); 117 this.uri_box.hide(); 118 this.quickaction_box.hide(); 119 120 this.current_type = type; 121 122 switch (type) { 123 case "bookmarks": case "clipboard": case "devices": 124 case "menu": case "session": case "window_list": 125 this.no_options_box.show(); 126 this.set_icon(icon); 127 break; 128 case "app": 129 this.name_box.show(); 130 this.command_box.show(); 131 this.quickaction_box.show(); 132 this.icon_button.sensitive = true; 133 if (this.current_custom_icon == "") this.set_icon(icon); 134 else this.set_icon(this.current_custom_icon); 135 break; 136 case "key": 137 this.name_box.show(); 138 this.hotkey_box.show(); 139 this.quickaction_box.show(); 140 this.icon_button.sensitive = true; 141 if (this.current_custom_icon == "") this.set_icon(icon); 142 else this.set_icon(this.current_custom_icon); 143 break; 144 case "pie": 145 this.pie_box.show(); 146 this.quickaction_box.show(); 147 this.set_icon(PieManager.all_pies[this.pie_select.current_id].icon); 148 break; 149 case "uri": 150 this.name_box.show(); 151 this.uri_box.show(); 152 this.quickaction_box.show(); 153 this.icon_button.sensitive = true; 154 if (this.current_custom_icon == "") this.set_icon(icon); 155 else this.set_icon(this.current_custom_icon); 156 break; 157 } 158 }); 159 160 this.name_box = builder.get_object("name-box") as Gtk.Box; 161 this.command_box = builder.get_object("command-box") as Gtk.Box; 162 this.icon_button = builder.get_object("icon-button") as Gtk.Button; 163 this.no_options_box = builder.get_object("no-options-box") as Gtk.Box; 164 this.pie_box = builder.get_object("pie-box") as Gtk.Box; 165 this.pie_select = new PieComboList(); 166 this.pie_select.on_select.connect((id) => { 167 this.current_pie_to_open = id; 168 this.set_icon(PieManager.all_pies[id].icon); 169 }); 170 171 this.pie_box.pack_start(this.pie_select, true, true); 172 173 this.hotkey_box = builder.get_object("hotkey-box") as Gtk.Box; 174 this.key_select = new TriggerSelectButton(false); 175 this.hotkey_box.pack_start(this.key_select, false, true); 176 this.key_select.on_select.connect((trigger) => { 177 this.current_hotkey = trigger.name; 178 }); 179 180 this.uri_box = builder.get_object("uri-box") as Gtk.Box; 181 182 this.name_entry = builder.get_object("name-entry") as Gtk.Entry; 183 this.uri_entry = builder.get_object("uri-entry") as Gtk.Entry; 184 this.command_entry = builder.get_object("command-entry") as Gtk.Entry; 185 this.quickaction_checkbutton = builder.get_object("quick-action-checkbutton") as Gtk.CheckButton; 186 187 this.quickaction_box = builder.get_object("quickaction-box") as Gtk.Box; 188 this.icon = builder.get_object("icon") as Gtk.Image; 189 190 this.icon_button.clicked.connect(on_icon_button_clicked); 191 192 var scroll_area = builder.get_object("slice-scrolledwindow") as Gtk.ScrolledWindow; 193 scroll_area.add(this.slice_type_list); 194 195 this.window = builder.get_object("window") as Gtk.Dialog; 196 197 (builder.get_object("ok-button") as Gtk.Button).clicked.connect(on_ok_button_clicked); 198 (builder.get_object("cancel-button") as Gtk.Button).clicked.connect(on_cancel_button_clicked); 199 200 this.window.delete_event.connect(this.window.hide_on_delete); 201 202 } catch (GLib.Error e) { 203 error("Could not load UI: %s\n", e.message); 204 } 205 } 206 207 ///////////////////////////////////////////////////////////////////// 208 /// Sets the parent window, in order to make this window stay in 209 /// front. 210 ///////////////////////////////////////////////////////////////////// 211 212 public void set_parent(Gtk.Window parent) { 213 this.window.set_transient_for(parent); 214 } 215 216 ///////////////////////////////////////////////////////////////////// 217 /// Sows the window on the screen. 218 ///////////////////////////////////////////////////////////////////// 219 220 public void show() { 221 this.slice_type_list.select_first(); 222 this.pie_select.select_first(); 223 this.key_select.set_trigger(new Trigger()); 224 this.window.show_all(); 225 } 226 227 ///////////////////////////////////////////////////////////////////// 228 /// Reloads the window. 229 ///////////////////////////////////////////////////////////////////// 230 231 public void reload() { 232 this.pie_select.reload(); 233 } 234 235 ///////////////////////////////////////////////////////////////////// 236 /// Makes all widgets display stuff according to the given action. 237 ///////////////////////////////////////////////////////////////////// 238 239 public void set_action(ActionGroup group, int position) { 240 this.set_default(group.parent_id, position); 241 242 this.add_as_new_slice = false; 243 string type = ""; 244 245 if (group.get_type().depth() == 2) { 246 var action = group.actions[0]; 247 type = ActionRegistry.descriptions[action.get_type().name()].id; 248 this.select_type(type); 249 250 this.set_icon(action.icon); 251 this.quickaction_checkbutton.active = action.is_quickaction; 252 this.name_entry.text = action.name; 253 254 switch (type) { 255 case "app": 256 this.current_custom_icon = action.icon; 257 this.command_entry.text = action.real_command; 258 break; 259 case "key": 260 this.current_custom_icon = action.icon; 261 this.current_hotkey = action.real_command; 262 this.key_select.set_trigger(new Trigger.from_string(action.real_command)); 263 break; 264 case "pie": 265 this.pie_select.select(action.real_command); 266 break; 267 case "uri": 268 this.current_custom_icon = action.icon; 269 this.uri_entry.text = action.real_command; 270 break; 271 } 272 273 } else { 274 type = GroupRegistry.descriptions[group.get_type().name()].id; 275 this.select_type(type); 276 } 277 } 278 279 ///////////////////////////////////////////////////////////////////// 280 /// Selects a default action. 281 ///////////////////////////////////////////////////////////////////// 282 283 public void set_default(string pie_id, int position) { 284 this.slice_position = position; 285 this.add_as_new_slice = true; 286 this.current_custom_icon = ""; 287 this.select_type("app"); 288 this.current_id = pie_id; 289 this.key_select.set_trigger(new Trigger()); 290 this.pie_select.select_first(); 291 this.name_entry.text = _("Rename me!"); 292 this.command_entry.text = ""; 293 this.uri_entry.text = ""; 294 } 295 296 ///////////////////////////////////////////////////////////////////// 297 /// Selects a specific action type. 298 ///////////////////////////////////////////////////////////////////// 299 300 private void select_type(string type) { 301 this.current_type = type; 302 this.slice_type_list.select(type); 303 } 304 305 ///////////////////////////////////////////////////////////////////// 306 /// Called, when the user presses the ok button. 307 ///////////////////////////////////////////////////////////////////// 308 309 private void on_ok_button_clicked() { 310 this.window.hide(); 311 312 ActionGroup group = null; 313 314 switch (this.current_type) { 315 case "bookmarks": group = new BookmarkGroup(this.current_id); break; 316 case "clipboard": group = new ClipboardGroup(this.current_id); break; 317 case "devices": group = new DevicesGroup(this.current_id); break; 318 case "menu": group = new MenuGroup(this.current_id); break; 319 case "session": group = new SessionGroup(this.current_id); break; 320 case "window_list": group = new WindowListGroup(this.current_id); break; 321 322 case "app": 323 group = new ActionGroup(this.current_id); 324 group.add_action(new AppAction(this.name_entry.text, this.current_icon, 325 this.command_entry.text, 326 this.quickaction_checkbutton.active)); 327 break; 328 case "key": 329 group = new ActionGroup(this.current_id); 330 group.add_action(new KeyAction(this.name_entry.text, this.current_icon, 331 this.current_hotkey, 332 this.quickaction_checkbutton.active)); 333 break; 334 case "pie": 335 group = new ActionGroup(this.current_id); 336 group.add_action(new PieAction(this.current_pie_to_open, 337 this.quickaction_checkbutton.active)); 338 break; 339 case "uri": 340 group = new ActionGroup(this.current_id); 341 group.add_action(new UriAction(this.name_entry.text, this.current_icon, 342 this.uri_entry.text, 343 this.quickaction_checkbutton.active)); 344 break; 345 } 346 347 this.on_select(group, this.add_as_new_slice, this.slice_position); 348 } 349 350 ///////////////////////////////////////////////////////////////////// 351 /// Called when the user presses the cancel button. 352 ///////////////////////////////////////////////////////////////////// 353 354 private void on_cancel_button_clicked() { 355 this.window.hide(); 356 } 357 358 ///////////////////////////////////////////////////////////////////// 359 /// Called when the user presses the icon select button. 360 ///////////////////////////////////////////////////////////////////// 361 362 private void on_icon_button_clicked(Gtk.Button button) { 363 if (this.icon_window == null) { 364 this.icon_window = new IconSelectWindow(this.window); 365 this.icon_window.on_ok.connect((icon) => { 366 this.current_custom_icon = icon; 367 this.set_icon(icon); 368 }); 369 } 370 371 this.icon_window.show(); 372 this.icon_window.set_icon(this.current_icon); 373 } 374 375 ///////////////////////////////////////////////////////////////////// 376 /// Helper method which sets the icon of the icon select button. 377 /// It assures that both can be displayed: A customly chosen image 378 /// from or an icon from the current theme. 379 ///////////////////////////////////////////////////////////////////// 380 381 private void set_icon(string icon) { 382 if (icon.contains("/")) 383 try { 384 this.icon.pixbuf = new Gdk.Pixbuf.from_file_at_scale(icon, this.icon.get_pixel_size(), 385 this.icon.get_pixel_size(), true); 386 } catch (GLib.Error error) { 387 warning(error.message); 388 } 389 else 390 this.icon.icon_name = icon; 391 392 this.current_icon = icon; 393 } 394} 395 396} 397