1 # -*- coding: utf-8 -*-
2 # vim: set noexpandtab:
3 # Alacarte Menu Editor - Simple fd.o Compliant Menu Editor
4 # Copyright (C) 2006 Travis Watkins
6 # This library is free software; you can redistribute it and/or
7 # modify it under the terms of the GNU Library General Public
8 # License as published by the Free Software Foundation; either
9 # version 2 of the License, or (at your option) any later version.
11 # This library is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 # Library General Public License for more details.
16 # You should have received a copy of the GNU Library General Public
17 # License along with this library; if not, write to the Free Software
18 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 from gi
.repository
import Gtk
, GObject
, Gio
, GdkPixbuf
, Gdk
, GMenu
26 from Alacarte
import config
27 gettext
.bindtextdomain(config
.GETTEXT_PACKAGE
,config
.localedir
)
28 gettext
.textdomain(config
.GETTEXT_PACKAGE
)
32 from Alacarte
.MenuEditor
import MenuEditor
33 from Alacarte
import util
35 from traceback
import print_stack
39 #hack to make editing menu properties work
42 dnd_items
= [('ALACARTE_ITEM_ROW', Gtk
.TargetFlags
.SAME_APP
, 0), ('text/plain', 0, 1)]
43 dnd_menus
= [('ALACARTE_MENU_ROW', Gtk
.TargetFlags
.SAME_APP
, 0)]
44 dnd_both
= [dnd_items
[0],] + dnd_menus
48 def __init__(self
, datadir
, version
, argv
):
49 self
.file_path
= datadir
50 self
.version
= version
51 self
.editor
= MenuEditor()
52 Gtk
.Window
.set_default_icon_name('alacarte')
53 self
.tree
= Gtk
.Builder()
54 self
.tree
.set_translation_domain(config
.GETTEXT_PACKAGE
)
55 self
.tree
.add_from_file(os
.path
.join(self
.file_path
, 'alacarte.ui'))
56 self
.tree
.connect_signals(self
)
59 self
.tree
.get_object('edit_delete').set_sensitive(False)
60 self
.tree
.get_object('edit_revert_to_original').set_sensitive(False)
61 self
.tree
.get_object('edit_properties').set_sensitive(False)
62 self
.tree
.get_object('move_up_button').set_sensitive(False)
63 self
.tree
.get_object('move_down_button').set_sensitive(False)
64 self
.tree
.get_object('new_separator_button').set_sensitive(False)
65 accelgroup
= Gtk
.AccelGroup()
66 keyval
, modifier
= Gtk
.accelerator_parse('<Ctrl>Z')
67 accelgroup
.connect(keyval
, modifier
, Gtk
.AccelFlags
.VISIBLE
, self
.on_mainwindow_undo
)
68 keyval
, modifier
= Gtk
.accelerator_parse('<Ctrl><Shift>Z')
69 accelgroup
.connect(keyval
, modifier
, Gtk
.AccelFlags
.VISIBLE
, self
.on_mainwindow_redo
)
70 keyval
, modifier
= Gtk
.accelerator_parse('F1')
71 accelgroup
.connect(keyval
, modifier
, Gtk
.AccelFlags
.VISIBLE
, self
.on_help_button_clicked
)
72 self
.tree
.get_object('mainwindow').add_accel_group(accelgroup
)
76 self
.editor
.applications
.tree
.connect("changed", self
.menuChanged
)
77 self
.tree
.get_object('mainwindow').show_all()
80 def menuChanged(self
, *a
):
81 print >> sys
.stderr
, "changed!\n"
83 GObject
.source_remove(self
.timer
)
85 self
.timer
= GObject
.timeout_add(3, self
.loadUpdates
)
87 def loadUpdates(self
):
88 print >> sys
.stderr
, "%d\n" % self
.editor
.applications
.tree
.disconnect_by_func(self
.menuChanged
)
89 self
.editor
.reloadMenus()
90 self
.editor
.applications
.tree
.connect("changed", self
.menuChanged
)
92 if not self
.allow_update
:
94 menu_tree
= self
.tree
.get_object('menu_tree')
95 item_tree
= self
.tree
.get_object('item_tree')
96 items
, iter = item_tree
.get_selection().get_selected()
99 item_id
, separator_path
= None, None
102 if isinstance(items
[iter][3], GMenu
.TreeEntry
):
103 item_id
= items
[iter][3].get_desktop_file_id()
104 update_type
= GMenu
.TreeItemType
.ENTRY
105 elif isinstance(items
[iter][3], GMenu
.TreeDirectory
):
106 item_id
= os
.path
.split(items
[iter][3].get_desktop_file_path())[1]
107 update_type
= GMenu
.TreeItemType
.DIRECTORY
108 elif isinstance(items
[iter][3], GMenu
.Tree
.Separator
):
109 item_id
= items
.get_path(iter)
110 update_type
= GMenu
.TreeItemType
.SEPARATOR
111 menus
, iter = menu_tree
.get_selection().get_selected()
115 if menus
[iter][2].get_desktop_file_path():
116 menu_id
= os
.path
.split(menus
[iter][2].get_desktop_file_path())[1]
118 menu_id
= menus
[iter][2].get_menu_id()
121 #find current menu in new tree
123 menu_tree
.get_model().foreach(self
.findMenu
, menu_id
)
124 menus
, iter = menu_tree
.get_selection().get_selected()
126 self
.on_menu_tree_cursor_changed(menu_tree
)
127 #find current item in new list
130 for item
in item_tree
.get_model():
132 if update_type
!= GMenu
.TreeItemType
.SEPARATOR
:
133 if isinstance (item
[3], GMenu
.TreeEntry
) and item
[3].get_desktop_file_id() == item_id
:
135 if isinstance (item
[3], GMenu
.TreeDirectory
) and item
[3].get_desktop_file_path() and update_type
== GMenu
.TreeItemType
.DIRECTORY
:
136 if os
.path
.split(item
[3].get_desktop_file_path())[1] == item_id
:
138 if isinstance(item
[3], GMenu
.TreeSeparator
):
139 if not isinstance(item_id
, tuple):
140 #we may not skip the increment via "continue"
143 #separators have no id, have to find them manually
144 #probably won't work with two separators together
145 if (item_id
[0] - 1,) == (i
,):
147 elif (item_id
[0] + 1,) == (i
,):
149 elif (item_id
[0],) == (i
,):
152 item_tree
.get_selection().select_path((i
,))
153 self
.on_item_tree_cursor_changed(item_tree
)
158 def findMenu(self
, menus
, path
, iter, menu_id
):
159 if not menus
[path
][2].get_desktop_file_path():
160 if menu_id
== menus
[path
][2].get_menu_id():
161 menu_tree
= self
.tree
.get_object('menu_tree')
162 menu_tree
.expand_to_path(path
)
163 menu_tree
.get_selection().select_path(path
)
166 if os
.path
.split(menus
[path
][2].get_desktop_file_path())[1] == menu_id
:
167 menu_tree
= self
.tree
.get_object('menu_tree')
168 menu_tree
.expand_to_path(path
)
169 menu_tree
.get_selection().select_path(path
)
172 def setupMenuTree(self
):
173 self
.menu_store
= Gtk
.TreeStore(GdkPixbuf
.Pixbuf
, str, object)
174 menus
= self
.tree
.get_object('menu_tree')
175 column
= Gtk
.TreeViewColumn(_('Name'))
176 column
.set_spacing(4)
177 cell
= Gtk
.CellRendererPixbuf()
178 column
.pack_start(cell
, False)
179 column
.add_attribute(cell
, 'pixbuf', 0)
180 cell
= Gtk
.CellRendererText()
181 column
.pack_start(cell
, True)
182 column
.add_attribute(cell
, 'markup', 1)
183 menus
.append_column(column
)
184 menus
.enable_model_drag_source(Gdk
.ModifierType
.BUTTON1_MASK
, self
.dnd_menus
, Gdk
.DragAction
.COPY
)
185 menus
.enable_model_drag_dest(self
.dnd_both
, Gdk
.DragAction
.PRIVATE
)
186 menus
.get_selection().set_mode(Gtk
.SelectionMode
.BROWSE
)
188 def setupItemTree(self
):
189 items
= self
.tree
.get_object('item_tree')
190 column
= Gtk
.TreeViewColumn(_('Show'))
191 cell
= Gtk
.CellRendererToggle()
192 cell
.connect('toggled', self
.on_item_tree_show_toggled
)
193 column
.pack_start(cell
, True)
194 column
.add_attribute(cell
, 'active', 0)
195 #hide toggle for separators
196 column
.set_cell_data_func(cell
, self
._cell
_data
_toggle
_func
)
197 items
.append_column(column
)
198 column
= Gtk
.TreeViewColumn(_('Item'))
199 column
.set_spacing(4)
200 cell
= Gtk
.CellRendererPixbuf()
201 column
.pack_start(cell
, False)
202 column
.add_attribute(cell
, 'pixbuf', 1)
203 cell
= Gtk
.CellRendererText()
204 column
.pack_start(cell
, True)
205 column
.add_attribute(cell
, 'markup', 2)
206 items
.append_column(column
)
207 self
.item_store
= Gtk
.ListStore(bool, GdkPixbuf
.Pixbuf
, str, object)
208 items
.set_model(self
.item_store
)
209 items
.enable_model_drag_source(Gdk
.ModifierType
.BUTTON1_MASK
, self
.dnd_items
, Gdk
.DragAction
.COPY
)
210 items
.enable_model_drag_dest(self
.dnd_items
, Gdk
.DragAction
.PRIVATE
)
212 def _cell_data_toggle_func(self
, tree_column
, renderer
, model
, treeiter
, data
=None):
213 if isinstance(model
[treeiter
][3], GMenu
.TreeSeparator
):
214 renderer
.set_property('visible', False)
216 renderer
.set_property('visible', True)
219 self
.menu_store
.clear()
220 for menu
in self
.editor
.getMenus():
222 self
.loadMenu(iters
, menu
)
223 menu_tree
= self
.tree
.get_object('menu_tree')
224 menu_tree
.set_model(self
.menu_store
)
225 for menu
in self
.menu_store
:
226 #this might not work for some reason
228 menu_tree
.expand_to_path(menu
.path
)
231 menu_tree
.get_selection().select_path((0,))
232 self
.on_menu_tree_cursor_changed(menu_tree
)
234 def loadMenu(self
, iters
, parent
, depth
=0):
236 icon
= util
.getIcon(parent
)
237 iters
[depth
] = self
.menu_store
.append(None, (icon
, cgi
.escape(parent
.get_name()), parent
))
239 for menu
, show
in self
.editor
.getMenus(parent
):
241 name
= cgi
.escape(menu
.get_name())
243 name
= '<small><i>' + cgi
.escape(menu
.get_name()) + '</i></small>'
244 icon
= util
.getIcon(menu
)
245 iters
[depth
] = self
.menu_store
.append(iters
[depth
-1], (icon
, name
, menu
))
246 self
.loadMenu(iters
, menu
, depth
)
249 def loadItems(self
, menu
, menu_path
):
250 self
.item_store
.clear()
251 for item
, show
in self
.editor
.getItems(menu
):
253 if isinstance(item
, GMenu
.TreeSeparator
):
256 elif isinstance(item
, GMenu
.TreeEntry
):
257 app_info
= item
.get_app_info()
259 name
= cgi
.escape(app_info
.get_display_name())
261 name
= '<small><i>' + cgi
.escape(app_info
.get_display_name()) + '</i></small>'
262 icon
= util
.getIcon(item
)
265 name
= cgi
.escape(item
.get_name())
267 name
= '<small><i>' + cgi
.escape(item
.get_name()) + '</i></small>'
268 icon
= util
.getIcon(item
)
269 self
.item_store
.append((show
, icon
, name
, item
))
271 #this is a little timeout callback to insert new items after
272 #gnome-desktop-item-edit has finished running
273 def waitForNewItemProcess(self
, process
, parent_id
, file_path
):
274 if process
.poll() != None:
275 if os
.path
.isfile(file_path
):
276 self
.editor
.insertExternalItem(os
.path
.split(file_path
)[1], parent_id
)
280 def waitForNewMenuProcess(self
, process
, parent_id
, file_path
):
281 if process
.poll() != None:
282 #hack for broken gnome-desktop-item-edit
283 broken_path
= os
.path
.join(os
.path
.split(file_path
)[0], '.directory')
284 if os
.path
.isfile(broken_path
):
285 os
.rename(broken_path
, file_path
)
286 if os
.path
.isfile(file_path
):
287 self
.editor
.insertExternalMenu(os
.path
.split(file_path
)[1], parent_id
)
291 #this callback keeps you from editing the same item twice
292 def waitForEditProcess(self
, process
, file_path
):
293 if process
.poll() != None:
294 self
.edit_pool
.remove(file_path
)
298 def on_new_menu_button_clicked(self
, button
):
299 menu_tree
= self
.tree
.get_object('menu_tree')
300 menus
, iter = menu_tree
.get_selection().get_selected()
302 parent
= menus
[(0,)][2]
303 menu_tree
.expand_to_path((0,))
304 menu_tree
.get_selection().select_path((0,))
306 parent
= menus
[iter][2]
307 file_path
= os
.path
.join(util
.getUserDirectoryPath(), util
.getUniqueFileId('alacarte-made', '.directory'))
308 process
= subprocess
.Popen(['gnome-desktop-item-edit', file_path
], env
=os
.environ
)
309 GObject
.timeout_add(100, self
.waitForNewMenuProcess
, process
, parent
.get_menu_id(), file_path
)
311 def on_new_item_button_clicked(self
, button
):
312 menu_tree
= self
.tree
.get_object('menu_tree')
313 menus
, iter = menu_tree
.get_selection().get_selected()
315 parent
= menus
[(0,)][2]
316 menu_tree
.expand_to_path((0,))
317 menu_tree
.get_selection().select_path((0,))
319 parent
= menus
[iter][2]
320 file_path
= os
.path
.join(util
.getUserItemPath(), util
.getUniqueFileId('alacarte-made', '.desktop'))
321 process
= subprocess
.Popen(['gnome-desktop-item-edit', file_path
], env
=os
.environ
)
322 GObject
.timeout_add(100, self
.waitForNewItemProcess
, process
, parent
.get_menu_id(), file_path
)
324 def on_new_separator_button_clicked(self
, button
):
325 item_tree
= self
.tree
.get_object('item_tree')
326 items
, iter = item_tree
.get_selection().get_selected()
330 after
= items
[iter][3]
331 menu_tree
= self
.tree
.get_object('menu_tree')
332 menus
, iter = menu_tree
.get_selection().get_selected()
333 parent
= menus
[iter][2]
334 self
.editor
.createSeparator(parent
, after
=after
)
336 def on_edit_delete_activate(self
, menu
):
337 item_tree
= self
.tree
.get_object('item_tree')
338 items
, iter = item_tree
.get_selection().get_selected()
341 item
= items
[iter][3]
342 if isinstance(item
, GMenu
.TreeEntry
):
343 self
.editor
.deleteItem(item
)
344 elif isinstance(item
, GMenu
.TreeDirectory
):
345 self
.editor
.deleteMenu(item
)
346 elif isinstance(item
, GMenu
.TreeSeparator
):
347 self
.editor
.deleteSeparator(item
)
349 def on_edit_revert_to_original_activate(self
, menu
):
350 item_tree
= self
.tree
.get_object('item_tree')
351 items
, iter = item_tree
.get_selection().get_selected()
354 item
= items
[iter][3]
355 if isinstance(item
, GMenu
.TreeEntry
):
356 self
.editor
.revertItem(item
)
357 elif isinstance(item
, GMenu
.TreeDirectory
):
358 self
.editor
.revertMenu(item
)
360 def on_edit_properties_activate(self
, menu
):
361 item_tree
= self
.tree
.get_object('item_tree')
362 items
, iter = item_tree
.get_selection().get_selected()
365 item
= items
[iter][3]
366 if not isinstance(item
, GMenu
.TreeEntry
) and not isinstance(item
, GMenu
.TreeDirectory
):
369 if isinstance(item
, GMenu
.TreeEntry
):
370 file_path
= os
.path
.join(util
.getUserItemPath(), item
.get_desktop_file_id())
372 elif isinstance(item
, GMenu
.TreeDirectory
):
373 if item
.get_desktop_file_path() == None:
374 file_path
= util
.getUniqueFileId('alacarte-made', '.directory')
375 parser
= util
.DesktopParser(file_path
, 'Directory')
376 parser
.set('Name', item
.get_name())
377 parser
.set('Comment', item
.get_comment())
378 parser
.set('Icon', item
.get_icon())
379 parser
.write(open(file_path
))
381 file_path
= os
.path
.join(util
.getUserDirectoryPath(), os
.path
.split(item
.get_desktop_file_path())[1])
384 if not os
.path
.isfile(file_path
):
385 data
= open(item
.get_desktop_file_path()).read()
386 open(file_path
, 'w').write(data
)
387 self
.editor
._MenuEditor
__addUndo
([(file_type
, os
.path
.split(file_path
)[1]),])
389 self
.editor
._MenuEditor
__addUndo
([item
,])
390 if file_path
not in self
.edit_pool
:
391 self
.edit_pool
.append(file_path
)
392 process
= subprocess
.Popen(['gnome-desktop-item-edit', file_path
], env
=os
.environ
)
393 GObject
.timeout_add(100, self
.waitForEditProcess
, process
, file_path
)
395 def on_menu_tree_cursor_changed(self
, treeview
):
396 menus
, iter = treeview
.get_selection().get_selected()
397 menu_path
= menus
.get_path(iter)
398 item_tree
= self
.tree
.get_object('item_tree')
399 item_tree
.get_selection().unselect_all()
400 self
.loadItems(self
.menu_store
[menu_path
][2], menu_path
)
401 self
.tree
.get_object('edit_delete').set_sensitive(False)
402 self
.tree
.get_object('edit_revert_to_original').set_sensitive(False)
403 self
.tree
.get_object('edit_properties').set_sensitive(False)
404 self
.tree
.get_object('move_up_button').set_sensitive(False)
405 self
.tree
.get_object('move_down_button').set_sensitive(False)
406 self
.tree
.get_object('new_separator_button').set_sensitive(False)
407 self
.tree
.get_object('properties_button').set_sensitive(False)
408 self
.tree
.get_object('delete_button').set_sensitive(False)
410 def on_menu_tree_drag_data_get(self
, treeview
, context
, selection
, target_id
, etime
):
411 menus
, iter = treeview
.get_selection().get_selected()
412 self
.drag_data
= menus
[iter][2]
414 def on_menu_tree_drag_data_received(self
, treeview
, context
, x
, y
, selection
, info
, etime
):
415 menus
= treeview
.get_model()
416 drop_info
= treeview
.get_dest_row_at_pos(x
, y
)
418 path
, position
= drop_info
419 types_before
= (Gtk
.TreeViewDropPosition
.INTO_OR_BEFORE
, Gtk
.TreeViewDropPosition
.INTO_OR_AFTER
)
420 types_into
= (Gtk
.TreeViewDropPosition
.INTO_OR_BEFORE
, Gtk
.TreeViewDropPosition
.INTO_OR_AFTER
)
421 types_after
= (Gtk
.TreeViewDropPosition
.AFTER
, Gtk
.TreeViewDropPosition
.INTO_OR_AFTER
)
422 if position
not in types
:
423 context
.finish(False, False, etime
)
425 if selection
.target
in ('ALACARTE_ITEM_ROW', 'ALACARTE_MENU_ROW'):
426 if self
.drag_data
== None:
428 item
= self
.drag_data
429 new_parent
= menus
[path
][2]
430 treeview
.get_selection().select_path(path
)
431 if isinstance(item
, GMenu
.TreeEntry
):
432 self
.editor
.copyItem(item
, new_parent
)
433 elif isinstance(item
, GMenu
.TreeDirectory
):
434 if self
.editor
.moveMenu(item
, new_parent
) == False:
436 elif isinstance(item
, GMenu
.TreeSeparator
):
437 self
.editor
.moveSeparator(item
, new_parent
)
439 context
.finish(False, False, etime
)
440 context
.finish(True, True, etime
)
441 self
.drag_data
= None
443 def on_item_tree_show_toggled(self
, cell
, path
):
444 item
= self
.item_store
[path
][3]
445 if isinstance(item
, GMenu
.TreeSeparator
):
447 if self
.item_store
[path
][0]:
448 self
.editor
.setVisible(item
, False)
450 self
.editor
.setVisible(item
, True)
451 self
.item_store
[path
][0] = not self
.item_store
[path
][0]
453 def on_item_tree_cursor_changed(self
, treeview
):
454 items
, iter = treeview
.get_selection().get_selected()
457 item
= items
[iter][3]
458 self
.tree
.get_object('edit_delete').set_sensitive(True)
459 self
.tree
.get_object('new_separator_button').set_sensitive(True)
460 self
.tree
.get_object('delete_button').set_sensitive(True)
461 if self
.editor
.canRevert(item
):
462 self
.tree
.get_object('edit_revert_to_original').set_sensitive(True)
464 self
.tree
.get_object('edit_revert_to_original').set_sensitive(False)
465 if not isinstance(item
, GMenu
.TreeSeparator
):
466 self
.tree
.get_object('edit_properties').set_sensitive(True)
467 self
.tree
.get_object('properties_button').set_sensitive(True)
469 self
.tree
.get_object('edit_properties').set_sensitive(False)
470 self
.tree
.get_object('properties_button').set_sensitive(False)
473 if items
.get_path(iter).get_indices()[0] == 0:
474 self
.tree
.get_object('move_up_button').set_sensitive(False)
476 self
.tree
.get_object('move_up_button').set_sensitive(True)
479 if items
.get_path(iter).get_indices()[0] == (len(items
)-1):
480 self
.tree
.get_object('move_down_button').set_sensitive(False)
482 self
.tree
.get_object('move_down_button').set_sensitive(True)
484 def on_item_tree_row_activated(self
, treeview
, path
, column
):
485 self
.on_edit_properties_activate(None)
487 def on_item_tree_popup_menu(self
, item_tree
, event
=None):
488 model
, iter = item_tree
.get_selection().get_selected()
490 #don't show if it's not the right mouse button
491 if event
.button
!= 3:
493 button
= event
.button
494 event_time
= event
.time
495 info
= item_tree
.get_path_at_pos(int(event
.x
), int(event
.y
))
497 path
, col
, cellx
, celly
= info
498 item_tree
.grab_focus()
499 item_tree
.set_cursor(path
, col
, 0)
501 path
= model
.get_path(iter)
504 item_tree
.grab_focus()
505 item_tree
.set_cursor(path
, item_tree
.get_columns()[0], 0)
506 popup
= self
.tree
.get_object('edit_menu')
507 popup
.popup(None, None, None, button
, event_time
)
508 #without this shift-f10 won't work
511 def on_item_tree_drag_data_get(self
, treeview
, context
, selection
, target_id
, etime
):
512 items
, iter = treeview
.get_selection().get_selected()
513 self
.drag_data
= items
[iter][3]
515 def on_item_tree_drag_data_received(self
, treeview
, context
, x
, y
, selection
, info
, etime
):
516 items
= treeview
.get_model()
517 types
= (Gtk
.TreeViewDropPosition
.BEFORE
, Gtk
.TreeViewDropPosition
.INTO_OR_BEFORE
)
518 if selection
.target
== 'ALACARTE_ITEM_ROW':
519 drop_info
= treeview
.get_dest_row_at_pos(x
, y
)
522 if self
.drag_data
== None:
524 item
= self
.drag_data
525 # by default we assume, that the items stays in the same menu
526 destination
= item
.get_parent()
528 path
, position
= drop_info
529 target
= items
[path
][3]
530 # move the item to the directory, if the item was dropped into it
531 if isinstance(target
, GMenu
.TreeDirectory
) and (position
in types_into
):
532 # append the selected item to the choosen menu
534 elif position
in types_before
:
536 elif position
in types_after
:
539 # this does not happen
542 path
= (len(items
) - 1,)
543 after
= items
[path
][3]
544 if isinstance(item
, GMenu
.TreeEntry
):
545 self
.editor
.moveItem(item
, destination
, before
, after
)
546 elif isinstance(item
, GMenu
.TreeDirectory
):
547 if self
.editor
.moveMenu(item
, destination
, before
, after
) == False:
549 elif isinstance(item
, GMenu
.TreeSeparator
):
550 self
.editor
.moveSeparator(item
, destination
, before
, after
)
551 context
.finish(True, True, etime
)
552 elif selection
.target
== 'text/plain':
553 if selection
.data
== None:
555 menus
, iter = self
.tree
.get_object('menu_tree').get_selection().get_selected()
556 parent
= menus
[iter][2]
557 drop_info
= treeview
.get_dest_row_at_pos(x
, y
)
561 path
, position
= drop_info
562 if position
in types
:
563 before
= items
[path
][3]
565 after
= items
[path
][3]
567 path
= (len(items
) - 1,)
568 after
= items
[path
][3]
569 file_path
= urllib
.unquote(selection
.data
).strip()
570 if not file_path
.startswith('file:'):
572 myfile
= Gio
.File(uri
=file_path
)
573 file_info
= myfile
.query_info(Gio
.FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE
)
574 content_type
= file_info
.get_content_type()
575 if content_type
== 'application/x-desktop':
576 input_stream
= myfile
.read()
577 (fd
, tmppath
) = tempfile
.mkstemp(prefix
='alacarte-dnd', suffix
='.desktop')
579 f
= os
.open(tmppath
, 'w')
580 f
.write(input_stream
.read())
582 parser
= util
.DesktopParser(tmppath
)
583 self
.editor
.createItem(parent
, parser
.get('Icon'), parser
.get('Name', self
.editor
.locale
), parser
.get('Comment', self
.editor
.locale
), parser
.get('Exec'), parser
.get('Terminal'), before
, after
)
584 elif content_type
in ('application/x-shellscript', 'application/x-executable'):
585 self
.editor
.createItem(parent
, None, os
.path
.split(file_path
)[1].strip(), None, file_path
.replace('file://', '').strip(), False, before
, after
)
586 self
.drag_data
= None
588 def on_item_tree_key_press_event(self
, item_tree
, event
):
589 if event
.keyval
== Gdk
.KEY_Delete
:
590 self
.on_edit_delete_activate(item_tree
)
592 def on_move_up_button_clicked(self
, button
):
593 item_tree
= self
.tree
.get_object('item_tree')
594 items
, iter = item_tree
.get_selection().get_selected()
597 path
= items
.get_path(iter)
598 #at top, can't move up
599 if path
.get_indices()[0] == 0:
601 item
= items
[path
][3]
602 before
= items
[(path
.get_indices()[0] - 1,)][3]
603 if isinstance(item
, GMenu
.TreeEntry
):
604 self
.editor
.moveItem(item
, item
.get_parent(), before
=before
)
605 elif isinstance(item
, GMenu
.TreeDirectory
):
606 self
.editor
.moveMenu(item
, item
.get_parent(), before
=before
)
607 elif isinstance(item
, GMenu
.TreeSeparator
):
608 self
.editor
.moveSeparator(item
, item
.get_parent(), before
=before
)
610 def on_move_down_button_clicked(self
, button
):
611 item_tree
= self
.tree
.get_object('item_tree')
612 items
, iter = item_tree
.get_selection().get_selected()
615 path
= items
.get_path(iter)
616 #at bottom, can't move down
617 if path
.get_indices()[0] == (len(items
) - 1):
619 item
= items
[path
][3]
620 after
= items
[path
][3]
621 if isinstance(item
, GMenu
.TreeEntry
):
622 self
.editor
.moveItem(item
, item
.get_parent(), after
=after
)
623 elif isinstance(item
, GMenu
.TreeDirectory
):
624 self
.editor
.moveMenu(item
, item
.get_parent(), after
=after
)
625 elif isinstance(item
, GMenu
.TreeSeparator
):
626 self
.editor
.moveSeparator(item
, item
.get_parent(), after
=after
)
628 def on_mainwindow_undo(self
, accelgroup
, window
, keyval
, modifier
):
631 def on_mainwindow_redo(self
, accelgroup
, window
, keyval
, modifier
):
634 def on_help_button_clicked(self
, *args
):
635 Gtk
.show_uri(Gdk
.Screen
.get_default(), "ghelp:user-guide#menu-editor", Gtk
.get_current_event_time())
637 def on_revert_button_clicked(self
, button
):
638 dialog
= self
.tree
.get_object('revertdialog')
639 dialog
.set_transient_for(self
.tree
.get_object('mainwindow'))
641 if dialog
.run() == Gtk
.ResponseType
.YES
:
645 def on_close_button_clicked(self
, button
):
647 self
.tree
.get_object('mainwindow').hide()
650 GObject
.timeout_add(10, self
.quit
)
652 def on_properties_button_clicked(self
, button
):
653 self
.on_edit_properties_activate(None)
654 def on_delete_button_clicked(self
, button
):
655 self
.on_edit_delete_activate(None)
657 def on_style_set(self
, *args
):