~ubuntu-branches/debian/experimental/spyder/experimental

« back to all changes in this revision

Viewing changes to spyderlib/widgets/comboboxes.py

  • Committer: Package Import Robot
  • Author(s): Picca Frédéric-Emmanuel
  • Date: 2013-02-27 09:51:28 UTC
  • mfrom: (1.1.18)
  • Revision ID: package-import@ubuntu.com-20130227095128-wtx1irpvf4vl79lj
Tags: 2.2.0~beta3+dfsg-1
* Imported Upstream version 2.2.0~beta3+dfsg
* debian /patches
  - 0002-feature-forwarded-add-icon-to-desktop-file.patch (deleted)
    this patch was integrated by the upstream.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# -*- coding: utf-8 -*-
2
 
#
3
 
# Copyright © 2009-2010 Pierre Raybaut
4
 
# Licensed under the terms of the MIT License
5
 
# (see spyderlib/__init__.py for details)
6
 
 
7
 
"""Customized combobox widgets"""
8
 
 
9
 
# pylint: disable=C0103
10
 
# pylint: disable=R0903
11
 
# pylint: disable=R0911
12
 
# pylint: disable=R0201
13
 
 
14
 
from spyderlib.qt.QtGui import (QComboBox, QFont, QToolTip, QSizePolicy,
15
 
                                QCompleter)
16
 
from spyderlib.qt.QtCore import SIGNAL, Qt, QUrl, QTimer
17
 
 
18
 
import os.path as osp
19
 
 
20
 
# Local imports
21
 
from spyderlib.baseconfig import _
22
 
 
23
 
 
24
 
class BaseComboBox(QComboBox):
25
 
    """Editable combo box base class"""
26
 
    def __init__(self, parent):
27
 
        QComboBox.__init__(self, parent)
28
 
        self.setEditable(True)
29
 
        self.setCompleter(QCompleter(self))
30
 
 
31
 
    # --- overrides
32
 
    def keyPressEvent(self, event):
33
 
        """Handle key press events"""
34
 
        if event.key() == Qt.Key_Return or event.key() == Qt.Key_Enter:
35
 
            self.add_current_text()
36
 
        else:
37
 
            QComboBox.keyPressEvent(self, event)
38
 
 
39
 
    def focusOutEvent(self, event):
40
 
        """Handle focus out event"""
41
 
        # Calling asynchronously the 'add_current_text' to avoid crash
42
 
        # https://groups.google.com/group/spyderlib/browse_thread/thread/2257abf530e210bd
43
 
        QTimer.singleShot(50, self.add_current_text)
44
 
        QComboBox.focusOutEvent(self, event)
45
 
 
46
 
    # --- own methods
47
 
    def is_valid(self, qstr):
48
 
        """
49
 
        Return True if string is valid
50
 
        Return None if validation can't be done
51
 
        """
52
 
        pass
53
 
        
54
 
    def selected(self):
55
 
        """Action to be executed when a valid item has been selected"""
56
 
        self.emit(SIGNAL('valid(bool)'), True)
57
 
        
58
 
    def add_text(self, text):
59
 
        """Add text to combo box: add a new item if text is not found in 
60
 
        combo box items"""
61
 
        index = self.findText(text)
62
 
        while index != -1:
63
 
            self.removeItem(index)
64
 
            index = self.findText(text)
65
 
        self.insertItem(0, text)
66
 
        index = self.findText('')
67
 
        if index != -1:
68
 
            self.removeItem(index)
69
 
            self.insertItem(0, '')
70
 
            self.setCurrentIndex(1)
71
 
        else:
72
 
            self.setCurrentIndex(0)
73
 
            
74
 
    def add_current_text(self):
75
 
        """Add current text to combo box history (convenient method)"""
76
 
        valid = self.is_valid(self.currentText())
77
 
        if valid or valid is None:
78
 
            self.add_text(self.currentText())
79
 
            self.selected()
80
 
        
81
 
 
82
 
class PatternComboBox(BaseComboBox):
83
 
    """Search pattern combo box"""
84
 
    def __init__(self, parent, items=None, tip=None,
85
 
                 adjust_to_minimum=True):
86
 
        BaseComboBox.__init__(self, parent)
87
 
        if adjust_to_minimum:
88
 
            self.setSizeAdjustPolicy(QComboBox.AdjustToMinimumContentsLength)
89
 
        self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
90
 
        if items is not None:
91
 
            self.addItems(items)
92
 
        if tip is not None:
93
 
            self.setToolTip(tip)
94
 
 
95
 
 
96
 
class EditableComboBox(BaseComboBox):
97
 
    """
98
 
    Editable combo box + Validate
99
 
    """
100
 
    def __init__(self, parent):
101
 
        BaseComboBox.__init__(self, parent)
102
 
        self.setSizeAdjustPolicy(QComboBox.AdjustToMinimumContentsLength)
103
 
        self.font = QFont()
104
 
        self.connect(self, SIGNAL("editTextChanged(QString)"), self.validate)
105
 
        self.connect(self, SIGNAL("activated(QString)"),
106
 
                     lambda qstr: self.validate(qstr, editing=False))
107
 
        self.set_default_style()
108
 
        self.tips = {True: _("Press enter to validate this entry"),
109
 
                     False: _('This entry is incorrect')}
110
 
        
111
 
    def show_tip(self, tip=""):
112
 
        """Show tip"""
113
 
        QToolTip.showText(self.mapToGlobal(self.pos()), tip, self)
114
 
        
115
 
    def set_default_style(self):
116
 
        """Set widget style to default"""
117
 
        self.font.setBold(False)
118
 
        self.setFont(self.font)
119
 
        self.setStyleSheet("")
120
 
        self.show_tip()
121
 
        
122
 
    def selected(self):
123
 
        """Action to be executed when a valid item has been selected"""
124
 
        BaseComboBox.selected(self)
125
 
        self.set_default_style()
126
 
        
127
 
    def validate(self, qstr, editing=True):
128
 
        """Validate entered path"""
129
 
        valid = self.is_valid(qstr)
130
 
        if self.hasFocus() and valid is not None:
131
 
            self.font.setBold(True)
132
 
            self.setFont(self.font)
133
 
            if valid:
134
 
                self.setStyleSheet("color:rgb(50, 155, 50);")
135
 
            else:
136
 
                self.setStyleSheet("color:rgb(200, 50, 50);")
137
 
            if editing:
138
 
                # Combo box text is being modified: invalidate the entry
139
 
                self.show_tip(self.tips[valid])
140
 
                self.emit(SIGNAL('valid(bool)'), False)
141
 
            else:
142
 
                # A new item has just been selected
143
 
                if valid:
144
 
                    self.selected()
145
 
                else:
146
 
                    self.emit(SIGNAL('valid(bool)'), False)
147
 
        else:
148
 
            self.set_default_style()
149
 
            
150
 
 
151
 
class PathComboBox(EditableComboBox):
152
 
    """
153
 
    QComboBox handling path locations
154
 
    """
155
 
    def __init__(self, parent, adjust_to_contents=False):
156
 
        EditableComboBox.__init__(self, parent)
157
 
        if adjust_to_contents:
158
 
            self.setSizeAdjustPolicy(QComboBox.AdjustToContents)
159
 
        else:
160
 
            self.setSizeAdjustPolicy(QComboBox.AdjustToMinimumContentsLength)
161
 
            self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
162
 
        self.tips = {True: _("Press enter to validate this path"),
163
 
                     False: _('This path is incorrect.\n'
164
 
                                    'Enter a correct directory path,\n'
165
 
                                    'then press enter to validate')}
166
 
        
167
 
    def is_valid(self, qstr=None):
168
 
        """Return True if string is valid"""
169
 
        if qstr is None:
170
 
            qstr = self.currentText()
171
 
        return osp.isdir( unicode(qstr) )
172
 
    
173
 
    def selected(self):
174
 
        """Action to be executed when a valid item has been selected"""
175
 
        EditableComboBox.selected(self)
176
 
        self.emit(SIGNAL("open_dir(QString)"), self.currentText())
177
 
 
178
 
 
179
 
class UrlComboBox(PathComboBox):
180
 
    """
181
 
    QComboBox handling urls
182
 
    """
183
 
    def __init__(self, parent, adjust_to_contents=False):
184
 
        PathComboBox.__init__(self, parent, adjust_to_contents)
185
 
        self.disconnect(self, SIGNAL("editTextChanged(QString)"), self.validate)
186
 
        
187
 
    def is_valid(self, qstr=None):
188
 
        """Return True if string is valid"""
189
 
        if qstr is None:
190
 
            qstr = self.currentText()
191
 
        return QUrl(qstr).isValid()
192
 
 
193
 
 
194
 
def is_module_or_package(path):
195
 
    """Return True if path is a Python module/package"""
196
 
    is_module = osp.isfile(path) and osp.splitext(path)[1] in ('.py', '.pyw')
197
 
    is_package = osp.isdir(path) and osp.isfile(osp.join(path, '__init__.py'))
198
 
    return is_module or is_package
199
 
 
200
 
class PythonModulesComboBox(PathComboBox):
201
 
    """
202
 
    QComboBox handling Python modules or packages path
203
 
    (i.e. .py, .pyw files *and* directories containing __init__.py)
204
 
    """
205
 
    def __init__(self, parent, adjust_to_contents=False):
206
 
        PathComboBox.__init__(self, parent, adjust_to_contents)
207
 
        
208
 
    def is_valid(self, qstr=None):
209
 
        """Return True if string is valid"""
210
 
        if qstr is None:
211
 
            qstr = self.currentText()
212
 
        return is_module_or_package(unicode(qstr))
213
 
    
214
 
    def selected(self):
215
 
        """Action to be executed when a valid item has been selected"""
216
 
        EditableComboBox.selected(self)
217
 
        self.emit(SIGNAL("open(QString)"), self.currentText())
 
1
# -*- coding: utf-8 -*-
 
2
#
 
3
# Copyright © 2009-2010 Pierre Raybaut
 
4
# Licensed under the terms of the MIT License
 
5
# (see spyderlib/__init__.py for details)
 
6
 
 
7
"""Customized combobox widgets"""
 
8
 
 
9
# pylint: disable=C0103
 
10
# pylint: disable=R0903
 
11
# pylint: disable=R0911
 
12
# pylint: disable=R0201
 
13
 
 
14
from spyderlib.qt.QtGui import (QComboBox, QFont, QToolTip, QSizePolicy,
 
15
                                QCompleter)
 
16
from spyderlib.qt.QtCore import SIGNAL, Qt, QUrl, QTimer
 
17
 
 
18
import os.path as osp
 
19
 
 
20
# Local imports
 
21
from spyderlib.baseconfig import _
 
22
 
 
23
 
 
24
class BaseComboBox(QComboBox):
 
25
    """Editable combo box base class"""
 
26
    def __init__(self, parent):
 
27
        QComboBox.__init__(self, parent)
 
28
        self.setEditable(True)
 
29
        self.setCompleter(QCompleter(self))
 
30
 
 
31
    # --- overrides
 
32
    def keyPressEvent(self, event):
 
33
        """Handle key press events"""
 
34
        if event.key() == Qt.Key_Return or event.key() == Qt.Key_Enter:
 
35
            if self.add_current_text_if_valid():
 
36
                self.selected()
 
37
        else:
 
38
            QComboBox.keyPressEvent(self, event)
 
39
 
 
40
    def focusOutEvent(self, event):
 
41
        """Handle focus out event"""
 
42
        # Calling asynchronously the 'add_current_text' to avoid crash
 
43
        # https://groups.google.com/group/spyderlib/browse_thread/thread/2257abf530e210bd
 
44
        QTimer.singleShot(50, self.add_current_text_if_valid)
 
45
        QComboBox.focusOutEvent(self, event)
 
46
 
 
47
    # --- own methods
 
48
    def is_valid(self, qstr):
 
49
        """
 
50
        Return True if string is valid
 
51
        Return None if validation can't be done
 
52
        """
 
53
        pass
 
54
        
 
55
    def selected(self):
 
56
        """Action to be executed when a valid item has been selected"""
 
57
        self.emit(SIGNAL('valid(bool)'), True)
 
58
        
 
59
    def add_text(self, text):
 
60
        """Add text to combo box: add a new item if text is not found in 
 
61
        combo box items"""
 
62
        index = self.findText(text)
 
63
        while index != -1:
 
64
            self.removeItem(index)
 
65
            index = self.findText(text)
 
66
        self.insertItem(0, text)
 
67
        index = self.findText('')
 
68
        if index != -1:
 
69
            self.removeItem(index)
 
70
            self.insertItem(0, '')
 
71
            if text != '':
 
72
                self.setCurrentIndex(1)
 
73
            else:
 
74
                self.setCurrentIndex(0)
 
75
        else:
 
76
            self.setCurrentIndex(0)
 
77
            
 
78
    def add_current_text(self):
 
79
        """Add current text to combo box history (convenient method)"""
 
80
        self.add_text(self.currentText())
 
81
            
 
82
    def add_current_text_if_valid(self):
 
83
        """Add current text to combo box history if valid"""
 
84
        valid = self.is_valid(self.currentText())
 
85
        if valid or valid is None:
 
86
            self.add_current_text()
 
87
            return True
 
88
        
 
89
 
 
90
class PatternComboBox(BaseComboBox):
 
91
    """Search pattern combo box"""
 
92
    def __init__(self, parent, items=None, tip=None,
 
93
                 adjust_to_minimum=True):
 
94
        BaseComboBox.__init__(self, parent)
 
95
        if adjust_to_minimum:
 
96
            self.setSizeAdjustPolicy(QComboBox.AdjustToMinimumContentsLength)
 
97
        self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
 
98
        if items is not None:
 
99
            self.addItems(items)
 
100
        if tip is not None:
 
101
            self.setToolTip(tip)
 
102
 
 
103
 
 
104
class EditableComboBox(BaseComboBox):
 
105
    """
 
106
    Editable combo box + Validate
 
107
    """
 
108
    def __init__(self, parent):
 
109
        BaseComboBox.__init__(self, parent)
 
110
        self.setSizeAdjustPolicy(QComboBox.AdjustToMinimumContentsLength)
 
111
        self.font = QFont()
 
112
        self.connect(self, SIGNAL("editTextChanged(QString)"), self.validate)
 
113
        self.connect(self, SIGNAL("activated(QString)"),
 
114
                     lambda qstr: self.validate(qstr, editing=False))
 
115
        self.set_default_style()
 
116
        self.tips = {True: _("Press enter to validate this entry"),
 
117
                     False: _('This entry is incorrect')}
 
118
        
 
119
    def show_tip(self, tip=""):
 
120
        """Show tip"""
 
121
        QToolTip.showText(self.mapToGlobal(self.pos()), tip, self)
 
122
        
 
123
    def set_default_style(self):
 
124
        """Set widget style to default"""
 
125
        self.font.setBold(False)
 
126
        self.setFont(self.font)
 
127
        self.setStyleSheet("")
 
128
        self.show_tip()
 
129
        
 
130
    def selected(self):
 
131
        """Action to be executed when a valid item has been selected"""
 
132
        BaseComboBox.selected(self)
 
133
        self.set_default_style()
 
134
        
 
135
    def validate(self, qstr, editing=True):
 
136
        """Validate entered path"""
 
137
        valid = self.is_valid(qstr)
 
138
        if self.hasFocus() and valid is not None:
 
139
            self.font.setBold(True)
 
140
            self.setFont(self.font)
 
141
            if valid:
 
142
                self.setStyleSheet("color:rgb(50, 155, 50);")
 
143
            else:
 
144
                self.setStyleSheet("color:rgb(200, 50, 50);")
 
145
            if editing:
 
146
                # Combo box text is being modified: invalidate the entry
 
147
                self.show_tip(self.tips[valid])
 
148
                self.emit(SIGNAL('valid(bool)'), False)
 
149
            else:
 
150
                # A new item has just been selected
 
151
                if valid:
 
152
                    self.selected()
 
153
                else:
 
154
                    self.emit(SIGNAL('valid(bool)'), False)
 
155
        else:
 
156
            self.set_default_style()
 
157
            
 
158
 
 
159
class PathComboBox(EditableComboBox):
 
160
    """
 
161
    QComboBox handling path locations
 
162
    """
 
163
    def __init__(self, parent, adjust_to_contents=False):
 
164
        EditableComboBox.__init__(self, parent)
 
165
        if adjust_to_contents:
 
166
            self.setSizeAdjustPolicy(QComboBox.AdjustToContents)
 
167
        else:
 
168
            self.setSizeAdjustPolicy(QComboBox.AdjustToMinimumContentsLength)
 
169
            self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
 
170
        self.tips = {True: _("Press enter to validate this path"),
 
171
                     False: _('This path is incorrect.\n'
 
172
                                    'Enter a correct directory path,\n'
 
173
                                    'then press enter to validate')}
 
174
        
 
175
    def is_valid(self, qstr=None):
 
176
        """Return True if string is valid"""
 
177
        if qstr is None:
 
178
            qstr = self.currentText()
 
179
        return osp.isdir( unicode(qstr) )
 
180
    
 
181
    def selected(self):
 
182
        """Action to be executed when a valid item has been selected"""
 
183
        EditableComboBox.selected(self)
 
184
        self.emit(SIGNAL("open_dir(QString)"), self.currentText())
 
185
 
 
186
 
 
187
class UrlComboBox(PathComboBox):
 
188
    """
 
189
    QComboBox handling urls
 
190
    """
 
191
    def __init__(self, parent, adjust_to_contents=False):
 
192
        PathComboBox.__init__(self, parent, adjust_to_contents)
 
193
        self.disconnect(self, SIGNAL("editTextChanged(QString)"), self.validate)
 
194
        
 
195
    def is_valid(self, qstr=None):
 
196
        """Return True if string is valid"""
 
197
        if qstr is None:
 
198
            qstr = self.currentText()
 
199
        return QUrl(qstr).isValid()
 
200
 
 
201
 
 
202
def is_module_or_package(path):
 
203
    """Return True if path is a Python module/package"""
 
204
    is_module = osp.isfile(path) and osp.splitext(path)[1] in ('.py', '.pyw')
 
205
    is_package = osp.isdir(path) and osp.isfile(osp.join(path, '__init__.py'))
 
206
    return is_module or is_package
 
207
 
 
208
class PythonModulesComboBox(PathComboBox):
 
209
    """
 
210
    QComboBox handling Python modules or packages path
 
211
    (i.e. .py, .pyw files *and* directories containing __init__.py)
 
212
    """
 
213
    def __init__(self, parent, adjust_to_contents=False):
 
214
        PathComboBox.__init__(self, parent, adjust_to_contents)
 
215
        
 
216
    def is_valid(self, qstr=None):
 
217
        """Return True if string is valid"""
 
218
        if qstr is None:
 
219
            qstr = self.currentText()
 
220
        return is_module_or_package(unicode(qstr))
 
221
    
 
222
    def selected(self):
 
223
        """Action to be executed when a valid item has been selected"""
 
224
        EditableComboBox.selected(self)
 
225
        self.emit(SIGNAL("open(QString)"), self.currentText())