home *** CD-ROM | disk | FTP | other *** search
/ PC Welt 2006 November (DVD) / PCWELT_11_2006.ISO / casper / filesystem.squashfs / usr / lib / python2.4 / site-packages / Alacarte / DialogHandler.py < prev    next >
Encoding:
Python Source  |  2006-07-25  |  16.7 KB  |  463 lines

  1. # -*- coding: utf-8 -*-
  2. #   Alacarte Menu Editor - Simple fd.o Compliant Menu Editor
  3. #   Copyright (C) 2006  Travis Watkins
  4. #
  5. #   This library is free software; you can redistribute it and/or
  6. #   modify it under the terms of the GNU Library General Public
  7. #   License as published by the Free Software Foundation; either
  8. #   version 2 of the License, or (at your option) any later version.
  9. #
  10. #   This library is distributed in the hope that it will be useful,
  11. #   but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. #   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  13. #   Library General Public License for more details.
  14. #
  15. #   You should have received a copy of the GNU Library General Public
  16. #   License along with this library; if not, write to the Free Software
  17. #   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  18.  
  19. import os, cgi
  20. import gmenu, gtk, gtk.glade, gobject
  21. import gettext
  22. gettext.bindtextdomain('alacarte')
  23. gettext.textdomain('alacarte')
  24. gtk.glade.bindtextdomain('alacarte')
  25. gtk.glade.textdomain('alacarte')
  26. _ = gettext.gettext
  27. from Alacarte import util
  28.  
  29. class DialogHandler:
  30.     editor = None
  31.     file_path = None
  32.     timer = None
  33.     in_revert = False
  34.     first_change = False
  35.  
  36.     def __init__(self, parent, editor, file_path):
  37.         self.parent = parent
  38.         self.editor = editor
  39.         self.file_path = file_path
  40.         self.command_completion = gtk.EntryCompletion()
  41.         self.command_completion.set_property('popup-completion', False)
  42.         self.command_completion.set_inline_completion(True)
  43.         self.completion_full = gtk.ListStore(str)
  44.         self.completion_used = gtk.ListStore(str)
  45.         self.command_completion.set_text_column(0)
  46.         paths = os.getenv('PATH')
  47.         for path in paths.split(os.pathsep):
  48.             if os.path.isdir(path):
  49.                 try:
  50.                     for name in os.listdir(path):
  51.                         f = os.path.join(path, name)
  52.                         if os.path.isfile(f):
  53.                             if os.access(f, os.X_OK):
  54.                                 self.completion_full.append([name,])
  55.                 except:
  56.                     pass
  57.         self.command_completion.set_model(self.completion_used)
  58.  
  59.     def showError(self, message):
  60.         dialog = gtk.MessageDialog(None, 0, gtk.MESSAGE_WARNING, gtk.BUTTONS_CLOSE, None)
  61.         dialog.set_title('')
  62.         dialog.set_size_request(400, -1)
  63.         dialog.set_markup('<b>' + cgi.escape(message) + '</b>')
  64.         dialog.run()
  65.         dialog.destroy()
  66.  
  67.     def showCommandDialog(self, command_entry):
  68.         dialog = gtk.FileChooserDialog('Choose a Program', None, gtk.FILE_CHOOSER_ACTION_OPEN, (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_OK, gtk.RESPONSE_OK))
  69.         if len(command_entry.get_text()) and '/' in command_entry.get_text():
  70.             dialog.set_current_folder(command_entry.get_text().rsplit('/', 1)[0])
  71.         else:
  72.             dialog.set_current_folder('/usr/bin/')
  73.         file_filter = gtk.FileFilter()
  74.         file_filter.add_mime_type('application/x-executable')
  75.         file_filter.add_mime_type('application/x-shellscript')
  76.         dialog.set_filter(file_filter)
  77.         dialog.show_all()
  78.         if dialog.run() == gtk.RESPONSE_OK:
  79.             command_entry.set_text(dialog.get_filename())
  80.         dialog.destroy()
  81.  
  82.     def showIconDialog(self, button):
  83.         dialog = gtk.FileChooserDialog('Choose an Icon', None, gtk.FILE_CHOOSER_ACTION_OPEN, (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_OK, gtk.RESPONSE_OK))
  84.         if button.icon_path:
  85.             dialog.set_current_folder(button.icon_path.rsplit('/', 1)[0])
  86.         else:
  87.             dialog.set_current_folder('/usr/share/icons/')
  88.         preview = gtk.VBox()
  89.         preview.set_spacing(8)
  90.         preview.set_size_request(92, 92)
  91.         preview_text = gtk.Label('Preview')
  92.         preview.pack_start(preview_text, False, False)
  93.         preview_image = gtk.Image()
  94.         preview.pack_start(preview_image, False, False)
  95.         preview.show()
  96.         preview_text.show()
  97.         preview_image.show()
  98.         dialog.set_preview_widget(preview)
  99.         dialog.set_preview_widget_active(False)
  100.         dialog.set_use_preview_label(False)
  101.         dialog.connect('selection-changed', self.on_icon_dialog_selection_changed, preview_image)
  102.         file_filter = gtk.FileFilter()
  103.         file_filter.add_mime_type('image/png')
  104.         file_filter.add_mime_type('image/x-xpixmap')
  105.         file_filter.add_mime_type('image/svg+xml')
  106.         dialog.set_filter(file_filter)
  107.         dialog.show_all()
  108.         if dialog.run() == gtk.RESPONSE_OK:
  109.             button.remove(button.get_children()[0])
  110.             pixbuf = util.getIcon(dialog.get_filename())
  111.             button.icon_path = dialog.get_filename()
  112.             image = gtk.Image()
  113.             image.set_from_pixbuf(pixbuf)
  114.             image.show()
  115.             button.add(image)
  116.             dialog.destroy()
  117.             return True
  118.         dialog.destroy()
  119.         return False
  120.  
  121.     def on_icon_button_clicked(self, button):
  122.         self.showIconDialog(button)
  123.  
  124.     def on_icon_dialog_selection_changed(self, dialog, image):
  125.         icon_file = dialog.get_preview_filename()
  126.         try:
  127.             pixbuf = gtk.gdk.pixbuf_new_from_file(icon_file)
  128.         except:
  129.             dialog.set_preview_widget_active(False)
  130.             return
  131.         if pixbuf.get_width() > 64 or pixbuf.get_height() > 64:
  132.             pixbuf = pixbuf.scale_simple(32, 32, gtk.gdk.INTERP_HYPER)
  133.         image.set_from_pixbuf(pixbuf)
  134.         dialog.set_preview_widget_active(True)
  135.  
  136.     def newItemDialog(self):
  137.         self.tree = gtk.glade.XML(os.path.join(self.file_path, 'alacarte.glade'), 'newitemproperties')
  138.         signals = {}
  139.         for attr in dir(self):
  140.             signals[attr] = getattr(self, attr)
  141.         self.tree.signal_autoconnect(signals)
  142.         def responseChecker(response):
  143.             if response == gtk.RESPONSE_OK:
  144.                 if len(self.tree.get_widget('newitem_name_entry').get_text()) == 0:
  145.                     self.showError(_('A name is required.'))
  146.                     return False
  147.                 if len(self.tree.get_widget('newitem_command_entry').get_text()) == 0:
  148.                     self.showError(_('A command is required.'))
  149.                     return False
  150.                 return 'save'
  151.             return True
  152.         command_entry = self.tree.get_widget('newitem_command_entry')
  153.         command_entry.set_completion(self.command_completion)
  154.         icon_button = self.tree.get_widget('newitem_icon_button')
  155.         icon_button.remove(icon_button.get_children()[0])
  156.         label = gtk.Label('No Icon')
  157.         icon_button.add(label)
  158.         icon_button.icon_path = None
  159.         dialog = self.tree.get_widget('newitemproperties')
  160.         dialog.set_transient_for(self.parent)
  161.         dialog.show_all()
  162.         can_close = False
  163.         while can_close == False:
  164.             response = dialog.run()
  165.             can_close = responseChecker(response)
  166.         if can_close == 'save':
  167.             name_entry = self.tree.get_widget('newitem_name_entry')
  168.             comment_entry = self.tree.get_widget('newitem_comment_entry')
  169.             command_button = self.tree.get_widget('newitem_command_button')
  170.             term_check = self.tree.get_widget('newitem_terminal_check')
  171.             dialog.destroy()
  172.             return (icon_button.icon_path, name_entry.get_text(), comment_entry.get_text(), command_entry.get_text(), term_check.get_active())
  173.         dialog.destroy()
  174.  
  175.     def editItemDialog(self, item_row):
  176.         def responseChecker(response):
  177.             if response == gtk.RESPONSE_REJECT:
  178.                 self.revertItem()
  179.                 return False
  180.             if response == gtk.RESPONSE_CLOSE or response == gtk.RESPONSE_DELETE_EVENT:
  181.                 if len(self.tree.get_widget('item_name_entry').get_text()) == 0:
  182.                     self.showError(_('A name is required.'))
  183.                     return False
  184.                 if len(self.tree.get_widget('item_command_entry').get_text()) == 0:
  185.                     self.showError(_('A command is required.'))
  186.                     return False
  187.                 return True
  188.             return False
  189.         self.in_dialog_setup = True
  190.         self.item_row = item_row
  191.         self.item = item_row[3]
  192.         #item likes to lose it's parent
  193.         self.item_parent = self.item.get_parent()
  194.         #load widgets
  195.         self.tree = gtk.glade.XML(os.path.join(self.file_path, 'alacarte.glade'), 'itemproperties')
  196.         signals = {}
  197.         for attr in dir(self):
  198.             signals[attr] = getattr(self, attr)
  199.         self.tree.signal_autoconnect(signals)
  200.         dialog = self.tree.get_widget('itemproperties')
  201.         icon_button = self.tree.get_widget('item_icon_button')
  202.         name_entry = self.tree.get_widget('item_name_entry')
  203.         comment_entry = self.tree.get_widget('item_comment_entry')
  204.         command_entry = self.tree.get_widget('item_command_entry')
  205.         command_entry.set_completion(self.command_completion)
  206.         command_button = self.tree.get_widget('item_command_button')
  207.         term_check = self.tree.get_widget('item_terminal_check')
  208.  
  209.         dialog.set_transient_for(self.parent)
  210.         icon_button.remove(icon_button.get_children()[0])
  211.         pixbuf, path = util.getIcon(self.item, True)
  212.         if pixbuf:
  213.             image = gtk.Image()
  214.             image.set_from_pixbuf(pixbuf)
  215.             icon_button.add(image)
  216.             icon_button.icon_path = path
  217.         else:
  218.             label = gtk.Label('No Icon')
  219.             icon_button.add(label)
  220.             icon_button.icon_path = None
  221.         name_entry.set_text(self.item.get_name())
  222.         if self.item.get_comment():
  223.             comment_entry.set_text(self.item.get_comment())
  224.         if self.item.get_exec():
  225.             command_entry.set_text(self.item.get_exec())
  226.         if self.item.get_launch_in_terminal():
  227.             term_check.set_active(True)
  228.         dialog.show_all()
  229.         self.item_original_values = (
  230.             icon_button.icon_path,
  231.             name_entry.get_text(),
  232.             comment_entry.get_text(),
  233.             command_entry.get_text(),
  234.             term_check.get_active()
  235.             )
  236.         self.in_dialog_setup = False
  237.         #hack to make undo work
  238.         self.first_change = True
  239.         can_close = False
  240.         while can_close == False:
  241.             response = dialog.run()
  242.             can_close = responseChecker(response)
  243.         dialog.destroy()
  244.         self.first_change = False
  245.  
  246.     def on_item_contents_changed(self, garbage):
  247.         self.item_row[1] = util.getIcon(self.tree.get_widget('item_icon_button').icon_path)
  248.         self.item_row[2] = self.tree.get_widget('item_name_entry').get_text()
  249.         if self.first_change:
  250.             self.saveItem(self.item_original_values, True)
  251.             self.first_change = False
  252.         if self.in_revert:
  253.             self.in_revert = False
  254.             self.saveItemChanges()
  255.             return
  256.         if not self.in_dialog_setup:
  257.             self.tree.get_widget('item_revert_button').set_sensitive(True)
  258.             values = (
  259.                 self.tree.get_widget('item_icon_button').icon_path,
  260.                 self.tree.get_widget('item_name_entry').get_text(),
  261.                 self.tree.get_widget('item_comment_entry').get_text(),
  262.                 self.tree.get_widget('item_command_entry').get_text(),
  263.                 self.tree.get_widget('item_terminal_check').get_active()
  264.                 )
  265.             self.saveItem(values)
  266.  
  267.     def on_item_icon_button_clicked(self, button):
  268.         if self.showIconDialog(button):
  269.             self.on_item_contents_changed(button)    
  270.  
  271.     def on_item_command_entry_key_press_event(self, entry, event):
  272.         if event.keyval == gtk.keysyms.BackSpace:
  273.             return
  274.         if event.keyval == gtk.keysyms.Delete:
  275.             start, end = entry.get_selection_bounds()
  276.             entry.delete_text(start, end)
  277.         if event.keyval == gtk.keysyms.Tab:
  278.             start, end = entry.get_selection_bounds()
  279.             if start != end and start != 1 and end == len(entry.get_text()):
  280.                 entry.select_region(end, end)
  281.                 entry.set_position(-1)
  282.                 return True
  283.         elif len(entry.get_text()) == 2:
  284.             chars = entry.get_text()[:2]
  285.             self.completion_used.clear()
  286.             for item in self.completion_full:
  287.                 gobject.idle_add(self.compareCommands, item[0], chars)
  288.  
  289.     def compareCommands(self, possible_command, typed_chars):
  290.         if possible_command[:2] == typed_chars:
  291.             self.completion_used.append((possible_command,))
  292.         return False
  293.  
  294.     def on_item_command_button_clicked(self, button):
  295.         self.showCommandDialog(self.tree.get_widget('item_command_entry'))
  296.  
  297.     def on_newitem_command_button_clicked(self, button):
  298.         self.showCommandDialog(self.tree.get_widget('newitem_command_entry'))
  299.  
  300.     def saveItem(self, values, final=False):
  301.         pixbuf, path = util.getIcon(self.item, True)
  302.         #if the icon hasn't changed don't save the themed path
  303.         if path == values[0]:
  304.             self.editor.editItem(self.item, None, values[1], values[2], values[3], values[4], self.item_parent, final)
  305.         else:
  306.             self.editor.editItem(self.item, values[0], values[1], values[2], values[3], values[4], self.item_parent, final)
  307.  
  308.     def revertItem(self):
  309.         self.in_revert = True
  310.         icon_button = self.tree.get_widget('item_icon_button')
  311.         icon_button.remove(icon_button.get_children()[0])
  312.         if self.item_original_values[0]:
  313.             image = gtk.Image()
  314.             pixbuf = gtk.gdk.pixbuf_new_from_file_at_size(self.item_original_values[0], 24, 24)
  315.             image.set_from_pixbuf(pixbuf)
  316.             icon_button.add(image)
  317.             image.show()
  318.             icon_button.icon_path = self.item_original_values[0]
  319.         else:
  320.             label = gtk.Label('No Icon')
  321.             icon_button.add(label)
  322.         self.tree.get_widget('item_name_entry').set_text(self.item_original_values[1])
  323.         self.tree.get_widget('item_comment_entry').set_text(self.item_original_values[2])
  324.         self.tree.get_widget('item_command_entry').set_text(self.item_original_values[3])
  325.         self.tree.get_widget('item_terminal_check').set_active(self.item_original_values[4])
  326.         self.tree.get_widget('item_revert_button').set_sensitive(False)
  327.  
  328.     def newMenuDialog(self):
  329.         tree = gtk.glade.XML(os.path.join(self.file_path, 'alacarte.glade'), 'newmenuproperties')
  330.         signals = {}
  331.         for attr in dir(self):
  332.             signals[attr] = getattr(self, attr)
  333.         tree.signal_autoconnect(signals)
  334.         def responseChecker(response):
  335.             if response == gtk.RESPONSE_OK:
  336.                 if len(tree.get_widget('newmenu_name_entry').get_text()) == 0:
  337.                     self.showError(_('A name is required.'))
  338.                     return False
  339.                 return 'save'
  340.             return True
  341.         dialog = tree.get_widget('newmenuproperties')
  342.         dialog.set_transient_for(self.parent)
  343.         icon_button = tree.get_widget('newmenu_icon_button')
  344.         icon_button.remove(icon_button.get_children()[0])
  345.         label = gtk.Label('No Icon')
  346.         icon_button.add(label)
  347.         icon_button.icon_path = None
  348.         dialog.show_all()
  349.         can_close = False
  350.         while can_close == False:
  351.             response = dialog.run()
  352.             can_close = responseChecker(response)
  353.         if can_close == 'save':
  354.             name_entry = tree.get_widget('newmenu_name_entry')
  355.             comment_entry = tree.get_widget('newmenu_comment_entry')
  356.             dialog.destroy()
  357.             return (icon_button.icon_path, name_entry.get_text(), comment_entry.get_text())
  358.         dialog.destroy()
  359.         
  360.  
  361.     def editMenuDialog(self, menu_row):
  362.         def responseChecker(response):
  363.             if response == gtk.RESPONSE_REJECT:
  364.                 self.revertMenu()
  365.                 return False
  366.             if response == gtk.RESPONSE_CLOSE or response == gtk.RESPONSE_DELETE_EVENT:
  367.                 if len(self.tree.get_widget('menu_name_entry').get_text()) == 0:
  368.                     self.showError(_('A name is required.'))
  369.                     return False
  370.                 return True
  371.             return False
  372.         self.in_dialog_setup = True
  373.         self.menu_row = menu_row
  374.         self.menu = menu_row[3]
  375.         #load widgets
  376.         self.tree = gtk.glade.XML(os.path.join(self.file_path, 'alacarte.glade'), 'menuproperties')
  377.         signals = {}
  378.         for attr in dir(self):
  379.             signals[attr] = getattr(self, attr)
  380.         self.tree.signal_autoconnect(signals)
  381.         dialog = self.tree.get_widget('menuproperties')
  382.         icon_button = self.tree.get_widget('menu_icon_button')
  383.         name_entry = self.tree.get_widget('menu_name_entry')
  384.         comment_entry = self.tree.get_widget('menu_comment_entry')
  385.  
  386.         dialog.set_transient_for(self.parent)
  387.         icon_button.remove(icon_button.get_children()[0])
  388.         pixbuf, path = util.getIcon(self.menu, True)
  389.         icon_button.icon_path = None
  390.         if pixbuf:
  391.             image = gtk.Image()
  392.             image.set_from_pixbuf(pixbuf)
  393.             icon_button.add(image)
  394.             icon_button.icon_path = path
  395.         else:
  396.             label = gtk.Label('No Icon')
  397.             icon_button.add(label)
  398.         name_entry.set_text(self.menu.get_name())
  399.         if self.menu.get_comment():
  400.             comment_entry.set_text(self.menu.get_comment())
  401.         dialog.show_all()
  402.         self.menu_original_values = (
  403.             icon_button.icon_path,
  404.             name_entry.get_text(),
  405.             comment_entry.get_text()
  406.             )
  407.         self.in_dialog_setup = False
  408.         #hack to make undo work
  409.         self.first_change = True
  410.         can_close = False
  411.         while can_close == False:
  412.             response = dialog.run()
  413.             can_close = responseChecker(response)
  414.         dialog.destroy()
  415.  
  416.     def on_menu_contents_changed(self, garbage):
  417.         self.menu_row[1] = util.getIcon(self.tree.get_widget('menu_icon_button').icon_path)
  418.         self.menu_row[2] = self.tree.get_widget('menu_name_entry').get_text()
  419.         if self.first_change:
  420.             self.saveMenu(self.menu_original_values, True)
  421.             self.first_change = False
  422.         if self.in_revert:
  423.             self.in_revert = False
  424.             self.saveMenuChanges()
  425.             return
  426.         if not self.in_dialog_setup:
  427.             self.tree.get_widget('menu_revert_button').set_sensitive(True)
  428.             values = (
  429.                 self.tree.get_widget('menu_icon_button').icon_path,
  430.                 self.tree.get_widget('menu_name_entry').get_text(),
  431.                 self.tree.get_widget('menu_comment_entry').get_text()
  432.                 )
  433.             self.saveMenu(values)
  434.  
  435.     def on_menu_icon_button_clicked(self, button):
  436.         if self.showIconDialog(button):
  437.             self.on_menu_contents_changed(button)
  438.  
  439.     def saveMenu(self, values, final=False):
  440.         pixbuf, path = util.getIcon(self.menu, True)
  441.         #if the icon hasn't changed don't save the themed path
  442.         if path == values[0]:
  443.             self.editor.editMenu(self.menu, None, values[1], values[2], final)
  444.         else:
  445.             self.editor.editMenu(self.menu, values[0], values[1], values[2], final)
  446.  
  447.     def revertMenu(self):
  448.         self.in_revert = True
  449.         icon_button = self.tree.get_widget('menu_icon_button')
  450.         icon_button.remove(icon_button.get_children()[0])
  451.         if self.menu_original_values[0]:
  452.             image = gtk.Image()
  453.             pixbuf = gtk.gdk.pixbuf_new_from_file_at_size(self.menu_original_values[0], 24, 24)
  454.             image.set_from_pixbuf(pixbuf)
  455.             icon_button.add(image)
  456.             image.show()
  457.             icon_button.icon_path = self.menu_original_values[0]
  458.         else:
  459.             label = gtk.Label('No Icon')
  460.             icon_button.add(label)
  461.         self.tree.get_widget('menu_name_entry').set_text(self.menu_original_values[1])
  462.         self.tree.get_widget('menu_comment_entry').set_text(self.menu_original_values[2])
  463.