Ejemplo n.º 1
0
class SimpleSearchControl(QtGui.QWidget):
    """A control that displays a single text field in which search keywords can
  be typed

  emits a search and a cancel signal if the user starts or cancels the search
  """

    expand_search_options_signal = QtCore.pyqtSignal()
    cancel_signal = QtCore.pyqtSignal()
    search_signal = QtCore.pyqtSignal(str)
    

    def __init__(self, parent):
        QtGui.QWidget.__init__(self, parent)
        layout = QtGui.QHBoxLayout()
        layout.setSpacing(0)
        layout.setMargin(3)

        # Search button
        self.search_button = QtGui.QToolButton()
        icon = Icon('tango/16x16/actions/system-search.png').getQIcon()
        self.search_button.setIcon(icon)
        self.search_button.setIconSize(QtCore.QSize(14, 14))
        self.search_button.setAutoRaise(True)
        self.search_button.setToolTip(_('Expand or collapse search options'))
        self.search_button.clicked.connect( self.emit_expand_search_options )

        # Search input
        from camelot.view.controls.decorated_line_edit import DecoratedLineEdit
        self.search_input = DecoratedLineEdit(self)
        self.search_input.set_background_text(_('Search...'))
        self.search_input.setToolTip(_('type words to search for'))
        #self.search_input.setStyleSheet('QLineEdit{ border-radius: 0.25em;}')
        self.search_input.returnPressed.connect( self.emit_search )
        self.search_input.textEdited.connect( self.emit_search )

        self.setFocusProxy( self.search_input )

        # Cancel button
        self.cancel_button = QtGui.QToolButton()
        icon = Icon('tango/16x16/actions/edit-clear.png').getQIcon()
        self.cancel_button.setIcon(icon)
        self.cancel_button.setIconSize(QtCore.QSize(14, 14))
        self.cancel_button.setAutoRaise(True)
        self.cancel_button.clicked.connect( self.emit_cancel )

        # Setup layout
        layout.addWidget(self.search_button)
        layout.addWidget(self.search_input)
        layout.addWidget(self.cancel_button)
        self.setLayout(layout)

    def search(self, search_text):
        """Start searching for search_text"""
        self.search_input.setText(search_text)
        self.emit_search()

    @QtCore.pyqtSlot()
    def emit_expand_search_options(self):
        self.expand_search_options_signal.emit()

    @QtCore.pyqtSlot()
    @QtCore.pyqtSlot(str)
    def emit_search(self, str=''):
        text = unicode(self.search_input.user_input())
        self.search_signal.emit( text )

    @QtCore.pyqtSlot()
    def emit_cancel(self):
        self.search_input.setText('')
        self.cancel_signal.emit()
Ejemplo n.º 2
0
class SimpleSearchControl(QtGui.QWidget):
    """A control that displays a single text field in which search keywords can
  be typed

  emits a search and a cancel signal if the user starts or cancels the search
  """

    expand_search_options_signal = QtCore.pyqtSignal()
    cancel_signal = QtCore.pyqtSignal()
    search_signal = QtCore.pyqtSignal(str)

    def __init__(self, parent):
        QtGui.QWidget.__init__(self, parent)
        layout = QtGui.QHBoxLayout()
        layout.setSpacing(0)
        layout.setMargin(3)

        # Search button
        self.search_button = QtGui.QToolButton()
        icon = Icon('tango/16x16/actions/system-search.png').getQIcon()
        self.search_button.setIcon(icon)
        self.search_button.setIconSize(QtCore.QSize(14, 14))
        self.search_button.setAutoRaise(True)
        self.search_button.setToolTip(_('Expand or collapse search options'))
        self.search_button.clicked.connect(self.emit_expand_search_options)

        # Search input
        from camelot.view.controls.decorated_line_edit import DecoratedLineEdit
        self.search_input = DecoratedLineEdit(self)
        self.search_input.set_background_text(_('Search...'))
        self.search_input.setToolTip(_('type words to search for'))
        #self.search_input.setStyleSheet('QLineEdit{ border-radius: 0.25em;}')
        self.search_input.returnPressed.connect(self.emit_search)
        self.search_input.textEdited.connect(self.emit_search)

        self.setFocusProxy(self.search_input)

        # Cancel button
        self.cancel_button = QtGui.QToolButton()
        icon = Icon('tango/16x16/actions/edit-clear.png').getQIcon()
        self.cancel_button.setIcon(icon)
        self.cancel_button.setIconSize(QtCore.QSize(14, 14))
        self.cancel_button.setAutoRaise(True)
        self.cancel_button.clicked.connect(self.emit_cancel)

        # Setup layout
        layout.addWidget(self.search_button)
        layout.addWidget(self.search_input)
        layout.addWidget(self.cancel_button)
        self.setLayout(layout)

    def search(self, search_text):
        """Start searching for search_text"""
        self.search_input.setText(search_text)
        self.emit_search()

    @QtCore.pyqtSlot()
    def emit_expand_search_options(self):
        self.expand_search_options_signal.emit()

    @QtCore.pyqtSlot()
    @QtCore.pyqtSlot(str)
    def emit_search(self, str=''):
        text = unicode(self.search_input.user_input())
        self.search_signal.emit(text)

    @QtCore.pyqtSlot()
    def emit_cancel(self):
        self.search_input.setText('')
        self.cancel_signal.emit()
Ejemplo n.º 3
0
class VirtualAddressEditor(CustomEditor):

    def __init__(self, 
                 parent = None, 
                 editable = True, 
                 address_type = None, 
                 address_validator = default_address_validator,
                 field_name = 'virtual_address',
                 **kwargs):
        """
        :param address_type: limit the allowed address to be entered to be
            of a certain time, can be 'phone', 'fax', 'email', 'mobile', 'pager'.
            If set to None, all types are allowed.
            
        Upto now, the corrected address returned by the address validator is
        not yet taken into account.
        """
        CustomEditor.__init__(self, parent)
        self.setObjectName( field_name )
        self._address_type = address_type
        self._address_validator = address_validator
        self.layout = QtGui.QHBoxLayout()
        self.layout.setContentsMargins( 0, 0, 0, 0)
        self.combo = QtGui.QComboBox()
        self.combo.addItems(camelot.types.VirtualAddress.virtual_address_types)
        self.combo.setEnabled(editable)
        if address_type:
            self.combo.setVisible(False)
        self.layout.addWidget(self.combo)
        self.editor = DecoratedLineEdit( self )
        self.editor.setEnabled(editable)
        self.editor.set_minimum_width( 30 )
        self.layout.addWidget(self.editor)
        self.setFocusProxy(self.editor)
        self.editable = editable
        nullIcon = Icon('tango/16x16/apps/internet-mail.png').getQIcon()
        self.label = QtGui.QToolButton()
        self.label.setIcon(nullIcon)
        self.label.setAutoRaise(True)
        self.label.setEnabled(False)
        self.label.setToolButtonStyle(Qt.ToolButtonIconOnly)
        self.label.setFocusPolicy(Qt.ClickFocus)
        self.label.clicked.connect( self.mail_click )
        self.label.hide()

        self.layout.addWidget(self.label)
        self.editor.editingFinished.connect(self.emit_editing_finished)
        self.editor.textEdited.connect(self.editorValueChanged)
        self.combo.currentIndexChanged.connect(self.comboIndexChanged)

        self.setLayout(self.layout)
        self.checkValue(self.editor.text())

    @QtCore.pyqtSlot()
    def comboIndexChanged(self):
        self.checkValue(self.editor.text())
        self.emit_editing_finished()

    def set_value(self, value):
        value = CustomEditor.set_value(self, value)
        if value:
            self.editor.setText(value[1])
            idx = camelot.types.VirtualAddress.virtual_address_types.index(self._address_type or value[0])
            self.combo.setCurrentIndex(idx)
            icon = Icon('tango/16x16/devices/printer.png').getQIcon()
# These icons don't exist any more in the new tango icon set
#            if str(self.combo.currentText()) == 'phone':
#                icon = Icon('tango/16x16/devices/phone.png').getQIcon()
            if str(self.combo.currentText()) == 'fax':
                icon = Icon('tango/16x16/devices/printer.png').getQIcon()
#            if str(self.combo.currentText()) == 'mobile':
#                icon = Icon('tango/16x16/devices/mobile.png').getQIcon()
#            if str(self.combo.currentText()) == 'im':
#                icon = Icon('tango/16x16/places/instant-messaging.png').getQIcon()
#            if str(self.combo.currentText()) == 'pager':
#                icon = Icon('tango/16x16/devices/pager.png').getQIcon()
            if str(self.combo.currentText()) == 'email':
                icon = Icon('tango/16x16/apps/internet-mail.png').getQIcon()
                #self.label.setFocusPolicy(Qt.StrongFocus)
                #self.label.setAutoFillBackground(True)
                self.label.setIcon(icon)
                self.label.setEnabled( self.editable )
                self.label.show()
            else:
                self.label.hide()
                self.label.setIcon(icon)
                self.label.setEnabled(self.editable)
                self.label.setToolButtonStyle(Qt.ToolButtonIconOnly)

#      self.update()
#      self.label.update()
#      self.layout.update()


            self.checkValue(value[1])

    def get_value(self):
        value = (unicode(self.combo.currentText()), unicode(self.editor.text()))
        return CustomEditor.get_value(self) or value

    def set_enabled(self, editable=True):
        self.combo.setEnabled(editable)
        self.editor.setEnabled(editable)
        if not editable:
            self.label.setEnabled(False)
        else:
            if self.combo.currentText() == 'email':
                self.label.setEnabled(True)

    def checkValue(self, text):
        address_type = unicode( self.combo.currentText() )
        valid, _corrected = self._address_validator( address_type, unicode( text ) )
        self.editor.set_valid( valid )

    def editorValueChanged(self, text):
        self.checkValue(text)

    @QtCore.pyqtSlot()
    def mail_click(self):
        address = self.editor.text()
        url = QtCore.QUrl()
        url.setUrl( u'mailto:%s?subject=Subject'%unicode(address) )
        QtGui.QDesktopServices.openUrl(url)

    def emit_editing_finished(self):
        self.value = []
        self.value.append(str(self.combo.currentText()))
        self.value.append(str(self.editor.text()))
        self.set_value(self.value)
        # emiting editingFinished without a value for the mechanism itself will lead to
        # integrity errors
        if self.value[1]:
            self.editingFinished.emit()

    def set_background_color(self, background_color):
        set_background_color_palette( self.editor, background_color )
            
    def set_field_attributes(self, editable = True,
                                   background_color = None,
                                   tooltip = None, **kwargs):
        self.set_enabled(editable)
        self.set_background_color(background_color)
        self.setToolTip(unicode(tooltip or ''))
Ejemplo n.º 4
0
class FileEditor(CustomEditor):
    """Widget for editing File fields"""

    document_pixmap = Icon('tango/16x16/mimetypes/x-office-document.png')

    def __init__(self,
                 parent=None,
                 storage=None,
                 field_name='file',
                 remove_original=False,
                 actions=[
                     field_action.DetachFile(),
                     field_action.OpenFile(),
                     field_action.UploadFile(),
                     field_action.SaveFile()
                 ],
                 **kwargs):
        CustomEditor.__init__(self, parent)
        self.setSizePolicy(QtGui.QSizePolicy.Preferred,
                           QtGui.QSizePolicy.Fixed)
        self.setObjectName(field_name)
        self.storage = storage
        self.filename = None  # the widget containing the filename
        self.value = None
        self.file_name = None
        self.remove_original = remove_original
        self.actions = actions
        self.setup_widget()

    def setup_widget(self):
        """Called inside init, overwrite this method for custom
        file edit widgets"""
        self.layout = QtWidgets.QHBoxLayout()
        self.layout.setSpacing(0)
        self.layout.setContentsMargins(0, 0, 0, 0)

        # Filename
        self.filename = DecoratedLineEdit(self)
        self.filename.set_minimum_width(20)
        self.filename.setFocusPolicy(Qt.ClickFocus)

        # Setup layout
        self.document_label = QtWidgets.QLabel(self)
        self.document_label.setPixmap(self.document_pixmap.getQPixmap())
        self.layout.addWidget(self.document_label)
        self.layout.addWidget(self.filename)
        self.add_actions(self.actions, self.layout)
        self.setLayout(self.layout)

    def file_completion_activated(self, index):
        from camelot.view.storage import create_stored_file
        source_index = index.model().mapToSource(index)
        if not self.completions_model.isDir(source_index):
            path = self.completions_model.filePath(source_index)
            create_stored_file(
                self,
                self.storage,
                self.stored_file_ready,
                filter=self.filter,
                remove_original=self.remove_original,
                filename=path,
            )

    def set_value(self, value):
        value = CustomEditor.set_value(self, value)
        self.value = value
        if value is not None:
            self.filename.setText(value.verbose_name)
        else:
            self.filename.setText('')
        self.update_actions()
        return value

    def get_value(self):
        return CustomEditor.get_value(self) or self.value

    def set_field_attributes(self, **kwargs):
        super(FileEditor, self).set_field_attributes(**kwargs)
        self.set_enabled(kwargs.get('editable', False))
        if self.filename:
            set_background_color_palette(self.filename,
                                         kwargs.get('background_color', None))
            self.filename.setToolTip(six.text_type(
                kwargs.get('tooltip') or ''))
        self.remove_original = kwargs.get('remove_original', False)

    def set_enabled(self, editable=True):
        self.filename.setEnabled(editable)
        self.filename.setReadOnly(not editable)
        self.document_label.setEnabled(editable)
        self.setAcceptDrops(editable)

    #
    # Drag & Drop
    #
    def dragEnterEvent(self, event):
        event.acceptProposedAction()

    def dragMoveEvent(self, event):
        event.acceptProposedAction()

    def dropEvent(self, event):
        from camelot.view.storage import create_stored_file
        if event.mimeData().hasUrls():
            url = event.mimeData().urls()[0]
            filename = url.toLocalFile()
            if filename:
                create_stored_file(
                    self,
                    self.storage,
                    self.stored_file_ready,
                    filter=self.filter,
                    remove_original=self.remove_original,
                    filename=filename,
                )
Ejemplo n.º 5
0
class Many2OneEditor(CustomEditor):
    """Widget for editing many 2 one relations"""

    arrow_down_key_pressed = QtCore.qt_signal()

    class CompletionsModel(QtCore.QAbstractListModel):
        def __init__(self, parent=None):
            QtCore.QAbstractListModel.__init__(self, parent)
            self._completions = []

        def setCompletions(self, completions):
            self._completions = completions
            self.layoutChanged.emit()

        def data(self, index, role):
            return py_to_variant(self._completions[index.row()].get(role))

        def rowCount(self, index=None):
            return len(self._completions)

        def columnCount(self, index=None):
            return 1

    def __init__(self,
                 admin=None,
                 parent=None,
                 editable=True,
                 field_name='manytoone',
                 actions=[
                     field_action.ClearObject(),
                     field_action.SelectObject(),
                     field_action.NewObject(),
                     field_action.OpenObject()
                 ],
                 **kwargs):
        """
        :param entity_admin : The Admin interface for the object on the one
        side of the relation
        """
        CustomEditor.__init__(self, parent)
        self.setSizePolicy(QtGui.QSizePolicy.Preferred,
                           QtGui.QSizePolicy.Fixed)
        self.setObjectName(field_name)
        self.admin = admin
        self.new_value = None
        self._entity_representation = ''
        self.obj = None
        self._last_highlighted_entity_getter = None

        self.layout = QtWidgets.QHBoxLayout()
        self.layout.setSpacing(0)
        self.layout.setContentsMargins(0, 0, 0, 0)

        # Search input
        self.search_input = DecoratedLineEdit(self)
        self.search_input.setPlaceholderText(_('Search...'))
        self.search_input.textEdited.connect(self.textEdited)
        self.search_input.set_minimum_width(20)
        self.search_input.arrow_down_key_pressed.connect(
            self.on_arrow_down_key_pressed)
        # suppose garbage was entered, we need to refresh the content
        self.search_input.editingFinished.connect(
            self.search_input_editing_finished)
        self.setFocusProxy(self.search_input)

        # Search Completer
        self.completer = QtGui.QCompleter()
        self.completions_model = self.CompletionsModel(self.completer)
        self.completer.setModel(self.completions_model)
        self.completer.setCaseSensitivity(Qt.CaseInsensitive)
        self.completer.setCompletionMode(
            QtGui.QCompleter.UnfilteredPopupCompletion)
        self.completer.activated[QtCore.QModelIndex].connect(
            self.completionActivated)
        self.completer.highlighted[QtCore.QModelIndex].connect(
            self.completion_highlighted)
        self.search_input.setCompleter(self.completer)

        # Setup layout
        self.layout.addWidget(self.search_input)
        self.setLayout(self.layout)
        self.add_actions(actions, self.layout)
        get_signal_handler().connect_signals(self)

    def set_field_attributes(self, **kwargs):
        super(Many2OneEditor, self).set_field_attributes(**kwargs)
        set_background_color_palette(self.search_input,
                                     kwargs.get('background_color'))
        self.search_input.setToolTip(kwargs.get('tooltip') or '')
        self.search_input.setEnabled(kwargs.get('editable', False))
        self.update_actions()

    def on_arrow_down_key_pressed(self):
        self.arrow_down_key_pressed.emit()

    def textEdited(self, text):
        self._last_highlighted_entity_getter = None
        text = six.text_type(self.search_input.text())

        def create_search_completion(text):
            return lambda: self.search_completions(text)

        post(create_search_completion(six.text_type(text)),
             self.display_search_completions)
        self.completer.complete()

    def search_completions(self, text):
        """Search for object that match text, to fill the list of completions

        :return: a list of tuples of (dict_of_object_representation, object)
        """
        search_decorator = create_entity_search_query_decorator(
            self.admin, text)
        if search_decorator:
            sresult = [
                self.admin.get_search_identifiers(e)
                for e in search_decorator(self.admin.get_query()).limit(20)
            ]
            return text, sresult
        return text, []

    def display_search_completions(self, prefix_and_completions):
        assert object_thread(self)
        prefix, completions = prefix_and_completions
        self.completions_model.setCompletions(completions)
        self.completer.setCompletionPrefix(prefix)
        self.completer.complete()

    def completionActivated(self, index):
        obj = index.data(Qt.EditRole)
        self.set_object(variant_to_py(obj))

    def completion_highlighted(self, index):
        obj = index.data(Qt.EditRole)
        self._last_highlighted_entity_getter = variant_to_py(obj)

    @QtCore.qt_slot(object, object)
    def handle_entity_update(self, sender, entity):
        if entity is self.get_value():
            self.set_object(entity, False)

    @QtCore.qt_slot(object, object)
    def handle_entity_delete(self, sender, entity):
        if entity is self.get_value():
            self.set_object(None, False)

    @QtCore.qt_slot(object, object)
    def handle_entity_create(self, sender, entity):
        if entity is self.new_value:
            self.new_value = None
            self.set_object(entity)

    def search_input_editing_finished(self):
        if self.obj is None:
            # Only try to 'guess' what the user meant when no entity is set
            # to avoid inappropriate removal of data, (eg when the user presses
            # Esc, editingfinished will be called as well, and we should not
            # overwrite the current entity set)
            if self._last_highlighted_entity_getter:
                self.set_object(self._last_highlighted_entity_getter)
            elif self.completions_model.rowCount() == 1:
                # There is only one possible option
                index = self.completions_model.index(0, 0)
                entity_getter = variant_to_py(index.data(Qt.EditRole))
                self.set_object(entity_getter)
        self.search_input.setText(self._entity_representation or u'')

    def set_value(self, value):
        """:param value: either ValueLoading, or a function that returns None
        or the entity to be shown in the editor"""
        self._last_highlighted_entity_getter = None
        self.new_value = None
        value = CustomEditor.set_value(self, value)
        self.set_object(value, propagate=False)
        self.update_actions()

    def get_value(self):
        """:return: a function that returns the selected entity or ValueLoading
        or None"""
        value = CustomEditor.get_value(self)
        if value is not None:
            return value
        return self.obj

    @QtCore.qt_slot(tuple)
    def set_instance_representation(self, representation_and_propagate):
        """Update the gui"""
        (desc, propagate) = representation_and_propagate
        self._entity_representation = desc
        self.search_input.setText(desc or u'')

        if propagate:
            self.editingFinished.emit()

    def set_object(self, obj, propagate=True):
        self.obj = obj

        def get_instance_representation(obj, propagate):
            """Get a representation of the instance"""
            if obj is not None:
                return (self.admin.get_verbose_object_name(obj), propagate)
            return (None, propagate)

        post(
            update_wrapper(
                partial(get_instance_representation, obj, propagate),
                get_instance_representation), self.set_instance_representation)

    selected_object = property(fset=set_object)
Ejemplo n.º 6
0
class LocalFileEditor(CustomEditor):
    """Widget for browsing local files and directories"""

    browse_icon = Icon('tango/16x16/places/folder-saved-search.png')

    def __init__(self,
                 parent=None,
                 field_name='local_file',
                 directory=False,
                 save_as=False,
                 file_filter='All files (*)',
                 **kwargs):
        CustomEditor.__init__(self, parent)
        self.setObjectName(field_name)
        self._directory = directory
        self._save_as = save_as
        self._file_filter = file_filter
        self.setup_widget()

    def setup_widget(self):
        """Called inside init, overwrite this method for custom
        file edit widgets"""
        layout = QtGui.QHBoxLayout()
        layout.setSpacing(0)
        layout.setContentsMargins(0, 0, 0, 0)

        browse_button = QtGui.QToolButton(self)
        browse_button.setFocusPolicy(Qt.ClickFocus)
        browse_button.setIcon(self.browse_icon.getQIcon())
        browse_button.setToolTip(_('Browse'))
        browse_button.setAutoRaise(True)
        browse_button.clicked.connect(self.browse_button_clicked)

        self.filename = DecoratedLineEdit(self)
        self.filename.editingFinished.connect(self.filename_editing_finished)
        self.setFocusProxy(self.filename)

        layout.addWidget(self.filename)
        layout.addWidget(browse_button)
        self.setLayout(layout)

    @QtCore.pyqtSlot()
    def filename_editing_finished(self):
        self.valueChanged.emit()
        self.editingFinished.emit()

    @QtCore.pyqtSlot()
    def browse_button_clicked(self):
        current_directory = os.path.dirname(self.get_value())
        if self._directory:
            value = QtGui.QFileDialog.getExistingDirectory(
                self, directory=current_directory)
        elif self._save_as:
            value = QtGui.QFileDialog.getSaveFileName(
                self, filter=self._file_filter, directory=current_directory)
        else:
            value = QtGui.QFileDialog.getOpenFileName(
                self, filter=self._file_filter, directory=current_directory)
        value = os.path.abspath(unicode(value))
        self.filename.setText(value)
        self.valueChanged.emit()
        self.editingFinished.emit()

    def set_value(self, value):
        value = CustomEditor.set_value(self, value)
        if value:
            self.filename.setText(value)
        else:
            self.filename.setText('')
        self.valueChanged.emit()
        return value

    def get_value(self):
        return CustomEditor.get_value(self) or unicode(self.filename.text())

    value = QtCore.pyqtProperty(str, get_value, set_value)

    def set_field_attributes(self,
                             editable=True,
                             background_color=None,
                             tooltip=None,
                             **kwargs):
        self.setEnabled(editable)
        if self.filename:
            set_background_color_palette(self.filename, background_color)
            self.filename.setToolTip(unicode(tooltip or ''))
Ejemplo n.º 7
0
class SimpleSearchControl(AbstractSearchWidget):
    """A control that displays a single text field in which search keywords can
    be typed

    emits a search and a cancel signal if the user starts or cancels the search
    """
    def __init__(self, parent):
        QtGui.QWidget.__init__(self, parent)
        layout = QtGui.QHBoxLayout()
        layout.setSpacing(0)
        layout.setContentsMargins(3, 3, 3, 3)

        #
        # The search timer reduced the number of search signals that are
        # emitted, by waiting for the next keystroke before emitting the
        # search signal
        #
        timer = QtCore.QTimer(self)
        timer.setInterval(300)
        timer.setSingleShot(True)
        timer.setObjectName('timer')
        timer.timeout.connect(self.emit_search)

        # Search button
        self.search_button = QtGui.QToolButton()
        icon = Icon('tango/16x16/actions/system-search.png').getQIcon()
        self.search_button.setIcon(icon)
        self.search_button.setIconSize(QtCore.QSize(14, 14))
        self.search_button.setAutoRaise(True)
        self.search_button.setToolTip(_('Expand or collapse search options'))
        self.search_button.clicked.connect(self.emit_expand_search_options)

        # Search input
        from camelot.view.controls.decorated_line_edit import DecoratedLineEdit
        self.search_input = DecoratedLineEdit(self)
        self.search_input.set_background_text(_('Search...'))
        #self.search_input.setStyleSheet('QLineEdit{ border-radius: 0.25em;}')
        self.search_input.returnPressed.connect(self.emit_search)
        self.search_input.textEdited.connect(self._start_search_timer)
        self.search_input.arrow_down_key_pressed.connect(
            self.on_arrow_down_key_pressed)

        self.setFocusProxy(self.search_input)

        # Cancel button
        self.cancel_button = QtGui.QToolButton()
        icon = Icon('tango/16x16/actions/edit-clear.png').getQIcon()
        self.cancel_button.setIcon(icon)
        self.cancel_button.setIconSize(QtCore.QSize(14, 14))
        self.cancel_button.setAutoRaise(True)
        self.cancel_button.clicked.connect(self.emit_cancel)

        # Setup layout
        layout.addWidget(self.search_button)
        layout.addWidget(self.search_input)
        layout.addWidget(self.cancel_button)
        self.setLayout(layout)

    def search(self, search_text):
        """Start searching for search_text"""
        self.search_input.setText(search_text)
        self.emit_search()

    @QtCore.pyqtSlot()
    @QtCore.pyqtSlot(str)
    def _start_search_timer(self, str=''):
        timer = self.findChild(QtCore.QTimer, 'timer')
        if timer:
            timer.stop()
            timer.start()

    @QtCore.pyqtSlot()
    def emit_expand_search_options(self):
        self.expand_search_options_signal.emit()

    @QtCore.pyqtSlot()
    @QtCore.pyqtSlot(str)
    def emit_search(self, str=''):
        timer = self.findChild(QtCore.QTimer, 'timer')
        if timer:
            timer.stop()
        text = unicode(self.search_input.user_input())
        self.search_signal.emit(text)

    @QtCore.pyqtSlot()
    def emit_cancel(self):
        timer = self.findChild(QtCore.QTimer, 'timer')
        if timer:
            timer.stop()
        self.search_input.setText('')
        self.cancel_signal.emit()

    @QtCore.pyqtSlot()
    def on_arrow_down_key_pressed(self):
        self.on_arrow_down_signal.emit()
Ejemplo n.º 8
0
class SimpleSearchControl(AbstractSearchWidget):
    """A control that displays a single text field in which search keywords can
    be typed

    emits a search and a cancel signal if the user starts or cancels the search
    """

    def __init__(self, parent):
        QtGui.QWidget.__init__(self, parent)
        layout = QtGui.QHBoxLayout()
        layout.setSpacing(0)
        layout.setContentsMargins(3, 3, 3, 3)
        
        #
        # The search timer reduced the number of search signals that are
        # emitted, by waiting for the next keystroke before emitting the
        # search signal
        #
        timer = QtCore.QTimer( self )
        timer.setInterval( 300 )
        timer.setSingleShot( True )
        timer.setObjectName( 'timer' )
        timer.timeout.connect( self.emit_search )

        # Search button
        self.search_button = QtGui.QToolButton()
        icon = Icon('tango/16x16/actions/system-search.png').getQIcon()
        self.search_button.setIcon(icon)
        self.search_button.setIconSize(QtCore.QSize(14, 14))
        self.search_button.setAutoRaise(True)
        self.search_button.setToolTip(_('Expand or collapse search options'))
        self.search_button.clicked.connect( self.emit_expand_search_options )

        # Search input
        from camelot.view.controls.decorated_line_edit import DecoratedLineEdit
        self.search_input = DecoratedLineEdit(self)
        self.search_input.set_background_text(_('Search...'))
        #self.search_input.setStyleSheet('QLineEdit{ border-radius: 0.25em;}')
        self.search_input.returnPressed.connect( self.emit_search )
        self.search_input.textEdited.connect( self._start_search_timer )
        self.search_input.arrow_down_key_pressed.connect(self.on_arrow_down_key_pressed)

        self.setFocusProxy( self.search_input )

        # Cancel button
        self.cancel_button = QtGui.QToolButton()
        icon = Icon('tango/16x16/actions/edit-clear.png').getQIcon()
        self.cancel_button.setIcon(icon)
        self.cancel_button.setIconSize(QtCore.QSize(14, 14))
        self.cancel_button.setAutoRaise(True)
        self.cancel_button.clicked.connect( self.emit_cancel )

        # Setup layout
        layout.addWidget(self.search_button)
        layout.addWidget(self.search_input)
        layout.addWidget(self.cancel_button)
        self.setLayout(layout)

    def search(self, search_text):
        """Start searching for search_text"""
        self.search_input.setText(search_text)
        self.emit_search()

    @QtCore.pyqtSlot()
    @QtCore.pyqtSlot(str)
    def _start_search_timer(self, str=''):
        timer = self.findChild( QtCore.QTimer, 'timer' )
        if timer:
            timer.stop()
            timer.start()
        
    @QtCore.pyqtSlot()
    def emit_expand_search_options(self):
        self.expand_search_options_signal.emit()

    @QtCore.pyqtSlot()
    @QtCore.pyqtSlot(str)
    def emit_search(self, str=''):
        timer = self.findChild( QtCore.QTimer, 'timer' )
        if timer:
            timer.stop()
        text = unicode(self.search_input.user_input())
        self.search_signal.emit( text )

    @QtCore.pyqtSlot()
    def emit_cancel(self):
        timer = self.findChild( QtCore.QTimer, 'timer' )
        if timer:
            timer.stop()
        self.search_input.setText('')
        self.cancel_signal.emit()

    @QtCore.pyqtSlot()
    def on_arrow_down_key_pressed(self):
        self.on_arrow_down_signal.emit()
Ejemplo n.º 9
0
class LocalFileEditor( CustomEditor ):
    """Widget for browsing local files and directories"""

    browse_icon =  Icon( 'tango/16x16/places/folder-saved-search.png' )

    def __init__(self, 
                 parent = None, 
                 field_name = 'local_file', 
                 directory = False, 
                 save_as = False,
                 file_filter = 'All files (*)',
                 **kwargs):
        CustomEditor.__init__(self, parent)
        self.setObjectName( field_name )
        self._directory = directory
        self._save_as = save_as
        self._file_filter = file_filter
        self.setup_widget()

    def setup_widget(self):
        """Called inside init, overwrite this method for custom
        file edit widgets"""
        layout = QtGui.QHBoxLayout()
        layout.setSpacing(0)
        layout.setContentsMargins(0, 0, 0, 0)

        browse_button = QtGui.QToolButton( self )
        browse_button.setFocusPolicy( Qt.ClickFocus )
        browse_button.setIcon( self.browse_icon.getQIcon() )
        browse_button.setToolTip( _('Browse') )
        browse_button.setAutoRaise( True )
        browse_button.clicked.connect( self.browse_button_clicked )

        self.filename = DecoratedLineEdit(self)
        self.filename.editingFinished.connect( self.filename_editing_finished )
        self.setFocusProxy( self.filename )
        
        layout.addWidget( self.filename )
        layout.addWidget( browse_button )
        self.setLayout( layout )

    @QtCore.pyqtSlot()
    def filename_editing_finished(self):
        self.valueChanged.emit()
        self.editingFinished.emit()

    @QtCore.pyqtSlot()
    def browse_button_clicked(self):
        current_directory = os.path.dirname( self.get_value() )
        if self._directory:
            value = QtGui.QFileDialog.getExistingDirectory( self,
                                                            directory = current_directory )
        elif self._save_as:
            value = QtGui.QFileDialog.getSaveFileName( self,
                                                       filter = self._file_filter,
                                                       directory = current_directory )
        else:
            value = QtGui.QFileDialog.getOpenFileName( self,
                                                       filter = self._file_filter,
                                                       directory = current_directory )
        value = os.path.abspath( unicode( value ) )
        self.filename.setText( value )
        self.valueChanged.emit()
        self.editingFinished.emit()

    def set_value(self, value):
        value = CustomEditor.set_value(self, value)
        if value:
            self.filename.setText( value )
        else:
            self.filename.setText( '' )
        self.valueChanged.emit()
        return value

    def get_value(self):
        return CustomEditor.get_value(self) or unicode( self.filename.text() )
    
    value = QtCore.pyqtProperty( str, get_value, set_value )

    def set_field_attributes( self, 
                              editable = True,
                              background_color = None,
                              tooltip = None,
                              **kwargs):
        self.setEnabled( editable )
        if self.filename:
            set_background_color_palette( self.filename, background_color )
            self.filename.setToolTip(unicode(tooltip or ''))
Ejemplo n.º 10
0
class FileEditor(CustomEditor):
    """Widget for editing File fields"""

    filter = "All files (*)"
    add_icon = Icon("tango/16x16/actions/list-add.png")
    open_icon = Icon("tango/16x16/actions/document-open.png")
    clear_icon = Icon("tango/16x16/actions/edit-delete.png")
    save_as_icon = Icon("tango/16x16/actions/document-save-as.png")
    document_pixmap = Icon("tango/16x16/mimetypes/x-office-document.png")

    def __init__(self, parent=None, storage=None, field_name="file", remove_original=False, **kwargs):
        CustomEditor.__init__(self, parent)
        self.setObjectName(field_name)
        self.storage = storage
        self.filename = None  # the widget containing the filename
        self.value = None
        self.remove_original = remove_original
        self.setup_widget()

    def setup_widget(self):
        """Called inside init, overwrite this method for custom
        file edit widgets"""
        self.layout = QtGui.QHBoxLayout()
        self.layout.setSpacing(0)
        self.layout.setContentsMargins(0, 0, 0, 0)

        # Save As button
        self.save_as_button = QtGui.QToolButton()
        self.save_as_button.setFocusPolicy(Qt.ClickFocus)
        self.save_as_button.setIcon(self.save_as_icon.getQIcon())
        self.save_as_button.setToolTip(_("Save file as"))
        self.save_as_button.setAutoRaise(True)
        self.save_as_button.clicked.connect(self.save_as_button_clicked)

        # Clear button
        self.clear_button = QtGui.QToolButton()
        self.clear_button.setFocusPolicy(Qt.ClickFocus)
        self.clear_button.setIcon(self.clear_icon.getQIcon())
        self.clear_button.setToolTip(_("Delete file"))
        self.clear_button.setAutoRaise(True)
        self.clear_button.clicked.connect(self.clear_button_clicked)

        # Open button
        self.open_button = QtGui.QToolButton()
        self.open_button.setFocusPolicy(Qt.ClickFocus)
        self.open_button.setIcon(self.open_icon.getQIcon())
        self.open_button.setToolTip(_("Open file"))
        self.open_button.clicked.connect(self.open_button_clicked)
        self.open_button.setAutoRaise(True)

        # Add button
        self.add_button = QtGui.QToolButton()
        self.add_button.setFocusPolicy(Qt.StrongFocus)
        self.add_button.setIcon(self.add_icon.getQIcon())
        self.add_button.setToolTip(_("Attach file"))
        self.add_button.clicked.connect(self.add_button_clicked)
        self.add_button.setAutoRaise(True)

        # Filename
        self.filename = DecoratedLineEdit(self)
        self.filename.set_minimum_width(20)
        self.filename.setFocusPolicy(Qt.ClickFocus)

        # Search Completer
        #
        # Turn completion off, since it creates a thread per field on a form
        #
        # self.completer = QtGui.QCompleter()
        # self.completions_model = QtGui.QFileSystemModel()
        # self.completer.setCompletionMode(
        #    QtGui.QCompleter.UnfilteredPopupCompletion
        # )
        # self.completer.setModel( self.completions_model )
        # self.completer.activated[QtCore.QModelIndex].connect(self.file_completion_activated)
        # self.filename.setCompleter( self.completer )
        # settings = QtCore.QSettings()
        # last_path = settings.value('lastpath').toString()

        # # This setting of a rootPath causes a major delay on Windows, since
        # # the QFileSystemModel starts to fetch file information in a non-
        # # blocking way (although the documentation state the opposite).
        # # On Linux, there is no such delay, so it's safe to set such a root
        # # path and let the underlaying system start indexing.
        # import sys
        # if sys.platform != "win32":
        #    self.completions_model.setRootPath( last_path )

        # Setup layout
        self.document_label = QtGui.QLabel(self)
        self.document_label.setPixmap(self.document_pixmap.getQPixmap())
        self.layout.addWidget(self.document_label)
        self.layout.addWidget(self.filename)
        self.layout.addWidget(self.clear_button)
        self.layout.addWidget(self.open_button)
        self.layout.addWidget(self.add_button)
        self.layout.addWidget(self.save_as_button)
        self.setLayout(self.layout)

    def file_completion_activated(self, index):
        from camelot.view.storage import create_stored_file

        source_index = index.model().mapToSource(index)
        if not self.completions_model.isDir(source_index):
            path = self.completions_model.filePath(source_index)
            create_stored_file(
                self,
                self.storage,
                self.stored_file_ready,
                filter=self.filter,
                remove_original=self.remove_original,
                filename=path,
            )

    def set_value(self, value):
        value = CustomEditor.set_value(self, value)
        self.value = value
        if value:
            self.clear_button.setVisible(True)
            self.save_as_button.setVisible(True)
            self.open_button.setVisible(True)
            self.add_button.setVisible(False)
            self.filename.setText(value.verbose_name)
        else:
            self.clear_button.setVisible(False)
            self.save_as_button.setVisible(False)
            self.open_button.setVisible(False)
            self.add_button.setVisible(True)
            self.filename.setText("")
        return value

    def get_value(self):
        return CustomEditor.get_value(self) or self.value

    def set_field_attributes(self, editable=True, background_color=None, tooltip=None, remove_original=False, **kwargs):
        self.set_enabled(editable)
        if self.filename:
            set_background_color_palette(self.filename, background_color)
            self.filename.setToolTip(unicode(tooltip or ""))
        self.remove_original = remove_original

    def set_enabled(self, editable=True):
        self.clear_button.setEnabled(editable)
        self.add_button.setEnabled(editable)
        self.filename.setEnabled(editable)
        self.filename.setReadOnly(not editable)
        self.document_label.setEnabled(editable)
        self.setAcceptDrops(editable)

    def stored_file_ready(self, stored_file):
        """Slot to be called when a new stored_file has been created by
        the storage"""
        self.set_value(stored_file)
        self.editingFinished.emit()

    def save_as_button_clicked(self):
        from camelot.view.storage import save_stored_file

        value = self.get_value()
        if value:
            save_stored_file(self, value)

    def add_button_clicked(self):
        from camelot.view.storage import create_stored_file

        create_stored_file(
            self, self.storage, self.stored_file_ready, filter=self.filter, remove_original=self.remove_original
        )

    def open_button_clicked(self):
        from camelot.view.storage import open_stored_file

        open_stored_file(self, self.value)

    def clear_button_clicked(self):
        answer = QtGui.QMessageBox.question(
            self,
            _("Remove this file ?"),
            _("If you continue, you will no longer be able to open this file."),
            QtGui.QMessageBox.Yes,
            QtGui.QMessageBox.No,
        )
        if answer == QtGui.QMessageBox.Yes:
            self.value = None
            self.editingFinished.emit()

    #
    # Drag & Drop
    #
    def dragEnterEvent(self, event):
        event.acceptProposedAction()

    def dragMoveEvent(self, event):
        event.acceptProposedAction()

    def dropEvent(self, event):
        from camelot.view.storage import create_stored_file

        if event.mimeData().hasUrls():
            url = event.mimeData().urls()[0]
            filename = url.toLocalFile()
            if filename:
                create_stored_file(
                    self,
                    self.storage,
                    self.stored_file_ready,
                    filter=self.filter,
                    remove_original=self.remove_original,
                    filename=filename,
                )
Ejemplo n.º 11
0
class FileEditor(CustomEditor):
    """Widget for editing File fields"""

    filter = 'All files (*)'
    add_icon = Icon('tango/16x16/actions/list-add.png')
    open_icon = Icon('tango/16x16/actions/document-open.png')
    clear_icon = Icon('tango/16x16/actions/edit-delete.png')
    save_as_icon = Icon('tango/16x16/actions/document-save-as.png')
    document_pixmap = Icon('tango/16x16/mimetypes/x-office-document.png')

    def __init__(self,
                 parent=None,
                 storage=None,
                 field_name='file',
                 remove_original=False,
                 **kwargs):
        CustomEditor.__init__(self, parent)
        self.setObjectName(field_name)
        self.storage = storage
        self.filename = None  # the widget containing the filename
        self.value = None
        self.remove_original = remove_original
        self.setup_widget()

    def setup_widget(self):
        """Called inside init, overwrite this method for custom
        file edit widgets"""
        self.layout = QtGui.QHBoxLayout()
        self.layout.setSpacing(0)
        self.layout.setContentsMargins(0, 0, 0, 0)

        # Save As button
        self.save_as_button = QtGui.QToolButton()
        self.save_as_button.setFocusPolicy(Qt.ClickFocus)
        self.save_as_button.setIcon(self.save_as_icon.getQIcon())
        self.save_as_button.setToolTip(_('Save file as'))
        self.save_as_button.setAutoRaise(True)
        self.save_as_button.clicked.connect(self.save_as_button_clicked)

        # Clear button
        self.clear_button = QtGui.QToolButton()
        self.clear_button.setFocusPolicy(Qt.ClickFocus)
        self.clear_button.setIcon(self.clear_icon.getQIcon())
        self.clear_button.setToolTip(_('Delete file'))
        self.clear_button.setAutoRaise(True)
        self.clear_button.clicked.connect(self.clear_button_clicked)

        # Open button
        self.open_button = QtGui.QToolButton()
        self.open_button.setFocusPolicy(Qt.ClickFocus)
        self.open_button.setIcon(self.open_icon.getQIcon())
        self.open_button.setToolTip(_('Open file'))
        self.open_button.clicked.connect(self.open_button_clicked)
        self.open_button.setAutoRaise(True)

        # Add button
        self.add_button = QtGui.QToolButton()
        self.add_button.setFocusPolicy(Qt.StrongFocus)
        self.add_button.setIcon(self.add_icon.getQIcon())
        self.add_button.setToolTip(_('Attach file'))
        self.add_button.clicked.connect(self.add_button_clicked)
        self.add_button.setAutoRaise(True)

        # Filename
        self.filename = DecoratedLineEdit(self)
        self.filename.set_minimum_width(20)
        self.filename.setFocusPolicy(Qt.ClickFocus)

        # Search Completer
        #
        # Turn completion off, since it creates a thread per field on a form
        #
        # self.completer = QtGui.QCompleter()
        # self.completions_model = QtGui.QFileSystemModel()
        # self.completer.setCompletionMode(
        #    QtGui.QCompleter.UnfilteredPopupCompletion
        # )
        # self.completer.setModel( self.completions_model )
        # self.completer.activated[QtCore.QModelIndex].connect(self.file_completion_activated)
        # self.filename.setCompleter( self.completer )
        # settings = QtCore.QSettings()
        # last_path = settings.value('lastpath').toString()

        # # This setting of a rootPath causes a major delay on Windows, since
        # # the QFileSystemModel starts to fetch file information in a non-
        # # blocking way (although the documentation state the opposite).
        # # On Linux, there is no such delay, so it's safe to set such a root
        # # path and let the underlaying system start indexing.
        # import sys
        # if sys.platform != "win32":
        #    self.completions_model.setRootPath( last_path )

        # Setup layout
        self.document_label = QtGui.QLabel(self)
        self.document_label.setPixmap(self.document_pixmap.getQPixmap())
        self.layout.addWidget(self.document_label)
        self.layout.addWidget(self.filename)
        self.layout.addWidget(self.clear_button)
        self.layout.addWidget(self.open_button)
        self.layout.addWidget(self.add_button)
        self.layout.addWidget(self.save_as_button)
        self.setLayout(self.layout)

    def file_completion_activated(self, index):
        from camelot.view.storage import create_stored_file
        source_index = index.model().mapToSource(index)
        if not self.completions_model.isDir(source_index):
            path = self.completions_model.filePath(source_index)
            create_stored_file(
                self,
                self.storage,
                self.stored_file_ready,
                filter=self.filter,
                remove_original=self.remove_original,
                filename=path,
            )

    def set_value(self, value):
        value = CustomEditor.set_value(self, value)
        self.value = value
        if value:
            self.clear_button.setVisible(True)
            self.save_as_button.setVisible(True)
            self.open_button.setVisible(True)
            self.add_button.setVisible(False)
            self.filename.setText(value.verbose_name)
        else:
            self.clear_button.setVisible(False)
            self.save_as_button.setVisible(False)
            self.open_button.setVisible(False)
            self.add_button.setVisible(True)
            self.filename.setText('')
        return value

    def get_value(self):
        return CustomEditor.get_value(self) or self.value

    def set_field_attributes(self,
                             editable=True,
                             background_color=None,
                             tooltip=None,
                             remove_original=False,
                             **kwargs):
        self.set_enabled(editable)
        if self.filename:
            set_background_color_palette(self.filename, background_color)
            self.filename.setToolTip(unicode(tooltip or ''))
        self.remove_original = remove_original

    def set_enabled(self, editable=True):
        self.clear_button.setEnabled(editable)
        self.add_button.setEnabled(editable)
        self.filename.setEnabled(editable)
        self.filename.setReadOnly(not editable)
        self.document_label.setEnabled(editable)
        self.setAcceptDrops(editable)

    def stored_file_ready(self, stored_file):
        """Slot to be called when a new stored_file has been created by
        the storage"""
        self.set_value(stored_file)
        self.editingFinished.emit()

    def save_as_button_clicked(self):
        from camelot.view.storage import save_stored_file
        value = self.get_value()
        if value:
            save_stored_file(self, value)

    def add_button_clicked(self):
        from camelot.view.storage import create_stored_file
        create_stored_file(
            self,
            self.storage,
            self.stored_file_ready,
            filter=self.filter,
            remove_original=self.remove_original,
        )

    def open_button_clicked(self):
        from camelot.view.storage import open_stored_file
        open_stored_file(self, self.value)

    def clear_button_clicked(self):
        answer = QtGui.QMessageBox.question(
            self, _('Remove this file ?'),
            _('If you continue, you will no longer be able to open this file.'
              ), QtGui.QMessageBox.Yes, QtGui.QMessageBox.No)
        if answer == QtGui.QMessageBox.Yes:
            self.value = None
            self.editingFinished.emit()

    #
    # Drag & Drop
    #
    def dragEnterEvent(self, event):
        event.acceptProposedAction()

    def dragMoveEvent(self, event):
        event.acceptProposedAction()

    def dropEvent(self, event):
        from camelot.view.storage import create_stored_file
        if event.mimeData().hasUrls():
            url = event.mimeData().urls()[0]
            filename = url.toLocalFile()
            if filename:
                create_stored_file(
                    self,
                    self.storage,
                    self.stored_file_ready,
                    filter=self.filter,
                    remove_original=self.remove_original,
                    filename=filename,
                )
Ejemplo n.º 12
0
class VirtualAddressEditor(CustomEditor):
    def __init__(self,
                 parent=None,
                 editable=True,
                 address_type=None,
                 address_validator=default_address_validator,
                 field_name='virtual_address',
                 **kwargs):
        """
        :param address_type: limit the allowed address to be entered to be
            of a certain time, can be 'phone', 'fax', 'email', 'mobile', 'pager'.
            If set to None, all types are allowed.
            
        Upto now, the corrected address returned by the address validator is
        not yet taken into account.
        """
        CustomEditor.__init__(self, parent)
        self.setObjectName(field_name)
        self._address_type = address_type
        self._address_validator = address_validator
        self.layout = QtGui.QHBoxLayout()
        self.layout.setContentsMargins(0, 0, 0, 0)
        self.combo = QtGui.QComboBox()
        self.combo.addItems(camelot.types.VirtualAddress.virtual_address_types)
        self.combo.setEnabled(editable)
        if address_type:
            self.combo.setVisible(False)
        self.layout.addWidget(self.combo)
        self.editor = DecoratedLineEdit(self)
        self.editor.setEnabled(editable)
        self.editor.set_minimum_width(30)
        self.layout.addWidget(self.editor)
        self.setFocusProxy(self.editor)
        self.editable = editable
        nullIcon = Icon('tango/16x16/apps/internet-mail.png').getQIcon()
        self.label = QtGui.QToolButton()
        self.label.setIcon(nullIcon)
        self.label.setAutoRaise(True)
        self.label.setEnabled(False)
        self.label.setToolButtonStyle(Qt.ToolButtonIconOnly)
        self.label.setFocusPolicy(Qt.ClickFocus)
        self.label.clicked.connect(self.mail_click)
        self.label.hide()

        self.layout.addWidget(self.label)
        self.editor.editingFinished.connect(self.emit_editing_finished)
        self.editor.textEdited.connect(self.editorValueChanged)
        self.combo.currentIndexChanged.connect(self.comboIndexChanged)

        self.setLayout(self.layout)
        self.checkValue(self.editor.text())

    @QtCore.pyqtSlot()
    def comboIndexChanged(self):
        self.checkValue(self.editor.text())
        self.emit_editing_finished()

    def set_value(self, value):
        value = CustomEditor.set_value(self, value)
        if value:
            self.editor.setText(value[1])
            idx = camelot.types.VirtualAddress.virtual_address_types.index(
                self._address_type or value[0])
            self.combo.setCurrentIndex(idx)
            icon = Icon('tango/16x16/devices/printer.png').getQIcon()
            # These icons don't exist any more in the new tango icon set
            #            if str(self.combo.currentText()) == 'phone':
            #                icon = Icon('tango/16x16/devices/phone.png').getQIcon()
            if str(self.combo.currentText()) == 'fax':
                icon = Icon('tango/16x16/devices/printer.png').getQIcon()
#            if str(self.combo.currentText()) == 'mobile':
#                icon = Icon('tango/16x16/devices/mobile.png').getQIcon()
#            if str(self.combo.currentText()) == 'im':
#                icon = Icon('tango/16x16/places/instant-messaging.png').getQIcon()
#            if str(self.combo.currentText()) == 'pager':
#                icon = Icon('tango/16x16/devices/pager.png').getQIcon()
            if str(self.combo.currentText()) == 'email':
                icon = Icon('tango/16x16/apps/internet-mail.png').getQIcon()
                #self.label.setFocusPolicy(Qt.StrongFocus)
                #self.label.setAutoFillBackground(True)
                self.label.setIcon(icon)
                self.label.setEnabled(self.editable)
                self.label.show()
            else:
                self.label.hide()
                self.label.setIcon(icon)
                self.label.setEnabled(self.editable)
                self.label.setToolButtonStyle(Qt.ToolButtonIconOnly)

#      self.update()
#      self.label.update()
#      self.layout.update()

            self.checkValue(value[1])

    def get_value(self):
        value = (unicode(self.combo.currentText()),
                 unicode(self.editor.text()))
        return CustomEditor.get_value(self) or value

    def set_enabled(self, editable=True):
        self.combo.setEnabled(editable)
        self.editor.setEnabled(editable)
        if not editable:
            self.label.setEnabled(False)
        else:
            if self.combo.currentText() == 'email':
                self.label.setEnabled(True)

    def checkValue(self, text):
        address_type = unicode(self.combo.currentText())
        valid, _corrected = self._address_validator(address_type,
                                                    unicode(text))
        self.editor.set_valid(valid)

    def editorValueChanged(self, text):
        self.checkValue(text)

    @QtCore.pyqtSlot()
    def mail_click(self):
        address = self.editor.text()
        url = QtCore.QUrl()
        url.setUrl(u'mailto:%s?subject=Subject' % unicode(address))
        QtGui.QDesktopServices.openUrl(url)

    def emit_editing_finished(self):
        self.value = []
        self.value.append(str(self.combo.currentText()))
        self.value.append(str(self.editor.text()))
        self.set_value(self.value)
        # emiting editingFinished without a value for the mechanism itself will lead to
        # integrity errors
        if self.value[1]:
            self.editingFinished.emit()

    def set_background_color(self, background_color):
        set_background_color_palette(self.editor, background_color)

    def set_field_attributes(self,
                             editable=True,
                             background_color=None,
                             tooltip=None,
                             **kwargs):
        self.set_enabled(editable)
        self.set_background_color(background_color)
        self.setToolTip(unicode(tooltip or ''))
Ejemplo n.º 13
0
class VirtualAddressEditor(CustomEditor):
    def __init__(self,
                 parent=None,
                 address_type=None,
                 field_name='virtual_address',
                 **kwargs):
        """
        :param address_type: limit the allowed address to be entered to be
            of a certain time, can be 'phone', 'fax', 'email', 'mobile', 'pager'.
            If set to None, all types are allowed.
            
        Upto now, the corrected address returned by the address validator is
        not yet taken into account.
        """
        CustomEditor.__init__(self, parent)
        self.setSizePolicy(QtGui.QSizePolicy.Preferred,
                           QtGui.QSizePolicy.Fixed)
        self.setObjectName(field_name)
        self._address_type = address_type
        self.layout = QtWidgets.QHBoxLayout()
        self.layout.setContentsMargins(0, 0, 0, 0)
        self.combo = QtWidgets.QComboBox()
        self.combo.addItems(camelot.types.VirtualAddress.virtual_address_types)
        self.layout.addWidget(self.combo)
        self.editor = DecoratedLineEdit(self)
        self.editor.set_minimum_width(30)
        if address_type:
            self.combo.setVisible(False)
            idx = camelot.types.VirtualAddress.virtual_address_types.index(
                address_type)
            self.combo.setCurrentIndex(idx)
        self.layout.addWidget(self.editor)
        self.setFocusProxy(self.editor)
        nullIcon = Icon('tango/16x16/apps/internet-mail.png').getQIcon()
        self.label = QtWidgets.QToolButton()
        self.label.setIcon(nullIcon)
        self.label.setAutoRaise(True)
        self.label.setEnabled(False)
        self.label.setToolButtonStyle(Qt.ToolButtonIconOnly)
        self.label.setFocusPolicy(Qt.ClickFocus)
        self.label.clicked.connect(self.mail_click)
        self.label.hide()
        self.layout.addWidget(self.label)
        self.editor.editingFinished.connect(self.emit_editing_finished)
        self.combo.currentIndexChanged.connect(self.comboIndexChanged)
        self.setLayout(self.layout)
        self.update_validator()

    @QtCore.qt_slot()
    def comboIndexChanged(self):
        self.update_validator()
        self.emit_editing_finished()

    def set_value(self, value):
        value = CustomEditor.set_value(self, value)
        if value is None:
            self.editor.setText('')
        else:
            self.editor.setText(value[1])
            idx = camelot.types.VirtualAddress.virtual_address_types.index(
                self._address_type or value[0])
            self.combo.setCurrentIndex(idx)
            icon = Icon('tango/16x16/devices/printer.png').getQIcon()
            if six.text_type(self.combo.currentText()) == 'fax':
                icon = Icon('tango/16x16/devices/printer.png').getQIcon()
            if six.text_type(self.combo.currentText()) == 'email':
                icon = Icon('tango/16x16/apps/internet-mail.png').getQIcon()
                self.label.setIcon(icon)
                self.label.show()
            else:
                self.label.hide()
                self.label.setIcon(icon)
                self.label.setToolButtonStyle(Qt.ToolButtonIconOnly)
            self.update_validator()

    def get_value(self):
        address_value = six.text_type(self.editor.text())
        if not len(address_value):
            value = None
        else:
            value = (six.text_type(self.combo.currentText()), address_value)
        return CustomEditor.get_value(self) or value

    def set_enabled(self, editable=True):
        self.combo.setEnabled(editable)
        self.editor.setEnabled(editable)
        if not editable:
            self.label.setEnabled(False)
        else:
            if self.combo.currentText() == 'email':
                self.label.setEnabled(True)

    def update_validator(self):
        address_type = six.text_type(self.combo.currentText())
        validator = validators.get(address_type, any_character_validator)
        # change the validator instead of the regexp of the validator to inform
        # the editor it needs to update its background color
        self.editor.setValidator(validator)

    @QtCore.qt_slot()
    def mail_click(self):
        address = self.editor.text()
        url = QtCore.QUrl()
        url.setUrl(u'mailto:%s?subject=Subject' % six.text_type(address))
        QtGui.QDesktopServices.openUrl(url)

    def emit_editing_finished(self):
        self.value = []
        self.value.append(six.text_type(self.combo.currentText()))
        self.value.append(six.text_type(self.editor.text()))
        self.set_value(self.value)
        # emiting editingFinished without a value for the mechanism itself will lead to
        # integrity errors
        if self.value[1]:
            self.editingFinished.emit()

    def set_background_color(self, background_color):
        set_background_color_palette(self.editor, background_color)

    def set_field_attributes(self, **kwargs):
        super(VirtualAddressEditor, self).set_field_attributes(**kwargs)
        self.set_enabled(kwargs.get('editable', False))
        self.setToolTip(six.text_type(kwargs.get('tooltip') or ''))