1 /* This file is part of the KDE project
2 * Copyright (C) 2006-2009 Thomas Zander <zander@kde.org>
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
13 *
14 * You should have received a copy of the GNU Library General Public License
15 * along with this library; see the file COPYING.LIB. If not, write to
16 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
18 */
19 #include "KoVariable.h"
20
21 #include "KoInlineObject_p.h"
22
23 #include <KoShape.h>
24
25 #include <QPainter>
26 #include <QFontMetricsF>
27 #include <QTextDocument>
28 #include <QTextInlineObject>
29 #include "TextDebug.h"
30
31 class KoVariablePrivate : public KoInlineObjectPrivate
32 {
33 public:
KoVariablePrivate()34 KoVariablePrivate()
35 : modified(true),
36 document(0),
37 lastPositionInDocument(-1)
38 {
39 }
40
printDebug(QDebug dbg) const41 QDebug printDebug(QDebug dbg) const override
42 {
43 dbg.nospace() << "KoVariable value=" << value;
44 return dbg.space();
45 }
46
47 QString value;
48 bool modified;
49 const QTextDocument *document;
50 int lastPositionInDocument;
51 };
52
KoVariable(bool propertyChangeListener)53 KoVariable::KoVariable(bool propertyChangeListener)
54 : KoInlineObject(*(new KoVariablePrivate()), propertyChangeListener)
55 {
56 }
57
~KoVariable()58 KoVariable::~KoVariable()
59 {
60 }
61
setValue(const QString & value)62 void KoVariable::setValue(const QString &value)
63 {
64 Q_D(KoVariable);
65 if (d->value == value)
66 return;
67 d->value = value;
68 d->modified = true;
69 if (d->document) {
70 const_cast<QTextDocument *>(d->document)->markContentsDirty(d->lastPositionInDocument, 0);
71 }
72 }
73
updatePosition(const QTextDocument * document,int posInDocument,const QTextCharFormat & format)74 void KoVariable::updatePosition(const QTextDocument *document, int posInDocument, const QTextCharFormat & format)
75 {
76 Q_D(KoVariable);
77 if (d->document) {
78 disconnect(d->document, SIGNAL(destroyed()), this, SLOT(documentDestroyed()));
79 }
80 d->document = document;
81 connect(d->document, SIGNAL(destroyed()), this, SLOT(documentDestroyed()));
82 d->lastPositionInDocument = posInDocument;
83 Q_UNUSED(format);
84 // Variables are always 'in place' so the position is 100% defined by the text layout.
85 variableMoved(d->document, posInDocument);
86 }
87
resize(const QTextDocument * document,QTextInlineObject & object,int posInDocument,const QTextCharFormat & format,QPaintDevice * pd)88 void KoVariable::resize(const QTextDocument *document, QTextInlineObject &object, int posInDocument, const QTextCharFormat &format, QPaintDevice *pd)
89 {
90 Q_D(KoVariable);
91 Q_UNUSED(document);
92 Q_UNUSED(posInDocument);
93 if (d->modified == false)
94 return;
95 if (object.isValid() == false)
96 return;
97 d->modified = true;
98 Q_ASSERT(format.isCharFormat());
99 QFontMetricsF fm(format.font(), pd);
100
101 qreal width = qMax(qreal(0.0), fm.width(d->value));
102 qreal ascent = fm.ascent();
103 qreal descent = fm.descent();
104 if (object.width() != width) {
105 object.setWidth(width);
106 }
107 if (object.ascent() != ascent) {
108 object.setAscent(ascent);
109 }
110 if (object.descent() != descent) {
111 object.setDescent(descent);
112 }
113 }
114
paint(QPainter & painter,QPaintDevice * pd,const QTextDocument * document,const QRectF & rect,const QTextInlineObject & object,int posInDocument,const QTextCharFormat & format)115 void KoVariable::paint(QPainter &painter, QPaintDevice *pd, const QTextDocument *document, const QRectF &rect, const QTextInlineObject &object, int posInDocument, const QTextCharFormat &format)
116 {
117 Q_D(KoVariable);
118 Q_UNUSED(document);
119 Q_UNUSED(posInDocument);
120
121 // TODO set all the font properties from the format (color etc)
122 QFont font(format.font(), pd);
123 QTextLayout layout(d->value, font, pd);
124 layout.setCacheEnabled(true);
125 QList<QTextLayout::FormatRange> layouts;
126 QTextLayout::FormatRange range;
127 range.start = 0;
128 range.length = d->value.length();
129 range.format = format;
130 layouts.append(range);
131 layout.setAdditionalFormats(layouts);
132
133 QTextOption option(Qt::AlignLeft | Qt::AlignAbsolute);
134 if (object.isValid()) {
135 option.setTextDirection(object.textDirection());
136 }
137 layout.setTextOption(option);
138 layout.beginLayout();
139 layout.createLine();
140 layout.endLayout();
141 layout.draw(&painter, rect.topLeft());
142 }
143
variableMoved(const QTextDocument * document,int posInDocument)144 void KoVariable::variableMoved(const QTextDocument *document, int posInDocument)
145 {
146 Q_UNUSED(document);
147 Q_UNUSED(posInDocument);
148 }
149
value() const150 QString KoVariable::value() const
151 {
152 Q_D(const KoVariable);
153 return d->value;
154 }
155
positionInDocument() const156 int KoVariable::positionInDocument() const
157 {
158 Q_D(const KoVariable);
159 return d->lastPositionInDocument;
160 }
161
documentDestroyed()162 void KoVariable::documentDestroyed()
163 {
164 // 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
165 // therefore commit suicide.
166 // See http://www.parashift.com/c++-faq-lite/delete-this.html
167 delete(this);
168 }
169