init
[qstardict] / qstardict / cssedit.cpp
diff --git a/qstardict/cssedit.cpp b/qstardict/cssedit.cpp
new file mode 100644 (file)
index 0000000..b96731d
--- /dev/null
@@ -0,0 +1,364 @@
+/*****************************************************************************
+ * cssedit.cpp - QStarDict, a StarDict clone written with using Qt           *
+ * Copyright (C) 2008 Alexander Rodin                                        *
+ *                                                                           *
+ * This program is free software; you can redistribute it and/or modify      *
+ * it under the terms of the GNU General Public License as published by      *
+ * the Free Software Foundation; either version 2 of the License, or         *
+ * (at your option) any later version.                                       *
+ *                                                                           *
+ * This program is distributed in the hope that it will be useful,           *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of            *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             *
+ * GNU General Public License for more details.                              *
+ *                                                                           *
+ * You should have received a copy of the GNU General Public License along   *
+ * with this program; if not, write to the Free Software Foundation, Inc.,   *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.               *
+ *****************************************************************************/
+
+#include "cssedit.h"
+
+#include <QApplication>
+#include <QColorDialog>
+
+namespace QStarDict
+{
+CSSEdit::CSSEdit(QWidget *parent)
+    : QWidget(parent)
+{
+    setupUi(this);
+    m_preview->setProperty("FingerScrollable", true);
+
+    connect(m_elementCombo, SIGNAL(currentIndexChanged(int)), SLOT(setCurrentElement(int)));
+    connect(m_fontCombo, SIGNAL(currentFontChanged(const QFont&)), SLOT(propertyChanged()));
+    connect(m_sizeSpin, SIGNAL(valueChanged(int)), SLOT(propertyChanged()));
+    connect(m_boldButton, SIGNAL(toggled(bool)), SLOT(propertyChanged()));
+    connect(m_italicButton, SIGNAL(toggled(bool)), SLOT(propertyChanged()));
+    connect(m_underlineButton, SIGNAL(toggled(bool)), SLOT(propertyChanged()));
+    connect(m_colorButton, SIGNAL(clicked()), SLOT(colorSelectClicked()));
+    connect(m_backgroundButton, SIGNAL(clicked()), SLOT(colorSelectClicked()));
+}
+
+void CSSEdit::setCSS(const QString &css)
+{
+    m_elements.clear();
+    bool inBlock = false;
+    QString element;
+    QString currentProperty;
+    QString currentValue;
+    for (int i = 0; i < css.length(); ++i)
+    {
+        if (! inBlock)
+        {
+            element.clear();
+            for (; i < css.length() && css[i] != '{'; ++i)
+                if (! css[i].isSpace())
+                    element += css[i];
+            if (i < css.length() && css[i] == '{')
+            {
+                inBlock = true;
+                ++i;
+            }
+        }
+        else
+        {
+            currentProperty.clear();
+            for (; i < css.length() && css[i] != ':'; ++i)
+                if (! css[i].isSpace())
+                    currentProperty += css[i];
+            if (! inBlock)
+                continue;
+            currentValue.clear();
+            char quote = '\0';
+            for (++i; i < css.length() && css[i] != ';'; ++i)
+            {
+                if (quote)
+                {
+                    if (css[i] == quote)
+                    {
+                        while (i < css.length() && css[i] != ';')
+                            ++i;
+                        break;
+                    }
+                    else
+                        currentValue += css[i];
+                }
+                else if (! css[i].isSpace())
+                {
+                    if (css[i] == '\'' || css[i] == '\"')
+                        quote = css[i].toAscii();
+                    else
+                        currentValue += css[i];
+                }
+            }
+            m_elements[element][currentProperty] = currentValue;
+            while (css[i + 1].isSpace())
+                ++i;
+            if (css[i + 1] == '}')
+            {
+                ++i;
+                inBlock = false;
+            }
+        }
+    }
+
+    updateElementCombo();
+    updatePreview();
+}
+
+void CSSEdit::setElementsAliases(const QHash<QString, QString> &aliases)
+{
+    m_elementsAliases = aliases;
+    updateElementCombo();
+    updatePreview();
+}
+
+QString CSSEdit::css() const
+{
+    QString result;
+    for (QHash<QString, Element>::const_iterator i = m_elements.begin(); i != m_elements.end(); ++i)
+    {
+        result += i.key() + "\n{\n";
+        for (Element::const_iterator j = i->begin(); j != i->end(); ++j)
+        {
+            result += j.key() + ": ";
+            if (j->contains(' '))
+                result += "\"" + *j + "\";\n";
+            else
+                result += *j + ";\n";
+        }
+        result += "}\n";
+    }
+    return result;
+}
+
+void CSSEdit::setCurrentElement(int index)
+{
+    if (! m_elements.contains(m_elementCombo->itemData(index).toString()))
+        return;
+    m_currentElement = m_elementCombo->itemData(index).toString();
+    Element *element = &m_elements[m_currentElement];
+    Element parentElement = getParentElement(m_currentElement);
+
+    QColor color(element->contains("color") ? element->value("color") : parentElement["color"]);
+    m_colorButton->setText(color.name());
+    QPalette palette = m_colorButton->palette();
+    palette.setColor(QPalette::Normal, QPalette::ButtonText, color);
+    m_colorButton->setPalette(palette);
+
+    color = QColor(element->contains("background-color") ?
+        element->value("background-color") : parentElement["background-color"]);
+    m_backgroundButton->setText(color.name());
+    palette = m_backgroundButton->palette();
+    palette.setColor(QPalette::Normal, QPalette::ButtonText, color);
+    m_backgroundButton->setPalette(palette);
+
+    m_fontCombo->setCurrentFont(element->contains("font-family") ?
+            element->value("font-family") : parentElement["font-family"]);
+
+    QString value = element->contains("font-size") ?
+        element->value("font-size") : parentElement["font-size"];
+    if (! value.endsWith("pt"))
+        value = parentElement["font-size"];
+    m_sizeSpin->setValue(value.left(value.length() - 2).toInt());
+
+    value = element->contains("font-weight") ? element->value("font-weight") : parentElement["font-weight"];
+    m_boldButton->setChecked(value == "bold");
+
+    value = element->contains("font-style") ? element->value("font-style") : parentElement["font-style"];
+    m_italicButton->setChecked(value == "italic");
+
+    value = element->contains("text-decoration") ? element->value("text-decoration") : parentElement["text-decoration"];
+    m_underlineButton->setChecked(value == "underline");
+
+    updatePreview();
+}
+
+void CSSEdit::propertyChanged()
+{
+    if (! sender())
+        return;
+    if (! m_elements.contains(m_currentElement))
+        return;
+    Element *element = &m_elements[m_currentElement];
+    Element parentElement = getParentElement(m_currentElement);
+
+    if (sender() == m_fontCombo)
+    {
+        QString font = m_fontCombo->currentText();
+        if (parentElement["font-family"] == font)
+            element->remove("font-family");
+        else
+            element->insert("font-family", font);
+    }
+    else if (sender() == m_sizeSpin)
+    {
+        QString size = QString::number(m_sizeSpin->value()) + "pt";
+        if (parentElement["font-size"] == size)
+            element->remove("font-size");
+        else
+            element->insert("font-size", size);
+    }
+    else if (sender() == m_boldButton)
+    {
+        QString weight = (m_boldButton->isChecked() ? "bold" : "normal");
+        if (parentElement["font-weight"] == weight)
+            element->remove("font-weight");
+        else
+            element->insert("font-weight", weight);
+    }
+    else if(sender() == m_italicButton)
+    {
+        QString style = (m_italicButton->isChecked() ? "italic" : "normal");
+        if (parentElement["font-style"] == style)
+            element->remove("font-style");
+        else
+            element->insert("font-style", style);
+    }
+    else if(sender() == m_underlineButton)
+    {
+        QString decoration = (m_underlineButton->isChecked() ? "underline" : "none");
+        if (parentElement["text-decoration"] == decoration)
+            element->remove("text-decoration");
+        else
+            element->insert("text-decoration", decoration);
+    }
+
+    updatePreview();
+}
+
+void CSSEdit::colorSelectClicked()
+{
+    QToolButton *colorButton;
+    QString propertyName;
+    if (sender() == m_colorButton)
+    {
+        colorButton = m_colorButton;
+        propertyName = "color";
+    }
+    else if (sender() == m_backgroundButton)
+    {
+        colorButton = m_backgroundButton;
+        propertyName = "background-color";
+    }
+    else
+        return;
+
+    if (! m_elements.contains(m_currentElement))
+        return;
+    Element *element = &m_elements[m_currentElement];
+    Element parentElement = getParentElement(m_currentElement);
+    QColor color = QColorDialog::getColor(QColor(colorButton->text()), this);
+    if (color.isValid())
+    {
+        colorButton->setText(color.name());
+        QPalette palette = colorButton->palette();
+        palette.setColor(QPalette::Normal, QPalette::ButtonText, color);
+        colorButton->setPalette(palette);
+        if (parentElement[propertyName] == color.name())
+            element->remove(propertyName);
+        else
+            element->insert(propertyName, color.name());
+        updatePreview();
+    }
+}
+
+void CSSEdit::updatePreview()
+{
+    QString html = "<style>" +  css()  +  "</style>";
+    html += "<body>";
+    for (QHash<QString, Element>::const_iterator i = m_elements.begin(); i != m_elements.end(); ++i)
+    {
+        QString alias;
+        if (m_elementsAliases.contains(i.key()))
+            alias = m_elementsAliases.value(i.key());
+        else
+            alias = i.key();
+        int pos = i.key().indexOf('.');
+        if (pos == -1)
+            html += "<" + i.key() + ">" + alias + "</" + i.key() + "><br>";
+        else
+        {
+            QString parent = i.key().left(pos);
+            QString class_ = i.key().mid(pos + 1);
+            html += "<" + parent + " class=\'" + class_ + "\'>" + alias + "</" + parent + "><br>";
+        }
+    }
+    html += "</body>";
+    m_preview->setHtml(html);
+}
+
+void CSSEdit::updateElementCombo()
+{
+    m_elementCombo->clear();
+    for (QHash<QString, Element>::const_iterator i = m_elements.begin(); i != m_elements.end(); ++i)
+    {
+        QString alias;
+        if (m_elementsAliases.contains(i.key()))
+            alias = m_elementsAliases.value(i.key());
+        else
+            alias = i.key();
+        m_elementCombo->addItem(alias, i.key());
+    }
+    if (m_elements.begin() != m_elements.end())
+        m_currentElement = m_elements.begin().key();
+    else
+        m_currentElement.clear();
+}
+
+CSSEdit::Element CSSEdit::getParentElement(const QString &elementName)
+{
+    Element body = m_elements.value("body");
+
+    if (elementName == "body")
+    {
+        body["color"] = QApplication::palette().color(QPalette::Normal, QPalette::Text).name();
+        body["background-color"] = QApplication::palette().color(QPalette::Normal, QPalette::Base).name();
+        body["font-family"] = QApplication::font().family();
+        body["font-size"] = QString::number(QApplication::font().pointSize()) + "pt";
+        body["font-weight"] = (QApplication::font().weight() == QFont::Bold) ? "bold" : "normal";
+        body["font-style"] = (QApplication::font().style() == QFont::StyleItalic) ? "italic" : "normal";
+        body["text-decoration"] = QApplication::font().underline() ? "underline" : "none";
+        return body;
+    }
+    else
+    {
+        if (! body.contains("color"))
+            body["color"] = QApplication::palette().color(QPalette::Normal, QPalette::Text).name();
+        if (! body.contains("background-color"))
+            body["background-color"] = QApplication::palette().color(QPalette::Normal, QPalette::Base).name();
+        if (! body.contains("font-family"))
+            body["font-family"] = QApplication::font().family();
+        if (! body.contains("font-size"))
+            body["font-size"] = QString::number(QApplication::font().pointSize()) + "pt";
+        if (! body.contains("font-weight"))
+            body["font-weight"] = (QApplication::font().weight() == QFont::Bold) ? "bold" : "normal";
+        if (! body.contains("font-style"))
+            body["font-style"] = (QApplication::font().style() == QFont::StyleItalic) ? "italic" : "normal";
+        if (! body.contains("text-decoration"))
+            body["text-decoration"] = QApplication::font().underline() ? "underline" : "none";
+    }
+
+    QString parentName;
+    int pos = elementName.indexOf('.');
+    if (pos != -1)
+    {
+        parentName = elementName.left(pos);
+        if (m_elements.contains(parentName))
+        {
+            Element parent = m_elements[parentName];
+            for (Element::const_iterator i = body.begin(); i != body.end(); ++i)
+                if (! parent.contains(i.key()))
+                    parent[i.key()] = *i;
+            return parent;
+        }
+        else
+            return body;
+    }
+    return body;
+}
+}
+
+// vim: tabstop=4 softtabstop=4 shiftwidth=4 expandtab cindent textwidth=120 formatoptions=tc
+