Why Gemfury? Push, build, and install  RubyGems npm packages Python packages Maven artifacts PHP packages Go Modules Bower components Debian packages RPM packages NuGet packages

beebox / crossover   deb

Repository URL to install this package:

Version: 18.5.0-1 

/ opt / cxoffice / lib / python / cxassocwidget.py

# (c) Copyright 2009-2012. CodeWeavers, Inc.

import traceback

import gobject
import gtk

import cxlog
import cxutils

import cxassoc

import cxguitools
import pyop

# for localization
from cxutils import cxgettext as _

# positions of columns in the ListStore
_COLUMN_EASSOC = 0
_COLUMN_MODE = 1
_COLUMN_LOCALIZED_MODE = 2
_COLUMN_EXTENSION = 3
_COLUMN_VERBNAME = 4
_COLUMN_APPLICATION = 5
_COLUMN_ICON_PIXBUF = 6
_COLUMN_MODE_COLOR = 7
_COLUMN_EXTENSION_SORT = 8

_mode_settings = ('default', 'alternative', 'mime', 'ignore')

_mode_colors = {
    'default': gtk.gdk.color_parse('green'),
    'alternative': gtk.gdk.color_parse('yellow'),
    'mime': gtk.gdk.color_parse('#E4E4E4'),
    'ignore': gtk.gdk.color_parse('#E4E4E4'),
    }

class AssocEditorPrefs(cxassoc.CXAssocPrefs):
    def mode_changed(self, eassoc, newmode, _user):
        row_index = self.editor_widget.row_indexes[eassoc]
        row_iter = self.editor_widget.liststore.get_iter((row_index,))

        mode_color = _mode_colors[newmode]

        self.editor_widget.liststore.set(row_iter,
                                         _COLUMN_MODE, newmode,
                                         _COLUMN_LOCALIZED_MODE, self.editor_widget.localized_modes[newmode],
                                         _COLUMN_MODE_COLOR, mode_color)

    def __init__(self, bottlename, managed, editor_widget):
        cxassoc.CXAssocPrefs.__init__(self, bottlename, managed)
        self.editor_widget = editor_widget

class AssocEditor(gtk.VBox):
    __gtype_name__ = 'AssocEditor'

    bottlename = None
    managed = None
    prefs = None

    def set_bottle(self, bottlename, managed):
        if self.bottlename:
            raise ValueError("bottle is already set")
        self.bottlename = bottlename
        self.managed = managed
        if not self.managed:
            self.mode_renderer.connect('edited', self.on_mode_edited)
        elif hasattr(self.mode_renderer, 'set_sensitive'):
            self.mode_renderer.set_sensitive(False)

        self.prefs = AssocEditorPrefs(bottlename, managed, self)

    def __init__(self):
        gtk.VBox.__init__(self)

        self.row_indexes = {} # mapping of section names to liststore rows

        self.localized_modes = {'default': _("Use when double-clicking"),
                                'alternative': _("Include in Open With"),
                                'mime': _("Register file type"),
                                'ignore': _("Ignore extension")}

        self.localized_verbs = {'': _("&Open"),
                                'edit': _("&Edit"),
                                'install': _("&Install"), # for the CrossOver associations
                                'open': _("&Open"),
                                'opennew': _("&Open"),
                                'play': _("&Play"),
                                'preview': _("Pre&view"),
                                'print': _("&Print"),
                                'restore': _("&Restore"), # for the CrossOver associations
                                'run': _("&Run")}         # for the CrossOver associations

        self.filter_function = None

        self.progbar = gtk.ProgressBar()

        self.pack_start(self.progbar, expand=True, fill=False, padding=0)

        self.liststore = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_STRING,
                                       gobject.TYPE_STRING, gobject.TYPE_STRING, gobject.TYPE_STRING,
                                       gobject.TYPE_STRING, gtk.gdk.Pixbuf, gtk.gdk.Color, gobject.TYPE_STRING)

        self.filteredmodel = self.liststore.filter_new()
        self.filteredmodel.set_visible_func(self.row_is_visible)

        self.sortedmodel = gtk.TreeModelSort(self.filteredmodel)
        self.sortedmodel.set_sort_column_id(_COLUMN_EXTENSION_SORT, gtk.SORT_ASCENDING)

        self.treeview = gtk.TreeView(self.sortedmodel)
        self.treeview.set_property('headers-clickable', True)
        self.treeview.show()

        self.scrolledview = gtk.ScrolledWindow()
        self.scrolledview.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
        self.scrolledview.add(self.treeview)

        icon_renderer = gtk.CellRendererPixbuf()
        icon_column = gtk.TreeViewColumn(_("Icon"), icon_renderer)
        icon_column.add_attribute(icon_renderer, 'pixbuf', _COLUMN_ICON_PIXBUF)
        self.treeview.append_column(icon_column)

        ext_renderer = gtk.CellRendererText()
        ext_column = gtk.TreeViewColumn(_("Extension"), ext_renderer)
        ext_column.set_resizable(True)
        ext_column.add_attribute(ext_renderer, 'text', _COLUMN_EXTENSION)
        ext_column.set_sort_column_id(_COLUMN_EXTENSION_SORT)
        self.treeview.append_column(ext_column)

        action_renderer = gtk.CellRendererText()
        action_column = gtk.TreeViewColumn(_("Action"), action_renderer)
        action_column.set_resizable(True)
        action_column.add_attribute(action_renderer, 'text', _COLUMN_VERBNAME)
        action_column.set_sort_column_id(_COLUMN_VERBNAME)
        self.treeview.append_column(action_column)

        app_renderer = gtk.CellRendererText()
        app_column = gtk.TreeViewColumn(_("Application"), app_renderer)
        app_column.set_resizable(True)
        app_column.add_attribute(app_renderer, 'text', _COLUMN_APPLICATION)
        app_column.set_sort_column_id(_COLUMN_APPLICATION)
        self.treeview.append_column(app_column)

        # create a liststore containing the possible mode values for the mode
        # combo box
        self.mode_model = gtk.ListStore(gobject.TYPE_STRING)
        for mode in _mode_settings:
            self.mode_model.append((self.localized_modes[mode],))

        # create the mode column
        self.mode_renderer = gtk.CellRendererCombo()
        self.mode_renderer.set_property('has-entry', False)
        self.mode_renderer.set_property('model', self.mode_model)
        self.mode_renderer.set_property('text-column', 0)
        self.mode_renderer.set_property('editable', True)
        self.mode_renderer.set_property('editable-set', True)
        self.mode_renderer.set_property('foreground-gdk', gtk.gdk.color_parse('black'))
        self.mode_column = gtk.TreeViewColumn(_("State"), self.mode_renderer)
        self.mode_column.add_attribute(self.mode_renderer, 'text', _COLUMN_LOCALIZED_MODE)
        self.mode_column.add_attribute(self.mode_renderer, 'background-gdk', _COLUMN_MODE_COLOR)
        self.mode_column.set_sort_column_id(_COLUMN_LOCALIZED_MODE)
        self.treeview.append_column(self.mode_column)

        if hasattr(self.treeview, 'set_has_tooltip'):
            # GTK+ >= 2.12
            self.treeview.set_has_tooltip(True)

            self.treeview.connect('query-tooltip', self.on_query_tooltip)

        self.pack_start(self.scrolledview, expand=True, fill=True, padding=0)

        self.pulse_timer = None

    def on_query_tooltip(self, widget, x, y, keyboard_mode, tooltip):
        if not keyboard_mode:
            res = widget.get_path_at_pos(x, y)
            # res is (path, column, x, y)
            if res and res[1] == self.mode_column:
                tooltip.set_text(_("Click twice to change"))
                return True

        return False

    def pulse(self):
        self.progbar.pulse()
        return True

    def pulse_start(self, text):
        self.progbar.set_text(text)
        self.progbar.show()
        self.pulse_timer = gobject.timeout_add(100, self.pulse)
        self.scrolledview.set_sensitive(False)

    def pulse_stop(self):
        if self.pulse_timer:
            gobject.source_remove(self.pulse_timer)
            self.pulse_timer = None
            self.progbar.hide()
            self.scrolledview.set_sensitive(True)

    def refresh(self, success_notify, failure_notify):
        if self.pulse_timer:
            return
        self.pulse_start(_(u"Reading the associations of %(bottlename)s\u2026") % {'bottlename': self.prefs.bottlename})
        operation = RefreshAssociationsOp(self, success_notify, failure_notify)
        pyop.sharedOperationQueue.enqueue(operation)

    def recreate_assocs(self, success_notify, failure_notify):
        if self.pulse_timer:
            return
        self.pulse_start(_(u"Recreating the associations in %(bottlename)s\u2026") % {'bottlename': self.prefs.bottlename})
        operation = RecreateAssocsOp(self, success_notify, failure_notify)
        pyop.sharedOperationQueue.enqueue(operation)

    def commit(self, success_notify, failure_notify):
        if self.pulse_timer:
            return
        self.pulse_start(_(u"Saving changes\u2026"))
        operation = CommitAssociationsOp(self, success_notify, failure_notify)
        pyop.sharedOperationQueue.enqueue(operation)

    def update_assoclist(self):
        "read the list of associations from self.prefs"
        self.liststore.clear()
        self.row_indexes.clear()

        for n, eassoc in enumerate(self.prefs):
            assoc = self.prefs[eassoc]
            icon_filename = assoc.get_iconfilename()
            icon = None
            if icon_filename:
                try:
                    icon = gtk.gdk.pixbuf_new_from_file(icon_filename)
                except gobject.GError:
                    cxlog.warn("couldn't load icon file %s:\n%s" % (cxlog.debug_str(icon_filename), traceback.format_exc()))
            if icon is None:
                icon = cxguitools.get_std_icon('crossover')
            if icon is not None:
                icon = icon.scale_simple(24, 24, gtk.gdk.INTERP_BILINEAR)
            verbname = cxutils.remove_accelerators(self.localized_verbs.get(assoc.verbname, assoc.verbname))
            mode_color = _mode_colors[assoc.new_mode]
            sort_extension = '1'.join(assoc.extension) + '0' + eassoc
            self.liststore.append((eassoc, assoc.new_mode, self.localized_modes[assoc.new_mode],
                                   assoc.extension, verbname, assoc.appname, icon, mode_color, sort_extension))
            self.row_indexes[eassoc] = n

        # Don't pad the progress bar next time we show it; we want the treeview
        # to fill that space.
        self.set_child_packing(self.progbar, False, False, 0, gtk.PACK_START)

        self.scrolledview.show()

    def on_mode_edited(self, _cellrenderer, path, new_text):
        row_iter = self.sortedmodel.get_iter(path)
        eassoc = self.sortedmodel.get_value(row_iter, _COLUMN_EASSOC)

        for mode, local_mode in self.localized_modes.iteritems():
            if local_mode == new_text:
                self.prefs.set_mode(eassoc, mode)
                break
        else:
            cxlog.warn("got invalid association state from cell renderer: %s" % cxlog.debug_str(new_text))
            return

    def row_is_visible(self, model, row_iter):
        """See gtk.TreeModelFilter.set_visible_func()"""
        eassoc = model.get_value(row_iter, _COLUMN_EASSOC)

        if eassoc is not None: #FIXME: Why is this needed?
            if self.filter_function:
                return self.filter_function(eassoc)
            return True
        return False

    def set_filter(self, filter_function):
        self.filter_function = filter_function
        self.filteredmodel.refilter()

class RefreshAssociationsOp(pyop.PythonOperation):
    def __init__(self, editor, success_notify, failure_notify):
        pyop.PythonOperation.__init__(self)
        self.editor = editor
        self.success_notify = success_notify
        self.failure_notify = failure_notify
        self.error_text = None

    def main(self):
        self.error_text = None
        try:
            self.editor.prefs.refresh()
        except Exception: # pylint: disable=W0703
            self.error_text = traceback.format_exc()

    def finish(self):
        self.editor.pulse_stop()
        self.editor.update_assoclist()
        if self.error_text is None:
            self.success_notify()
        else:
            self.failure_notify(self.error_text)

class RecreateAssocsOp(pyop.PythonOperation):
    def __init__(self, editor, success_notify, failure_notify):
        pyop.PythonOperation.__init__(self)
        self.editor = editor
        self.success_notify = success_notify
        self.failure_notify = failure_notify
        self.error_text = None

    def main(self):
        self.error_text = None
        try:
            self.editor.prefs.recreate_assocs()
            self.editor.prefs.refresh()
        except Exception: # pylint: disable=W0703
            self.error_text = traceback.format_exc()

    def finish(self):
        self.editor.pulse_stop()
        self.editor.update_assoclist()
        if self.error_text is None:
            self.success_notify()
        else:
            self.failure_notify(self.error_text)

class CommitAssociationsOp(pyop.PythonOperation):
    def __init__(self, editor, success_notify, failure_notify):
        pyop.PythonOperation.__init__(self)
        self.editor = editor
        self.success_notify = success_notify
        self.failure_notify = failure_notify
        self.error_text = None

    def main(self):
        self.error_text = None
        try:
            self.editor.prefs.commit()
        except Exception: # pylint: disable=W0703
            self.error_text = traceback.format_exc()

    def finish(self):
        self.editor.pulse_stop()
        if self.error_text is None:
            self.success_notify()
        else:
            self.failure_notify(self.error_text)