Members of the KDE Community are recommended to subscribe to the kde-community mailing list at https://mail.kde.org/mailman/listinfo/kde-community to allow them to participate in important discussions and receive other important announcements

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) { ...@@ -370,8 +370,12 @@ bool KoShape::compareShapeZIndex(KoShape *s1, KoShape *s2) {
} }
void KoShape::setParent(KoShapeContainer *parent) { 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; d->parent = parent;
parent->addChild(this);
}
else else
d->parent = 0; d->parent = 0;
recalcMatrix(); recalcMatrix();
......
...@@ -48,6 +48,8 @@ set(kotext_LIB_SRCS ${libkohyphen_SRCS} ...@@ -48,6 +48,8 @@ set(kotext_LIB_SRCS ${libkohyphen_SRCS}
KoNamedVariable.cpp KoNamedVariable.cpp
KoTextLocator.cpp KoTextLocator.cpp
KoTextReference.cpp KoTextReference.cpp
KoTextAnchor.cpp
KoTextShapeContainerModel.cpp
styles/Styles_p.cpp styles/Styles_p.cpp
styles/KoCharacterStyle.cpp styles/KoCharacterStyle.cpp
......
...@@ -18,8 +18,7 @@ ...@@ -18,8 +18,7 @@
*/ */
#include "InsertVariableActionBase.h" #include "InsertVariableActionBase.h"
// #include "KoInlineTextObjectManager.h" #include "KoVariable.h"
// #include "KoVariableManager.h"
#include "KoTextSelectionHandler.h" #include "KoTextSelectionHandler.h"
#include <KoToolProxy.h> #include <KoToolProxy.h>
...@@ -43,7 +42,7 @@ void InsertVariableActionBase::activated() { ...@@ -43,7 +42,7 @@ void InsertVariableActionBase::activated() {
if(handler) { if(handler) {
KoVariable *variable = createVariable(); KoVariable *variable = createVariable();
if(variable) if(variable)
handler->insertVariable(variable); handler->insertInlineObject(variable);
} }
else else
kWarning(32500) << "InsertVariableAction: No texttool selected while trying to insert variable\n"; 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: ...@@ -153,6 +153,9 @@ public:
KoShape* shapeForPosition(int position) const; KoShape* shapeForPosition(int position) const;
/// reimplemented from QAbstractTextDocumentLayout
void documentChanged(int position, int charsRemoved, int charsAdded);
public slots: public slots:
/// make sure we start a layout run /// make sure we start a layout run
void scheduleLayout(); void scheduleLayout();
...@@ -160,10 +163,6 @@ public slots: ...@@ -160,10 +163,6 @@ public slots:
protected: protected:
LayoutState *m_state; LayoutState *m_state;
friend class KoVariable;
/// reimplemented from QAbstractTextDocumentLayout
void documentChanged(int position, int charsRemoved, int charsAdded);
/// make sure we start a layout run /// make sure we start a layout run
virtual void relayout(); virtual void relayout();
......
...@@ -22,7 +22,7 @@ ...@@ -22,7 +22,7 @@
#include "KoTextDocumentLayout.h" #include "KoTextDocumentLayout.h"
#include "KoTextShapeData.h" #include "KoTextShapeData.h"
#include "KoInlineTextObjectManager.h" #include "KoInlineTextObjectManager.h"
#include "KoVariable.h" // #include "KoInlineObject.h"
#include "KoTextLocator.h" #include "KoTextLocator.h"
#include "styles/KoParagraphStyle.h" #include "styles/KoParagraphStyle.h"
#include "styles/KoCharacterStyle.h" #include "styles/KoCharacterStyle.h"
...@@ -310,11 +310,11 @@ void KoTextSelectionHandler::selectFont(QWidget *parent) { ...@@ -310,11 +310,11 @@ void KoTextSelectionHandler::selectFont(QWidget *parent) {
delete fontDlg; delete fontDlg;
} }
void KoTextSelectionHandler::insertVariable(KoVariable *variable) { void KoTextSelectionHandler::insertInlineObject(KoInlineObject *inliner) {
KoTextDocumentLayout *layout = dynamic_cast<KoTextDocumentLayout*> (d->textShapeData->document()->documentLayout()); KoTextDocumentLayout *layout = dynamic_cast<KoTextDocumentLayout*> (d->textShapeData->document()->documentLayout());
Q_ASSERT(layout); Q_ASSERT(layout);
Q_ASSERT(layout->inlineObjectTextManager()); Q_ASSERT(layout->inlineObjectTextManager());
layout->inlineObjectTextManager()->insertInlineObject(*d->caret, variable); layout->inlineObjectTextManager()->insertInlineObject(*d->caret, inliner);
} }
void KoTextSelectionHandler::setStyle(KoParagraphStyle* style) { void KoTextSelectionHandler::setStyle(KoParagraphStyle* style) {
......
...@@ -30,7 +30,7 @@ ...@@ -30,7 +30,7 @@
class KoParagraphStyle; class KoParagraphStyle;
class KoCharacterStyle; class KoCharacterStyle;
class KoTextShapeData; class KoTextShapeData;
class KoVariable; class KoInlineObject;
class QTextCursor; class QTextCursor;
class QStackedWidget; class QStackedWidget;
class KoTextLocator; class KoTextLocator;
...@@ -110,10 +110,10 @@ public slots: ...@@ -110,10 +110,10 @@ public slots:
void nextParagraph(); void nextParagraph();
/** /**
* Insert a variable at the current cursor position. Possibly replacing the selection. * Insert an inlineObject (such as a variable) at the current cursor position. Possibly replacing the selection.
* @param variable the new variable. * @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. * 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