#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
#The MIT License (MIT)
#
#Copyright (c) <2013-2014> <Colin Duquesnoy and others, see AUTHORS.txt>
#
#Permission is hereby granted, free of charge, to any person obtaining a copy
#of this software and associated documentation files (the "Software"), to deal
#in the Software without restriction, including without limitation the rights
#to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
#copies of the Software, and to permit persons to whom the Software is
#furnished to do so, subject to the following conditions:
#
#The above copyright notice and this permission notice shall be included in
#all copies or substantial portions of the Software.
#
#THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
#IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
#FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
#AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
#LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
#OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
#THE SOFTWARE.
#
"""
Contains a widget to show and edit a PropertyRegistry
"""
import pyqode.core
from pyqode.qt import QtGui, QtCore

try:
    from pyqode.qt.QtCore import Property
except:
    class Property(object):
        def __init__(self, *args, **kwargs):
            pass

class QColorButton(QtGui.QWidget):
    """
    Simple color button used in :class:`pyqode.widgets.QPropertyGrid`.

    The widget is a combination of QPushButton and a QLabel layout with a
    QHBoxLayout.
    """

    #: Signal emitted when the color value changed.
    valueChanged = QtCore.Signal(QtGui.QColor)

    def __getColor(self):
        return self._color

    def __setColor(self, color):
        self._color = color
        self.label.setText(color.name())
        self.button.setStyleSheet("background-color: %s;" % color.name())

    #: The color to display
    color = Property(QtGui.QColor, fget=__getColor, fset=__setColor)

    def __init__(self, parent=None):
        QtGui.QWidget.__init__(self, parent)
        layout = QtGui.QHBoxLayout()
        layout.setContentsMargins(0, 0, 0, 0)

        self.button = QtGui.QToolButton()
        self.button.clicked.connect(self.showColorDialog)
        self._color = QtGui.QColor(255, 255, 255, 255)
        layout.addWidget(self.button)

        self.label = QtGui.QLabel()
        layout.addWidget(self.label)
        layout.setStretch(1, 1)
        self.setLayout(layout)

        self.color = QtGui.QColor("#FFFFFF")

    def showColorDialog(self):
        """
        Slots that executes a QColorDialog when the user click the on the
        button.
        """
        c = QtGui.QColorDialog.getColor(self._color, self)
        if c.isValid():
            self.__setColor(c)
            self.valueChanged.emit(c)


class QTextStyleWidget(QtGui.QWidget):
    """
    Widgets specialised to edit a :class:`pyqode.core.TextStyle`.
    """
    #: Signal emitted when the value changed.
    valueChanged = QtCore.Signal(object)

    @property
    def textStyle(self):
        """
        Gets/Sets the text style to edit.

        You retrieve the user modifications through this property.
        """
        return self.__textStyle

    @textStyle.setter
    def textStyle(self, textStyle):
        assert isinstance(textStyle, pyqode.core.TextStyle)
        self.colorButton.__setColor(textStyle.color)
        self.checkBoxBold.setChecked(textStyle.bold)
        self.checkBoxItalic.setChecked(textStyle.italic)
        self.checkBoxUnderlined.setChecked(textStyle.underlined)
        self.__textStyle = textStyle

    def __init__(self, parent=None):
        QtGui.QWidget.__init__(self, parent)
        layout = QtGui.QHBoxLayout()

        self.colorButton = QColorButton()
        self.colorButton.valueChanged.connect(self.onValueChanged)
        self.colorButton.label.hide()
        layout.addWidget(self.colorButton)

        self.checkBoxBold = QtGui.QCheckBox()
        self.checkBoxBold.stateChanged.connect(self.onValueChanged)
        self.checkBoxBold.setText("Bold")
        layout.addWidget(self.checkBoxBold)

        self.checkBoxItalic = QtGui.QCheckBox()
        self.checkBoxItalic.stateChanged.connect(self.onValueChanged)
        self.checkBoxItalic.setText("Italic")
        layout.addWidget(self.checkBoxItalic)

        self.checkBoxUnderlined = QtGui.QCheckBox()
        self.checkBoxUnderlined.stateChanged.connect(self.onValueChanged)
        self.checkBoxUnderlined.setText("Underlined")
        layout.addWidget(self.checkBoxUnderlined)
        layout.setContentsMargins(0, 0, 0, 0)
        layout.setStretch(3, 3)
        self.setLayout(layout)
        self.setContentsMargins(0, 0, 0, 0)

        self.__textStyle = None

    def onValueChanged(self):
        if self.__textStyle:
            ts = pyqode.core.TextStyle()
            ts.bold = self.checkBoxBold.isChecked()
            ts.italic = self.checkBoxItalic.isChecked()
            ts.underlined = self.checkBoxUnderlined.isChecked()
            ts.color = self.colorButton.color
            #if str(ts) != str(self.__textStyle):
            self.__textStyle = ts
            self.valueChanged.emit(ts)


class QPropertyGrid(QtGui.QWidget):
    """
    This widget displays and lets the user edit the properties of a
    :class:`pyqode.core.PropertyRegistry`

    Use :meth:`pyqode.widgets.setPropertyRegistry` set the property
    registry do edit. Use :attr:`pyqode.widgets.QPropertyGrid.registry` to get
    the modified property registry.

    You can use :attr:`pyqode.core.PropertyRegistry.valueChanged` to
    get notified about value changes.
    """

    rehighlightRequested = QtCore.Signal()

    @property
    def currentSection(self):
        """
        Gets the current section of the :class:`pyqode.core.PropetyRegistry`

        :rtype: str
        """
        return self.comboSections.currentText()

    def __init__(self, parent=None):
        QtGui.QWidget.__init__(self, parent)
        layout = QtGui.QVBoxLayout()
        #: The edited property registry.
        self.registry = None
        self.__widgets = {}

        # sections
        glayout = QtGui.QGridLayout()
        self.lblSection = QtGui.QLabel("Section")
        glayout.addWidget(self.lblSection, 0, 0)
        self.comboSections = QtGui.QComboBox()
        self.comboSections.currentIndexChanged.connect(self.onSectionChanged)
        glayout.addWidget(self.comboSections, 0, 1)
        glayout.setColumnStretch(1, 1)
        layout.addLayout(glayout)

        # grid
        self.table = QtGui.QTableWidget()
        hv = self.table.horizontalHeader()
        hv.setStretchLastSection(True)
        hv.setResizeMode(QtGui.QHeaderView.ResizeToContents)
        self.table.verticalHeader().hide()
        self.table.setHorizontalHeader(hv)
        #self.table.setMinimumSize(400, 0)
        self.table.setAlternatingRowColors(True)

        layout.addWidget(self.table)
        self.setLayout(layout)

    def setPropertyRegistry(self, registry):
        """
        Sets the :class:`pyqode.core.PropetyRegistry` to show/edit.

        :param registry: The property registry to edit/display
        :type registry: pyqode.core.PropertyRegistry
        """
        assert isinstance(registry, pyqode.core.PropertyRegistry)
        self.registry = None
        index = 0
        for i, name in enumerate(registry.sections()):
            if name == "General":
                index = i
            self.comboSections.addItem(name)
        self.comboSections.setCurrentIndex(index)
        section = self.comboSections.currentText()
        self._displayProperties(section, registry)
        self.registry = registry
        self.lblSection.setVisible(self.comboSections.count() > 1)
        self.comboSections.setVisible(self.comboSections.count() > 1)

    def onSectionChanged(self, index):
        if self.registry:
            section = self.comboSections.itemText(index)
            self._displayProperties(section, self.registry)

    def _displayProperties(self, section, registry):
        properties = registry.properties(section)
        self.__widgets.clear()
        self.table.clear()
        self.table.setColumnCount(2)
        self.table.setRowCount(0)
        self.table.setHorizontalHeaderLabels(["Property", "Value"])
        for k in sorted(properties.keys()):
            v = registry.value(k, section=section)
            if not isinstance(v, list):  # what to do with list items???
                row = self.table.rowCount()
                self.table.insertRow(row)
                # name item
                #item = QtGui.QTableWidgetItem(k)
                lbl = QtGui.QLabel(k)
                lbl.setContentsMargins(3, 0, 0, 0)
                #self.table.setItem(row, 0, item)
                self.table.setCellWidget(row, 0, lbl)
                widget = self.makePropertyItem(k, v)
                if widget:
                    widget.key = k
                    widget.setContentsMargins(3, 0, 0, 0)
                    self.table.setCellWidget(row, 1, widget)
                    self.__widgets[k] = widget
        hv = self.table.horizontalHeader()
        hv.adjustSize()

    def makePropertyItem(self, key, value):
        if key == "pygmentsStyle":  # specific case this is a combo box
            widget = QtGui.QComboBox()
            index = -1
            for i, s in enumerate(pyqode.core.PYGMENTS_STYLES):
                if s == value:
                    index = i
                widget.addItem(s)
            widget.setCurrentIndex(index)
            widget.currentIndexChanged.connect(self.onComboIndexChanged)
        elif key == "font":
            widget = QtGui.QFontComboBox()
            widget.setCurrentFont(QtGui.QFont(value))
            widget.currentFontChanged.connect(
                self.onFontComboBoxCurrentFontChanged)
            widget.setFontFilters(QtGui.QFontComboBox.MonospacedFonts)
            return widget
        elif isinstance(value, bool):
            widget = QtGui.QCheckBox()
            widget.setChecked(value)
            widget.stateChanged.connect(self.onCheckBoxStateChanged)
        elif isinstance(value, float):
            widget = QtGui.QDoubleSpinBox()
            widget.setValue(value)
            widget.editingFinished.connect(self.onSpinBoxEditingFinished)
        elif isinstance(value, int):
            widget = QtGui.QSpinBox()
            widget.setValue(value)
            widget.editingFinished.connect(self.onSpinBoxEditingFinished)
        elif isinstance(value, pyqode.core.TextStyle):
            widget = QTextStyleWidget()
            widget.textStyle = value
            widget.valueChanged.connect(self.onTextStyleValueChanged)
            return widget
        elif isinstance(value, QtGui.QColor):
            widget = QColorButton()
            widget.color = value
            widget.valueChanged.connect(self.onColorButtonValudeChanged)
            return widget
        else:
            widget = QtGui.QLineEdit()
            widget.setText(value)
            widget.editingFinished.connect(self.onLineEditEditingFinished)
        return widget

    def onComboIndexChanged(self):
        key = self.sender().key
        value = self.sender().currentText()
        self.registry.setValue(key, value, self.currentSection)
        if key == "pygmentsStyle":
            # the background, the foreground and the caret line background
            # properties must be updated
            k = "background"
            colorButton = self.__widgets[k]
            colorButton.color = self.registry.value(k, self.currentSection)
            colorButton.valueChanged.emit(colorButton.color)

            k = "foreground"
            colorButton = self.__widgets[k]
            colorButton.color = self.registry.value(k, self.currentSection)
            colorButton.valueChanged.emit(colorButton.color)

            k = "caretLineBackground"
            colorButton = self.__widgets[k]
            colorButton.color = self.registry.value(k, self.currentSection)
            colorButton.valueChanged.emit(colorButton.color)

    def onCheckBoxStateChanged(self, state):
        key = self.sender().key
        self.registry.setValue(key, bool(state), self.currentSection)

    def onSpinBoxEditingFinished(self):
        key = self.sender().key
        value = self.sender().value()
        self.registry.setValue(key, value, self.currentSection)

    def onLineEditEditingFinished(self):
        key = self.sender().key
        value = self.sender().text()
        self.registry.setValue(key, value, self.currentSection)

    def onColorButtonValudeChanged(self, value):
        key = self.sender().key
        self.registry.setValue(key, value, self.currentSection)

    def onFontComboBoxCurrentFontChanged(self, font):
        key = self.sender().key
        value = font.family()
        self.registry.setValue(key, value, self.currentSection)

    def onTextStyleValueChanged(self, value):
        key = self.sender().key
        self.registry.setValue(key, value, self.currentSection)
        self.rehighlightRequested.emit()


if __name__ == "__main__":
    import sys
    #import pyqode.python

    app = QtGui.QApplication(sys.argv)
    win = QtGui.QMainWindow()
    #editor = pyqode.python.QPythonCodeEdit()
    editor = pyqode.core.QGenericCodeEdit()
    editor.openFile(__file__, encoding="utf-8")
    win.setCentralWidget(editor)

    dockStyle = QtGui.QDockWidget("Style")
    grid = QPropertyGrid()
    grid.rehighlightRequested.connect(editor.syntaxHighlighterMode.rehighlight)
    grid.setPropertyRegistry(editor.style)
    grid.showNormal()
    dockStyle.setWidget(grid)
    win.addDockWidget(QtCore.Qt.RightDockWidgetArea, dockStyle)

    dockStyle = QtGui.QDockWidget("Settings")
    grid = QPropertyGrid()
    grid.setPropertyRegistry(editor.settings)
    grid.showNormal()
    dockStyle.setWidget(grid)
    win.addDockWidget(QtCore.Qt.RightDockWidgetArea, dockStyle)

    win.resize(1280, 1024)
    win.show()

    app.exec_()
