Commit f1323ae6 authored by Thomas Zander's avatar Thomas Zander

Some explorative work on inline shapes for the text flake.

svn path=/trunk/koffice/; revision=651131
parent c2dda3f8
......@@ -370,8 +370,12 @@ bool KoShape::compareShapeZIndex(KoShape *s1, KoShape *s2) {
}
void KoShape::setParent(KoShapeContainer *parent) {
if(dynamic_cast<KoShape*>(parent) != this)
if(d->parent == parent)
return;
if(parent && dynamic_cast<KoShape*>(parent) != this) {
d->parent = parent;
parent->addChild(this);
}
else
d->parent = 0;
recalcMatrix();
......
......@@ -48,6 +48,8 @@ set(kotext_LIB_SRCS ${libkohyphen_SRCS}
KoNamedVariable.cpp
KoTextLocator.cpp
KoTextReference.cpp
KoTextAnchor.cpp
KoTextShapeContainerModel.cpp
styles/Styles_p.cpp
styles/KoCharacterStyle.cpp
......
......@@ -18,8 +18,7 @@
*/
#include "InsertVariableActionBase.h"
// #include "KoInlineTextObjectManager.h"
// #include "KoVariableManager.h"
#include "KoVariable.h"
#include "KoTextSelectionHandler.h"
#include <KoToolProxy.h>
......@@ -43,7 +42,7 @@ void InsertVariableActionBase::activated() {
if(handler) {
KoVariable *variable = createVariable();
if(variable)
handler->insertVariable(variable);
handler->insertInlineObject(variable);
}
else
kWarning(32500) << "InsertVariableAction: No texttool selected while trying to insert variable\n";
......
/* This file is part of the KDE project
* Copyright (C) 2007 Thomas Zander <zander@kde.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include "KoTextAnchor.h"
#include "KoTextDocumentLayout.h"
#include "KoTextShapeContainerModel.h"
#include <KoShapeContainer.h>
#include <QTextInlineObject>
#include <KDebug>
class KoTextAnchor::Private {
public:
Private(KoTextAnchor *p, KoShape *s)
: parent(p),
shape(s),
horizontalAlignment(HorizontalOffset),
verticalAlignment(VerticalOffset),
document(0),
position(-1),
model(0)
{
distance = shape->position();
}
void relayout() {
if(document) {
KoTextDocumentLayout *lay = dynamic_cast<KoTextDocumentLayout*> (document->documentLayout());
if(lay)
lay->documentChanged(position, 0, 0);
}
}
void setContainer(KoShapeContainer *container) {
kDebug() << "setContainer " << container << endl;
if(container == 0) {
model = 0;
return;
}
bool first = model == 0; // first time
model = dynamic_cast<KoTextShapeContainerModel*> (container->model());
if(first) {
distance = shape->position();
model->addAnchor(parent);
}
}
KoTextAnchor * const parent;
KoShape * const shape;
AnchorHorizontal horizontalAlignment;
AnchorVertical verticalAlignment;
const QTextDocument *document;
int position;
KoTextShapeContainerModel *model;
QPointF distance;
};
KoTextAnchor::KoTextAnchor(KoShape *shape)
: KoInlineObject(false),
d(new Private(this, shape))
{
}
KoTextAnchor::~KoTextAnchor() {
if(d->model)
d->model->removeAnchor(this);
delete d;
}
KoShape *KoTextAnchor::shape() const {
return d->shape;
}
void KoTextAnchor::setAlignment(KoTextAnchor::AnchorHorizontal horizontal) {
d->horizontalAlignment = horizontal;
d->relayout();
}
void KoTextAnchor::setAlignment(KoTextAnchor::AnchorVertical vertical) {
d->verticalAlignment = vertical;
}
KoTextAnchor::AnchorVertical KoTextAnchor::verticalAlignment() const {
return d->verticalAlignment;
}
KoTextAnchor::AnchorHorizontal KoTextAnchor::horizontalAlignment() const {
return d->horizontalAlignment;
}
void KoTextAnchor::updatePosition(const QTextDocument *document, QTextInlineObject object, int posInDocument, const QTextCharFormat &format) {
kDebug() << "KoTextAnchor::updatePosition " << posInDocument << endl;
Q_UNUSED(object);
Q_UNUSED(format);
d->document = document;
d->position = posInDocument;
d->setContainer(dynamic_cast<KoShapeContainer*> (shapeForPosition(document, posInDocument)));
if(d->model)
d->model->reposition(d->shape);
}
void KoTextAnchor::resize(const QTextDocument *document, QTextInlineObject object, int posInDocument, const QTextCharFormat &format, QPaintDevice *pd) {
Q_UNUSED(document);
Q_UNUSED(object);
Q_UNUSED(posInDocument);
Q_UNUSED(format);
Q_UNUSED(pd);
if(d->model)
d->model->reposition(d->shape);
}
void KoTextAnchor::paint (QPainter &painter, QPaintDevice *pd, const QTextDocument *document, const QRectF &rect, QTextInlineObject object, int posInDocument, const QTextCharFormat &format) {
Q_UNUSED(document);
Q_UNUSED(painter);
Q_UNUSED(pd);
Q_UNUSED(rect);
Q_UNUSED(object);
Q_UNUSED(posInDocument);
Q_UNUSED(format);
// we never paint ourselves; the shape can do that.
}
int KoTextAnchor::positionInDocument() const {
return d->position;
}
const QTextDocument *KoTextAnchor::document() const {
return d->document;
}
const QPointF &KoTextAnchor::offset() const {
return d->distance;
}
/* This file is part of the KDE project
* Copyright (C) 2007 Thomas Zander <zander@kde.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifndef KOTEXTANCHOR_H
#define KOTEXTANCHOR_H
#include "KoInlineObject.h"
#include <kotext_export.h>
#include <QPointF>
class KoShape;
/**
* This class is the object that is positioned in the text to be an anchor for a shape.
* The idea is that when the text is relayouted and this inline character is moved, the shape
* associated with it is repositioned based on a set of rules influenced by the data on this anchor.
*/
class KOTEXT_EXPORT KoTextAnchor : public KoInlineObject {
public:
/// the vertical alignment options for the shape this anchor holds.
enum AnchorVertical {
TopOfFrame,
TopOfParagraph,
AboveCurrentLine,
BelowCurrentLine,
BottomOfParagraph,
BottomOfFrame,
VerticalOffset
};
/// the horizontal alignment options for the shape this anchor holds.
enum AnchorHorizontal {
Left,
Right,
Center,
ClosestToBinding,
FurtherFromBinding,
HorizontalOffset
};
KoTextAnchor(KoShape *shape);
~KoTextAnchor();
KoShape *shape() const;
void setAlignment(AnchorHorizontal horizontal);
void setAlignment(AnchorVertical vertical);
AnchorVertical verticalAlignment() const;
AnchorHorizontal horizontalAlignment() const;
int positionInDocument() const;
const QTextDocument *document() const;
virtual void updatePosition(const QTextDocument *document, QTextInlineObject object,
int posInDocument, const QTextCharFormat &format);
virtual void resize(const QTextDocument *document, QTextInlineObject object,
int posInDocument, const QTextCharFormat &format, QPaintDevice *pd);
virtual void paint (QPainter &painter, QPaintDevice *pd, const QTextDocument *document,
const QRectF &rect, QTextInlineObject object, int posInDocument, const QTextCharFormat &format);
const QPointF &offset() const;
private:
class Private;
Private * const d;
};
#endif
......@@ -153,6 +153,9 @@ public:
KoShape* shapeForPosition(int position) const;
/// reimplemented from QAbstractTextDocumentLayout
void documentChanged(int position, int charsRemoved, int charsAdded);
public slots:
/// make sure we start a layout run
void scheduleLayout();
......@@ -160,10 +163,6 @@ public slots:
protected:
LayoutState *m_state;
friend class KoVariable;
/// reimplemented from QAbstractTextDocumentLayout
void documentChanged(int position, int charsRemoved, int charsAdded);
/// make sure we start a layout run
virtual void relayout();
......
......@@ -22,7 +22,7 @@
#include "KoTextDocumentLayout.h"
#include "KoTextShapeData.h"
#include "KoInlineTextObjectManager.h"
#include "KoVariable.h"
// #include "KoInlineObject.h"
#include "KoTextLocator.h"
#include "styles/KoParagraphStyle.h"
#include "styles/KoCharacterStyle.h"
......@@ -310,11 +310,11 @@ void KoTextSelectionHandler::selectFont(QWidget *parent) {
delete fontDlg;
}
void KoTextSelectionHandler::insertVariable(KoVariable *variable) {
void KoTextSelectionHandler::insertInlineObject(KoInlineObject *inliner) {
KoTextDocumentLayout *layout = dynamic_cast<KoTextDocumentLayout*> (d->textShapeData->document()->documentLayout());
Q_ASSERT(layout);
Q_ASSERT(layout->inlineObjectTextManager());
layout->inlineObjectTextManager()->insertInlineObject(*d->caret, variable);
layout->inlineObjectTextManager()->insertInlineObject(*d->caret, inliner);
}
void KoTextSelectionHandler::setStyle(KoParagraphStyle* style) {
......
......@@ -30,7 +30,7 @@
class KoParagraphStyle;
class KoCharacterStyle;
class KoTextShapeData;
class KoVariable;
class KoInlineObject;
class QTextCursor;
class QStackedWidget;
class KoTextLocator;
......@@ -110,10 +110,10 @@ public slots:
void nextParagraph();
/**
* Insert a variable at the current cursor position. Possibly replacing the selection.
* @param variable the new variable.
* Insert an inlineObject (such as a variable) at the current cursor position. Possibly replacing the selection.
* @param inliner the object to insert.
*/
void insertVariable(KoVariable *variable);
void insertInlineObject(KoInlineObject *inliner);
/**
* Set the selected text to follow the layout of the paragraph style.
......
/* This file is part of the KDE project
* Copyright (C) 2007 Thomas Zander <zander@kde.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include "KoTextShapeContainerModel.h"
#include "KoTextAnchor.h"
#include "KoTextShapeData.h"
#include <QTextBlock>
#include <QTextLayout>
#include <QTextLine>
#include <QTextDocument>
#include <KDebug>
class Relation {
public:
Relation(KoShape *shape) :child(shape), anchor(0), nested(false) {}
KoShape *child;
KoTextAnchor *anchor;
bool nested;
};
class KoTextShapeContainerModel::Private {
public:
Private() : textShape(0) {}
KoShapeContainer *textShape;
QHash<KoShape*, Relation*> children;
};
KoTextShapeContainerModel::KoTextShapeContainerModel()
: d(new Private())
{
}
void KoTextShapeContainerModel::add(KoShape *child) {
if(d->children.contains(child))
return;
Relation *relation = new Relation(child);
d->children.insert(child, relation);
}
void KoTextShapeContainerModel::remove(KoShape *child) {
Relation *relation = d->children.value(child);
delete relation;
d->children.remove(child);
}
void KoTextShapeContainerModel::setClipping(const KoShape *child, bool clipping) {
Relation *relation = d->children.value( const_cast<KoShape*>(child));
Q_ASSERT(relation);
relation->nested = clipping;
}
bool KoTextShapeContainerModel::childClipped(const KoShape *child) const {
Relation *relation = d->children.value( const_cast<KoShape*>(child));
Q_ASSERT(relation);
return relation->nested;
}
int KoTextShapeContainerModel::count() const {
return d->children.count();
}
QList<KoShape*> KoTextShapeContainerModel::iterator() const {
return d->children.keys();
}
void KoTextShapeContainerModel::containerChanged(KoShapeContainer *container) {
// TODO
// For children which are aligned to the side of the page we may need to update the position so they will stay at the same vertical position.
}
void KoTextShapeContainerModel::addAnchor(KoTextAnchor *anchor) {
kDebug() << "addAnchor!\n";
Relation *relation = d->children.value(anchor->shape());
Q_ASSERT(relation);
relation->anchor = anchor;
}
void KoTextShapeContainerModel::removeAnchor(KoTextAnchor *anchor) {
Relation *relation = d->children.value(anchor->shape());
if(relation)
relation->anchor = 0;
}
void KoTextShapeContainerModel::reposition(KoShape *shape) {
kDebug() << "KoTextShapeContainerModel::reposition\n";
Q_ASSERT(shape->parent());
Relation *relation = d->children.value(shape);
kDebug() << "relation: " << relation << endl;
if(relation == 0 || relation->anchor == 0)
return;
kDebug() << " still here\n";
const int positionInDocument = relation->anchor->positionInDocument();
QTextBlock block = relation->anchor->document()->findBlock( positionInDocument );
QPointF newPosition;
// TODO rewrite the below to account for rotation etc.
QRectF boundingRect = shape->boundingRect();
QRectF containerBoundingRect = shape->parent()->boundingRect();
switch(relation->anchor->horizontalAlignment()) {
case KoTextAnchor::ClosestToBinding: // TODO figure out a way to do pages...
case KoTextAnchor::Left:
/*newPosition.setX(0);*/ break;
case KoTextAnchor::FurtherFromBinding: // TODO figure out a way to do pages...
case KoTextAnchor::Right:
newPosition.setX(containerBoundingRect.width() - boundingRect.width());
break;
case KoTextAnchor::Center:
newPosition.setX(containerBoundingRect.width() - boundingRect.width() / 2.0);
break;
case KoTextAnchor::HorizontalOffset: {
kDebug() << " HorizontalOffset!\n";
QTextLayout *layout = block.layout();
return;
Q_ASSERT(layout);
QTextLine tl = layout->lineForTextPosition(positionInDocument);
if(! tl.isValid()) return;
Q_ASSERT(tl.isValid());
double x = tl.cursorToX(positionInDocument - block.position());
newPosition.setX(x + relation->anchor->offset().x());
kDebug() << " x: " << newPosition.x() << endl;
break;
}
default:
Q_ASSERT(false); // new enum added?
}
switch(relation->anchor->verticalAlignment()) {
case KoTextAnchor::TopOfFrame: /*newPosition.setY(0);*/ break;
case KoTextAnchor::TopOfParagraph: {
QTextLayout *layout = block.layout();
double topOfParagraph = layout->lineAt(0).y();
KoTextShapeData *data = dynamic_cast<KoTextShapeData*> (shape->parent()->userData());
Q_ASSERT(data);
newPosition.setY(topOfParagraph - data->documentOffset());
break;
}
case KoTextAnchor::AboveCurrentLine: {
QTextLayout *layout = block.layout();
QTextLine tl = layout->lineForTextPosition(positionInDocument);
newPosition.setY(tl.y() - boundingRect.height());
break;
}
case KoTextAnchor::BelowCurrentLine: {
QTextLayout *layout = block.layout();
QTextLine tl = layout->lineForTextPosition(positionInDocument);
newPosition.setY(tl.y() + tl.ascent() - boundingRect.height());
break;
}
case KoTextAnchor::BottomOfParagraph: {
QTextLayout *layout = block.layout();
QTextLine tl = layout->lineAt(layout->lineCount()-1);
newPosition.setY(tl.y() + tl.ascent() - boundingRect.height() );
break;
}
case KoTextAnchor::BottomOfFrame:
break;
case KoTextAnchor::VerticalOffset: {
kDebug() << " VerticalOffset!\n";
QTextLayout *layout = block.layout();
QTextLine tl = layout->lineForTextPosition(positionInDocument);
newPosition.setX(tl.y() + tl.ascent() + relation->anchor->offset().y());
kDebug() << " y: " << newPosition.y() << endl;
break;
}
default:
Q_ASSERT(false); // new enum added?
}
// TODO check for difference? If the offset is tiny; just ignore it to avoid endless loops
shape->setPosition(newPosition);
}
/* workflows
1) child shape moves
Position is determined by this model; so we need the shapeMoveStrategy to get vetoable coordinate changes through this model.
When we have that we can alter the anchor to the new alignment policies. Which will do a relayout
2) text anchor moves
The anchor get notified. The anchor tells us that we need to reposition the child.
void reposition(anchor, shape);
Using the data from the anchor, we place the shape at the right position.
3) parent shape moves
Children move automatically; little to do.
For children which are aligned to the side of the page we may need to update the position so they will stay at the same vertical position.
Init
4) loading
??
5) inlining by user [done]
New anchor is created and added with the child as member.
When layout comes the anchor figures out which frame is the 'parent' and it adds the child.
This class will then get notified.
The anchor should also register itself with this model.
void addAnchor(KoTextAnchor *)
point 2 is followed next.
*/
/* This file is part of the KDE project
* Copyright (C) 2007 Thomas Zander <zander@kde.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifndef KOTEXTSHAPECONTAINERMODEL_H
#define KOTEXTSHAPECONTAINERMODEL_H
#include <KoShapeContainerModel.h>
#include <KoShapeContainer.h>
#include <kotext_export.h>
class KoTextAnchor;
/// A model to position children of the text shape.
class KOTEXT_EXPORT KoTextShapeContainerModel : public KoShapeContainerModel {
public:
KoTextShapeContainerModel();
/// reimplemented from KoShapeContainerModel
virtual void add(KoShape *child);
/// reimplemented from KoShapeContainerModel
virtual void remove(KoShape *child);
/// reimplemented from KoShapeContainerModel
virtual void setClipping(const KoShape *child, bool clipping);
/// reimplemented from KoShapeContainerModel
virtual bool childClipped(const KoShape *child) const;
/// reimplemented from KoShapeContainerModel
virtual int count() const;
/// reimplemented from KoShapeContainerModel
virtual QList<KoShape*> iterator() const;
/// reimplemented from KoShapeContainerModel
virtual void containerChanged(KoShapeContainer *container);
/// each child that is added due to being anchored in the text has an anchor; register it for rules based placement.
void addAnchor(KoTextAnchor *anchor);
/// When a shape is removed or stops being anchored, remove it.
void removeAnchor(KoTextAnchor *anchor);
/// Check the anchor rules and move the shape to the right place.
void reposition(KoShape *shape);
private:
class Private;
Private * const d;
};
#endif
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment