Merge lp:~matttbe/ubuntu/raring/alacarte/lp1076318 into lp:ubuntu/raring/alacarte
- Raring (13.04)
- lp1076318
- Merge into raring
Proposed by
Matthieu Baerts
Status: | Merged |
---|---|
Merge reported by: | Sebastien Bacher |
Merged at revision: | not available |
Proposed branch: | lp:~matttbe/ubuntu/raring/alacarte/lp1076318 |
Merge into: | lp:ubuntu/raring/alacarte |
Diff against target: |
646 lines (+599/-1) 6 files modified
.pc/50-xdg-menu-prefix.patch/Alacarte/MenuEditor.py (+570/-0) .pc/applied-patches (+1/-0) Alacarte/MenuEditor.py (+1/-1) debian/changelog (+7/-0) debian/patches/50-xdg-menu-prefix.patch (+19/-0) debian/patches/series (+1/-0) |
To merge this branch: | bzr merge lp:~matttbe/ubuntu/raring/alacarte/lp1076318 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Ubuntu Sponsors | Pending | ||
Review via email: mp+133451@code.launchpad.net |
Commit message
Description of the change
Hello,
This new version fixes the bug #1076318. It just includes a patch from upstream GIT repository: http://
Thank you for your help :)
To post a comment you must log in.
Revision history for this message
Sebastien Bacher (seb128) wrote : | # |
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === added directory '.pc/50-xdg-menu-prefix.patch' |
2 | === added directory '.pc/50-xdg-menu-prefix.patch/Alacarte' |
3 | === added file '.pc/50-xdg-menu-prefix.patch/Alacarte/MenuEditor.py' |
4 | --- .pc/50-xdg-menu-prefix.patch/Alacarte/MenuEditor.py 1970-01-01 00:00:00 +0000 |
5 | +++ .pc/50-xdg-menu-prefix.patch/Alacarte/MenuEditor.py 2012-11-08 11:14:24 +0000 |
6 | @@ -0,0 +1,570 @@ |
7 | +# -*- coding: utf-8 -*- |
8 | +# Alacarte Menu Editor - Simple fd.o Compliant Menu Editor |
9 | +# Copyright (C) 2006 Travis Watkins, Heinrich Wendel |
10 | +# |
11 | +# This library is free software; you can redistribute it and/or |
12 | +# modify it under the terms of the GNU Library General Public |
13 | +# License as published by the Free Software Foundation; either |
14 | +# version 2 of the License, or (at your option) any later version. |
15 | +# |
16 | +# This library is distributed in the hope that it will be useful, |
17 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
18 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
19 | +# Library General Public License for more details. |
20 | +# |
21 | +# You should have received a copy of the GNU Library General Public |
22 | +# License along with this library; if not, write to the Free Software |
23 | +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
24 | + |
25 | +import os |
26 | +import xml.dom.minidom |
27 | +import xml.parsers.expat |
28 | +from gi.repository import GMenu, GLib |
29 | +from Alacarte import util |
30 | + |
31 | +class MenuEditor(object): |
32 | + def __init__(self, name=os.environ['XDG_MENU_PREFIX'] + 'applications.menu'): |
33 | + self.name = name |
34 | + |
35 | + self.tree = GMenu.Tree.new(name, GMenu.TreeFlags.SHOW_EMPTY|GMenu.TreeFlags.INCLUDE_EXCLUDED|GMenu.TreeFlags.INCLUDE_NODISPLAY|GMenu.TreeFlags.SHOW_ALL_SEPARATORS|GMenu.TreeFlags.SORT_DISPLAY_NAME) |
36 | + self.tree.connect('changed', self.menuChanged) |
37 | + self.load() |
38 | + |
39 | + self.path = os.path.join(util.getUserMenuPath(), self.tree.props.menu_basename) |
40 | + self.loadDOM() |
41 | + |
42 | + def loadDOM(self): |
43 | + try: |
44 | + self.dom = xml.dom.minidom.parse(self.path) |
45 | + except (IOError, xml.parsers.expat.ExpatError), e: |
46 | + self.dom = xml.dom.minidom.parseString(util.getUserMenuXml(self.tree)) |
47 | + util.removeWhitespaceNodes(self.dom) |
48 | + |
49 | + def load(self): |
50 | + if not self.tree.load_sync(): |
51 | + raise ValueError("can not load menu tree %r" % (self.name,)) |
52 | + |
53 | + def menuChanged(self, *a): |
54 | + self.load() |
55 | + |
56 | + def save(self): |
57 | + fd = open(self.path, 'w') |
58 | + fd.write(self.dom.toprettyxml()) |
59 | + fd.close() |
60 | + |
61 | + def restoreToSystem(self): |
62 | + self.restoreTree(self.tree.get_root_directory()) |
63 | + path = os.path.join(util.getUserMenuPath(), os.path.basename(self.tree.get_canonical_menu_path())) |
64 | + try: |
65 | + os.unlink(path) |
66 | + except OSError: |
67 | + pass |
68 | + |
69 | + self.loadDOM() |
70 | + self.save() |
71 | + |
72 | + def restoreTree(self, menu): |
73 | + item_iter = menu.iter() |
74 | + item_type = item_iter.next() |
75 | + while item_type != GMenu.TreeItemType.INVALID: |
76 | + if item_type == GMenu.TreeItemType.DIRECTORY: |
77 | + item = item_iter.get_directory() |
78 | + self.restoreTree(item) |
79 | + elif item_type == GMenu.TreeItemType.ENTRY: |
80 | + item = item_iter.get_entry() |
81 | + self.restoreItem(item) |
82 | + item_type = item_iter.next() |
83 | + self.restoreMenu(menu) |
84 | + |
85 | + def restoreItem(self, item): |
86 | + if not self.canRevert(item): |
87 | + return |
88 | + try: |
89 | + os.remove(item.get_desktop_file_path()) |
90 | + except OSError: |
91 | + pass |
92 | + self.save() |
93 | + |
94 | + def restoreMenu(self, menu): |
95 | + if not self.canRevert(menu): |
96 | + return |
97 | + #wtf happened here? oh well, just bail |
98 | + if not menu.get_desktop_file_path(): |
99 | + return |
100 | + file_id = os.path.split(menu.get_desktop_file_path())[1] |
101 | + path = os.path.join(util.getUserDirectoryPath(), file_id) |
102 | + try: |
103 | + os.remove(path) |
104 | + except OSError: |
105 | + pass |
106 | + self.save() |
107 | + |
108 | + def getMenus(self, parent): |
109 | + if parent is None: |
110 | + yield (self.tree.get_root_directory(), True) |
111 | + return |
112 | + |
113 | + item_iter = parent.iter() |
114 | + item_type = item_iter.next() |
115 | + while item_type != GMenu.TreeItemType.INVALID: |
116 | + if item_type == GMenu.TreeItemType.DIRECTORY: |
117 | + item = item_iter.get_directory() |
118 | + yield (item, self.isVisible(item)) |
119 | + item_type = item_iter.next() |
120 | + |
121 | + def getContents(self, item): |
122 | + contents = [] |
123 | + item_iter = item.iter() |
124 | + item_type = item_iter.next() |
125 | + |
126 | + while item_type != GMenu.TreeItemType.INVALID: |
127 | + item = None |
128 | + if item_type == GMenu.TreeItemType.DIRECTORY: |
129 | + item = item_iter.get_directory() |
130 | + elif item_type == GMenu.TreeItemType.ENTRY: |
131 | + item = item_iter.get_entry() |
132 | + elif item_type == GMenu.TreeItemType.HEADER: |
133 | + item = item_iter.get_header() |
134 | + elif item_type == GMenu.TreeItemType.ALIAS: |
135 | + item = item_iter.get_alias() |
136 | + elif item_type == GMenu.TreeItemType.SEPARATOR: |
137 | + item = item_iter.get_separator() |
138 | + if item: |
139 | + contents.append(item) |
140 | + item_type = item_iter.next() |
141 | + return contents |
142 | + |
143 | + def getItems(self, menu): |
144 | + item_iter = menu.iter() |
145 | + item_type = item_iter.next() |
146 | + while item_type != GMenu.TreeItemType.INVALID: |
147 | + item = None |
148 | + if item_type == GMenu.TreeItemType.ENTRY: |
149 | + item = item_iter.get_entry() |
150 | + elif item_type == GMenu.TreeItemType.DIRECTORY: |
151 | + item = item_iter.get_directory() |
152 | + elif item_type == GMenu.TreeItemType.HEADER: |
153 | + item = item_iter.get_header() |
154 | + elif item_type == GMenu.TreeItemType.ALIAS: |
155 | + item = item_iter.get_alias() |
156 | + elif item_type == GMenu.TreeItemType.SEPARATOR: |
157 | + item = item_iter.get_separator() |
158 | + yield (item, self.isVisible(item)) |
159 | + item_type = item_iter.next() |
160 | + |
161 | + def canRevert(self, item): |
162 | + if isinstance(item, GMenu.TreeEntry): |
163 | + if util.getItemPath(item.get_desktop_file_id()) is not None: |
164 | + path = util.getUserItemPath() |
165 | + if os.path.isfile(os.path.join(path, item.get_desktop_file_id())): |
166 | + return True |
167 | + elif isinstance(item, GMenu.TreeDirectory): |
168 | + if item.get_desktop_file_path(): |
169 | + file_id = os.path.split(item.get_desktop_file_path())[1] |
170 | + else: |
171 | + file_id = item.get_menu_id() + '.directory' |
172 | + if util.getDirectoryPath(file_id) is not None: |
173 | + path = util.getUserDirectoryPath() |
174 | + if os.path.isfile(os.path.join(path, file_id)): |
175 | + return True |
176 | + return False |
177 | + |
178 | + def setVisible(self, item, visible): |
179 | + dom = self.dom |
180 | + if isinstance(item, GMenu.TreeEntry): |
181 | + menu_xml = self.getXmlMenu(self.getPath(item.get_parent()), dom.documentElement, dom) |
182 | + if visible: |
183 | + self.addXmlFilename(menu_xml, dom, item.get_desktop_file_id(), 'Include') |
184 | + self.writeItem(item, NoDisplay=False) |
185 | + else: |
186 | + self.addXmlFilename(menu_xml, dom, item.get_desktop_file_id(), 'Exclude') |
187 | + self.addXmlTextElement(menu_xml, 'AppDir', util.getUserItemPath(), dom) |
188 | + elif isinstance(item, GMenu.TreeDirectory): |
189 | + item_iter = item.iter() |
190 | + first_child_type = item_iter.next() |
191 | + #don't mess with it if it's empty |
192 | + if first_child_type == GMenu.TreeItemType.INVALID: |
193 | + return |
194 | + menu_xml = self.getXmlMenu(self.getPath(item), dom.documentElement, dom) |
195 | + for node in self.getXmlNodesByName(['Deleted', 'NotDeleted'], menu_xml): |
196 | + node.parentNode.removeChild(node) |
197 | + self.writeMenu(item, NoDisplay=not visible) |
198 | + self.addXmlTextElement(menu_xml, 'DirectoryDir', util.getUserDirectoryPath(), dom) |
199 | + self.save() |
200 | + |
201 | + def createItem(self, parent, before, after, **kwargs): |
202 | + file_id = self.writeItem(None, **kwargs) |
203 | + self.insertExternalItem(file_id, parent.get_menu_id(), before, after) |
204 | + |
205 | + def insertExternalItem(self, file_id, parent_id, before=None, after=None): |
206 | + parent = self.findMenu(parent_id) |
207 | + dom = self.dom |
208 | + self.addItem(parent, file_id, dom) |
209 | + self.positionItem(parent, ('Item', file_id), before, after) |
210 | + self.save() |
211 | + |
212 | + def insertExternalMenu(self, file_id, parent_id, before=None, after=None): |
213 | + menu_id = file_id.rsplit('.', 1)[0] |
214 | + parent = self.findMenu(parent_id) |
215 | + dom = self.dom |
216 | + self.addXmlDefaultLayout(self.getXmlMenu(self.getPath(parent), dom.documentElement, dom) , dom) |
217 | + menu_xml = self.getXmlMenu(self.getPath(parent) + [menu_id], dom.documentElement, dom) |
218 | + self.addXmlTextElement(menu_xml, 'Directory', file_id, dom) |
219 | + self.positionItem(parent, ('Menu', menu_id), before, after) |
220 | + self.save() |
221 | + |
222 | + def createSeparator(self, parent, before=None, after=None): |
223 | + self.positionItem(parent, ('Separator',), before, after) |
224 | + self.save() |
225 | + |
226 | + def editItem(self, item, icon, name, comment, command, use_term, parent=None, final=True): |
227 | + #if nothing changed don't make a user copy |
228 | + app_info = item.get_app_info() |
229 | + if icon == app_info.get_icon() and name == app_info.get_display_name() and comment == item.get_comment() and command == item.get_exec() and use_term == item.get_launch_in_terminal(): |
230 | + return |
231 | + #hack, item.get_parent() seems to fail a lot |
232 | + if not parent: |
233 | + parent = item.get_parent() |
234 | + self.writeItem(item, Icon=icon, Name=name, Comment=comment, Exec=command, Terminal=use_term) |
235 | + if final: |
236 | + dom = self.dom |
237 | + menu_xml = self.getXmlMenu(self.getPath(parent), dom.documentElement, dom) |
238 | + self.addXmlTextElement(menu_xml, 'AppDir', util.getUserItemPath(), dom) |
239 | + self.save() |
240 | + |
241 | + def editMenu(self, menu, icon, name, comment, final=True): |
242 | + #if nothing changed don't make a user copy |
243 | + if icon == menu.get_icon() and name == menu.get_name() and comment == menu.get_comment(): |
244 | + return |
245 | + #we don't use this, we just need to make sure the <Menu> exists |
246 | + #otherwise changes won't show up |
247 | + dom = self.dom |
248 | + menu_xml = self.getXmlMenu(self.getPath(menu), dom.documentElement, dom) |
249 | + self.writeMenu(menu, Icon=icon, Name=name, Comment=comment) |
250 | + if final: |
251 | + self.addXmlTextElement(menu_xml, 'DirectoryDir', util.getUserDirectoryPath(), dom) |
252 | + self.save() |
253 | + |
254 | + def copyItem(self, item, new_parent, before=None, after=None): |
255 | + dom = self.dom |
256 | + file_path = item.get_desktop_file_path() |
257 | + keyfile = GLib.KeyFile() |
258 | + keyfile.load_from_file(file_path, util.KEY_FILE_FLAGS) |
259 | + |
260 | + util.fillKeyFile(keyfile, dict(Categories=[], Hidden=False)) |
261 | + |
262 | + app_info = item.get_app_info() |
263 | + file_id = util.getUniqueFileId(app_info.get_name().replace(os.sep, '-'), '.desktop') |
264 | + out_path = os.path.join(util.getUserItemPath(), file_id) |
265 | + |
266 | + contents, length = keyfile.to_data() |
267 | + |
268 | + f = open(out_path, 'w') |
269 | + f.write(contents) |
270 | + f.close() |
271 | + |
272 | + self.addItem(new_parent, file_id, dom) |
273 | + self.positionItem(new_parent, ('Item', file_id), before, after) |
274 | + self.save() |
275 | + return file_id |
276 | + |
277 | + def deleteItem(self, item): |
278 | + self.writeItem(item, Hidden=True) |
279 | + self.save() |
280 | + |
281 | + def deleteMenu(self, menu): |
282 | + dom = self.dom |
283 | + menu_xml = self.getXmlMenu(self.getPath(menu), dom.documentElement, dom) |
284 | + self.addDeleted(menu_xml, dom) |
285 | + self.save() |
286 | + |
287 | + def deleteSeparator(self, item): |
288 | + parent = item.get_parent() |
289 | + contents = self.getContents(parent) |
290 | + contents.remove(item) |
291 | + layout = self.createLayout(contents) |
292 | + dom = self.dom |
293 | + menu_xml = self.getXmlMenu(self.getPath(parent), dom.documentElement, dom) |
294 | + self.addXmlLayout(menu_xml, layout, dom) |
295 | + self.save() |
296 | + |
297 | + def findMenu(self, menu_id, parent=None): |
298 | + if parent is None: |
299 | + parent = self.tree.get_root_directory() |
300 | + |
301 | + if menu_id == parent.get_menu_id(): |
302 | + return parent |
303 | + |
304 | + item_iter = parent.iter() |
305 | + item_type = item_iter.next() |
306 | + while item_type != GMenu.TreeItemType.INVALID: |
307 | + if item_type == GMenu.TreeItemType.DIRECTORY: |
308 | + item = item_iter.get_directory() |
309 | + if item.get_menu_id() == menu_id: |
310 | + return item |
311 | + menu = self.findMenu(menu_id, item) |
312 | + if menu is not None: |
313 | + return menu |
314 | + item_type = item_iter.next() |
315 | + |
316 | + def isVisible(self, item): |
317 | + if isinstance(item, GMenu.TreeEntry): |
318 | + app_info = item.get_app_info() |
319 | + return not (item.get_is_excluded() or app_info.get_nodisplay()) |
320 | + elif isinstance(item, GMenu.TreeDirectory): |
321 | + return not item.get_is_nodisplay() |
322 | + return True |
323 | + |
324 | + def getPath(self, menu): |
325 | + names = [] |
326 | + current = menu |
327 | + while current is not None: |
328 | + names.append(current.get_menu_id()) |
329 | + current = current.get_parent() |
330 | + |
331 | + # XXX - don't append root menu name, alacarte doesn't |
332 | + # expect it. look into this more. |
333 | + names.pop(-1) |
334 | + return names[::-1] |
335 | + |
336 | + def getXmlMenuPart(self, element, name): |
337 | + for node in self.getXmlNodesByName('Menu', element): |
338 | + for child in self.getXmlNodesByName('Name', node): |
339 | + if child.childNodes[0].nodeValue == name: |
340 | + return node |
341 | + return None |
342 | + |
343 | + def getXmlMenu(self, path, element, dom): |
344 | + for name in path: |
345 | + found = self.getXmlMenuPart(element, name) |
346 | + if found is not None: |
347 | + element = found |
348 | + else: |
349 | + element = self.addXmlMenuElement(element, name, dom) |
350 | + return element |
351 | + |
352 | + def addXmlMenuElement(self, element, name, dom): |
353 | + node = dom.createElement('Menu') |
354 | + self.addXmlTextElement(node, 'Name', name, dom) |
355 | + return element.appendChild(node) |
356 | + |
357 | + def addXmlTextElement(self, element, name, text, dom): |
358 | + for temp in element.childNodes: |
359 | + if temp.nodeName == name: |
360 | + if temp.childNodes[0].nodeValue == text: |
361 | + return |
362 | + node = dom.createElement(name) |
363 | + text = dom.createTextNode(text) |
364 | + node.appendChild(text) |
365 | + return element.appendChild(node) |
366 | + |
367 | + def addXmlFilename(self, element, dom, filename, type = 'Include'): |
368 | + # remove old filenames |
369 | + for node in self.getXmlNodesByName(['Include', 'Exclude'], element): |
370 | + if node.childNodes[0].nodeName == 'Filename' and node.childNodes[0].childNodes[0].nodeValue == filename: |
371 | + element.removeChild(node) |
372 | + |
373 | + # add new filename |
374 | + node = dom.createElement(type) |
375 | + node.appendChild(self.addXmlTextElement(node, 'Filename', filename, dom)) |
376 | + return element.appendChild(node) |
377 | + |
378 | + def addDeleted(self, element, dom): |
379 | + node = dom.createElement('Deleted') |
380 | + return element.appendChild(node) |
381 | + |
382 | + def makeKeyFile(self, file_path, kwargs): |
383 | + if 'KeyFile' in kwargs: |
384 | + return kwargs['KeyFile'] |
385 | + |
386 | + keyfile = GLib.KeyFile() |
387 | + |
388 | + if file_path is not None: |
389 | + keyfile.load_from_file(file_path, util.KEY_FILE_FLAGS) |
390 | + |
391 | + util.fillKeyFile(keyfile, kwargs) |
392 | + return keyfile |
393 | + |
394 | + def writeItem(self, item, **kwargs): |
395 | + if item is not None: |
396 | + file_path = item.get_desktop_file_path() |
397 | + else: |
398 | + file_path = None |
399 | + |
400 | + keyfile = self.makeKeyFile(file_path, kwargs) |
401 | + |
402 | + if item is not None: |
403 | + file_id = item.get_desktop_file_id() |
404 | + else: |
405 | + file_id = util.getUniqueFileId(keyfile.get_string(GLib.KEY_FILE_DESKTOP_GROUP, 'Name'), '.desktop') |
406 | + |
407 | + contents, length = keyfile.to_data() |
408 | + |
409 | + f = open(os.path.join(util.getUserItemPath(), file_id), 'w') |
410 | + f.write(contents) |
411 | + f.close() |
412 | + return file_id |
413 | + |
414 | + def writeMenu(self, menu, **kwargs): |
415 | + if menu is not None: |
416 | + file_id = os.path.split(menu.get_desktop_file_path())[1] |
417 | + file_path = menu.get_desktop_file_path() |
418 | + keyfile = GLib.KeyFile() |
419 | + keyfile.load_from_file(file_path, util.KEY_FILE_FLAGS) |
420 | + elif menu is None and 'Name' not in kwargs: |
421 | + raise Exception('New menus need a name') |
422 | + else: |
423 | + file_id = util.getUniqueFileId(kwargs['Name'], '.directory') |
424 | + keyfile = GLib.KeyFile() |
425 | + |
426 | + util.fillKeyFile(keyfile, kwargs) |
427 | + |
428 | + contents, length = keyfile.to_data() |
429 | + |
430 | + f = open(os.path.join(util.getUserDirectoryPath(), file_id), 'w') |
431 | + f.write(contents) |
432 | + f.close() |
433 | + return file_id |
434 | + |
435 | + def getXmlNodesByName(self, name, element): |
436 | + for child in element.childNodes: |
437 | + if child.nodeType == xml.dom.Node.ELEMENT_NODE: |
438 | + if isinstance(name, str) and child.nodeName == name: |
439 | + yield child |
440 | + elif isinstance(name, list) or isinstance(name, tuple): |
441 | + if child.nodeName in name: |
442 | + yield child |
443 | + |
444 | + def addXmlMove(self, element, old, new, dom): |
445 | + if not self.undoMoves(element, old, new, dom): |
446 | + node = dom.createElement('Move') |
447 | + node.appendChild(self.addXmlTextElement(node, 'Old', old, dom)) |
448 | + node.appendChild(self.addXmlTextElement(node, 'New', new, dom)) |
449 | + #are parsed in reverse order, need to put at the beginning |
450 | + return element.insertBefore(node, element.firstChild) |
451 | + |
452 | + def addXmlLayout(self, element, layout, dom): |
453 | + # remove old layout |
454 | + for node in self.getXmlNodesByName('Layout', element): |
455 | + element.removeChild(node) |
456 | + |
457 | + # add new layout |
458 | + node = dom.createElement('Layout') |
459 | + for order in layout: |
460 | + if order[0] == 'Separator': |
461 | + child = dom.createElement('Separator') |
462 | + node.appendChild(child) |
463 | + elif order[0] == 'Filename': |
464 | + child = self.addXmlTextElement(node, 'Filename', order[1], dom) |
465 | + elif order[0] == 'Menuname': |
466 | + child = self.addXmlTextElement(node, 'Menuname', order[1], dom) |
467 | + elif order[0] == 'Merge': |
468 | + child = dom.createElement('Merge') |
469 | + child.setAttribute('type', order[1]) |
470 | + node.appendChild(child) |
471 | + return element.appendChild(node) |
472 | + |
473 | + def addXmlDefaultLayout(self, element, dom): |
474 | + # remove old default layout |
475 | + for node in self.getXmlNodesByName('DefaultLayout', element): |
476 | + element.removeChild(node) |
477 | + |
478 | + # add new layout |
479 | + node = dom.createElement('DefaultLayout') |
480 | + node.setAttribute('inline', 'false') |
481 | + return element.appendChild(node) |
482 | + |
483 | + def createLayout(self, items): |
484 | + layout = [] |
485 | + layout.append(('Merge', 'menus')) |
486 | + for item in items: |
487 | + if isinstance(item, GMenu.TreeDirectory): |
488 | + layout.append(('Menuname', item.get_menu_id())) |
489 | + elif isinstance(item, GMenu.TreeEntry): |
490 | + layout.append(('Filename', item.get_desktop_file_id())) |
491 | + elif isinstance(item, GMenu.TreeSeparator): |
492 | + layout.append(('Separator',)) |
493 | + else: |
494 | + layout.append(item) |
495 | + layout.append(('Merge', 'files')) |
496 | + return layout |
497 | + |
498 | + def addItem(self, parent, file_id, dom): |
499 | + xml_parent = self.getXmlMenu(self.getPath(parent), dom.documentElement, dom) |
500 | + self.addXmlFilename(xml_parent, dom, file_id, 'Include') |
501 | + |
502 | + def moveItem(self, parent, item, before=None, after=None): |
503 | + self.positionItem(parent, item, before=before, after=after) |
504 | + self.save() |
505 | + |
506 | + def positionItem(self, parent, item, before=None, after=None): |
507 | + contents = self.getContents(parent) |
508 | + if after: |
509 | + index = contents.index(after) + 1 |
510 | + elif before: |
511 | + index = contents.index(before) |
512 | + else: |
513 | + # append the item to the list |
514 | + index = len(contents) |
515 | + #if this is a move to a new parent you can't remove the item |
516 | + if item in contents: |
517 | + # decrease the destination index, if we shorten the list |
518 | + if (before and (contents.index(item) < index)) \ |
519 | + or (after and (contents.index(item) < index - 1)): |
520 | + index -= 1 |
521 | + contents.remove(item) |
522 | + contents.insert(index, item) |
523 | + layout = self.createLayout(contents) |
524 | + dom = self.dom |
525 | + menu_xml = self.getXmlMenu(self.getPath(parent), dom.documentElement, dom) |
526 | + self.addXmlLayout(menu_xml, layout, dom) |
527 | + |
528 | + def undoMoves(self, element, old, new, dom): |
529 | + nodes = [] |
530 | + matches = [] |
531 | + original_old = old |
532 | + final_old = old |
533 | + #get all <Move> elements |
534 | + for node in self.getXmlNodesByName(['Move'], element): |
535 | + nodes.insert(0, node) |
536 | + #if the <New> matches our old parent we've found a stage to undo |
537 | + for node in nodes: |
538 | + xml_old = node.getElementsByTagName('Old')[0] |
539 | + xml_new = node.getElementsByTagName('New')[0] |
540 | + if xml_new.childNodes[0].nodeValue == old: |
541 | + matches.append(node) |
542 | + #we should end up with this path when completed |
543 | + final_old = xml_old.childNodes[0].nodeValue |
544 | + #undoing <Move>s |
545 | + for node in matches: |
546 | + element.removeChild(node) |
547 | + if len(matches) > 0: |
548 | + for node in nodes: |
549 | + xml_old = node.getElementsByTagName('Old')[0] |
550 | + xml_new = node.getElementsByTagName('New')[0] |
551 | + path = os.path.split(xml_new.childNodes[0].nodeValue) |
552 | + if path[0] == original_old: |
553 | + element.removeChild(node) |
554 | + for node in dom.getElementsByTagName('Menu'): |
555 | + name_node = node.getElementsByTagName('Name')[0] |
556 | + name = name_node.childNodes[0].nodeValue |
557 | + if name == os.path.split(new)[1]: |
558 | + #copy app and dir directory info from old <Menu> |
559 | + root_path = dom.getElementsByTagName('Menu')[0].getElementsByTagName('Name')[0].childNodes[0].nodeValue |
560 | + xml_menu = self.getXmlMenu(root_path + '/' + new, dom.documentElement, dom) |
561 | + for app_dir in node.getElementsByTagName('AppDir'): |
562 | + xml_menu.appendChild(app_dir) |
563 | + for dir_dir in node.getElementsByTagName('DirectoryDir'): |
564 | + xml_menu.appendChild(dir_dir) |
565 | + parent = node.parentNode |
566 | + parent.removeChild(node) |
567 | + node = dom.createElement('Move') |
568 | + node.appendChild(self.addXmlTextElement(node, 'Old', xml_old.childNodes[0].nodeValue, dom)) |
569 | + node.appendChild(self.addXmlTextElement(node, 'New', os.path.join(new, path[1]), dom)) |
570 | + element.appendChild(node) |
571 | + if final_old == new: |
572 | + return True |
573 | + node = dom.createElement('Move') |
574 | + node.appendChild(self.addXmlTextElement(node, 'Old', final_old, dom)) |
575 | + node.appendChild(self.addXmlTextElement(node, 'New', new, dom)) |
576 | + return element.appendChild(node) |
577 | |
578 | === modified file '.pc/applied-patches' |
579 | --- .pc/applied-patches 2012-11-06 13:34:28 +0000 |
580 | +++ .pc/applied-patches 2012-11-08 11:14:24 +0000 |
581 | @@ -1,3 +1,4 @@ |
582 | 03-bind_textdomain_codeset.patch |
583 | 30-python_private_dir.patch |
584 | 40-call-exo-d-i-e-on-xfce.patch |
585 | +50-xdg-menu-prefix.patch |
586 | |
587 | === modified file 'Alacarte/MenuEditor.py' |
588 | --- Alacarte/MenuEditor.py 2012-11-06 13:34:28 +0000 |
589 | +++ Alacarte/MenuEditor.py 2012-11-08 11:14:24 +0000 |
590 | @@ -23,7 +23,7 @@ |
591 | from Alacarte import util |
592 | |
593 | class MenuEditor(object): |
594 | - def __init__(self, name=os.environ['XDG_MENU_PREFIX'] + 'applications.menu'): |
595 | + def __init__(self, name=os.environ.get('XDG_MENU_PREFIX', '') + 'applications.menu'): |
596 | self.name = name |
597 | |
598 | self.tree = GMenu.Tree.new(name, GMenu.TreeFlags.SHOW_EMPTY|GMenu.TreeFlags.INCLUDE_EXCLUDED|GMenu.TreeFlags.INCLUDE_NODISPLAY|GMenu.TreeFlags.SHOW_ALL_SEPARATORS|GMenu.TreeFlags.SORT_DISPLAY_NAME) |
599 | |
600 | === modified file 'debian/changelog' |
601 | --- debian/changelog 2012-11-06 13:34:28 +0000 |
602 | +++ debian/changelog 2012-11-08 11:14:24 +0000 |
603 | @@ -1,3 +1,10 @@ |
604 | +alacarte (3.6.1-0ubuntu2) raring; urgency=low |
605 | + |
606 | + * debian/patches/50-xdg-menu-prefix.patch: |
607 | + - deal with the case of having no $XDG_MENU_PREFIX (LP: #1076318) |
608 | + |
609 | + -- Matthieu Baerts (matttbe) <matttbe@ubuntu.com> Thu, 08 Nov 2012 12:07:16 +0100 |
610 | + |
611 | alacarte (3.6.1-0ubuntu1) raring; urgency=low |
612 | |
613 | * New upstream version |
614 | |
615 | === added file 'debian/patches/50-xdg-menu-prefix.patch' |
616 | --- debian/patches/50-xdg-menu-prefix.patch 1970-01-01 00:00:00 +0000 |
617 | +++ debian/patches/50-xdg-menu-prefix.patch 2012-11-08 11:14:24 +0000 |
618 | @@ -0,0 +1,19 @@ |
619 | +From fe7211f2eb4c8bcf7cbddca75bf4e28ee7b98659 Mon Sep 17 00:00:00 2001 |
620 | +From: Jasper St. Pierre <jstpierre@mecheye.net> |
621 | +Date: Tue, 23 Oct 2012 03:08:38 +0000 |
622 | +Subject: MenuEditor: deal with the case of having no $XDG_MENU_PREFIX |
623 | + |
624 | +--- |
625 | +Index: alacarte/Alacarte/MenuEditor.py |
626 | +=================================================================== |
627 | +--- alacarte.orig/Alacarte/MenuEditor.py 2012-11-08 11:59:35.600092000 +0100 |
628 | ++++ alacarte/Alacarte/MenuEditor.py 2012-11-08 12:01:29.810085416 +0100 |
629 | +@@ -23,7 +23,7 @@ |
630 | + from Alacarte import util |
631 | + |
632 | + class MenuEditor(object): |
633 | +- def __init__(self, name=os.environ['XDG_MENU_PREFIX'] + 'applications.menu'): |
634 | ++ def __init__(self, name=os.environ.get('XDG_MENU_PREFIX', '') + 'applications.menu'): |
635 | + self.name = name |
636 | + |
637 | + self.tree = GMenu.Tree.new(name, GMenu.TreeFlags.SHOW_EMPTY|GMenu.TreeFlags.INCLUDE_EXCLUDED|GMenu.TreeFlags.INCLUDE_NODISPLAY|GMenu.TreeFlags.SHOW_ALL_SEPARATORS|GMenu.TreeFlags.SORT_DISPLAY_NAME) |
638 | |
639 | === modified file 'debian/patches/series' |
640 | --- debian/patches/series 2012-11-06 13:34:28 +0000 |
641 | +++ debian/patches/series 2012-11-08 11:14:24 +0000 |
642 | @@ -1,3 +1,4 @@ |
643 | 03-bind_textdomain_codeset.patch |
644 | 30-python_private_dir.patch |
645 | 40-call-exo-d-i-e-on-xfce.patch |
646 | +50-xdg-menu-prefix.patch |
Thank you for your work!