Commit f4a7d803 authored by Denis Kuplyakov's avatar Denis Kuplyakov

Applied this patch https://git.reviewboard.kde.org/r/122278/.

Can't merge as original branch contains master code.
parent 28255c29
......@@ -40,7 +40,6 @@ public:
explicit KoSectionPrivate(const QTextDocument *_document)
: manager(KoTextDocument(_document).sectionManager())
, sectionStyle(0)
, modelItem(0)
{
Q_ASSERT(manager);
name = manager->possibleNewName();
......@@ -62,7 +61,6 @@ public:
QScopedPointer<KoSectionEnd> sectionEnd; //< pointer to the corresponding section end
int level; //< level of the section in document, root sections have 0 level
QPair<int, int> bounds; //< start and end position of section in QDocument
QStandardItem *modelItem;
};
KoSection::KoSection(const QTextCursor &cursor)
......@@ -107,8 +105,8 @@ bool KoSection::setName(const QString &name)
}
if (d->manager->isValidNewName(name)) {
d->manager->sectionRenamed(d->name, name);
d->name = name;
d->manager->invalidate();
return true;
}
return false;
......@@ -190,15 +188,3 @@ void KoSection::setLevel(int level)
Q_D(KoSection);
d->level = level;
}
QStandardItem *KoSection::modelItem()
{
Q_D(KoSection);
return d->modelItem;
}
void KoSection::setModelItem(QStandardItem *item)
{
Q_D(KoSection);
d->modelItem = item;
}
......@@ -22,10 +22,11 @@
#include "kotext_export.h"
#include <QMetaType>
#include <QList>
#include <QString>
#include <QPair>
#include <QScopedPointer>
#include <QStandardItem>
#include <QTextCursor>
class KoXmlElement;
......@@ -83,11 +84,12 @@ private:
void setBeginPos(int pos);
void setEndPos(int pos);
void setLevel(int level);
void setModelItem(QStandardItem *item);
QStandardItem *modelItem();
friend class KoSectionManager;
friend class KoSectionEnd;
};
Q_DECLARE_METATYPE(KoSection *)
Q_DECLARE_METATYPE(QList<KoSection *>)
#endif // KOSECTION_H
......@@ -53,7 +53,7 @@ QString KoSectionEnd::name() const
return d->section->name();
}
KoSection* KoSectionEnd::correspondingSection() const
KoSection *KoSectionEnd::correspondingSection() const
{
Q_D(const KoSectionEnd);
return d->section;
......
......@@ -22,6 +22,8 @@
#include "kotext_export.h"
#include <QMetaType>
#include <QList>
#include <QString>
#include <QScopedPointer>
......@@ -50,4 +52,7 @@ private:
Q_DECLARE_PRIVATE(KoSectionEnd)
};
Q_DECLARE_METATYPE(KoSectionEnd *)
Q_DECLARE_METATYPE(QList<KoSectionEnd *>)
#endif // KOSECTIONEND_H
......@@ -23,6 +23,7 @@
#include "KoSectionEnd.h"
#include <KLocalizedString>
#include <KoTextDocument.h>
#include "KoSectionUtils.h"
#include <QHash>
#include <QString>
......@@ -31,27 +32,56 @@
#include <kdebug.h>
KoSectionManagerPrivate::KoSectionManagerPrivate(QTextDocument *_doc)
: doc(_doc)
, valid(false)
, sectionCount(0)
, model(new QStandardItemModel())
class KoSectionManagerPrivate
{
Q_ASSERT(_doc);
}
public:
KoSectionManagerPrivate(KoSectionManager *parent, QTextDocument *_doc)
: doc(_doc)
, valid(false)
, q_ptr(parent)
{
Q_ASSERT(_doc);
}
KoSectionManagerPrivate::~KoSectionManagerPrivate()
{
QHash<QString, KoSection *>::iterator it = sectionNames.begin();
for (; it != sectionNames.end(); it++) {
delete it.value(); // KoSectionEnd will be deleted in KoSection
~KoSectionManagerPrivate()
{
QSet<KoSection *>::iterator it = registeredSections.begin();
for (; it != registeredSections.end(); it++) {
delete *it; // KoSectionEnd will be deleted in KoSection
}
}
}
QTextDocument *doc;
bool valid; //< is current section info is valid
QSet<KoSection *> registeredSections; //< stores pointer to sections that sometime was registered
// used to prevent using sectionNames without update
QHash<QString, KoSection *> &sectionNames()
{
Q_Q(KoSectionManager);
q->update();
return m_sectionNames;
}
protected:
KoSectionManager *q_ptr;
private:
Q_DISABLE_COPY(KoSectionManagerPrivate)
Q_DECLARE_PUBLIC(KoSectionManager);
QHash<QString, KoSection *> m_sectionNames; //< stores name -> pointer reference, for sections that are visible in document now
};
KoSectionManager::KoSectionManager(QTextDocument* doc)
: d_ptr(new KoSectionManagerPrivate(doc))
: d_ptr(new KoSectionManagerPrivate(this, doc))
{
KoTextDocument(doc).setSectionManager(this); //FIXME: setting it back from here looks bad
}
KoSectionManager::~KoSectionManager()
{
KoTextDocument(doc).setSectionManager(this);
delete d_ptr;
}
KoSection *KoSectionManager::sectionAtPosition(int pos)
......@@ -61,8 +91,8 @@ KoSection *KoSectionManager::sectionAtPosition(int pos)
KoSection *result = 0;
int smallest = INT_MAX; //smallest in size section will be the deepest
QHash<QString, KoSection *>::iterator it = d->sectionNames.begin();
for (; it != d->sectionNames.end(); it++) {
QHash<QString, KoSection *>::iterator it = d->sectionNames().begin();
for (; it != d->sectionNames().end(); it++) {
if (it.value()->bounds().first > pos || it.value()->bounds().second < pos) {
continue;
}
......@@ -82,21 +112,20 @@ void KoSectionManager::invalidate()
d->valid = false;
}
bool KoSectionManager::isValidNewName(const QString &name) const
bool KoSectionManager::isValidNewName(const QString &name)
{
Q_D(const KoSectionManager);
return (d->sectionNames.find(name) == d->sectionNames.end());
Q_D(KoSectionManager);
return (d->sectionNames().constFind(name) == d->sectionNames().constEnd());
}
QString KoSectionManager::possibleNewName() const
QString KoSectionManager::possibleNewName()
{
Q_D(const KoSectionManager);
Q_D(KoSectionManager);
QString newName;
int i = d->sectionCount;
int i = d->registeredSections.count();
do {
++i;
i++;
newName = i18nc("new numbered section name", "New section %1", i);
} while (!isValidNewName(newName));
......@@ -106,73 +135,57 @@ QString KoSectionManager::possibleNewName() const
void KoSectionManager::registerSection(KoSection* section)
{
Q_D(KoSectionManager);
d->sectionCount++;
d->sectionNames[section->name()] = section;
d->registeredSections.insert(section);
invalidate();
}
void KoSectionManager::sectionRenamed(const QString &oldName, const QString &name)
{
Q_D(KoSectionManager);
QHash<QString, KoSection *>::iterator it = d->sectionNames.find(oldName);
KoSection *sec = *it;
d->sectionNames.erase(it);
d->sectionNames[name] = sec;
if (sec->modelItem()) {
sec->modelItem()->setData(name, Qt::DisplayRole);
}
}
void KoSectionManager::unregisterSection(KoSection* section)
{
Q_D(KoSectionManager);
d->sectionCount--;
d->sectionNames.remove(section->name());
d->registeredSections.remove(section);
invalidate();
}
void KoSectionManager::update()
QStandardItemModel *KoSectionManager::update(bool needModel)
{
Q_D(KoSectionManager);
if (d->valid) {
return;
if (d->valid && !needModel) {
return 0;
}
d->valid = true;
d->sectionNames().clear();
QHash<QString, KoSection *>::iterator it = d->sectionNames.begin();
for (; it != d->sectionNames.end(); it++) {
it.value()->setBeginPos(-1);
it.value()->setEndPos(-1);
it.value()->setLevel(-1);
QSet<KoSection *>::iterator it = d->registeredSections.begin();
for (; it != d->registeredSections.end(); it++) {
(*it)->setBeginPos(-1);
(*it)->setEndPos(-1);
(*it)->setLevel(-1);
}
QTextBlock block = d->doc->begin();
QStringList head;
head << i18n("Section");
d->model->clear();
d->model->setHorizontalHeaderLabels(head);
d->model->setColumnCount(1);
QStandardItemModel *model = 0;
QStack<QStandardItem *> curChain;
curChain.push(d->model->invisibleRootItem());
if (needModel) {
model = new QStandardItemModel();
curChain.push(model->invisibleRootItem());
}
int curLevel = -1;
do {
QTextBlockFormat fmt = block.blockFormat();
if (fmt.hasProperty(KoParagraphStyle::SectionStartings)) {
QList<QVariant> starts = fmt.property(KoParagraphStyle::SectionStartings).value< QList<QVariant> >();
foreach (const QVariant &sv, starts) {
curLevel++;
KoSection *sec = static_cast<KoSection *>(sv.value<void *>());
sec->setBeginPos(block.position());
sec->setLevel(curLevel);
foreach (KoSection *sec, KoSectionUtils::sectionStartings(fmt)) {
curLevel++;
sec->setBeginPos(block.position());
sec->setLevel(curLevel);
d->sectionNames()[sec->name()] = sec;
if (needModel) {
QStandardItem *item = new QStandardItem(sec->name());
item->setData(qVariantFromValue(static_cast<void *>(sec)), Qt::UserRole + 1);
sec->setModelItem(item);
item->setData(QVariant::fromValue<KoSection *>(sec), Qt::UserRole + 1);
curChain.top()->appendRow(item);
......@@ -180,24 +193,15 @@ void KoSectionManager::update()
}
}
if (fmt.hasProperty(KoParagraphStyle::SectionEndings)) {
QList<QVariant> ends = fmt.property(KoParagraphStyle::SectionEndings).value< QList<QVariant> >();
foreach (const QVariant &sv, ends) {
curLevel--;
KoSectionEnd *sec = static_cast<KoSectionEnd *>(sv.value<void *>());
sec->correspondingSection()->setEndPos(block.position() + block.length());
foreach (const KoSectionEnd *sec, KoSectionUtils::sectionEndings(fmt)) {
curLevel--;
sec->correspondingSection()->setEndPos(block.position() + block.length());
if (needModel) {
curChain.pop();
}
}
} while ((block = block.next()).isValid());
d->valid = true;
}
QStandardItemModel* KoSectionManager::sectionsModel()
{
Q_D(KoSectionManager);
update();
return d->model.data();
return model;
}
......@@ -22,23 +22,13 @@
#include <QTextDocument>
#include <QMetaType>
#include <QStandardItemModel>
#include <QSet>
#include <kotext_export.h>
class KoSection;
class KoSectionManagerPrivate;
class KoSectionManagerPrivate
{
public:
explicit KoSectionManagerPrivate(QTextDocument *_doc);
~KoSectionManagerPrivate();
QTextDocument *doc;
bool valid; //< is current section info is valid
QHash<QString, KoSection *> sectionNames; //< stores name -> pointer reference
int sectionCount; //< how many sections is registered
QScopedPointer<QStandardItemModel> model;
};
/**
* Used to handle all the sections in the document
*
......@@ -54,6 +44,7 @@ class KOTEXT_EXPORT KoSectionManager
{
public:
explicit KoSectionManager(QTextDocument* doc);
~KoSectionManager();
/**
* Returns pointer to the deepest KoSection that covers @p pos
......@@ -64,34 +55,29 @@ public:
/**
* Returns name for the new section
*/
QString possibleNewName() const;
QString possibleNewName();
/**
* Returns if this name is possible.
*/
bool isValidNewName(const QString &name) const;
/**
* Returns tree model of sections to use in views
*/
QStandardItemModel *sectionsModel();
bool isValidNewName(const QString &name);
public Q_SLOTS:
/**
* Call this to recalc all sections information
* @param needModel place @c true to it if you need model to use in GUI and @c false otherwise
* @return pointer to QStandardItemModel, build according to s*ection tree
* with a pointers to KoSection at Qt::UserRole + 1 and section name
* for display role.
* NOTE: it is not updated further by KoSectionManager
*/
void update();
QStandardItemModel *update(bool needModel = false);
/**
* Call this to notify manager that info in it is invalidated.
* Call this to notify manager that info in it has invalidated.
*/
void invalidate();
/**
* Call this to notify that some section changed its name
*/
void sectionRenamed(const QString &oldName, const QString &name);
/**
* Call this to register new section in manager
*/
......@@ -103,7 +89,7 @@ public Q_SLOTS:
void unregisterSection(KoSection *section);
protected:
const QScopedPointer<KoSectionManagerPrivate> d_ptr;
KoSectionManagerPrivate * const d_ptr;
private:
Q_DISABLE_COPY(KoSectionManager)
......
......@@ -18,8 +18,7 @@
*/
#include <KoSectionUtils.h>
#include <KoSection.h>
#include <KoSectionEnd.h>
#include <KoParagraphStyle.h>
bool KoSectionUtils::getNextBlock(QTextCursor &cur)
{
......@@ -38,12 +37,40 @@ bool KoSectionUtils::getNextBlock(QTextCursor &cur)
return true;
}
QString KoSectionUtils::sectionStartName(const QVariant &q)
void KoSectionUtils::setSectionStartings(QTextBlockFormat &fmt, QList<KoSection *> &list)
{
return static_cast<KoSection *>(q.value<void *>())->name();
if (list.empty()) {
fmt.clearProperty(KoParagraphStyle::SectionStartings);
} else {
fmt.setProperty(KoParagraphStyle::SectionStartings,
QVariant::fromValue< QList<KoSection *> >(list));
}
}
void KoSectionUtils::setSectionEndings(QTextBlockFormat &fmt, QList<KoSectionEnd *> &list)
{
if (list.empty()) {
fmt.clearProperty(KoParagraphStyle::SectionEndings);
} else {
fmt.setProperty(KoParagraphStyle::SectionEndings,
QVariant::fromValue< QList<KoSectionEnd *> >(list));
}
}
QString KoSectionUtils::sectionEndName(const QVariant &q)
QList<KoSection *> KoSectionUtils::sectionStartings(const QTextBlockFormat &fmt)
{
return static_cast<KoSectionEnd *>(q.value<void *>())->name();
if (!fmt.hasProperty(KoParagraphStyle::SectionStartings)) {
return QList<KoSection *>();
} else {
return fmt.property(KoParagraphStyle::SectionStartings).value< QList<KoSection *> >();
}
}
QList<KoSectionEnd *> KoSectionUtils::sectionEndings(const QTextBlockFormat &fmt)
{
if (!fmt.hasProperty(KoParagraphStyle::SectionEndings)) {
return QList<KoSectionEnd *>();
} else {
return fmt.property(KoParagraphStyle::SectionEndings).value< QList<KoSectionEnd *> >();
}
}
......@@ -19,6 +19,9 @@
#ifndef KOSECTIONUTILS_H
#define KOSECTIONUTILS_H
#include <KoSection.h>
#include <KoSectionEnd.h>
#include <QTextCursor>
#include <QVariant>
#include <QString>
......@@ -30,26 +33,41 @@ namespace KoSectionUtils {
* @return @c false if there is no next block, @c true otherwise
*/
bool getNextBlock(QTextCursor &cur);
/**
* Convinient function to get name of a section from QVariant
* that is really a KoSection *.
*
* There is no internal check that \p q is a KoSection *.
* Convinient function to set a list of startings to QTextBlockFormat.
* This checks that list is empty.
*
* @param q QVariant version of pointer to a KoSection
* @return name of a specified section
* @param fmt QTextBlockFormat reference to set startings.
* @param list QList<KoSection *> is a list to set.
*/
QString sectionStartName(const QVariant &q);
KOTEXT_EXPORT void setSectionStartings(QTextBlockFormat &fmt, QList<KoSection *> &list);
/**
* Convinient function to get name of a section from QVariant
* that is really a KoSectionEnd *.
*
* There is no internal check that \p q is a KoSectionEnd *.
* Convinient function to set a list of endings to QTextBlockFormat.
* This checks that list is empty.
*
* @param q QVariant version of pointer to a KoSectionEnd
* @return name of a specified section
* @param fmt QTextBlockFormat reference to set endings.
* @param list QList<KoSectionEnd *> is a list to set.
*/
KOTEXT_EXPORT void setSectionEndings(QTextBlockFormat& fmt, QList<KoSectionEnd *> &list);
/**
* Convinient function to get section startings from QTextBlockFormat.
* @param fmt QTextBlockFormat format to retrieve section startings from.
* @return QList<KoSection *> that contains pointers to sections that start
* according to QTextBlockFormat.
*/
KOTEXT_EXPORT QList<KoSection *> sectionStartings(const QTextBlockFormat &fmt);
/**
* Convinient function to get section endings from QTextBlockFormat.
* @param fmt QTextBlockFormat format to retrieve section startings from.
* @return QList<KoSectionEnd *> that contains pointers to sections that end
* according to QTextBlockFormat.
*/
QString sectionEndName(const QVariant &q);
KOTEXT_EXPORT QList<KoSectionEnd *> sectionEndings(const QTextBlockFormat& fmt);
}
#endif //KOSECTIONUTILS_H
......@@ -30,10 +30,12 @@
#include <KoTextEditor.h>
#include <opendocument/KoTextLoader.h>
#include <KoTextSharedLoadingData.h>
#include <KoSectionManager.h>
#include <kdebug.h>
#ifdef SHOULD_BUILD_RDF
#include "KoTextRdfCore.h"
#include "KoSectionManager.h"
#include <Soprano/Soprano>
#endif
......@@ -83,6 +85,8 @@ bool KoTextPaste::process(const KoXmlElement &body, KoOdfReadStore &odfStore)
// load the paste directly into the editor's cursor -- which breaks encapsulation
loader.loadBody(body, *d->editor->cursor(), KoTextLoader::PasteMode); // now let's load the body from the ODF KoXmlElement.
context.sectionManager()->invalidate();
#ifdef SHOULD_BUILD_RDF
kDebug(30015) << "text paste, rdf handling" << d->rdfModel;
// RDF: Grab RDF metadata from ODF file if present & load it into rdfModel
......
This diff is collapsed.
......@@ -24,6 +24,7 @@
#include <KoParagraphStyle.h>
#include <KoSectionManager.h>
#include <KoTextEditor.h>
#include <KoSectionUtils.h>
#include <klocale.h>
#include <kundo2command.h>
......@@ -63,22 +64,14 @@ void NewSectionCommand::redo()
KoSectionEnd *end = new KoSectionEnd(start);
QTextBlockFormat fmt = editor->blockFormat();
QList< QVariant > sectionStartings;
if (fmt.hasProperty(KoParagraphStyle::SectionStartings)) {
sectionStartings = fmt.property(KoParagraphStyle::SectionStartings)
.value< QList<QVariant> >();
}
QList< QVariant > sectionEndings;
if (fmt.hasProperty(KoParagraphStyle::SectionEndings)) {
sectionEndings = fmt.property(KoParagraphStyle::SectionEndings)
.value< QList<QVariant> >();
}
QList<KoSection *> sectionStartings = KoSectionUtils::sectionStartings(fmt);
QList<KoSectionEnd *> sectionEndings = KoSectionUtils::sectionEndings(fmt);
sectionStartings.append(qVariantFromValue<void *>(static_cast<void *>(start)));
sectionEndings.prepend(qVariantFromValue<void *>(static_cast<void *>(end)));
sectionStartings.append(start);
sectionEndings.prepend(end);
fmt.setProperty(KoParagraphStyle::SectionStartings, sectionStartings);
fmt.setProperty(KoParagraphStyle::SectionEndings, sectionEndings);
KoSectionUtils::setSectionStartings(fmt, sectionStartings);
KoSectionUtils::setSectionEndings(fmt, sectionEndings);
editor->setBlockFormat(fmt);
}
......
......@@ -83,6 +83,7 @@
#include "styles/KoTableColumnStyle.h"
#include "styles/KoTableCellStyle.h"
#include "styles/KoSectionStyle.h"
#include <KoSectionUtils.h>
#include <klocale.h>
#include <kdebug.h>
......@@ -139,7 +140,7 @@ public:
int loadSpanInitialPos;
QVector<QString> nameSpacesList;
QList<QVariant> openingSections;
QList<KoSection *> openingSections;
QMap<QString, KoList *> xmlIdToListMap;
QVector<KoList *> m_previousList;
......@@ -313,25 +314,18 @@ void KoTextLoader::loadBody(const KoXmlElement &bodyElem, QTextCursor &cursor, L
// If we are pasting text, we should handle sections correctly
// we are saving which sections end in current block
// and put their ends after the inserted text.
QList<QVariant> oldSectionEndings;
QList<KoSectionEnd *> oldSectionEndings;
if (mode == PasteMode) {
QTextBlockFormat fmt = cursor.blockFormat();
if (fmt.hasProperty(KoParagraphStyle::SectionEndings)) {
oldSectionEndings = fmt.property(KoParagraphStyle::SectionEndings)
.value< QList<QVariant> >();
}