File indexing completed on 2024-05-26 16:15:58

0001 /* This file is part of the KDE project
0002  * Copyright (C) 2006-2009 Thomas Zander <zander@kde.org>
0003  *
0004  * This library is free software; you can redistribute it and/or
0005  * modify it under the terms of the GNU Library General Public
0006  * License as published by the Free Software Foundation; either
0007  * version 2 of the License, or (at your option) any later version.
0008  *
0009  * This library is distributed in the hope that it will be useful,
0010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0012  * Library General Public License for more details.
0013  *
0014  * You should have received a copy of the GNU Library General Public License
0015  * along with this library; see the file COPYING.LIB.  If not, write to
0016  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0017  * Boston, MA 02110-1301, USA.
0018  */
0019 #include "KoVariable.h"
0020 
0021 #include "KoInlineObject_p.h"
0022 
0023 #include <KoShape.h>
0024 
0025 #include <QPainter>
0026 #include <QFontMetricsF>
0027 #include <QTextDocument>
0028 #include <QTextInlineObject>
0029 #include "TextDebug.h"
0030 
0031 class KoVariablePrivate : public KoInlineObjectPrivate
0032 {
0033 public:
0034     KoVariablePrivate()
0035             : modified(true),
0036             document(0),
0037             lastPositionInDocument(-1)
0038     {
0039     }
0040 
0041     QDebug printDebug(QDebug dbg) const override
0042     {
0043         dbg.nospace() << "KoVariable value=" << value;
0044         return dbg.space();
0045     }
0046 
0047     QString value;
0048     bool modified;
0049     const QTextDocument *document;
0050     int lastPositionInDocument;
0051 };
0052 
0053 KoVariable::KoVariable(bool propertyChangeListener)
0054         : KoInlineObject(*(new KoVariablePrivate()), propertyChangeListener)
0055 {
0056 }
0057 
0058 KoVariable::~KoVariable()
0059 {
0060 }
0061 
0062 void KoVariable::setValue(const QString &value)
0063 {
0064     Q_D(KoVariable);
0065     if (d->value == value)
0066         return;
0067     d->value = value;
0068     d->modified = true;
0069     if (d->document) {
0070         const_cast<QTextDocument *>(d->document)->markContentsDirty(d->lastPositionInDocument, 0);
0071     }
0072 }
0073 
0074 void KoVariable::updatePosition(const QTextDocument *document, int posInDocument, const QTextCharFormat & format)
0075 {
0076     Q_D(KoVariable);
0077     if (d->document) {
0078         disconnect(d->document, SIGNAL(destroyed()), this, SLOT(documentDestroyed()));
0079     }
0080     d->document = document;
0081     connect(d->document, SIGNAL(destroyed()), this, SLOT(documentDestroyed()));
0082     d->lastPositionInDocument = posInDocument;
0083     Q_UNUSED(format);
0084     // Variables are always 'in place' so the position is 100% defined by the text layout.
0085     variableMoved(d->document, posInDocument);
0086 }
0087 
0088 void KoVariable::resize(const QTextDocument *document, QTextInlineObject &object, int posInDocument, const QTextCharFormat &format, QPaintDevice *pd)
0089 {
0090     Q_D(KoVariable);
0091     Q_UNUSED(document);
0092     Q_UNUSED(posInDocument);
0093     if (d->modified == false)
0094         return;
0095     if (object.isValid() == false)
0096         return;
0097     d->modified = true;
0098     Q_ASSERT(format.isCharFormat());
0099     QFontMetricsF fm(format.font(), pd);
0100 
0101     qreal width = qMax(qreal(0.0), fm.width(d->value));
0102     qreal ascent = fm.ascent();
0103     qreal descent = fm.descent();
0104     if (object.width() != width) {
0105         object.setWidth(width);
0106     }
0107     if (object.ascent() != ascent) {
0108         object.setAscent(ascent);
0109     }
0110     if (object.descent() != descent) {
0111         object.setDescent(descent);
0112     }
0113 }
0114 
0115 void KoVariable::paint(QPainter &painter, QPaintDevice *pd, const QTextDocument *document, const QRectF &rect, const QTextInlineObject &object, int posInDocument, const QTextCharFormat &format)
0116 {
0117     Q_D(KoVariable);
0118     Q_UNUSED(document);
0119     Q_UNUSED(posInDocument);
0120 
0121     // TODO set all the font properties from the format (color etc)
0122     QFont font(format.font(), pd);
0123     QTextLayout layout(d->value, font, pd);
0124     layout.setCacheEnabled(true);
0125     QList<QTextLayout::FormatRange> layouts;
0126     QTextLayout::FormatRange range;
0127     range.start = 0;
0128     range.length = d->value.length();
0129     range.format = format;
0130     layouts.append(range);
0131     layout.setAdditionalFormats(layouts);
0132 
0133     QTextOption option(Qt::AlignLeft | Qt::AlignAbsolute);
0134     if (object.isValid()) {
0135         option.setTextDirection(object.textDirection());
0136     }
0137     layout.setTextOption(option);
0138     layout.beginLayout();
0139     layout.createLine();
0140     layout.endLayout();
0141     layout.draw(&painter, rect.topLeft());
0142 }
0143 
0144 void KoVariable::variableMoved(const QTextDocument *document, int posInDocument)
0145 {
0146     Q_UNUSED(document);
0147     Q_UNUSED(posInDocument);
0148 }
0149 
0150 QString KoVariable::value() const
0151 {
0152     Q_D(const KoVariable);
0153     return d->value;
0154 }
0155 
0156 int KoVariable::positionInDocument() const
0157 {
0158     Q_D(const KoVariable);
0159     return d->lastPositionInDocument;
0160 }
0161 
0162 void KoVariable::documentDestroyed()
0163 {
0164     // deleteLater(); does not work when closing a document as the inline object manager is deleted before the control is given back to the event loop
0165     // therefore commit suicide.
0166     // See http://www.parashift.com/c++-faq-lite/delete-this.html
0167     delete(this);
0168 }