File: encodings.py

package info (click to toggle)
turing 0.11-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 10,340 kB
  • sloc: python: 106,582; xml: 101; makefile: 53; sh: 29
file content (195 lines) | stat: -rw-r--r-- 7,215 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
"""
This module contains the encodings related widgets (combox, menus,...)
"""
import locale
import logging
from pyqode.core.api import ENCODINGS_MAP, convert_to_codec_key
from pyqode.qt import QtCore, QtWidgets
from pyqode.core.cache import Cache


def _logger():
    return logging.getLogger(__name__)


class EncodingsComboBox(QtWidgets.QComboBox):
    """
    This combo box display the list of user preferred encoding.
    The last item let you choose an additional encoding from the list
    of encodings define in :mod:`pyqode.core.api.encodings` using
    the EncodingsEditorDialog.

    You can also set the current encoding, it will be automatically appended
    if not in the user list or set as the current index.
    """
    @property
    def current_encoding(self):
        """
        Gets/Sets the current encoding
        """
        return self._current_encoding

    @current_encoding.setter
    def current_encoding(self, value):
        self._current_encoding = convert_to_codec_key(value)
        self._refresh_items()

    def __init__(self, parent, default_encoding=locale.getpreferredencoding()):
        super(EncodingsComboBox, self).__init__(parent)
        self._current_encoding = default_encoding
        self._lock = False
        self._refresh_items()
        self.currentIndexChanged.connect(self._on_current_changed)

    def _on_current_changed(self, index):
        if self._lock:
            return
        if index == self.count() - 1:
            from pyqode.core.dialogs import DlgPreferredEncodingsEditor
            if DlgPreferredEncodingsEditor.edit_encoding(self):
                self._refresh_items()
        else:
            self._current_encoding = self.itemData(index, QtCore.Qt.UserRole)

    def _refresh_items(self):
        self._lock = True
        self.clear()
        for i, encoding in enumerate(sorted(Cache().preferred_encodings)):
            encoding = convert_to_codec_key(encoding)
            try:
                alias, lang = ENCODINGS_MAP[encoding]
            except KeyError:
                _logger().warning('KeyError with encoding: %s', encoding)
            else:
                self.addItem('%s (%s)' % (alias, lang))
                self.setItemData(i, encoding, QtCore.Qt.UserRole)
                if encoding == self._current_encoding or \
                        convert_to_codec_key(alias) == self._current_encoding:
                    self.setCurrentIndex(i)
        self.insertSeparator(self.count())
        self.addItem('Add or remove')
        self._lock = False


class EncodingsMenu(QtWidgets.QMenu):
    """
    Implements a menu that show the user preferred encoding and emit
    reload_requested when the user changed the selected encoding.

    This menu is a general purpose menu that you can put anywhere in your
    application but you will have to manage the reload operation yourself.
    For an integrated context menu, prefer using
    :class:`pyqode.core.widgets.EncodingsContextMenu`.

    """
    #: Signal emitted when the user triggered an action.
    reload_requested = QtCore.Signal(str)

    @property
    def current_encoding(self):
        """
        Gets/Sets the current encoding
        """
        return self._current_encoding

    @current_encoding.setter
    def current_encoding(self, value):
        self._current_encoding = convert_to_codec_key(value)
        self._refresh()

    def __init__(self, title=_('Encodings'), parent=None,
                 selected_encoding=locale.getpreferredencoding()):
        super(EncodingsMenu, self).__init__(parent)
        self.setTitle(title)
        self._group = QtWidgets.QActionGroup(self)
        self._edit_action = None
        self._current_encoding = ''
        self.current_encoding = selected_encoding

    def _clear_actions(self):
        for action in self._group.actions():
            self._group.removeAction(action)
            self.removeAction(action)
        self.removeAction(self._edit_action)

    def _refresh(self):
        self._clear_actions()
        for i, encoding in enumerate(sorted(Cache().preferred_encodings)):
            encoding = convert_to_codec_key(encoding)
            try:
                alias, lang = ENCODINGS_MAP[encoding]
            except KeyError:
                _logger().warn('KeyError with encoding:', encoding)
            else:
                action = QtWidgets.QAction('%s (%s)' % (alias, lang), self)
                action.setData(encoding)
                action.setCheckable(True)
                if encoding == self._current_encoding or \
                        convert_to_codec_key(alias) == self._current_encoding:
                    action.setChecked(True)
                self.addAction(action)
                self._group.addAction(action)
        self._group.triggered.connect(self._on_encoding_triggered)
        self.addSeparator()
        self._edit_action = QtWidgets.QAction(_('Add or remove'), self)
        self._edit_action.triggered.connect(self._on_edit_requested)
        self.addAction(self._edit_action)

    def _on_edit_requested(self):
        from pyqode.core.dialogs import DlgPreferredEncodingsEditor
        if DlgPreferredEncodingsEditor.edit_encoding(self):
            self._refresh()

    def _on_encoding_triggered(self, action):
        self.reload_requested.emit(action.data())


class EncodingsContextMenu(EncodingsMenu):
    """
    Extends the encoding menu to be tightly coupled with a CodeEdit instance
    for an easier integration (automatically reload the editor file content
    when the encoding changed).

    The parent widget of the menu must be set to a CodeEdit instance.
    """
    def __init__(self, title='Encodings', parent=None,
                 selected_encoding=locale.getpreferredencoding()):
        from pyqode.core.api import CodeEdit
        assert isinstance(parent, CodeEdit)
        super(EncodingsContextMenu, self).__init__(
            title, parent, selected_encoding)
        self.reload_requested.connect(self._on_reload_requested)
        parent.new_text_set.connect(self._refresh)
        sep = QtWidgets.QAction(self.parent())
        sep.setSeparator(True)
        self.parent().add_menu(self)
        self._timer = QtCore.QTimer()
        self._timer.setInterval(1)
        self._timer.timeout.connect(self._reload)
        self._refresh()

    def _refresh(self):
        self._current_encoding = convert_to_codec_key(
            self.parent().file.encoding)
        super(EncodingsContextMenu, self)._refresh()

    def _on_reload_requested(self, encoding):
        self._encoding = encoding
        self._timer.start()

    def _reload(self):
        self._timer.stop()
        try:
            self.parent().file.reload(self._encoding)
        except UnicodeDecodeError:
            QtWidgets.QMessageBox.warning(
                self.parent(), _('Decoding error'),
                _('Failed to reload file with encoding %s') % self._encoding)
        else:
            try:
                from pyqode.core.panels import EncodingPanel
                panel = self.parent().panels.get(EncodingPanel)
            except KeyError:
                pass
            else:
                panel.close_panel()