Warning, file /office/calligra/libs/textlayout/KoTextLayoutNoteArea.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

0001 /* This file is part of the KDE project
0002  * Copyright (C) 2011 Brijesh Patel <brijesh3105@gmail.com>
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 
0020 #include "KoTextLayoutNoteArea.h"
0021 
0022 #include "FrameIterator.h"
0023 #include "KoStyleManager.h"
0024 #include "KoParagraphStyle.h"
0025 #include "KoTextLayoutObstruction.h"
0026 #include "KoPointedAt.h"
0027 #include <KoOdfNumberDefinition.h>
0028 #include <KoInlineNote.h>
0029 #include <KoTextDocument.h>
0030 
0031 #include <QPainter>
0032 
0033 #define OVERLAPPREVENTION 1000
0034 
0035 class Q_DECL_HIDDEN KoTextLayoutNoteArea::Private
0036 {
0037 public:
0038     Private()
0039     {
0040     }
0041     KoInlineNote *note;
0042     QTextLayout *textLayout;
0043     QTextLayout *postLayout;
0044     qreal labelIndent;
0045     bool isContinuedArea;
0046     qreal labelWidth;
0047     qreal labelHeight;
0048     qreal labelYOffset;
0049 };
0050 
0051 KoTextLayoutNoteArea::KoTextLayoutNoteArea(KoInlineNote *note, KoTextLayoutArea *parent, KoTextDocumentLayout *documentLayout)
0052   : KoTextLayoutArea(parent, documentLayout)
0053   , d(new Private)
0054 {
0055     Q_ASSERT(note);
0056     Q_ASSERT(parent);
0057 
0058     d->note = note;
0059     d->isContinuedArea = false;
0060     d->postLayout = 0;
0061 }
0062 
0063 KoTextLayoutNoteArea::~KoTextLayoutNoteArea()
0064 {
0065     delete d;
0066 }
0067 
0068 void KoTextLayoutNoteArea::paint(QPainter *painter, const KoTextDocumentLayout::PaintContext &context)
0069 {
0070     painter->save();
0071     if (d->isContinuedArea) {
0072         painter->translate(0, -OVERLAPPREVENTION);
0073     }
0074 
0075     KoTextLayoutArea::paint(painter, context);
0076     if (d->postLayout) {
0077         d->postLayout->draw(painter, QPointF(left() + d->labelIndent, top() + d->labelYOffset));
0078     }
0079     d->textLayout->draw(painter, QPointF(left() + d->labelIndent, top() + d->labelYOffset));
0080     painter->restore();
0081 }
0082 
0083 bool KoTextLayoutNoteArea::layout(FrameIterator *cursor)
0084 {
0085     KoOdfNotesConfiguration *notesConfig = 0;
0086     if (d->note->type() == KoInlineNote::Footnote) {
0087         notesConfig = KoTextDocument(d->note->textFrame()->document()).styleManager()->notesConfiguration(KoOdfNotesConfiguration::Footnote);
0088     } else if (d->note->type() == KoInlineNote::Endnote) {
0089         notesConfig = KoTextDocument(d->note->textFrame()->document()).styleManager()->notesConfiguration(KoOdfNotesConfiguration::Endnote);
0090     }
0091 
0092     QString label;
0093     if (d->isContinuedArea) {
0094         if (! notesConfig->footnoteContinuationBackward().isEmpty()) {
0095             label = notesConfig->footnoteContinuationBackward() + " " + d->note->label();
0096         }
0097         setReferenceRect(left(), right(), top() + OVERLAPPREVENTION
0098                                     , maximumAllowedBottom() + OVERLAPPREVENTION);
0099     } else {
0100         label = d->note->label();
0101     }
0102     label.prepend(notesConfig->numberFormat().prefix());
0103     label.append(notesConfig->numberFormat().suffix());
0104     QPaintDevice *pd = documentLayout()->paintDevice();
0105     QTextBlock block = cursor->it.currentBlock();
0106     QTextCharFormat format = block.charFormat();
0107     KoCharacterStyle *style = static_cast<KoCharacterStyle *>(notesConfig->citationTextStyle());
0108     if (style) {
0109         style->applyStyle(format);
0110     }
0111     QFont font(format.font(), pd);
0112     d->textLayout = new QTextLayout(label, font, pd);
0113     QList<QTextLayout::FormatRange> layouts;
0114     QTextLayout::FormatRange range;
0115     range.start = 0;
0116     range.length = label.length();
0117     range.format = format;
0118     layouts.append(range);
0119     d->textLayout->setAdditionalFormats(layouts);
0120 
0121     QTextOption option(Qt::AlignLeft | Qt::AlignAbsolute);
0122     d->textLayout->setTextOption(option);
0123     d->textLayout->beginLayout();
0124     QTextLine line = d->textLayout->createLine();
0125     d->textLayout->endLayout();
0126 
0127     KoParagraphStyle pStyle(block.blockFormat(), QTextCharFormat());
0128     d->labelIndent = textIndent(d->note->textFrame()->begin().currentBlock(), 0, pStyle);
0129     if (line.naturalTextWidth() > -d->labelIndent) {
0130         KoTextLayoutArea::setExtraTextIndent(line.naturalTextWidth());
0131     } else {
0132         KoTextLayoutArea::setExtraTextIndent(-d->labelIndent);
0133     }
0134     d->labelIndent += pStyle.leftMargin();
0135     d->labelWidth = line.naturalTextWidth();
0136     d->labelHeight = line.naturalTextRect().bottom() - line.naturalTextRect().top();
0137     d->labelYOffset = -line.ascent();
0138 
0139     bool contNotNeeded = KoTextLayoutArea::layout(cursor);
0140 
0141     QTextLine blockLayoutLine = block.layout()->lineAt(0);
0142 
0143     if (blockLayoutLine.isValid()) {
0144         d->labelYOffset += blockLayoutLine.ascent();
0145     }
0146 
0147     if (!contNotNeeded) {
0148         QString contNote = notesConfig->footnoteContinuationForward();
0149         font.setBold(true);
0150         d->postLayout = new QTextLayout(contNote, font, pd);
0151         QList<QTextLayout::FormatRange> contTextLayouts;
0152         QTextLayout::FormatRange contTextRange;
0153         contTextRange.start = 0;
0154         contTextRange.length = contNote.length();
0155         contTextRange.format = block.charFormat();;
0156         contTextLayouts.append(contTextRange);
0157         d->postLayout->setAdditionalFormats(contTextLayouts);
0158 
0159         QTextOption contTextOption(Qt::AlignLeft | Qt::AlignAbsolute);
0160         //option.setTextDirection();
0161         d->postLayout->setTextOption(contTextOption);
0162         d->postLayout->beginLayout();
0163         QTextLine contTextLine = d->postLayout->createLine();
0164         d->postLayout->endLayout();
0165         contTextLine.setPosition(QPointF(right() - contTextLine.naturalTextWidth(), bottom() - contTextLine.height()));
0166 
0167         documentLayout()->setContinuationObstruction(new
0168                                     KoTextLayoutObstruction(contTextLine.naturalTextRect(), false));
0169     }
0170     return contNotNeeded;
0171 }
0172 
0173 void KoTextLayoutNoteArea::setAsContinuedArea(bool isContinuedArea)
0174 {
0175     d->isContinuedArea = isContinuedArea;
0176 }
0177 
0178 KoPointedAt KoTextLayoutNoteArea::hitTest(const QPointF &p, Qt::HitTestAccuracy accuracy) const
0179 {
0180     KoPointedAt pointedAt;
0181     pointedAt.noteReference = -1;
0182     QPointF tmpP(p.x(), p.y() + (d->isContinuedArea ? OVERLAPPREVENTION : 0));
0183 
0184     pointedAt = KoTextLayoutArea::hitTest(tmpP, accuracy);
0185 
0186     if (tmpP.x() > left() && tmpP.x() < d->labelWidth && tmpP.y() < top() + d->labelYOffset + d->labelHeight)
0187     {
0188         pointedAt.noteReference = d->note->getPosInDocument();
0189         pointedAt.position = tmpP.x();
0190     }
0191 
0192     return pointedAt;
0193 }
0194 
0195 QRectF KoTextLayoutNoteArea::selectionBoundingBox(QTextCursor &cursor) const
0196 {
0197     return KoTextLayoutArea::selectionBoundingBox(cursor).translated(0
0198                                         , d->isContinuedArea ? -OVERLAPPREVENTION : 0);
0199 
0200 }