]> git.sven.stormbind.net Git - sven/vym.git/blob - src/headingobj.cpp
Replace Pierre as the maintainer
[sven/vym.git] / src / headingobj.cpp
1 #include <QDebug>
2 #include <QGraphicsScene>
3 #include <QRegExp>
4
5 #include "headingobj.h"
6
7 extern bool debug;
8
9 /////////////////////////////////////////////////////////////////
10 // HeadingObj
11 /////////////////////////////////////////////////////////////////
12 HeadingObj::HeadingObj(QGraphicsItem *parent) : MapObj(parent)
13 {
14     // qDebug() << "Const HeadingObj (s) ";
15     init();
16 }
17
18 HeadingObj::~HeadingObj()
19 {
20     //  qDebug() << "Destr. HeadingObj "<<heading;
21     while (!textline.isEmpty())
22         delete textline.takeFirst();
23 }
24
25 void HeadingObj::init()
26 {
27     textwidth = 40;
28     color = QColor("black");
29     font = QFont();
30     heading = "";
31     angle = 0;
32 }
33
34 void HeadingObj::copy(HeadingObj *other)
35 {
36     MapObj::copy(other);
37     textwidth = other->textwidth;
38     color = other->color;
39     font = other->font;
40     setText(other->text());
41 }
42
43 void HeadingObj::move(double x, double y)
44 {
45     MapObj::move(x, y);
46
47     qreal h;  // height of a textline
48     qreal ho; // offset of height while drawing all lines
49
50     if (!textline.isEmpty())
51         h = textline.first()->boundingRect().height();
52     else
53         h = 2;
54     ho = 0;
55     for (int i = 0; i < textline.size(); ++i) {
56         textline.at(i)->setPos(x, y + ho);
57         ho = ho + h;
58     }
59 }
60
61 void HeadingObj::moveBy(double x, double y)
62 {
63     move(x + absPos.x(), y + absPos.y());
64 }
65
66 void HeadingObj::positionBBox()
67 {
68     bbox.setX(absPos.x());
69     bbox.setY(absPos.y());
70 }
71
72 void HeadingObj::calcBBoxSize()
73 {
74     qreal w = 0;
75     qreal h = 0;
76     // Using Backspace an empty heading might easily be created, then there
77     // would be textline.first()==NULL This can be worked around by the
78     // following, but then no selection would be visible, thus we prevent it in
79     // ::setText()
80     if (!textline.isEmpty()) {
81         for (int i = 0; i < textline.size(); i++) {
82             h += textline.at(i)->boundingRect().height();
83             if (w < textline.at(i)->boundingRect().width())
84                 w = textline.at(i)->boundingRect().width();
85         }
86     }
87     bbox.setSize(QSizeF(w, h));
88 }
89
90 QGraphicsTextItem *HeadingObj::newLine(QString s)
91 {
92     QGraphicsTextItem *t = new QGraphicsTextItem(s, parentItem());
93     t->setFont(font);
94     t->setZValue(dZ_TEXT);
95     t->setDefaultTextColor(color);
96     t->setRotation(angle);
97     return t;
98 }
99
100 void HeadingObj::setTransformOriginPoint(const QPointF &p)
101 {
102     for (int i = 0; i < textline.size(); i++) {
103         textline.at(i)->setTransformOriginPoint(p);
104     }
105 }
106
107 void HeadingObj::setRotation(const qreal &a)
108 {
109     angle = a;
110     for (int i = 0; i < textline.size(); i++)
111         textline.at(i)->setRotation(angle);
112 }
113
114 qreal HeadingObj::getRotation() { return angle; }
115
116 void HeadingObj::setText(QString s)
117 {
118     heading = s;
119
120     // remove old textlines and prepare generating new ones
121     while (!textline.isEmpty())
122         delete textline.takeFirst();
123
124     if (s.startsWith("<html>") ||
125         s.startsWith("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\" "
126                      "\"http://www.w3.org/TR/REC-html40/strict.dtd\">")) {
127         QGraphicsTextItem *t = new QGraphicsTextItem();
128         t->setFont(font);
129         t->setZValue(dZ_TEXT);
130         t->setHtml(s);
131         t->setDefaultTextColor(color);
132         t->setRotation(angle);
133         scene()->addItem(t);
134         textline.append(t);
135     }
136     else {
137         // prevent empty textline, so at least a small selection stays
138         // visible for this heading
139         if (s.length() == 0)
140             s = "  ";
141
142         int i = 0;  // index for actual search for ws
143         int j = 0;  // index of last ws
144         int k = 0;  // index of "<br>" or similar linebreak
145         int br = 0; // width of found break, e.g. for <br> it is 4
146         QRegExp re("<br.*/>");
147         re.setMinimal(true);
148
149         // set the text and wrap lines
150         while (s.length() > 0) {
151             // ok, some people wanted manual linebreaks, here we go
152             k = re.indexIn(s, i);
153             if (k >= 0) {
154                 br = re.cap(0).length();
155                 i = k;
156             }
157             else
158                 i = s.indexOf(" ", i);
159             if (i < 0 && j == 0) { // no ws found at all in s
160                 // append whole s
161                 textline.append(newLine(s));
162                 s = "";
163             }
164             else {
165                 if (i < 0 && j > 0) { // no ws found in actual search
166                     if (s.length() <= textwidth) {
167                         textline.append(newLine(s));
168                         s = "";
169                     }
170                     else {
171                         textline.append(newLine(s.left(j)));
172                         s = s.mid(j + 1, s.length());
173                         j = 0;
174                     }
175                 }
176                 else {
177                     if (i >= 0 &&
178                         i <= static_cast<int>(
179                                  textwidth)) { // there is a ws in textwidth
180                         if (br > 0) {
181                             // here is a linebreak
182                             textline.append(newLine(s.left(i)));
183                             s = s.mid(i + br, s.length());
184                             i = 0;
185                             j = 0;
186                             br = 0;
187                         }
188                         else {
189                             j = i;
190                             i++;
191                         }
192                     }
193                     else {
194                         if (i > static_cast<int>(textwidth)) {
195                             if (j > 0) { // a ws out of textwidth, but we have
196                                          // also one in
197                                 textline.append(newLine(s.left(j)));
198                                 s = s.mid(j + 1, s.length());
199                                 i = 0;
200                                 j = 0;
201                             }
202                             else { // a ws out of text, but none in
203                                 textline.append(newLine(s.left(i)));
204                                 s = s.mid(i + 1, s.length());
205                                 i = 0;
206                             }
207                         }
208                     }
209                 }
210             }
211         }
212     } // ASCII heading with multiple lines
213     setVisibility(visible);
214     move(absPos.x(), absPos.y());
215     calcBBoxSize();
216 }
217
218 QString HeadingObj::text() { return heading; }
219
220 void HeadingObj::setFont(QFont f)
221 {
222     if (font != f) {
223         font = f;
224         setText(text());
225     }
226 }
227
228 QFont HeadingObj::getFont() { return font; }
229
230 void HeadingObj::setColor(QColor c)
231 {
232     if (color != c) {
233         color = c;
234         for (int i = 0; i < textline.size(); ++i)
235             // TextItem
236             textline.at(i)->setDefaultTextColor(c);
237         // SimpleTextItem
238         // textline.at(i)->setBrush(c);
239     }
240 }
241
242 QColor HeadingObj::getColor() { return color; }
243
244 void HeadingObj::setZValue(double z)
245 {
246     for (int i = 0; i < textline.size(); ++i)
247         textline.at(i)->setZValue(z);
248 }
249
250 void HeadingObj::setVisibility(bool v)
251 {
252     MapObj::setVisibility(v);
253     for (int i = 0; i < textline.size(); ++i)
254         if (v)
255             textline.at(i)->show();
256         else
257             textline.at(i)->hide();
258 }
259
260 qreal HeadingObj::getHeight() { return bbox.height(); }
261
262 qreal HeadingObj::getWidth() { return bbox.width(); }