Merge lp:~julien-spautz/switchboard-plug-startup-applications/new-design into lp:switchboard-plug-startup-applications
- new-design
- Merge into trunk
Proposed by
Julien Spautz
Status: | Merged |
---|---|
Merged at revision: | 50 |
Proposed branch: | lp:~julien-spautz/switchboard-plug-startup-applications/new-design |
Merge into: | lp:switchboard-plug-startup-applications |
Diff against target: |
1312 lines (+430/-627) 8 files modified
src/Backend/KeyFile.vala (+83/-32) src/Backend/KeyFileFactory.vala (+4/-23) src/CMakeLists.txt (+7/-9) src/Dialogs/AppChooser.vala (+142/-188) src/Plug.vala (+14/-37) src/Widgets/Editor.vala (+0/-102) src/Widgets/List.vala (+180/-175) src/Widgets/Toolbar.vala (+0/-61) |
To merge this branch: | bzr merge lp:~julien-spautz/switchboard-plug-startup-applications/new-design |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Julien Spautz | Pending | ||
Review via email: mp+214391@code.launchpad.net |
Commit message
Description of the change
Implemented new design, now using Gtk.Popover and Gtk.ListBox requiring Gtk+ 3.12
Simplified interface by removing the editor pane because it's kind of useless, apps can still be added and removed, custom commands also still work.
To post a comment you must log in.
- 47. By Julien Spautz
-
make label insensitive when app is inactive
- 48. By Julien Spautz
-
rewrote AppChooser dialog using gtk.listbox
- 49. By Julien Spautz
-
remove gobject-style construction
- 50. By Julien Spautz
-
simplify KeyFileFactory and hide popover instead of destroying and recreating every time
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'src/Backend/KeyFile.vala' | |||
2 | --- src/Backend/KeyFile.vala 2014-03-22 11:07:44 +0000 | |||
3 | +++ src/Backend/KeyFile.vala 2014-04-07 13:03:25 +0000 | |||
4 | @@ -18,13 +18,15 @@ | |||
5 | 18 | ***/ | 18 | ***/ |
6 | 19 | 19 | ||
7 | 20 | /** | 20 | /** |
9 | 21 | * Stores information about an app found in it's .desktop file | 21 | * Stores information about an app found in it's .desktop file |
10 | 22 | * and allows us to modify it. | 22 | * and allows us to modify it. |
11 | 23 | * http://standards.freedesktop.org/desktop-entry-spec/latest/index.html | ||
12 | 23 | */ | 24 | */ |
13 | 24 | public class Pantheon.Startup.Backend.KeyFile : GLib.Object { | 25 | public class Pantheon.Startup.Backend.KeyFile : GLib.Object { |
14 | 25 | 26 | ||
15 | 26 | const int ICON_SIZE = 48; | 27 | const int ICON_SIZE = 48; |
16 | 27 | const string FALLBACK_ICON = "application-default-icon"; | 28 | const string FALLBACK_ICON = "application-default-icon"; |
17 | 29 | const string CUSTOM_COMMAND_NAME = _("Custom Command"); | ||
18 | 28 | 30 | ||
19 | 29 | const string KEY_NAME = KeyFileDesktop.KEY_NAME; | 31 | const string KEY_NAME = KeyFileDesktop.KEY_NAME; |
20 | 30 | const string KEY_COMMAND = KeyFileDesktop.KEY_EXEC; | 32 | const string KEY_COMMAND = KeyFileDesktop.KEY_EXEC; |
21 | @@ -33,7 +35,10 @@ | |||
22 | 33 | const string KEY_ACTIVE = "X-GNOME-Autostart-enabled"; | 35 | const string KEY_ACTIVE = "X-GNOME-Autostart-enabled"; |
23 | 34 | const string KEY_TYPE = KeyFileDesktop.KEY_TYPE; | 36 | const string KEY_TYPE = KeyFileDesktop.KEY_TYPE; |
24 | 35 | const string KEY_NO_DISPLAY = KeyFileDesktop.KEY_NO_DISPLAY; | 37 | const string KEY_NO_DISPLAY = KeyFileDesktop.KEY_NO_DISPLAY; |
26 | 36 | 38 | const string KEY_HIDDEN = KeyFileDesktop.KEY_HIDDEN; | |
27 | 39 | const string KEY_NOT_SHOW_IN = KeyFileDesktop.KEY_NOT_SHOW_IN; | ||
28 | 40 | const string KEY_ONLY_SHOW_IN = KeyFileDesktop.KEY_ONLY_SHOW_IN; | ||
29 | 41 | |||
30 | 37 | public string name { | 42 | public string name { |
31 | 38 | owned get { return get_key (KEY_NAME); } | 43 | owned get { return get_key (KEY_NAME); } |
32 | 39 | set { set_key (KEY_NAME, value); } | 44 | set { set_key (KEY_NAME, value); } |
33 | @@ -55,44 +60,54 @@ | |||
34 | 55 | } | 60 | } |
35 | 56 | 61 | ||
36 | 57 | public bool active { | 62 | public bool active { |
39 | 58 | get { return get_key (KEY_ACTIVE) != "false"; } | 63 | get { return get_bool_key (KEY_ACTIVE); } |
40 | 59 | set { set_key (KEY_ACTIVE, value.to_string ()); } | 64 | set { set_bool_key (KEY_ACTIVE, value); } |
41 | 60 | } | 65 | } |
45 | 61 | 66 | ||
46 | 62 | public bool dont_show { | 67 | public bool show { |
47 | 63 | get { return bool.parse (get_key (KEY_NO_DISPLAY)); } | 68 | get { |
48 | 69 | if (get_bool_key (KEY_NO_DISPLAY)) | ||
49 | 70 | return false; | ||
50 | 71 | if (get_bool_key (KEY_HIDDEN)) | ||
51 | 72 | return false; | ||
52 | 73 | return show_in_environment (); | ||
53 | 74 | } | ||
54 | 64 | } | 75 | } |
55 | 65 | 76 | ||
56 | 66 | public string path { get; set; } | 77 | public string path { get; set; } |
57 | 67 | 78 | ||
58 | 79 | public bool is_custom_command { | ||
59 | 80 | get { return name == CUSTOM_COMMAND_NAME; } | ||
60 | 81 | } | ||
61 | 82 | |||
62 | 68 | GLib.KeyFile keyfile; | 83 | GLib.KeyFile keyfile; |
63 | 69 | static string[] languages; | 84 | static string[] languages; |
64 | 70 | static string preferred_language; | 85 | static string preferred_language; |
66 | 71 | 86 | ||
67 | 72 | static construct { | 87 | static construct { |
68 | 73 | languages = Intl.get_language_names (); | 88 | languages = Intl.get_language_names (); |
69 | 74 | preferred_language = languages [0]; | 89 | preferred_language = languages [0]; |
70 | 75 | } | 90 | } |
72 | 76 | 91 | ||
73 | 77 | public KeyFile (string path) { | 92 | public KeyFile (string path) { |
75 | 78 | GLib.Object (path: path); | 93 | Object (path: path); |
76 | 79 | 94 | ||
77 | 80 | keyfile = new GLib.KeyFile (); | 95 | keyfile = new GLib.KeyFile (); |
78 | 81 | load_from_file (); | 96 | load_from_file (); |
79 | 82 | } | 97 | } |
81 | 83 | 98 | ||
82 | 84 | public KeyFile.from_command (string command) { | 99 | public KeyFile.from_command (string command) { |
83 | 85 | keyfile = new GLib.KeyFile (); | 100 | keyfile = new GLib.KeyFile (); |
85 | 86 | 101 | ||
86 | 87 | this.path = Utils.get_user_startup_dir () + command.split (" ")[0] + ".desktop"; | 102 | this.path = Utils.get_user_startup_dir () + command.split (" ")[0] + ".desktop"; |
88 | 88 | this.name = _("Custom Command"); | 103 | this.name = CUSTOM_COMMAND_NAME; |
89 | 89 | this.comment = command; | 104 | this.comment = command; |
90 | 90 | this.command = command; | 105 | this.command = command; |
91 | 91 | this.icon = FALLBACK_ICON; | 106 | this.icon = FALLBACK_ICON; |
92 | 92 | this.active = true; | 107 | this.active = true; |
94 | 93 | 108 | ||
95 | 94 | set_key (KEY_TYPE, "Application"); | 109 | set_key (KEY_TYPE, "Application"); |
97 | 95 | 110 | ||
98 | 96 | write_to_file (); | 111 | write_to_file (); |
99 | 97 | } | 112 | } |
100 | 98 | 113 | ||
101 | @@ -106,7 +121,7 @@ | |||
102 | 106 | } catch (Error e) { | 121 | } catch (Error e) { |
103 | 107 | warning (e.message); | 122 | warning (e.message); |
104 | 108 | } | 123 | } |
106 | 109 | 124 | ||
107 | 110 | message ("-- Saving to %s --", path); | 125 | message ("-- Saving to %s --", path); |
108 | 111 | message ("Name: %s", name); | 126 | message ("Name: %s", name); |
109 | 112 | message ("Comment: %s", comment); | 127 | message ("Comment: %s", comment); |
110 | @@ -124,31 +139,46 @@ | |||
111 | 124 | } | 139 | } |
112 | 125 | } | 140 | } |
113 | 126 | 141 | ||
114 | 142 | void set_bool_key (string key, bool value) { | ||
115 | 143 | var as_string = value ? "true" : "false"; | ||
116 | 144 | keyfile_set_string (key, as_string); | ||
117 | 145 | } | ||
118 | 146 | |||
119 | 147 | bool get_bool_key (string key) { | ||
120 | 148 | var as_string = keyfile_get_string (key); | ||
121 | 149 | return as_string == "true"; | ||
122 | 150 | } | ||
123 | 151 | |||
124 | 127 | void set_key (string key, string value) { | 152 | void set_key (string key, string value) { |
125 | 128 | if (key_is_localized (key)) | 153 | if (key_is_localized (key)) |
126 | 129 | keyfile_set_locale_string (key, value); | 154 | keyfile_set_locale_string (key, value); |
127 | 130 | else | 155 | else |
128 | 131 | keyfile_set_string (key, value); | 156 | keyfile_set_string (key, value); |
129 | 132 | } | 157 | } |
131 | 133 | 158 | ||
132 | 134 | string get_key (string key) { | 159 | string get_key (string key) { |
133 | 135 | if (key_is_localized (key)) | 160 | if (key_is_localized (key)) |
134 | 136 | return keyfile_get_locale_string (key); | 161 | return keyfile_get_locale_string (key); |
135 | 137 | else | 162 | else |
136 | 138 | return keyfile_get_string (key); | 163 | return keyfile_get_string (key); |
137 | 139 | } | 164 | } |
139 | 140 | 165 | ||
140 | 141 | bool key_is_localized (string key) { | 166 | bool key_is_localized (string key) { |
141 | 142 | switch (key) { | 167 | switch (key) { |
142 | 143 | case KEY_NAME: | 168 | case KEY_NAME: |
143 | 144 | case KEY_COMMENT: | 169 | case KEY_COMMENT: |
144 | 145 | return true; | 170 | return true; |
146 | 146 | 171 | ||
147 | 147 | case KEY_COMMAND: | 172 | case KEY_COMMAND: |
148 | 148 | case KEY_ICON: | 173 | case KEY_ICON: |
149 | 149 | case KEY_ACTIVE: | 174 | case KEY_ACTIVE: |
150 | 175 | case KEY_NO_DISPLAY: | ||
151 | 176 | case KEY_TYPE: | ||
152 | 177 | case KEY_ONLY_SHOW_IN: | ||
153 | 178 | case KEY_NOT_SHOW_IN: | ||
154 | 179 | case KEY_HIDDEN: | ||
155 | 150 | return false; | 180 | return false; |
157 | 151 | 181 | ||
158 | 152 | default: | 182 | default: |
159 | 153 | warn_if_reached (); | 183 | warn_if_reached (); |
160 | 154 | return false; | 184 | return false; |
161 | @@ -166,9 +196,7 @@ | |||
162 | 166 | string keyfile_get_string (string key) { | 196 | string keyfile_get_string (string key) { |
163 | 167 | try { | 197 | try { |
164 | 168 | return keyfile.get_string (KeyFileDesktop.GROUP, key); | 198 | return keyfile.get_string (KeyFileDesktop.GROUP, key); |
168 | 169 | } catch (KeyFileError e) { | 199 | } catch (KeyFileError e) { } |
166 | 170 | warning (e.message); | ||
167 | 171 | } | ||
169 | 172 | 200 | ||
170 | 173 | return ""; | 201 | return ""; |
171 | 174 | } | 202 | } |
172 | @@ -177,28 +205,51 @@ | |||
173 | 177 | foreach (string lang in languages) { | 205 | foreach (string lang in languages) { |
174 | 178 | try { | 206 | try { |
175 | 179 | return keyfile.get_locale_string (KeyFileDesktop.GROUP, key, lang); | 207 | return keyfile.get_locale_string (KeyFileDesktop.GROUP, key, lang); |
179 | 180 | } catch (KeyFileError e) { | 208 | } catch (KeyFileError e) { } |
177 | 181 | warning (e.message); | ||
178 | 182 | } | ||
180 | 183 | } | 209 | } |
181 | 184 | 210 | ||
182 | 185 | return ""; | 211 | return ""; |
183 | 186 | } | 212 | } |
185 | 187 | 213 | ||
186 | 214 | bool show_in_environment () { | ||
187 | 215 | var only_show_in = get_key (KEY_ONLY_SHOW_IN); | ||
188 | 216 | var not_show_in = get_key (KEY_NOT_SHOW_IN); | ||
189 | 217 | |||
190 | 218 | var session = Environment.get_variable ("DESKTOP_SESSION"); | ||
191 | 219 | |||
192 | 220 | if (session in only_show_in) | ||
193 | 221 | return true; | ||
194 | 222 | if (session in not_show_in) | ||
195 | 223 | return false; | ||
196 | 224 | |||
197 | 225 | if (only_show_in == "") | ||
198 | 226 | return true; | ||
199 | 227 | return false; | ||
200 | 228 | } | ||
201 | 229 | |||
202 | 188 | public void copy_to_local () { | 230 | public void copy_to_local () { |
203 | 189 | path = Utils.get_user_startup_dir () + name.down ().split (" ")[0] + ".desktop"; | 231 | path = Utils.get_user_startup_dir () + name.down ().split (" ")[0] + ".desktop"; |
204 | 190 | write_to_file (); | 232 | write_to_file (); |
205 | 191 | } | 233 | } |
207 | 192 | 234 | ||
208 | 193 | public string create_markup () { | 235 | public string create_markup () { |
210 | 194 | var markup = @"<span font_weight=\"bold\" size=\"large\">$name</span>\n$comment"; | 236 | var escaped_name = Markup.escape_text (name); |
211 | 237 | var escaped_comment = Markup.escape_text (comment); | ||
212 | 238 | var escaped_command = Markup.escape_text (command); | ||
213 | 239 | string markup; | ||
214 | 240 | |||
215 | 241 | if (is_custom_command) | ||
216 | 242 | markup = escaped_command; | ||
217 | 243 | else | ||
218 | 244 | markup = @"<span font_weight=\"bold\" size=\"large\">$escaped_name</span>\n$escaped_comment"; | ||
219 | 245 | |||
220 | 195 | return markup; | 246 | return markup; |
221 | 196 | } | 247 | } |
223 | 197 | 248 | ||
224 | 198 | public Gdk.Pixbuf create_icon (int size = ICON_SIZE) { | 249 | public Gdk.Pixbuf create_icon (int size = ICON_SIZE) { |
225 | 199 | var icon_theme = Gtk.IconTheme.get_default (); | 250 | var icon_theme = Gtk.IconTheme.get_default (); |
226 | 200 | var lookup_flags = Gtk.IconLookupFlags.GENERIC_FALLBACK; | 251 | var lookup_flags = Gtk.IconLookupFlags.GENERIC_FALLBACK; |
228 | 201 | 252 | ||
229 | 202 | try { | 253 | try { |
230 | 203 | if (icon_theme.has_icon (icon)) | 254 | if (icon_theme.has_icon (icon)) |
231 | 204 | return icon_theme.load_icon (icon, size, lookup_flags); | 255 | return icon_theme.load_icon (icon, size, lookup_flags); |
232 | @@ -207,7 +258,7 @@ | |||
233 | 207 | } catch (Error e) { | 258 | } catch (Error e) { |
234 | 208 | warning (e.message); | 259 | warning (e.message); |
235 | 209 | } | 260 | } |
237 | 210 | 261 | ||
238 | 211 | return (Gdk.Pixbuf) null; | 262 | return (Gdk.Pixbuf) null; |
239 | 212 | } | 263 | } |
240 | 213 | } | 264 | } |
241 | 214 | \ No newline at end of file | 265 | \ No newline at end of file |
242 | 215 | 266 | ||
243 | === modified file 'src/Backend/KeyFileFactory.vala' | |||
244 | --- src/Backend/KeyFileFactory.vala 2014-03-22 11:07:44 +0000 | |||
245 | +++ src/Backend/KeyFileFactory.vala 2014-04-07 13:03:25 +0000 | |||
246 | @@ -24,29 +24,10 @@ | |||
247 | 24 | public static void init () { | 24 | public static void init () { |
248 | 25 | cache = new Gee.HashMap <string, KeyFile> (); | 25 | cache = new Gee.HashMap <string, KeyFile> (); |
249 | 26 | } | 26 | } |
251 | 27 | 27 | ||
252 | 28 | public static KeyFile get_or_create (string path) { | 28 | public static KeyFile get_or_create (string path) { |
275 | 29 | if (key_file_is_cached (path)) | 29 | if (cache [path] == null) { |
276 | 30 | return get_key_file_from_path (path); | 30 | cache [path] = new KeyFile (path); |
277 | 31 | else | 31 | return cache [path]; |
256 | 32 | return create_key_file_from_path (path); | ||
257 | 33 | } | ||
258 | 34 | |||
259 | 35 | static KeyFile get_key_file_from_path (string path) | ||
260 | 36 | requires (key_file_is_cached (path)) { | ||
261 | 37 | return cache[path]; | ||
262 | 38 | } | ||
263 | 39 | |||
264 | 40 | static KeyFile create_key_file_from_path (string path) | ||
265 | 41 | requires (key_file_is_cached (path) == false) | ||
266 | 42 | ensures (key_file_is_cached (path)) { | ||
267 | 43 | |||
268 | 44 | var key_file = new KeyFile (path); | ||
269 | 45 | cache.set (path, key_file); | ||
270 | 46 | return key_file; | ||
271 | 47 | } | ||
272 | 48 | |||
273 | 49 | static bool key_file_is_cached (string path) { | ||
274 | 50 | return cache.has_key (path); | ||
278 | 51 | } | 32 | } |
279 | 52 | } | 33 | } |
280 | 53 | \ No newline at end of file | 34 | \ No newline at end of file |
281 | 54 | 35 | ||
282 | === modified file 'src/CMakeLists.txt' | |||
283 | --- src/CMakeLists.txt 2014-03-22 11:07:44 +0000 | |||
284 | +++ src/CMakeLists.txt 2014-04-07 13:03:25 +0000 | |||
285 | @@ -1,7 +1,12 @@ | |||
286 | 1 | find_package (PkgConfig) | 1 | find_package (PkgConfig) |
287 | 2 | 2 | ||
288 | 3 | # Add all your dependencies to the list below | 3 | # Add all your dependencies to the list below |
290 | 4 | pkg_check_modules (DEPS REQUIRED gthread-2.0 gtk+-3.0 switchboard-2.0 granite) | 4 | pkg_check_modules (DEPS REQUIRED |
291 | 5 | gthread-2.0 | ||
292 | 6 | gtk+-3.0>=3.12 | ||
293 | 7 | switchboard-2.0 | ||
294 | 8 | granite | ||
295 | 9 | ) | ||
296 | 5 | 10 | ||
297 | 6 | add_definitions (${DEPS_CFLAGS}) | 11 | add_definitions (${DEPS_CFLAGS}) |
298 | 7 | link_libraries (${DEPS_LIBRARIES}) | 12 | link_libraries (${DEPS_LIBRARIES}) |
299 | @@ -16,25 +21,18 @@ | |||
300 | 16 | vala_precompile (VALA_C | 21 | vala_precompile (VALA_C |
301 | 17 | Plug.vala | 22 | Plug.vala |
302 | 18 | Utils.vala | 23 | Utils.vala |
303 | 19 | |||
304 | 20 | Backend/KeyFile.vala | 24 | Backend/KeyFile.vala |
305 | 21 | Backend/KeyFileFactory.vala | 25 | Backend/KeyFileFactory.vala |
306 | 22 | Backend/DesktopFileEnumerator.vala | 26 | Backend/DesktopFileEnumerator.vala |
307 | 23 | |||
308 | 24 | Widgets/List.vala | 27 | Widgets/List.vala |
309 | 25 | Widgets/Editor.vala | ||
310 | 26 | Widgets/Toolbar.vala | ||
311 | 27 | |||
312 | 28 | Dialogs/AppChooser.vala | 28 | Dialogs/AppChooser.vala |
313 | 29 | |||
314 | 30 | ${CMAKE_CURRENT_BINARY_DIR}/config.vala | 29 | ${CMAKE_CURRENT_BINARY_DIR}/config.vala |
315 | 31 | PACKAGES | 30 | PACKAGES |
316 | 32 | switchboard-2.0 | 31 | switchboard-2.0 |
317 | 33 | granite | 32 | granite |
318 | 34 | OPTIONS | 33 | OPTIONS |
319 | 35 | --thread | 34 | --thread |
322 | 36 | --enable-experimental | 35 | --fatal-warnings |
321 | 37 | #--fatal-warnings | ||
323 | 38 | --verbose | 36 | --verbose |
324 | 39 | ) | 37 | ) |
325 | 40 | 38 | ||
326 | 41 | 39 | ||
327 | === modified file 'src/Dialogs/AppChooser.vala' | |||
328 | --- src/Dialogs/AppChooser.vala 2014-03-22 11:07:44 +0000 | |||
329 | +++ src/Dialogs/AppChooser.vala 2014-04-07 13:03:25 +0000 | |||
330 | @@ -1,204 +1,158 @@ | |||
331 | 1 | /*** | 1 | /*** |
335 | 2 | Copyright (C) 2013 Michael Langfermann | 2 | Copyright (C) 2013 Julien Spautz <spautz.julien@gmail.com> |
336 | 3 | 2013 Julien Spautz <spautz.julien@gmail.com> | 3 | |
334 | 4 | |||
337 | 5 | This program is free software: you can redistribute it and/or modify | 4 | This program is free software: you can redistribute it and/or modify |
338 | 6 | it under the terms of the GNU General Public License as published by | 5 | it under the terms of the GNU General Public License as published by |
339 | 7 | the Free Software Foundation, either version 3 of the License, or | 6 | the Free Software Foundation, either version 3 of the License, or |
340 | 8 | (at your option) any later version. | 7 | (at your option) any later version. |
342 | 9 | 8 | ||
343 | 10 | This program is distributed in the hope that it will be useful, | 9 | This program is distributed in the hope that it will be useful, |
344 | 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
345 | 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
346 | 13 | GNU General Public License for more details. | 12 | GNU General Public License for more details. |
348 | 14 | 13 | ||
349 | 15 | You should have received a copy of the GNU General Public License | 14 | You should have received a copy of the GNU General Public License |
350 | 16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | 15 | along with this program. If not, see <http://www.gnu.org/licenses/>. |
351 | 17 | ***/ | 16 | ***/ |
352 | 18 | 17 | ||
471 | 19 | public class Pantheon.Startup.Dialogs.AppChooser : Granite.Widgets.PopOver { | 18 | namespace Pantheon.Startup.Dialogs { |
472 | 20 | 19 | ||
473 | 21 | private Gtk.ListStore list_store; | 20 | public class AppRow : Gtk.Box { |
474 | 22 | private Gtk.TreeModelSort list_sort; | 21 | |
475 | 23 | private Gtk.TreeModelFilter list_filter; | 22 | public Backend.KeyFile app { get; construct; } |
476 | 24 | private Gtk.TreeView list; | 23 | |
477 | 25 | private Gtk.Widget apply_button; | 24 | public signal void deleted (); |
478 | 26 | private Granite.Widgets.SearchBar search; | 25 | |
479 | 27 | private Gtk.ScrolledWindow scroll; | 26 | public AppRow (Backend.KeyFile app) { |
480 | 28 | private Gtk.CellRendererText cell; | 27 | Object (app: app); |
481 | 29 | private Gtk.Entry command; | 28 | setup (); |
482 | 30 | 29 | } | |
483 | 31 | private string search_text = ""; | 30 | |
484 | 32 | 31 | void setup () { | |
485 | 33 | public AppInfo selected_app; | 32 | orientation = Gtk.Orientation.HORIZONTAL; |
486 | 34 | 33 | ||
487 | 35 | public signal void app_chosen (Backend.KeyFile key_file); | 34 | var markup = app.create_markup (); |
488 | 36 | public signal void app_selected (); | 35 | var icon = app.create_icon (32); |
489 | 37 | 36 | ||
490 | 38 | public AppChooser () { | 37 | margin = 6; |
491 | 39 | setup_gui (); | 38 | spacing = 12; |
492 | 40 | list_update (); | 39 | |
493 | 41 | connect_signals (); | 40 | var image = new Gtk.Image.from_pixbuf (icon); |
494 | 42 | } | 41 | add (image); |
495 | 43 | 42 | ||
496 | 44 | private void setup_gui () { | 43 | var label = new Gtk.Label (markup); |
497 | 45 | title = _("Choose an Application..."); | 44 | label.use_markup = true; |
498 | 46 | border_width = 5; | 45 | label.halign = Gtk.Align.START; |
499 | 47 | 46 | label.ellipsize = Pango.EllipsizeMode.END; | |
500 | 48 | list_store = new Gtk.ListStore (3, | 47 | add (label); |
501 | 49 | typeof (string), | 48 | |
502 | 50 | typeof (Gdk.Pixbuf), | 49 | show_all (); |
503 | 51 | typeof (Backend.KeyFile)); | 50 | } |
504 | 52 | 51 | } | |
505 | 53 | list_filter = new Gtk.TreeModelFilter (list_store, null); | 52 | |
506 | 54 | list_filter.set_visible_func (filter_func); | 53 | public class AppChooser : Gtk.Popover { |
507 | 55 | 54 | ||
508 | 56 | list_sort = new Gtk.TreeModelSort.with_model (list_filter); | 55 | Gtk.ListBox list; |
509 | 57 | list_sort.set_sort_column_id (0, Gtk.SortType.ASCENDING); | 56 | Granite.Widgets.SearchBar search_bar; |
510 | 58 | 57 | Gtk.Entry custom_bar; | |
511 | 59 | list = new Gtk.TreeView.with_model (list_sort); | 58 | |
512 | 60 | list.expand = true; | 59 | public signal void app_chosen (Backend.KeyFile key_file); |
513 | 61 | list.enable_search = false; | 60 | |
514 | 62 | list.headers_visible = false; | 61 | public AppChooser (Gtk.Widget widget) { |
515 | 63 | 62 | Object (relative_to: widget); | |
516 | 64 | Gtk.CellRendererPixbuf pixbuf = new Gtk.CellRendererPixbuf (); | 63 | setup_gui (); |
517 | 65 | list.insert_column_with_attributes (-1, null, pixbuf, "pixbuf", 1); | 64 | connect_signals (); |
518 | 66 | 65 | } | |
519 | 67 | cell = new Gtk.CellRendererText (); | 66 | |
520 | 68 | cell.wrap_mode = Pango.WrapMode.WORD_CHAR; | 67 | void setup_gui () { |
521 | 69 | list.insert_column_with_attributes (-1, null, cell, "markup", 0); | 68 | var grid = new Gtk.Grid (); |
522 | 70 | 69 | grid.margin = 12; | |
523 | 71 | search = new Granite.Widgets.SearchBar (_("Search Applications...")); | 70 | grid.row_spacing = 6; |
524 | 72 | 71 | ||
525 | 73 | scroll = new Gtk.ScrolledWindow (null, null); | 72 | search_bar = new Granite.Widgets.SearchBar (_("Search Applications")); |
526 | 74 | scroll.hscrollbar_policy = Gtk.PolicyType.NEVER; | 73 | |
527 | 75 | scroll.vscrollbar_policy = Gtk.PolicyType.AUTOMATIC; | 74 | var scrolled = new Gtk.ScrolledWindow (null, null); |
528 | 76 | scroll.shadow_type = Gtk.ShadowType.IN; | 75 | scrolled.height_request = 200; |
529 | 77 | scroll.expand = true; | 76 | scrolled.width_request = 250; |
530 | 78 | scroll.height_request = 250; | 77 | scrolled.vscrollbar_policy = Gtk.PolicyType.AUTOMATIC; |
531 | 79 | scroll.width_request = 150; | 78 | scrolled.shadow_type = Gtk.ShadowType.IN; |
532 | 80 | scroll.add (list); | 79 | |
533 | 81 | 80 | list = new Gtk.ListBox (); | |
534 | 82 | Gtk.Box content = get_content_area () as Gtk.Box; | 81 | list.expand = true; |
535 | 83 | content.pack_start (search, false, true, 0); | 82 | list.height_request = 200; |
536 | 84 | content.pack_start (scroll, false, true, 0); | 83 | list.width_request = 150; |
537 | 85 | 84 | list.set_sort_func (sort_function); | |
538 | 86 | command = new Gtk.Entry(); | 85 | list.set_filter_func (filter_function); |
539 | 87 | command.placeholder_text = _("Type in a custom command"); | 86 | scrolled.add (list); |
540 | 88 | command.primary_icon_name = "document-properties-symbolic"; | 87 | |
541 | 89 | command.primary_icon_activatable = false; | 88 | custom_bar = new Gtk.Entry(); |
542 | 90 | content.pack_start (command, false, true, 0); | 89 | custom_bar.placeholder_text = _("Type in a custom command"); |
543 | 91 | 90 | custom_bar.primary_icon_name = "document-properties-symbolic"; | |
544 | 92 | content.spacing = 10; | 91 | custom_bar.primary_icon_activatable = false; |
545 | 93 | 92 | ||
546 | 94 | add_button (Gtk.Stock.CANCEL, Gtk.ResponseType.CLOSE); | 93 | grid.attach (search_bar, 0, 0, 1, 1); |
547 | 95 | apply_button = add_button (Gtk.Stock.ADD, Gtk.ResponseType.APPLY); | 94 | grid.attach (scrolled, 0, 1, 1, 1); |
548 | 96 | apply_button.sensitive = false; | 95 | grid.attach (custom_bar, 0, 2, 1, 1); |
549 | 97 | } | 96 | |
550 | 98 | 97 | add (grid); | |
551 | 99 | void list_update () { | 98 | |
552 | 100 | var enumerator = new Backend.DesktopFileEnumerator ("/usr/share/applications/"); | 99 | list_update (); |
553 | 101 | var names = enumerator.get_desktop_files (); | 100 | } |
554 | 102 | 101 | ||
555 | 103 | foreach (var file in names) { | 102 | void list_update () { |
556 | 104 | var key_file = new Backend.KeyFile (file); | 103 | var enumerator = new Backend.DesktopFileEnumerator ("/usr/share/applications/"); |
557 | 105 | append_item_from_keyfile (key_file); | 104 | var paths = enumerator.get_desktop_files (); |
558 | 106 | } | 105 | |
559 | 107 | } | 106 | foreach (var path in paths) { |
560 | 108 | 107 | var key_file = Backend.KeyFileFactory.get_or_create (path); | |
561 | 109 | void append_item_from_keyfile (Backend.KeyFile key_file) { | 108 | if (key_file.show) |
562 | 110 | if (key_file.dont_show) | 109 | append_item_from_keyfile (key_file); |
445 | 111 | return; | ||
446 | 112 | |||
447 | 113 | Gtk.TreeIter iter; | ||
448 | 114 | list_store.append (out iter); | ||
449 | 115 | list_store.set (iter, 0, key_file.name, | ||
450 | 116 | 1, key_file.create_icon (32), | ||
451 | 117 | 2, key_file); | ||
452 | 118 | } | ||
453 | 119 | |||
454 | 120 | void connect_signals () { | ||
455 | 121 | command.icon_press.connect (() => command.text = ""); | ||
456 | 122 | |||
457 | 123 | command.changed.connect (() => { | ||
458 | 124 | var is_empty = (command.text == ""); | ||
459 | 125 | |||
460 | 126 | scroll.sensitive = is_empty; | ||
461 | 127 | search.sensitive = is_empty; | ||
462 | 128 | command.secondary_icon_sensitive = !is_empty; | ||
463 | 129 | apply_button.sensitive = !is_empty; | ||
464 | 130 | |||
465 | 131 | if (is_empty) { | ||
466 | 132 | command.secondary_icon_name = null; | ||
467 | 133 | list_update (); | ||
468 | 134 | } else { | ||
469 | 135 | list_store.clear (); | ||
470 | 136 | command.secondary_icon_name = "edit-clear-symbolic"; | ||
563 | 137 | } | 110 | } |
629 | 138 | }); | 111 | } |
630 | 139 | 112 | ||
631 | 140 | list.cursor_changed.connect (() => command.activate ()); | 113 | void append_item_from_keyfile (Backend.KeyFile key_file) { |
632 | 141 | response.connect (on_response); | 114 | var app_row = new AppRow (key_file); |
633 | 142 | 115 | list.prepend (app_row); | |
634 | 143 | command.activate.connect (() => { | 116 | } |
635 | 144 | app_chosen(get_app()); | 117 | |
636 | 145 | destroy (); | 118 | int sort_function (Gtk.ListBoxRow list_box_row_1, |
637 | 146 | }); | 119 | Gtk.ListBoxRow list_box_row_2) { |
638 | 147 | 120 | var row_1 = list_box_row_1.get_child () as AppRow; | |
639 | 148 | search.text_changed_pause.connect ((text) => { | 121 | var row_2 = list_box_row_2.get_child () as AppRow; |
640 | 149 | search_text = text; | 122 | |
641 | 150 | list_filter.refilter (); | 123 | var name_1 = row_1.app.name; |
642 | 151 | }); | 124 | var name_2 = row_2.app.name; |
643 | 152 | 125 | ||
644 | 153 | size_allocate.connect ((allocation) => | 126 | return name_1.collate (name_2); |
645 | 154 | cell.wrap_width = allocation.width - (allocation.width / 3)); | 127 | } |
646 | 155 | } | 128 | |
647 | 156 | 129 | bool filter_function (Gtk.ListBoxRow list_box_row) { | |
648 | 157 | private void on_response (Gtk.Dialog source, int response_id) { | 130 | var app_row = list_box_row.get_child () as AppRow; |
649 | 158 | if (response_id == Gtk.ResponseType.APPLY) { | 131 | return search_bar.text.down () in app_row.app.name.down (); |
650 | 159 | app_chosen (get_app()); | 132 | } |
651 | 160 | } | 133 | |
652 | 161 | 134 | void connect_signals () { | |
653 | 162 | destroy (); | 135 | list.row_activated.connect (on_app_selected); |
654 | 163 | } | 136 | search_bar.text_changed_pause.connect (apply_filter); |
655 | 164 | 137 | custom_bar.activate.connect (on_custom_command_entered); | |
656 | 165 | private Backend.KeyFile get_app () { | 138 | } |
657 | 166 | Gtk.TreeIter iter; | 139 | |
658 | 167 | Gtk.TreePath path; | 140 | void on_app_selected (Gtk.ListBoxRow list_box_row) { |
659 | 168 | Backend.KeyFile app = null; | 141 | var app_row = list_box_row.get_child () as AppRow; |
660 | 169 | 142 | app_row.app.copy_to_local (); | |
661 | 170 | list.get_cursor (out path, null); | 143 | app_row.app.active = true; |
662 | 171 | if (path != null) { | 144 | app_chosen (app_row.app); |
663 | 172 | path = list_sort.convert_path_to_child_path (path); | 145 | hide (); |
664 | 173 | path = list_filter.convert_path_to_child_path (path); | 146 | } |
665 | 174 | list_store.get_iter (out iter, path); | 147 | |
666 | 175 | list_store.get (iter, 2, out app); | 148 | void apply_filter () { |
667 | 176 | app.copy_to_local (); | 149 | list.set_filter_func (filter_function); |
668 | 177 | app.active = true; | 150 | } |
669 | 178 | return app; | 151 | |
670 | 179 | } else if (command.text != "" && command.text != null) { | 152 | void on_custom_command_entered () { |
671 | 180 | return create_command (); | 153 | var app = new Backend.KeyFile.from_command (custom_bar.text); |
672 | 181 | } | 154 | app_chosen (app); |
673 | 182 | 155 | hide (); | |
674 | 183 | return (Backend.KeyFile) null; | 156 | } |
610 | 184 | } | ||
611 | 185 | |||
612 | 186 | private bool filter_func (Gtk.TreeModel model, Gtk.TreeIter iter) { | ||
613 | 187 | Backend.KeyFile key_file; | ||
614 | 188 | string name; | ||
615 | 189 | |||
616 | 190 | list_store.get (iter, 2, out key_file); | ||
617 | 191 | name = key_file.name + key_file.comment; | ||
618 | 192 | |||
619 | 193 | if (search_text == "") | ||
620 | 194 | return true; | ||
621 | 195 | else if (name != null) | ||
622 | 196 | return name.up ().contains (search_text.up ()); | ||
623 | 197 | else | ||
624 | 198 | return false; | ||
625 | 199 | } | ||
626 | 200 | |||
627 | 201 | private Backend.KeyFile create_command () { | ||
628 | 202 | return new Backend.KeyFile.from_command (command.text); | ||
675 | 203 | } | 157 | } |
676 | 204 | } | 158 | } |
677 | 205 | \ No newline at end of file | 159 | \ No newline at end of file |
678 | 206 | 160 | ||
679 | === modified file 'src/Plug.vala' | |||
680 | --- src/Plug.vala 2014-03-22 11:07:44 +0000 | |||
681 | +++ src/Plug.vala 2014-04-07 13:03:25 +0000 | |||
682 | @@ -19,67 +19,44 @@ | |||
683 | 19 | 19 | ||
684 | 20 | public Switchboard.Plug get_plug (Module module) { | 20 | public Switchboard.Plug get_plug (Module module) { |
685 | 21 | debug ("Activating Startup Apps plug"); | 21 | debug ("Activating Startup Apps plug"); |
688 | 22 | var plug = new Pantheon.Startup.Plug (); | 22 | return new Pantheon.Startup.Plug (); |
687 | 23 | return plug; | ||
689 | 24 | } | 23 | } |
690 | 25 | 24 | ||
691 | 26 | public class Pantheon.Startup.Plug : Switchboard.Plug { | 25 | public class Pantheon.Startup.Plug : Switchboard.Plug { |
692 | 27 | 26 | ||
697 | 28 | Widgets.List list; | 27 | Gtk.ScrolledWindow scrolled; |
698 | 29 | Widgets.Editor editor; | 28 | |
695 | 30 | Granite.Widgets.ThinPaned paned = null; | ||
696 | 31 | |||
699 | 32 | public Plug () { | 29 | public Plug () { |
700 | 33 | Object (category: Category.PERSONAL, | 30 | Object (category: Category.PERSONAL, |
701 | 34 | code_name: "personal-pantheon-startup", | 31 | code_name: "personal-pantheon-startup", |
702 | 35 | display_name: _("Startup Apps"), | 32 | display_name: _("Startup Apps"), |
703 | 36 | description: _("Shows Startup Applications Settings…"), | 33 | description: _("Shows Startup Applications Settings…"), |
704 | 37 | icon: "preferences-system-session"); | 34 | icon: "preferences-system-session"); |
706 | 38 | 35 | ||
707 | 39 | Backend.KeyFileFactory.init (); | 36 | Backend.KeyFileFactory.init (); |
708 | 40 | } | 37 | } |
709 | 41 | 38 | ||
710 | 42 | public override Gtk.Widget get_widget () { | 39 | public override Gtk.Widget get_widget () { |
715 | 43 | if (paned == null) { | 40 | if (scrolled == null) { |
716 | 44 | setup_gui (); | 41 | scrolled = new Gtk.ScrolledWindow (null, null); |
717 | 45 | connect_signals (); | 42 | var list = new Widgets.List (); |
718 | 46 | initialize_state (); | 43 | scrolled.add (list); |
719 | 47 | } | 44 | } |
720 | 48 | 45 | ||
722 | 49 | return paned; | 46 | return scrolled; |
723 | 50 | } | 47 | } |
725 | 51 | 48 | ||
726 | 52 | public override void shown () { | 49 | public override void shown () { |
727 | 50 | scrolled.show_all (); | ||
728 | 53 | } | 51 | } |
730 | 54 | 52 | ||
731 | 55 | public override void hidden () { | 53 | public override void hidden () { |
732 | 56 | } | 54 | } |
733 | 57 | 55 | ||
734 | 58 | public override void search_callback (string location) { | 56 | public override void search_callback (string location) { |
735 | 59 | } | 57 | } |
736 | 60 | 58 | ||
760 | 61 | public override async Gee.TreeMap<string, string> search (string search) { | 59 | public override async Gee.TreeMap <string, string> search (string search) { |
761 | 62 | return new Gee.TreeMap<string, string> (null, null); | 60 | return new Gee.TreeMap <string, string> (null, null); |
739 | 63 | } | ||
740 | 64 | |||
741 | 65 | void setup_gui () { | ||
742 | 66 | this.list = new Widgets.List (); | ||
743 | 67 | this.editor = new Widgets.Editor (); | ||
744 | 68 | |||
745 | 69 | paned = new Granite.Widgets.ThinPaned (); | ||
746 | 70 | paned.pack1 (list, false, false); | ||
747 | 71 | paned.pack2 (editor, false, false); | ||
748 | 72 | |||
749 | 73 | paned.show_all (); | ||
750 | 74 | } | ||
751 | 75 | |||
752 | 76 | void connect_signals () { | ||
753 | 77 | list.selected.connect ((key_file) => { | ||
754 | 78 | editor.load_key_file (key_file); | ||
755 | 79 | }); | ||
756 | 80 | } | ||
757 | 81 | |||
758 | 82 | void initialize_state () { | ||
759 | 83 | list.select_first_item (); | ||
762 | 84 | } | 61 | } |
763 | 85 | } | 62 | } |
764 | 86 | \ No newline at end of file | 63 | \ No newline at end of file |
765 | 87 | 64 | ||
766 | === removed file 'src/Widgets/Editor.vala' | |||
767 | --- src/Widgets/Editor.vala 2014-03-22 11:07:44 +0000 | |||
768 | +++ src/Widgets/Editor.vala 1970-01-01 00:00:00 +0000 | |||
769 | @@ -1,102 +0,0 @@ | |||
770 | 1 | /*** | ||
771 | 2 | Copyright (C) 2013 Julien Spautz <spautz.julien@gmail.com> | ||
772 | 3 | |||
773 | 4 | This program or library is free software; you can redistribute it | ||
774 | 5 | and/or modify it under the terms of the GNU Lesser General Public | ||
775 | 6 | License as published by the Free Software Foundation; either | ||
776 | 7 | version 3 of the License, or (at your option) any later version. | ||
777 | 8 | |||
778 | 9 | This library is distributed in the hope that it will be useful, | ||
779 | 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
780 | 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
781 | 12 | Lesser General Public License for more details. | ||
782 | 13 | |||
783 | 14 | You should have received a copy of the GNU Lesser General | ||
784 | 15 | Public License along with this library; if not, write to the | ||
785 | 16 | Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | ||
786 | 17 | Boston, MA 02110-1301 USA. | ||
787 | 18 | ***/ | ||
788 | 19 | |||
789 | 20 | public class Pantheon.Startup.Widgets.Editor : Gtk.Grid { | ||
790 | 21 | |||
791 | 22 | public string icon { get; set; } | ||
792 | 23 | |||
793 | 24 | public new string name { | ||
794 | 25 | get { return name_entry.text; } | ||
795 | 26 | set { name_entry.text = value; } | ||
796 | 27 | } | ||
797 | 28 | |||
798 | 29 | public string comment { | ||
799 | 30 | get { return comment_entry.text; } | ||
800 | 31 | set { comment_entry.text = value; } | ||
801 | 32 | } | ||
802 | 33 | |||
803 | 34 | public string command { | ||
804 | 35 | get { return command_entry.text; } | ||
805 | 36 | set { command_entry.text = value; } | ||
806 | 37 | } | ||
807 | 38 | |||
808 | 39 | public bool revive { | ||
809 | 40 | get; set; | ||
810 | 41 | } | ||
811 | 42 | |||
812 | 43 | Backend.KeyFile key_file; | ||
813 | 44 | |||
814 | 45 | Gtk.Entry name_entry; | ||
815 | 46 | Gtk.Entry comment_entry; | ||
816 | 47 | Gtk.Entry command_entry; | ||
817 | 48 | |||
818 | 49 | public Editor () { | ||
819 | 50 | var name_label = new Gtk.Label (_("Name:")); | ||
820 | 51 | name_label.halign = Gtk.Align.END; | ||
821 | 52 | name_entry = new Gtk.Entry (); | ||
822 | 53 | name_entry.placeholder_text = _("Application name"); | ||
823 | 54 | name_entry.width_request = 300; | ||
824 | 55 | name_entry.valign = Gtk.Align.END; | ||
825 | 56 | |||
826 | 57 | var comment_label = new Gtk.Label (_("Description:")); | ||
827 | 58 | comment_label.halign = Gtk.Align.END; | ||
828 | 59 | comment_entry = new Gtk.Entry (); | ||
829 | 60 | comment_entry.placeholder_text = _("Short description"); | ||
830 | 61 | |||
831 | 62 | var command_label = new Gtk.Label (_("Command:")); | ||
832 | 63 | command_label.halign = Gtk.Align.END; | ||
833 | 64 | command_entry = new Gtk.Entry (); | ||
834 | 65 | command_entry.placeholder_text = _("Command to execute"); | ||
835 | 66 | |||
836 | 67 | this.attach (name_label, 0, 0, 1, 1); | ||
837 | 68 | this.attach (name_entry, 1, 0, 1, 1); | ||
838 | 69 | this.attach (comment_label, 0, 1, 1, 1); | ||
839 | 70 | this.attach (comment_entry, 1, 1, 1, 1); | ||
840 | 71 | this.attach (command_label, 0, 2, 1, 1); | ||
841 | 72 | this.attach (command_entry, 1, 2, 1, 1); | ||
842 | 73 | |||
843 | 74 | row_spacing = 6; | ||
844 | 75 | column_spacing = 6; | ||
845 | 76 | margin = 12; | ||
846 | 77 | halign = Gtk.Align.CENTER; | ||
847 | 78 | |||
848 | 79 | name_entry.notify["text"].connect (() => { | ||
849 | 80 | key_file.name = name_entry.text; | ||
850 | 81 | key_file.write_to_file (); | ||
851 | 82 | }); | ||
852 | 83 | |||
853 | 84 | comment_entry.notify["text"].connect (() => { | ||
854 | 85 | key_file.comment = comment_entry.text; | ||
855 | 86 | key_file.write_to_file (); | ||
856 | 87 | }); | ||
857 | 88 | |||
858 | 89 | command_entry.notify["text"].connect (() => { | ||
859 | 90 | key_file.command = command_entry.text; | ||
860 | 91 | key_file.write_to_file (); | ||
861 | 92 | }); | ||
862 | 93 | } | ||
863 | 94 | |||
864 | 95 | public void load_key_file (Backend.KeyFile key_file) { | ||
865 | 96 | this.key_file = key_file; | ||
866 | 97 | |||
867 | 98 | name_entry.text = key_file.name; | ||
868 | 99 | comment_entry.text = key_file.comment; | ||
869 | 100 | command_entry.text = key_file.command; | ||
870 | 101 | } | ||
871 | 102 | } | ||
872 | 103 | \ No newline at end of file | 0 | \ No newline at end of file |
873 | 104 | 1 | ||
874 | === modified file 'src/Widgets/List.vala' | |||
875 | --- src/Widgets/List.vala 2014-03-22 11:07:44 +0000 | |||
876 | +++ src/Widgets/List.vala 2014-04-07 13:03:25 +0000 | |||
877 | @@ -17,187 +17,192 @@ | |||
878 | 17 | Boston, MA 02110-1301 USA. | 17 | Boston, MA 02110-1301 USA. |
879 | 18 | ***/ | 18 | ***/ |
880 | 19 | 19 | ||
890 | 20 | class Pantheon.Startup.Widgets.List : Gtk.Grid { | 20 | class Pantheon.Startup.Widgets.AppRow : Gtk.Box { |
891 | 21 | 21 | ||
892 | 22 | private Gtk.ListStore list_store; | 22 | Gtk.Button delete_button; |
893 | 23 | private Gtk.TreeModelSort sorted_list; | 23 | Gtk.Label label; |
894 | 24 | private Gtk.TreeView list; | 24 | Gtk.Switch active_switch; |
895 | 25 | private Widgets.Toolbar toolbar; | 25 | Gtk.Image image; |
896 | 26 | private Gtk.ScrolledWindow scroll; | 26 | |
897 | 27 | private Gtk.CellRendererToggle toggle; | 27 | public Backend.KeyFile app { get; construct; } |
898 | 28 | 28 | ||
899 | 29 | public signal void deleted (); | ||
900 | 30 | |||
901 | 31 | public AppRow (Backend.KeyFile app) { | ||
902 | 32 | Object (app: app); | ||
903 | 33 | setup (); | ||
904 | 34 | connect_signals (); | ||
905 | 35 | on_active_changed (); | ||
906 | 36 | } | ||
907 | 37 | |||
908 | 38 | void setup () { | ||
909 | 39 | orientation = Gtk.Orientation.HORIZONTAL; | ||
910 | 40 | |||
911 | 41 | var markup = app.create_markup (); | ||
912 | 42 | var icon = app.create_icon (); | ||
913 | 43 | |||
914 | 44 | margin = 6; | ||
915 | 45 | spacing = 12; | ||
916 | 46 | |||
917 | 47 | active_switch = new Gtk.Switch (); | ||
918 | 48 | active_switch.active = app.active; | ||
919 | 49 | add (active_switch); | ||
920 | 50 | |||
921 | 51 | image = new Gtk.Image.from_pixbuf (icon); | ||
922 | 52 | add (image); | ||
923 | 53 | |||
924 | 54 | label = new Gtk.Label (markup); | ||
925 | 55 | label.expand = true; | ||
926 | 56 | label.use_markup = true; | ||
927 | 57 | label.halign = Gtk.Align.START; | ||
928 | 58 | label.ellipsize = Pango.EllipsizeMode.END; | ||
929 | 59 | label.sensitive = app.active; | ||
930 | 60 | add (label); | ||
931 | 61 | |||
932 | 62 | delete_button = new Gtk.Button.with_label (_("Delete")); | ||
933 | 63 | delete_button.get_style_context ().add_class ("destructive-action"); | ||
934 | 64 | delete_button.no_show_all = true; | ||
935 | 65 | delete_button.vexpand = false; | ||
936 | 66 | var button_box = new Gtk.ButtonBox (Gtk.Orientation.HORIZONTAL); | ||
937 | 67 | button_box.add (delete_button); | ||
938 | 68 | add (button_box); | ||
939 | 69 | |||
940 | 70 | show_all (); | ||
941 | 71 | } | ||
942 | 72 | |||
943 | 73 | void connect_signals () { | ||
944 | 74 | delete_button.clicked.connect (on_delete_clicked); | ||
945 | 75 | active_switch.notify["active"].connect (on_active_changed); | ||
946 | 76 | } | ||
947 | 77 | |||
948 | 78 | void on_delete_clicked () { | ||
949 | 79 | app.delete_file (); | ||
950 | 80 | deleted (); | ||
951 | 81 | } | ||
952 | 82 | |||
953 | 83 | void on_active_changed () { | ||
954 | 84 | var active = active_switch.active; | ||
955 | 85 | label.sensitive = active; | ||
956 | 86 | app.active = active; | ||
957 | 87 | app.write_to_file (); | ||
958 | 88 | } | ||
959 | 89 | |||
960 | 90 | public void show_delete (bool show) { | ||
961 | 91 | delete_button.no_show_all = !show; | ||
962 | 92 | delete_button.visible = show; | ||
963 | 93 | } | ||
964 | 94 | } | ||
965 | 95 | |||
966 | 96 | class Pantheon.Startup.Widgets.NewAppRow : Gtk.Box { | ||
967 | 97 | |||
968 | 98 | public signal void app_added (Backend.KeyFile app); | ||
969 | 99 | |||
970 | 100 | public NewAppRow () { | ||
971 | 101 | orientation = Gtk.Orientation.HORIZONTAL; | ||
972 | 102 | |||
973 | 103 | margin = 6; | ||
974 | 104 | spacing = 12; | ||
975 | 105 | |||
976 | 106 | var sw = new Gtk.Switch (); | ||
977 | 107 | sw.opacity = 0.0; | ||
978 | 108 | add (sw); | ||
979 | 109 | |||
980 | 110 | var add_button = new Gtk.Button.from_icon_name ("add", Gtk.IconSize.DIALOG); | ||
981 | 111 | add_button.relief = Gtk.ReliefStyle.NONE; | ||
982 | 112 | add (add_button); | ||
983 | 113 | |||
984 | 114 | var label = new Gtk.Label ("<i>" + _("Add Startup App") + "</i>"); | ||
985 | 115 | label.expand = true; | ||
986 | 116 | label.use_markup = true; | ||
987 | 117 | label.halign = Gtk.Align.START; | ||
988 | 118 | label.ellipsize = Pango.EllipsizeMode.END; | ||
989 | 119 | add (label); | ||
990 | 120 | |||
991 | 121 | var app_chooser = new Dialogs.AppChooser (add_button); | ||
992 | 122 | app_chooser.modal = true; | ||
993 | 123 | |||
994 | 124 | app_chooser.app_chosen.connect ((key_file) => { | ||
995 | 125 | app_added (key_file); | ||
996 | 126 | }); | ||
997 | 127 | |||
998 | 128 | add_button.clicked.connect (app_chooser.show_all); | ||
999 | 129 | } | ||
1000 | 130 | } | ||
1001 | 131 | |||
1002 | 132 | class Pantheon.Startup.Widgets.List : Gtk.ListBox { | ||
1003 | 133 | |||
1004 | 134 | NewAppRow new_app_row; | ||
1005 | 135 | |||
1006 | 136 | public string search_string { get; set; } | ||
1007 | 137 | |||
1008 | 29 | public signal void selected (Backend.KeyFile app); | 138 | public signal void selected (Backend.KeyFile app); |
1009 | 30 | 139 | ||
1010 | 31 | enum Column { | ||
1011 | 32 | ACTIVE, | ||
1012 | 33 | ICON, | ||
1013 | 34 | TEXT, | ||
1014 | 35 | APP, | ||
1015 | 36 | COUNT | ||
1016 | 37 | } | ||
1017 | 38 | |||
1018 | 39 | public List () { | 140 | public List () { |
1108 | 40 | setup_scrolled (); | 141 | setup_gui (); |
1109 | 41 | setup_toolbar (); | 142 | connect_signals (); |
1110 | 42 | 143 | } | |
1111 | 43 | attach (scroll, 0, 0, 1, 1); | 144 | |
1112 | 44 | attach (toolbar, 0, 1, 1, 1); | 145 | void setup_gui () { |
1113 | 45 | 146 | load_startup_apps (); | |
1114 | 46 | setup_signals (); | 147 | add_new_app_row (); |
1115 | 47 | 148 | } | |
1116 | 48 | load_apps (); | 149 | |
1117 | 49 | } | 150 | void connect_signals () { |
1118 | 50 | 151 | row_selected.connect (show_delete_button_on_select); | |
1119 | 51 | void setup_scrolled () { | 152 | set_sort_func (sort_function); |
1120 | 52 | list_store = new Gtk.ListStore (Column.COUNT, | 153 | new_app_row.app_added.connect (add_app); |
1121 | 53 | typeof (bool), | 154 | } |
1122 | 54 | typeof (Gdk.Pixbuf), | 155 | |
1123 | 55 | typeof (string), | 156 | void load_startup_apps () { |
1124 | 56 | typeof (Backend.KeyFile) | 157 | foreach (var path in get_auto_start_files ()) { |
1125 | 57 | ); | 158 | var app = Backend.KeyFileFactory.get_or_create (path); |
1126 | 58 | 159 | add_app (app); | |
1127 | 59 | sorted_list = new Gtk.TreeModelSort.with_model (list_store); | 160 | } |
1128 | 60 | sorted_list.set_sort_column_id (Column.TEXT, Gtk.SortType.ASCENDING); | 161 | } |
1129 | 61 | 162 | ||
1130 | 62 | list = new Gtk.TreeView.with_model (sorted_list); | 163 | void add_new_app_row () { |
1131 | 63 | 164 | new_app_row = new NewAppRow (); | |
1132 | 64 | toggle = new Gtk.CellRendererToggle (); | 165 | prepend (new_app_row); |
1133 | 65 | list.insert_column_with_attributes (-1, null, toggle, "active", Column.ACTIVE); | 166 | } |
1134 | 66 | 167 | ||
1135 | 67 | var pixbuf = new Gtk.CellRendererPixbuf (); | 168 | void show_delete_button_on_select (Gtk.ListBoxRow? selected_list_box_row) { |
1136 | 68 | list.insert_column_with_attributes (-1, null, pixbuf, "pixbuf", Column.ICON); | 169 | this.foreach ((row) => { |
1137 | 69 | 170 | var list_box_row = row as Gtk.ListBoxRow; | |
1138 | 70 | var cell = new Gtk.CellRendererText (); | 171 | var app_row = list_box_row.get_child () as AppRow; |
1139 | 71 | list.insert_column_with_attributes (-1, null, cell, "markup", Column.TEXT); | 172 | if (app_row != null) |
1140 | 72 | 173 | app_row.show_delete (false); | |
1141 | 73 | list.expand = true; | 174 | }); |
1142 | 74 | list.enable_search = false; | 175 | |
1143 | 75 | list.headers_visible = false; | 176 | if (selected_list_box_row != null) { |
1144 | 76 | 177 | var selected_app_row = selected_list_box_row.get_child () as AppRow; | |
1145 | 77 | scroll = new Gtk.ScrolledWindow (null, null); | 178 | selected_app_row.show_delete (true); |
1146 | 78 | scroll.width_request = 300; | 179 | } |
1147 | 79 | scroll.add (list); | 180 | } |
1148 | 80 | } | 181 | |
1149 | 81 | 182 | int sort_function (Gtk.ListBoxRow list_box_row_1, | |
1150 | 82 | void setup_toolbar () { | 183 | Gtk.ListBoxRow list_box_row_2) { |
1151 | 83 | toolbar = new Widgets.Toolbar (); | 184 | var row_1 = list_box_row_1.get_child (); |
1152 | 84 | } | 185 | var row_2 = list_box_row_2.get_child (); |
1153 | 85 | 186 | ||
1154 | 86 | void setup_signals () { | 187 | if (row_1 is NewAppRow) |
1155 | 87 | list.cursor_changed.connect (() => { | 188 | return 1; |
1156 | 88 | Gtk.TreeIter iter; | 189 | if (row_2 is NewAppRow) |
1157 | 89 | Gtk.TreePath tree_path; | 190 | return -1; |
1158 | 90 | GLib.Value app; | 191 | |
1159 | 91 | 192 | var name_1 = (row_1 as AppRow).app.name; | |
1160 | 92 | list.get_cursor (out tree_path, null); | 193 | var name_2 = (row_2 as AppRow).app.name; |
1161 | 93 | list.model.get_iter (out iter, tree_path); | 194 | return name_1.collate (name_2); |
1162 | 94 | list.model.get_value (iter, Column.APP, out app); | 195 | } |
1163 | 95 | 196 | ||
1075 | 96 | selected (app as Backend.KeyFile); | ||
1076 | 97 | }); | ||
1077 | 98 | |||
1078 | 99 | toggle.toggled.connect ((toggle, tree_path_string) => { | ||
1079 | 100 | GLib.Value app; | ||
1080 | 101 | |||
1081 | 102 | Gtk.TreePath tree_path = new Gtk.TreePath.from_string (tree_path_string); | ||
1082 | 103 | list.set_cursor (tree_path, null, false); | ||
1083 | 104 | Gtk.TreeIter iter; | ||
1084 | 105 | tree_path = sorted_list.convert_path_to_child_path (tree_path); | ||
1085 | 106 | |||
1086 | 107 | list_store.get_iter (out iter, tree_path); | ||
1087 | 108 | list_store.set (iter, Column.ACTIVE, !toggle.active); | ||
1088 | 109 | list_store.get_value (iter, Column.APP, out app); | ||
1089 | 110 | |||
1090 | 111 | (app as Backend.KeyFile).active = toggle.active; | ||
1091 | 112 | (app as Backend.KeyFile).write_to_file (); | ||
1092 | 113 | }); | ||
1093 | 114 | |||
1094 | 115 | toolbar.clicked_remove_button.connect (() => { | ||
1095 | 116 | remove_current_app (); | ||
1096 | 117 | }); | ||
1097 | 118 | |||
1098 | 119 | toolbar.clicked_add_button.connect ((key_file) => { | ||
1099 | 120 | add_app (key_file.path); | ||
1100 | 121 | }); | ||
1101 | 122 | } | ||
1102 | 123 | |||
1103 | 124 | void load_apps () { | ||
1104 | 125 | foreach (var file in get_auto_start_files ()) | ||
1105 | 126 | add_app (file); | ||
1106 | 127 | } | ||
1107 | 128 | |||
1164 | 129 | string[] get_auto_start_files () { | 197 | string[] get_auto_start_files () { |
1165 | 130 | var startup_dir = Utils.get_user_startup_dir (); | 198 | var startup_dir = Utils.get_user_startup_dir (); |
1166 | 131 | var enumerator = new Backend.DesktopFileEnumerator (startup_dir); | 199 | var enumerator = new Backend.DesktopFileEnumerator (startup_dir); |
1167 | 132 | return enumerator.get_desktop_files (); | 200 | return enumerator.get_desktop_files (); |
1168 | 133 | } | 201 | } |
1238 | 134 | 202 | ||
1239 | 135 | 203 | public void add_app (Backend.KeyFile app) { | |
1240 | 136 | public void select_first_item () { | 204 | var row = new AppRow (app); |
1241 | 137 | var path = new Gtk.TreePath.from_indices (0); | 205 | prepend (row); |
1242 | 138 | list.set_cursor (path, null, false); | 206 | row.deleted.connect (() => remove (row.parent)); |
1243 | 139 | } | 207 | } |
1175 | 140 | |||
1176 | 141 | public void remove_current_app () { | ||
1177 | 142 | Gtk.TreeIter iter; | ||
1178 | 143 | Gtk.TreePath path; | ||
1179 | 144 | GLib.Value app; | ||
1180 | 145 | |||
1181 | 146 | list.get_cursor (out path, null); | ||
1182 | 147 | path = sorted_list.convert_path_to_child_path (path); | ||
1183 | 148 | |||
1184 | 149 | list_store.get_iter (out iter, path); | ||
1185 | 150 | list_store.get_value (iter, Column.APP, out app); | ||
1186 | 151 | (app as Backend.KeyFile).delete_file (); | ||
1187 | 152 | |||
1188 | 153 | list_store.remove (iter); | ||
1189 | 154 | } | ||
1190 | 155 | |||
1191 | 156 | public void add_app (string path) { | ||
1192 | 157 | Gtk.TreeIter iter; | ||
1193 | 158 | |||
1194 | 159 | var app = Backend.KeyFileFactory.get_or_create (path); | ||
1195 | 160 | var markup = app.create_markup (); | ||
1196 | 161 | var icon = app.create_icon (); | ||
1197 | 162 | |||
1198 | 163 | list_store.append (out iter); | ||
1199 | 164 | list_store.set (iter, | ||
1200 | 165 | Column.ACTIVE, app.active, | ||
1201 | 166 | Column.ICON, icon, | ||
1202 | 167 | Column.TEXT, markup, | ||
1203 | 168 | Column.APP, app | ||
1204 | 169 | ); | ||
1205 | 170 | |||
1206 | 171 | app.notify["name"].connect (() => { | ||
1207 | 172 | update_list_item (iter, path); | ||
1208 | 173 | }); | ||
1209 | 174 | |||
1210 | 175 | app.notify["comment"].connect (() => { | ||
1211 | 176 | update_list_item (iter, path); | ||
1212 | 177 | }); | ||
1213 | 178 | |||
1214 | 179 | app.notify["command"].connect (() => { | ||
1215 | 180 | update_list_item (iter, path); | ||
1216 | 181 | }); | ||
1217 | 182 | } | ||
1218 | 183 | |||
1219 | 184 | void update_list_item (Gtk.TreeIter iter, string path) { | ||
1220 | 185 | var app = Backend.KeyFileFactory.get_or_create (path); | ||
1221 | 186 | var markup = app.create_markup (); | ||
1222 | 187 | var icon = app.create_icon (); | ||
1223 | 188 | |||
1224 | 189 | list_store.set (iter, | ||
1225 | 190 | Column.ACTIVE, app.active, | ||
1226 | 191 | Column.ICON, icon, | ||
1227 | 192 | Column.TEXT, markup, | ||
1228 | 193 | Column.APP, app | ||
1229 | 194 | ); | ||
1230 | 195 | } | ||
1231 | 196 | |||
1232 | 197 | /*Gtk.TreeIter get_iter_from_index (int index) { | ||
1233 | 198 | Gtk.TreeIter iter; | ||
1234 | 199 | var path = new Gtk.TreePath.from_indices (0); | ||
1235 | 200 | list_store.get_iter (out iter, path); | ||
1236 | 201 | return iter; | ||
1237 | 202 | }*/ | ||
1244 | 203 | } | 208 | } |
1245 | 204 | \ No newline at end of file | 209 | \ No newline at end of file |
1246 | 205 | 210 | ||
1247 | === removed file 'src/Widgets/Toolbar.vala' | |||
1248 | --- src/Widgets/Toolbar.vala 2014-03-22 11:07:44 +0000 | |||
1249 | +++ src/Widgets/Toolbar.vala 1970-01-01 00:00:00 +0000 | |||
1250 | @@ -1,61 +0,0 @@ | |||
1251 | 1 | /*** | ||
1252 | 2 | Copyright (C) 2013 Julien Spautz <spautz.julien@gmail.com> | ||
1253 | 3 | |||
1254 | 4 | This program or library is free software; you can redistribute it | ||
1255 | 5 | and/or modify it under the terms of the GNU Lesser General Public | ||
1256 | 6 | License as published by the Free Software Foundation; either | ||
1257 | 7 | version 3 of the License, or (at your option) any later version. | ||
1258 | 8 | |||
1259 | 9 | This library is distributed in the hope that it will be useful, | ||
1260 | 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
1261 | 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
1262 | 12 | Lesser General Public License for more details. | ||
1263 | 13 | |||
1264 | 14 | You should have received a copy of the GNU Lesser General | ||
1265 | 15 | Public License along with this library; if not, write to the | ||
1266 | 16 | Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | ||
1267 | 17 | Boston, MA 02110-1301 USA. | ||
1268 | 18 | ***/ | ||
1269 | 19 | |||
1270 | 20 | class Pantheon.Startup.Widgets.Toolbar : Gtk.Toolbar { | ||
1271 | 21 | |||
1272 | 22 | public signal void clicked_add_button (Backend.KeyFile key_file); | ||
1273 | 23 | public signal void clicked_remove_button (); | ||
1274 | 24 | |||
1275 | 25 | public Toolbar () { | ||
1276 | 26 | set_style (Gtk.ToolbarStyle.ICONS); | ||
1277 | 27 | set_icon_size (Gtk.IconSize.SMALL_TOOLBAR); | ||
1278 | 28 | set_show_arrow (false); | ||
1279 | 29 | get_style_context ().add_class (Gtk.STYLE_CLASS_INLINE_TOOLBAR); | ||
1280 | 30 | get_style_context ().set_junction_sides (Gtk.JunctionSides.TOP); | ||
1281 | 31 | |||
1282 | 32 | var add_button = new Gtk.ToolButton (null, _("Add...")); | ||
1283 | 33 | var remove_button = new Gtk.ToolButton (null, _("Remove")); | ||
1284 | 34 | |||
1285 | 35 | add_button.set_icon_name ("list-add-symbolic"); | ||
1286 | 36 | remove_button.set_icon_name ("list-remove-symbolic"); | ||
1287 | 37 | |||
1288 | 38 | add_button.set_tooltip_text (_("Add...")); | ||
1289 | 39 | remove_button.set_tooltip_text (_("Remove")); | ||
1290 | 40 | |||
1291 | 41 | insert (add_button, -1); | ||
1292 | 42 | insert (remove_button, -1); | ||
1293 | 43 | |||
1294 | 44 | add_button.clicked.connect (() => { | ||
1295 | 45 | var app_chooser = new Dialogs.AppChooser (); | ||
1296 | 46 | app_chooser.modal = true; | ||
1297 | 47 | |||
1298 | 48 | app_chooser.app_chosen.connect ((key_file) => { | ||
1299 | 49 | clicked_add_button (key_file); | ||
1300 | 50 | }); | ||
1301 | 51 | |||
1302 | 52 | app_chooser.move_to_widget (add_button); | ||
1303 | 53 | app_chooser.show_all (); | ||
1304 | 54 | app_chooser.present (); | ||
1305 | 55 | app_chooser.run (); | ||
1306 | 56 | app_chooser.destroy (); | ||
1307 | 57 | }); | ||
1308 | 58 | |||
1309 | 59 | remove_button.clicked.connect (() => clicked_remove_button ()); | ||
1310 | 60 | } | ||
1311 | 61 | } | ||
1312 | 62 | \ No newline at end of file | 0 | \ No newline at end of file |