Warning, file /office/calligra/libs/textlayout/InlineAnchorStrategy.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 Matus Hanzes <matus.hanzes@ixonos.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 "InlineAnchorStrategy.h"
0021 
0022 #include <KoShapeContainer.h>
0023 #include <KoTextShapeData.h>
0024 #include <KoAnchorInlineObject.h>
0025 
0026 #include <QTextLayout>
0027 #include <QTextBlock>
0028 #include <QTextDocument>
0029 #include <TextLayoutDebug.h>
0030 
0031 InlineAnchorStrategy::InlineAnchorStrategy(KoAnchorInlineObject *anchorObject, KoTextLayoutRootArea *rootArea)
0032     : AnchorStrategy(anchorObject->anchor(), rootArea)
0033     , m_anchorObject(anchorObject)
0034 {
0035 }
0036 
0037 InlineAnchorStrategy::~InlineAnchorStrategy()
0038 {
0039 }
0040 
0041 bool InlineAnchorStrategy::moveSubject()
0042 {
0043     if (!m_anchor->shape()->parent()) {
0044         return false; // let's fake we moved to force another relayout
0045     }
0046 
0047     KoTextShapeData *data = qobject_cast<KoTextShapeData*>(m_anchor->shape()->parent()->userData());
0048     if (!data) {
0049         return false; // let's fake we moved to force another relayout
0050     }
0051 
0052     QPointF newPosition;
0053     QTextBlock block = m_anchorObject->document()->findBlock(m_anchorObject->position());
0054     QTextLayout *layout = block.layout();
0055 
0056     // set anchor bounding rectangle horizontal position and size
0057     if (!countHorizontalPos(newPosition, block, layout)) {
0058         return false; // let's fake we moved to force another relayout
0059     }
0060 
0061     // set anchor bounding rectangle vertical position
0062     if (!countVerticalPos(newPosition, data, block, layout)) {
0063         return false; // let's fake we moved to force another relayout
0064     }
0065 
0066     // check the border of the parent shape an move the shape back to have it inside the parent shape
0067     checkParentBorder(newPosition);
0068 
0069     if (newPosition == m_anchor->shape()->position()) {
0070         return true;
0071     }
0072 
0073     // set the shape to the proper position based on the data
0074     m_anchor->shape()->update();
0075     m_anchor->shape()->setPosition(newPosition);
0076     m_anchor->shape()->update();
0077 
0078     return true; // fake no move as we don't wrap around inline so no need to waste cpu
0079 }
0080 
0081 bool InlineAnchorStrategy::countHorizontalPos(QPointF &newPosition, QTextBlock &block, QTextLayout *layout)
0082 {
0083     if (layout->lineCount() != 0) {
0084         QTextLine tl = layout->lineForTextPosition(m_anchorObject->position() - block.position());
0085         if (tl.isValid()) {
0086             newPosition.setX(tl.cursorToX(m_anchorObject->position() - block.position()));
0087         } else {
0088             return false; // lets go for a second round.
0089         }
0090     } else {
0091         return false; // lets go for a second round.
0092     }
0093     return true;
0094 }
0095 
0096 bool InlineAnchorStrategy::countVerticalPos(QPointF &newPosition, KoTextShapeData *data, QTextBlock &block, QTextLayout *layout)
0097 {
0098     if (layout->lineCount()) {
0099         QTextLine tl = layout->lineForTextPosition(m_anchorObject->position() - block.position());
0100         Q_ASSERT(tl.isValid());
0101         if (m_anchorObject->inlineObjectAscent() > 0) {
0102             newPosition.setY(tl.y() + tl.ascent() - m_anchorObject->inlineObjectAscent() - data->documentOffset());
0103         } else {
0104             newPosition.setY(tl.y() + tl.ascent() + m_anchorObject->inlineObjectDescent() - m_anchor->shape()->size().height() - data->documentOffset());
0105         }
0106     } else {
0107         return false; // lets go for a second round.
0108     }
0109     return true;
0110 }
0111 
0112 // Compared to FloatingAnchorStrategy::checkPageBorder this method doesn't check against the
0113 // page borders but against the shape's parent ShapeContainer (aka the page-content) borders.
0114 //
0115 // If size.width()>container.width() then the shape needs to align to the most left position
0116 // (aka x=0.0). We only check for the x/width and not for y/height cause the results are
0117 // matching more to what OO.org and MSOffice produce.
0118 void InlineAnchorStrategy::checkParentBorder(QPointF &newPosition)
0119 {
0120     QSizeF size = m_anchor->shape()->boundingRect().size();
0121     QSizeF container = m_anchor->shape()->parent()->boundingRect().size();
0122     if ((newPosition.x() + size.width()) > container.width()) {
0123         newPosition.setX(container.width() - size.width());
0124     }
0125     if (newPosition.x() < 0.0) {
0126         newPosition.setX(0.0);
0127     }
0128 }