1 /***************************************************************************
2 * This file is part of the Lime Report project *
3 * Copyright (C) 2015 by Alexander Arin *
4 * arin_a@bk.ru *
5 * *
6 ** GNU General Public License Usage **
7 * *
8 * This library is free software: you can redistribute it and/or modify *
9 * it under the terms of the GNU General Public License as published by *
10 * the Free Software Foundation, either version 3 of the License, or *
11 * (at your option) any later version. *
12 * You should have received a copy of the GNU General Public License *
13 * along with this program. If not, see <http://www.gnu.org/licenses/>. *
14 * *
15 ** GNU Lesser General Public License **
16 * *
17 * This library is free software: you can redistribute it and/or modify *
18 * it under the terms of the GNU Lesser General Public License as *
19 * published by the Free Software Foundation, either version 3 of the *
20 * License, or (at your option) any later version. *
21 * You should have received a copy of the GNU Lesser General Public *
22 * License along with this library. *
23 * If not, see <http://www.gnu.org/licenses/>. *
24 * *
25 * This library is distributed in the hope that it will be useful, *
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
28 * GNU General Public License for more details. *
29 ****************************************************************************/
30 #include <QtGui>
31 #include <QTextLayout>
32 #include <QLocale>
33 #include <QMessageBox>
34 #include <math.h>
35
36 #include "lrpagedesignintf.h"
37 #include "lrtextitem.h"
38 #include "lrdesignelementsfactory.h"
39 #include "lrglobal.h"
40 #include "lrdatasourcemanager.h"
41 #include "lrsimpletagparser.h"
42 #include "lrtextitemeditor.h"
43 #include "lrreportengine_p.h"
44 #include <QMenu>
45
46 namespace{
47
48 const QString xmlTag = "TextItem";
49
createTextItem(QObject * owner,LimeReport::BaseDesignIntf * parent)50 LimeReport::BaseDesignIntf * createTextItem(QObject* owner, LimeReport::BaseDesignIntf* parent){
51 return new LimeReport::TextItem(owner,parent);
52 }
53 bool VARIABLE_IS_NOT_USED registred = LimeReport::DesignElementsFactory::instance().registerCreator(xmlTag, LimeReport::ItemAttribs(QObject::tr("Text Item"),"TextItem"), createTextItem);
54
55 }
56
57 namespace LimeReport{
58
TextItem(QObject * owner,QGraphicsItem * parent)59 TextItem::TextItem(QObject *owner, QGraphicsItem *parent)
60 : ContentItemDesignIntf(xmlTag,owner,parent), m_angle(Angle0), m_trimValue(true), m_allowHTML(false),
61 m_allowHTMLInFields(false), m_replaceCarriageReturns(false), m_followTo(""), m_follower(0), m_textIndent(0),
62 m_textLayoutDirection(Qt::LayoutDirectionAuto), m_hideIfEmpty(false), m_fontLetterSpacing(0)
63 {
64 PageItemDesignIntf* pageItem = dynamic_cast<PageItemDesignIntf*>(parent);
65 BaseDesignIntf* parentItem = dynamic_cast<BaseDesignIntf*>(parent);
66 while (!pageItem && parentItem){
67 parentItem = dynamic_cast<BaseDesignIntf*>(parentItem->parentItem());
68 pageItem = dynamic_cast<PageItemDesignIntf*>(parentItem);
69 }
70
71 if (pageItem){
72 QFont defaultFont = pageItem->font();
73 setFont(defaultFont);
74 }
75 Init();
76 }
77
~TextItem()78 TextItem::~TextItem(){}
79
fakeMarginSize() const80 int TextItem::fakeMarginSize() const{
81 return marginSize()+5;
82 }
83
preparePopUpMenu(QMenu & menu)84 void TextItem::preparePopUpMenu(QMenu &menu)
85 {
86 QAction* editAction = menu.addAction(QIcon(":/report/images/edit_pecil2.png"),tr("Edit"));
87 menu.insertAction(menu.actions().at(0),editAction);
88 menu.insertSeparator(menu.actions().at(1));
89
90 menu.addSeparator();
91
92 QAction* action = menu.addAction(tr("Auto height"));
93 action->setCheckable(true);
94 action->setChecked(autoHeight());
95
96 action = menu.addAction(tr("Allow HTML"));
97 action->setCheckable(true);
98 action->setChecked(allowHTML());
99
100 action = menu.addAction(tr("Allow HTML in fields"));
101 action->setCheckable(true);
102 action->setChecked(allowHTMLInFields());
103
104 action = menu.addAction(tr("Stretch to max height"));
105 action->setCheckable(true);
106 action->setChecked(stretchToMaxHeight());
107
108 action = menu.addAction(tr("Transparent"));
109 action->setCheckable(true);
110 action->setChecked(backgroundMode() == TransparentMode);
111
112 action = menu.addAction(tr("Watermark"));
113 action->setCheckable(true);
114 action->setChecked(isWatermark());
115
116 action = menu.addAction(tr("Hide if empty"));
117 action->setCheckable(true);
118 action->setChecked(hideIfEmpty());
119
120 }
121
processPopUpAction(QAction * action)122 void TextItem::processPopUpAction(QAction *action)
123 {
124 if (action->text().compare(tr("Edit")) == 0){
125 this->showEditorDialog();
126 }
127 if (page()){
128 if (action->text().compare(tr("Auto height")) == 0){
129 page()->setPropertyToSelectedItems("autoHeight",action->isChecked());
130 }
131 if (action->text().compare(tr("Allow HTML")) == 0){
132 page()->setPropertyToSelectedItems("allowHTML",action->isChecked());
133 }
134 if (action->text().compare(tr("Allow HTML in fields")) == 0){
135 page()->setPropertyToSelectedItems("allowHTMLInFields",action->isChecked());
136 }
137 if (action->text().compare(tr("Stretch to max height")) == 0){
138 page()->setPropertyToSelectedItems("stretchToMaxHeight",action->isChecked());
139 }
140 }
141 if (action->text().compare(tr("Transparent")) == 0){
142 if (action->isChecked()){
143 setProperty("backgroundMode",TransparentMode);
144 } else {
145 setProperty("backgroundMode",OpaqueMode);
146 }
147 }
148 if (action->text().compare(tr("Watermark")) == 0){
149 page()->setPropertyToSelectedItems("watermark",action->isChecked());
150 }
151
152 if (action->text().compare(tr("Hide if empty")) == 0){
153 page()->setPropertyToSelectedItems("hideIfEmpty",action->isChecked());
154 }
155
156 ContentItemDesignIntf::processPopUpAction(action);
157 }
158
paint(QPainter * painter,const QStyleOptionGraphicsItem * style,QWidget * widget)159 void TextItem::paint(QPainter* painter, const QStyleOptionGraphicsItem* style, QWidget* widget) {
160 Q_UNUSED(widget);
161 Q_UNUSED(style);
162
163
164 TextPtr text = textDocument();
165
166 painter->save();
167
168 setupPainter(painter);
169 prepareRect(painter,style,widget);
170
171 QSizeF tmpSize = rect().size()-text->size();
172
173 if (!painter->clipRegion().isEmpty()){
174 QRegion clipReg=painter->clipRegion().xored(painter->clipRegion().subtracted(rect().toRect()));
175 painter->setClipRegion(clipReg);
176 } else {
177 painter->setClipRect(rect());
178 }
179
180 qreal hOffset = 0, vOffset = 0;
181 switch (m_angle){
182 case Angle0:
183 hOffset = fakeMarginSize();
184 if ((tmpSize.height() > 0) && (m_alignment & Qt::AlignVCenter)){
185 vOffset = tmpSize.height() / 2;
186 }
187 if ((tmpSize.height() > 0) && (m_alignment & Qt::AlignBottom)) // allow html
188 vOffset = tmpSize.height();
189 painter->translate(hOffset,vOffset);
190 break;
191 case Angle90:
192 hOffset = width() - fakeMarginSize();
193 vOffset = fakeMarginSize();
194 if (m_alignment & Qt::AlignVCenter){
195 hOffset = (width() - text->size().height()) / 2 + text->size().height();
196 }
197
198 if (m_alignment & Qt::AlignBottom){
199 hOffset = (text->size().height());
200 }
201 painter->translate(hOffset,vOffset);
202 painter->rotate(90);
203 break;
204 case Angle180:
205 hOffset = width() - fakeMarginSize();
206 vOffset = height() - fakeMarginSize();
207 if ((tmpSize.width()>0) && (m_alignment & Qt::AlignVCenter)){
208 vOffset = tmpSize.height() / 2+ text->size().height();
209 }
210 if ((tmpSize.height()>0) && (m_alignment & Qt::AlignBottom)){
211 vOffset = (text->size().height());
212 }
213 painter->translate(hOffset,vOffset);
214 painter->rotate(180);
215 break;
216 case Angle270:
217 hOffset = fakeMarginSize();
218 vOffset = height()-fakeMarginSize();
219 if (m_alignment & Qt::AlignVCenter){
220 hOffset = (width() - text->size().height())/2;
221 }
222
223 if (m_alignment & Qt::AlignBottom){
224 hOffset = (width() - text->size().height());
225 }
226 painter->translate(hOffset,vOffset);
227 painter->rotate(270);
228 break;
229 case Angle45:
230 painter->translate(width()/2,0);
231 painter->rotate(45);
232 text->setTextWidth(sqrt(2*(pow(width()/2,2))));
233 break;
234 case Angle315:
235 painter->translate(0,height()/2);
236 painter->rotate(315);
237 text->setTextWidth(sqrt(2*(pow(height()/2,2))));
238 break;
239 }
240
241 int lineHeight = painter->fontMetrics().height();
242 qreal curpos = 0;
243
244 if (m_underlines){
245 QPen pen = painter->pen();
246 pen.setWidth(m_underlineLineSize);
247 painter->setPen(pen);
248 }
249
250 painter->setOpacity(qreal(foregroundOpacity())/100);
251 QAbstractTextDocumentLayout::PaintContext ctx;
252 ctx.palette.setColor(QPalette::Text, fontColor());
253
254 for(QTextBlock it = text->begin(); it != text->end(); it=it.next()){
255 it.blockFormat().setLineHeight(m_lineSpacing,QTextBlockFormat::LineDistanceHeight);
256 for (int i=0;i<it.layout()->lineCount();i++){
257 QTextLine line = it.layout()->lineAt(i);
258 if (m_underlines){
259 painter->drawLine(QPointF(0,line.rect().bottomLeft().y()),QPoint(rect().width(),line.rect().bottomRight().y()));
260 lineHeight = line.height()+m_lineSpacing;
261 curpos = line.rect().bottom();
262 }
263 }
264 }
265
266 text->documentLayout()->draw(painter,ctx);
267
268 if (m_underlines){
269 if (lineHeight<0) lineHeight = painter->fontMetrics().height();
270 for (curpos+=lineHeight; curpos<rect().height();curpos+=lineHeight){
271 painter->drawLine(QPointF(0,curpos),QPoint(rect().width(),curpos));
272 }
273 }
274
275 painter->restore();
276 BaseDesignIntf::paint(painter, style, widget);
277 }
278
content() const279 QString TextItem::content() const{
280 return m_strText;
281 }
282
Init()283 void TextItem::Init()
284 {
285 m_autoWidth = NoneAutoWidth;
286 m_alignment = Qt::AlignLeft|Qt::AlignTop;
287 m_autoHeight = false;
288 m_textSize = QSizeF();
289 m_firstLineSize = 0;
290 m_foregroundOpacity = 100;
291 m_underlines = false;
292 m_adaptFontToSize = false;
293 m_underlineLineSize = 1;
294 m_lineSpacing = 1;
295 m_valueType = Default;
296 }
297
setContent(const QString & value)298 void TextItem::setContent(const QString &value)
299 {
300 if (m_strText.compare(value)!=0){
301 QString oldValue = m_strText;
302 if (m_trimValue)
303 m_strText=value.trimmed();
304 else
305 m_strText=value;
306
307 // if (itemMode() == DesignMode && (autoHeight())){
308 // initTextSizes();
309 // }
310
311 if (!isLoading()){
312 if (autoHeight() || autoWidth() || hasFollower())
313 initTextSizes();
314 update(rect());
315 notify("content",oldValue,value);
316 }
317 }
318 }
319
updateItemSize(DataSourceManager * dataManager,RenderPass pass,int maxHeight)320 void TextItem::updateItemSize(DataSourceManager* dataManager, RenderPass pass, int maxHeight)
321 {
322
323 if (isNeedExpandContent())
324 expandContent(dataManager, pass);
325
326 if (!isLoading() && (autoHeight() || autoWidth() || hasFollower()) )
327 initTextSizes();
328
329 if (m_textSize.width()>width() && ((m_autoWidth==MaxWordLength)||(m_autoWidth==MaxStringLength))){
330 setWidth(m_textSize.width() + fakeMarginSize()*2);
331 }
332
333 if (m_textSize.height()>height()) {
334 if (m_autoHeight)
335 setHeight(m_textSize.height()+borderLineSize()*2);
336 else if (hasFollower() && !content().isEmpty()){
337 follower()->setContent(getTextPart(0,height()));
338 setContent(getTextPart(height(),0));
339 }
340 }
341 BaseDesignIntf::updateItemSize(dataManager, pass, maxHeight);
342 if (isEmpty() && hideIfEmpty()) setVisible(false);
343 }
344
updateLayout()345 void TextItem::updateLayout()
346 {
347 // m_layout.setFont(transformToSceneFont(font()));
348 // m_layout.setText(content());
349 // qreal linePos = 0;
350 // m_layout.beginLayout();
351 // while(true){
352 // QTextLine line = m_layout.createLine();
353 // if (!line.isValid()) break;
354 // line.setLineWidth(width()-marginSize()*2);
355 // line.setPosition(QPoint(marginSize(),linePos));
356 // linePos+=line.height();
357 // }
358 // m_layout.endLayout();
359 }
360
isNeedExpandContent() const361 bool TextItem::isNeedExpandContent() const
362 {
363 QRegExp rx("$*\\{[^{]*\\}");
364 return content().contains(rx) || isContentBackedUp();
365 }
366
replaceBR(QString text) const367 QString TextItem::replaceBR(QString text) const
368 {
369 return text.replace("<br/>","\n");
370 }
371
replaceReturns(QString text) const372 QString TextItem::replaceReturns(QString text) const
373 {
374 QString result = text.replace("\r\n","<br/>");
375 result = result.replace("\n","<br/>");
376 return result;
377 }
378
setTextFont(TextPtr text,const QFont & value) const379 void TextItem::setTextFont(TextPtr text, const QFont& value) const {
380 text->setDefaultFont(value);
381 if ((m_angle==Angle0)||(m_angle==Angle180)){
382 text->setTextWidth(rect().width()-fakeMarginSize()*2);
383 } else {
384 text->setTextWidth(rect().height()-fakeMarginSize()*2);
385 }
386 }
387
adaptFontSize(TextPtr text) const388 void TextItem::adaptFontSize(TextPtr text) const{
389 QFont _font = transformToSceneFont(font());
390 do{
391 setTextFont(text,_font);
392 if (_font.pixelSize()>2)
393 _font.setPixelSize(_font.pixelSize()-1);
394 else break;
395 } while(text->size().height()>this->height() || text->size().width()>(this->width()) - fakeMarginSize() * 2);
396 }
397
underlineLineSize() const398 int TextItem::underlineLineSize() const
399 {
400 return m_underlineLineSize;
401 }
402
setUnderlineLineSize(int value)403 void TextItem::setUnderlineLineSize(int value)
404 {
405 int oldValue = m_underlineLineSize;
406 m_underlineLineSize = value;
407 update();
408 notify("underlineLineSize",oldValue,value);
409 }
410
lineSpacing() const411 int TextItem::lineSpacing() const
412 {
413 return m_lineSpacing;
414 }
415
setLineSpacing(int value)416 void TextItem::setLineSpacing(int value)
417 {
418 int oldValue = m_lineSpacing;
419 m_lineSpacing = value;
420 // if (autoHeight())
421 // initTextSizes();
422 update();
423 notify("lineSpacing",oldValue,value);
424 }
425
426
initTextSizes() const427 void TextItem::initTextSizes() const
428 {
429 TextPtr text = textDocument();
430 m_textSize= text->size();
431 if (text->begin().isValid() && text->begin().layout()->lineAt(0).isValid())
432 m_firstLineSize = text->begin().layout()->lineAt(0).height();
433 }
434
formatDateTime(const QDateTime & value)435 QString TextItem::formatDateTime(const QDateTime &value)
436 {
437 if (m_format.isEmpty())
438 {
439 return value.toString();
440 }
441
442 return value.toString(m_format);
443 }
444
formatNumber(const double value)445 QString TextItem::formatNumber(const double value)
446 {
447 QString str = QString::number(value);
448
449 if (m_format.contains("%"))
450 {
451 str.sprintf(m_format.toStdString().c_str(), value);
452 str = str.replace(",", QLocale::system().groupSeparator());
453 str = str.replace(".", QLocale::system().decimalPoint());
454 }
455
456 return str;
457 }
458
formatFieldValue()459 QString TextItem::formatFieldValue()
460 {
461 if (m_format.isEmpty()) {
462 return m_varValue.toString();
463 }
464
465 QVariant value = m_varValue;
466
467 if (m_valueType != Default) {
468 switch (m_valueType) {
469 case DateTime:
470 {
471 QDateTime dt = QDateTime::fromString(value.toString(), Qt::ISODate);
472 value = (dt.isValid() ? QVariant(dt) : m_varValue);
473 break;
474 }
475 case Double:
476 {
477 bool bOk = false;
478 double dbl = value.toDouble(&bOk);
479 value = (bOk ? QVariant(dbl) : m_varValue);
480 }
481 default: break;
482 }
483 }
484
485 switch (value.type()) {
486 case QVariant::Date:
487 case QVariant::DateTime:
488 return formatDateTime(value.toDateTime());
489 case QVariant::Double:
490 return formatNumber(value.toDouble());
491 default:
492 return value.toString();
493 }
494 }
495
textDocument() const496 TextItem::TextPtr TextItem::textDocument() const
497 {
498 TextPtr text(new QTextDocument);
499
500 if (allowHTML())
501 if (isReplaceCarriageReturns()){
502 text->setHtml(replaceReturns(m_strText));
503 } else {
504 text->setHtml(m_strText);
505 }
506 else
507 text->setPlainText(m_strText);
508
509 QTextOption to;
510 to.setAlignment(m_alignment);
511 to.setTextDirection(m_textLayoutDirection);
512
513 if (m_autoWidth!=MaxStringLength)
514 if (m_adaptFontToSize && (!(m_autoHeight || m_autoWidth)))
515 to.setWrapMode(QTextOption::WordWrap);
516 else
517 to.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere);
518 else to.setWrapMode(QTextOption::NoWrap);
519
520 text->setDocumentMargin(0);
521 text->setDefaultTextOption(to);
522
523 QFont _font = transformToSceneFont(font());
524 if (m_adaptFontToSize && (!(m_autoHeight || m_autoWidth))){
525 adaptFontSize(text);
526 } else {
527 setTextFont(text,_font);
528 }
529
530 if (follower())
531 text->documentLayout();
532
533 if (m_lineSpacing != 1 || m_textIndent !=0 ){
534
535 for ( QTextBlock block = text->begin(); block.isValid(); block = block.next())
536 {
537 QTextCursor tc = QTextCursor(block);
538 QTextBlockFormat fmt = block.blockFormat();
539 fmt.setTextIndent(m_textIndent);
540 if (fmt.lineHeight() != m_lineSpacing) {
541 fmt.setLineHeight(m_lineSpacing,QTextBlockFormat::LineDistanceHeight);
542 }
543 tc.setBlockFormat( fmt );
544 }
545
546 }
547
548 return text;
549
550 }
551
fontLetterSpacing() const552 int TextItem::fontLetterSpacing() const
553 {
554 return m_fontLetterSpacing;
555 }
556
setFontLetterSpacing(int value)557 void TextItem::setFontLetterSpacing(int value)
558 {
559 if (m_fontLetterSpacing != value){
560 int oldValue = m_fontLetterSpacing;
561 m_fontLetterSpacing = value;
562 QFont curFont = font();
563 curFont.setLetterSpacing(QFont::AbsoluteSpacing, m_fontLetterSpacing);
564 setFont(curFont);
565 notify("fontLetterSpacing", oldValue, value);
566 }
567 }
568
hideIfEmpty() const569 bool TextItem::hideIfEmpty() const
570 {
571 return m_hideIfEmpty;
572 }
573
setHideIfEmpty(bool hideEmpty)574 void TextItem::setHideIfEmpty(bool hideEmpty)
575 {
576 if (m_hideIfEmpty != hideEmpty){
577 m_hideIfEmpty = hideEmpty;
578 notify("hideIfEmpty",!m_hideIfEmpty, m_hideIfEmpty);
579 }
580 }
581
isReplaceCarriageReturns() const582 bool TextItem::isReplaceCarriageReturns() const
583 {
584 return m_replaceCarriageReturns;
585 }
586
setReplaceCarriageReturns(bool replaceCarriageReturns)587 void TextItem::setReplaceCarriageReturns(bool replaceCarriageReturns)
588 {
589 if (replaceCarriageReturns != m_replaceCarriageReturns){
590 m_replaceCarriageReturns = replaceCarriageReturns;
591 update();
592 notify("replaceCRwithBR",!replaceCarriageReturns, replaceCarriageReturns);
593 }
594
595 }
596
textIndent() const597 qreal TextItem::textIndent() const
598 {
599 return m_textIndent;
600 }
601
setTextIndent(const qreal & textIndent)602 void TextItem::setTextIndent(const qreal &textIndent)
603 {
604 if (m_textIndent != textIndent){
605 qreal oldValue = m_textIndent;
606 m_textIndent = textIndent;
607 update();
608 notify("textIndent", oldValue, textIndent);
609 }
610 }
611
textLayoutDirection() const612 Qt::LayoutDirection TextItem::textLayoutDirection() const
613 {
614 return m_textLayoutDirection;
615 }
616
setTextLayoutDirection(const Qt::LayoutDirection & textLayoutDirection)617 void TextItem::setTextLayoutDirection(const Qt::LayoutDirection &textLayoutDirection)
618 {
619 if (m_textLayoutDirection != textLayoutDirection){
620 int oldValue = int(m_textLayoutDirection);
621 m_textLayoutDirection = textLayoutDirection;
622 update();
623 notify("textLayoutDirection",oldValue,int(textLayoutDirection));
624 }
625 }
626
setWatermark(bool watermark)627 void TextItem::setWatermark(bool watermark)
628 {
629 if (watermark){
630 setBackgroundMode(TransparentMode);
631 }
632 BaseDesignIntf::setWatermark(watermark);
633
634 }
635
636
followTo() const637 QString TextItem::followTo() const
638 {
639 return m_followTo;
640 }
641
setFollowTo(const QString & followTo)642 void TextItem::setFollowTo(const QString &followTo)
643 {
644 if (m_followTo != followTo){
645 QString oldValue = m_followTo;
646 m_followTo = followTo;
647 if (!isLoading()){
648 TextItem* fi = scene()->findChild<TextItem*>(oldValue);
649 if (fi) fi->clearFollower();
650 fi = scene()->findChild<TextItem*>(followTo);
651 if (fi && fi != this){
652 if (initFollower(followTo)){
653 notify("followTo",oldValue,followTo);
654 } else {
655 m_followTo = "";
656 QMessageBox::critical(
657 0,
658 tr("Error"),
659 tr("TextItem \" %1 \" already has folower \" %2 \" ")
660 .arg(fi->objectName())
661 .arg(fi->follower()->objectName())
662 );
663 notify("followTo",followTo,"");
664 }
665 } else if (m_followTo != ""){
666 QMessageBox::critical(
667 0,
668 tr("Error"),
669 tr("TextItem \" %1 \" not found!")
670 .arg(m_followTo)
671 );
672 notify("followTo",followTo,"");
673 }
674 }
675 }
676 }
677
setFollower(TextItem * follower)678 void TextItem::setFollower(TextItem *follower)
679 {
680 if (!m_follower){
681 m_follower = follower;
682 }
683 }
684
clearFollower()685 void TextItem::clearFollower()
686 {
687 m_follower = 0;
688 }
689
hasFollower() const690 bool TextItem::hasFollower() const
691 {
692 return m_follower != 0;
693 }
694
initFollower(QString follower)695 bool TextItem::initFollower(QString follower)
696 {
697 TextItem* fi = scene()->findChild<TextItem*>(follower);
698 if (fi){
699 if (!fi->hasFollower()){
700 fi->setFollower(this);
701 return true;
702 }
703 }
704 return false;
705 }
706
pageObjectHasBeenLoaded()707 void TextItem::pageObjectHasBeenLoaded()
708 {
709 if (!m_followTo.isEmpty()){
710 initFollower(m_followTo);
711 }
712 }
713
valueType() const714 TextItem::ValueType TextItem::valueType() const
715 {
716 return m_valueType;
717 }
718
setValueType(const ValueType valueType)719 void TextItem::setValueType(const ValueType valueType)
720 {
721 m_valueType = valueType;
722 }
723
format() const724 QString TextItem::format() const
725 {
726 return m_format;
727 }
728
setFormat(const QString & format)729 void TextItem::setFormat(const QString &format)
730 {
731 m_format = format;
732 }
733
allowHTMLInFields() const734 bool TextItem::allowHTMLInFields() const
735 {
736 return m_allowHTMLInFields;
737 }
738
setAllowHTMLInFields(bool allowHTMLInFields)739 void TextItem::setAllowHTMLInFields(bool allowHTMLInFields)
740 {
741 if (m_allowHTMLInFields != allowHTMLInFields){
742 m_allowHTMLInFields = allowHTMLInFields;
743 notify("allowHTMLInFields",!m_allowHTMLInFields,allowHTMLInFields);
744 update();
745 }
746 }
747
allowHTML() const748 bool TextItem::allowHTML() const
749 {
750 return m_allowHTML;
751 }
752
setAllowHTML(bool allowHTML)753 void TextItem::setAllowHTML(bool allowHTML)
754 {
755 if (m_allowHTML!=allowHTML){
756 m_allowHTML = allowHTML;
757 // if (m_text){
758 // if (allowHTML)
759 // m_text->setHtml(m_strText);
760 // else
761 // m_text->setPlainText(m_strText);
762 // update();
763 // }
764 update();
765 notify("allowHTML",!m_allowHTML,allowHTML);
766 }
767 }
trimValue() const768 bool TextItem::trimValue() const
769 {
770 return m_trimValue;
771 }
772
setTrimValue(bool value)773 void TextItem::setTrimValue(bool value)
774 {
775 bool oldValue = m_trimValue;
776 m_trimValue = value;
777 notify("trimValue",oldValue,value);
778 }
779
780
geometryChangedEvent(QRectF,QRectF)781 void TextItem::geometryChangedEvent(QRectF , QRectF)
782 {}
783
isNeedUpdateSize(RenderPass pass) const784 bool TextItem::isNeedUpdateSize(RenderPass pass) const
785 {
786 Q_UNUSED(pass)
787
788 if ((autoHeight() || autoWidth()) || hasFollower()){
789 initTextSizes();
790 }
791
792 bool res = (m_textSize.height()>geometry().height()&&autoHeight()) ||
793 (m_textSize.width()>geometry().width()&&autoWidth()) ||
794 m_follower ||
795 isNeedExpandContent();
796 return res;
797 }
798
setAlignment(Qt::Alignment value)799 void TextItem::setAlignment(Qt::Alignment value)
800 {
801 if (m_alignment!=value){
802 Qt::Alignment oldValue = m_alignment;
803 m_alignment=value;
804 //m_layout.setTextOption(QTextOption(m_alignment));
805 if (!isLoading()){
806 update(rect());
807 notify("alignment",QVariant(oldValue),QVariant(value));
808 }
809 }
810 }
811
expandContent(DataSourceManager * dataManager,RenderPass pass)812 void TextItem::expandContent(DataSourceManager* dataManager, RenderPass pass)
813 {
814 QString context=content();
815 foreach (QString variableName, dataManager->variableNamesByRenderPass(SecondPass)) {
816 QRegExp rx(QString(Const::NAMED_VARIABLE_RX).arg(variableName));
817 if (context.contains(rx) && pass == FirstPass){
818 backupContent();
819 break;
820 }
821 }
822
823 ExpandType expandType = (allowHTML() && !allowHTMLInFields()) ? ReplaceHTMLSymbols : NoEscapeSymbols;
824 switch(pass){
825 case FirstPass:
826 if (!fillInSecondPass()){
827 context=expandUserVariables(context, pass, expandType, dataManager);
828 context=expandScripts(context, dataManager);
829 context=expandDataFields(context, expandType, dataManager);
830 } else {
831 context=expandDataFields(context, expandType, dataManager);
832 }
833 break;
834 case SecondPass:
835 if (isContentBackedUp()) {
836 restoreContent();
837 context = content();
838 }
839 context=expandUserVariables(context, pass, expandType, dataManager);
840 context=expandScripts(context, dataManager);
841 }
842
843 if (expandType == NoEscapeSymbols && !m_varValue.isNull() &&m_valueType != Default) {
844 setContent(formatFieldValue());
845 } else {
846 setContent(context);
847 }
848
849 }
850
setAutoHeight(bool value)851 void TextItem::setAutoHeight(bool value)
852 {
853 if (m_autoHeight!=value){
854 bool oldValue = m_autoHeight;
855 m_autoHeight=value;
856 notify("autoHeight",oldValue,value);
857 }
858 }
859
setAutoWidth(TextItem::AutoWidth value)860 void TextItem::setAutoWidth(TextItem::AutoWidth value)
861 {
862 if (m_autoWidth!=value){
863 TextItem::AutoWidth oldValue = m_autoWidth;
864 m_autoWidth=value;
865 notify("autoWidth",oldValue,value);
866 }
867 }
868
setAdaptFontToSize(bool value)869 void TextItem::setAdaptFontToSize(bool value)
870 {
871 if (m_adaptFontToSize!=value){
872 bool oldValue = m_adaptFontToSize;
873 m_adaptFontToSize=value;
874 // initText();
875 invalidateRect(rect());
876 notify("updateFontToSize",oldValue,value);
877 }
878 }
879
canBeSplitted(int height) const880 bool TextItem::canBeSplitted(int height) const
881 {
882 QFontMetrics fm(font());
883 return height > m_firstLineSize;
884 }
885
extractText(QTextBlock & curBlock,int height)886 QString TextItem::extractText(QTextBlock& curBlock, int height){
887 int curLine = 0;
888 int linesHeight = 0;
889 QString resultText;
890 for (;curBlock != curBlock.document()->end() || curLine<=curBlock.lineCount(); curBlock = curBlock.next(), curLine = 0, resultText += '\n' ){
891 linesHeight+=curBlock.blockFormat().topMargin();
892 for (;curLine < curBlock.layout()->lineCount(); curLine++){
893 linesHeight += curBlock.layout()->lineAt(curLine).height() + lineSpacing();
894 if (height > 0 && linesHeight > (height-borderLineSize() * 2)) {goto loop_exit;}
895 resultText += curBlock.text().mid(curBlock.layout()->lineAt(curLine).textStart(),
896 curBlock.layout()->lineAt(curLine).textLength());
897 }
898 }
899 loop_exit: return resultText;
900 }
901
getTextPart(int height,int skipHeight)902 QString TextItem::getTextPart(int height, int skipHeight){
903
904 QString resultText = "";
905 TextPtr text = textDocument();
906 text->size().height();
907 QTextBlock curBlock = text->begin();
908 QTextCursor cursor(text.data());
909 cursor.movePosition(QTextCursor::Start);
910
911 if (skipHeight > 0){
912 resultText = extractText(curBlock, skipHeight);
913 cursor.movePosition(QTextCursor::Right, QTextCursor::MoveAnchor, resultText.length());
914 }
915
916 resultText = extractText(curBlock, height);
917 cursor.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor, resultText.length());
918
919 if (allowHTML()){
920 resultText = cursor.selection().toHtml();
921 resultText.remove("<!--StartFragment-->");
922 resultText.remove("<!--EndFragment-->");
923 } else {
924 resultText = cursor.selection().toPlainText();
925 }
926
927 return resultText;
928 }
929
restoreLinksEvent()930 void TextItem::restoreLinksEvent()
931 {
932 if (!followTo().isEmpty()){
933 BaseDesignIntf* pi = dynamic_cast<BaseDesignIntf*>(parentItem());
934 if (pi){
935 foreach (BaseDesignIntf* bi, pi->childBaseItems()) {
936 if (bi->patternName().compare(followTo())==0){
937 TextItem* ti = dynamic_cast<TextItem*>(bi);
938 if (ti){
939 ti->setFollower(this);
940 }
941 }
942 }
943 }
944 }
945 }
946
cloneUpperPart(int height,QObject * owner,QGraphicsItem * parent)947 BaseDesignIntf *TextItem::cloneUpperPart(int height, QObject *owner, QGraphicsItem *parent)
948 {
949 TextItem* upperPart = dynamic_cast<TextItem*>(cloneItem(itemMode(),owner,parent));
950 upperPart->setContent(getTextPart(height,0));
951 upperPart->initTextSizes();
952 upperPart->setHeight(upperPart->textSize().height()+borderLineSize()*2);
953 return upperPart;
954 }
955
cloneBottomPart(int height,QObject * owner,QGraphicsItem * parent)956 BaseDesignIntf *TextItem::cloneBottomPart(int height, QObject *owner, QGraphicsItem *parent)
957 {
958 TextItem* bottomPart = dynamic_cast<TextItem*>(cloneItem(itemMode(),owner,parent));
959 bottomPart->setContent(getTextPart(0,height));
960 bottomPart->initTextSizes();
961 bottomPart->setHeight(bottomPart->textSize().height()+borderLineSize()*2);
962 return bottomPart;
963 }
964
createSameTypeItem(QObject * owner,QGraphicsItem * parent)965 BaseDesignIntf *TextItem::createSameTypeItem(QObject *owner, QGraphicsItem *parent)
966 {
967 return new TextItem(owner,parent);
968 }
969
cloneEmpty(int height,QObject * owner,QGraphicsItem * parent)970 BaseDesignIntf *TextItem::cloneEmpty(int height, QObject *owner, QGraphicsItem *parent)
971 {
972 TextItem* empty=dynamic_cast<TextItem*>(cloneItem(itemMode(),owner,parent));
973 empty->setContent("");
974 empty->setHeight(height);
975 return empty;
976 }
977
objectLoadFinished()978 void TextItem::objectLoadFinished()
979 {
980 ItemDesignIntf::objectLoadFinished();
981 // if (itemMode() == DesignMode || !isNeedExpandContent()){
982 // if (autoHeight() && autoWidth())
983 // initTextSizes();
984 // }
985 }
986
setTextItemFont(QFont value)987 void TextItem::setTextItemFont(QFont value)
988 {
989 if (font()!=value){
990 QFont oldValue = font();
991 value.setLetterSpacing(QFont::AbsoluteSpacing, m_fontLetterSpacing);
992 setFont(value);
993 if (!isLoading()) update();
994 notify("font",oldValue,value);
995 }
996 }
997
defaultEditor()998 QWidget *TextItem::defaultEditor()
999 {
1000 QSettings* l_settings = (page()->settings() != 0) ?
1001 page()->settings() :
1002 (page()->reportEditor()!=0) ? page()->reportEditor()->settings() : 0;
1003 QWidget* editor = new TextItemEditor(this,page(),l_settings);
1004 editor->setAttribute(Qt::WA_DeleteOnClose);
1005 return editor;
1006 }
1007
setBackgroundOpacity(int value)1008 void TextItem::setBackgroundOpacity(int value)
1009 {
1010 if (opacity()!=value){
1011 int oldValue = opacity();
1012 setOpacity(value);
1013 notify("backgroundOpacity",oldValue,value);
1014 }
1015 }
1016
setBackgroundModeProperty(BaseDesignIntf::BGMode value)1017 void TextItem::setBackgroundModeProperty(BaseDesignIntf::BGMode value)
1018 {
1019 if (value!=backgroundMode()){
1020 BaseDesignIntf::BGMode oldValue = backgroundMode();
1021 setBackgroundMode(value);
1022 notify("backgroundMode",oldValue,value);
1023 }
1024 }
1025
setBackgroundColorProperty(QColor value)1026 void TextItem::setBackgroundColorProperty(QColor value)
1027 {
1028 if(value!=backgroundColor()){
1029 QColor oldValue = backgroundColor();
1030 setBackgroundColor(value);
1031 notify("backgroundColor",oldValue,value);
1032 }
1033 }
1034
setFontColorProperty(QColor value)1035 void TextItem::setFontColorProperty(QColor value)
1036 {
1037 if(value!=fontColor()){
1038 QColor oldValue = fontColor();
1039 setFontColor(value);
1040 notify("fontColor",oldValue,value);
1041 }
1042 }
1043
angle() const1044 TextItem::AngleType TextItem::angle() const
1045 {
1046 return m_angle;
1047 }
1048
setAngle(const AngleType & value)1049 void TextItem::setAngle(const AngleType& value)
1050 {
1051 if (m_angle!=value){
1052 AngleType oldValue = m_angle;
1053 m_angle = value;
1054 if (!isLoading()){
1055 update();
1056 notify("angle",oldValue,value);
1057 }
1058 }
1059 }
1060
setForegroundOpacity(int value)1061 void TextItem::setForegroundOpacity(int value)
1062 {
1063 if (value>100){
1064 value=100;
1065 } else if(value<0){
1066 value=0;
1067 }
1068 if (m_foregroundOpacity != value){
1069 int oldValue = m_foregroundOpacity;
1070 m_foregroundOpacity = value;
1071 update();
1072 notify("foregroundOpacity",oldValue,value);
1073 }
1074 }
1075
setUnderlines(bool value)1076 void TextItem::setUnderlines(bool value)
1077 {
1078 if (m_underlines != value){
1079 bool oldValue = m_underlines;
1080 m_underlines = value;
1081 update();
1082 notify("underlines",oldValue,value);
1083 }
1084 }
1085
1086 } //namespace LimeReport
1087
1088
1089
1090