Commit ec38fbaf authored by C. Boemann's avatar C. Boemann

Merge branch 'text-undo-munichsprint'

Conflicts:
	libs/kotext/KoTextDocument.cpp
	libs/kotext/KoTextDocument.h
parents 160f4bba 5f4f3026
......@@ -25,6 +25,7 @@
#include "flake_export.h"
#include <QList>
#include <QMetaType>
class KoCanvasBase;
class KoShape;
......@@ -122,4 +123,6 @@ private:
Private * const d;
};
Q_DECLARE_METATYPE(KoShapeController *)
#endif
......@@ -17,6 +17,8 @@ set(kotext_LIB_SRCS
KoTextPaste.cpp
KoTextDocument.cpp
KoTextEditor.cpp
KoTextEditor_undo.cpp
KoTextEditor_format.cpp
KoList.cpp
KoTextEditingRegistry.cpp
......
......@@ -38,6 +38,7 @@
#include "KoList.h"
#include "KoOdfLineNumberingConfiguration.h"
#include "changetracker/KoChangeTracker.h"
#include <KoShapeController.h>
Q_DECLARE_METATYPE(QAbstractTextDocumentLayout::Selection)
Q_DECLARE_METATYPE(QTextFrame*)
......@@ -60,6 +61,7 @@ const QUrl KoTextDocument::ParaTableSpacingAtStartUrl = QUrl("kotext://spacingAt
const QUrl KoTextDocument::IndexGeneratorManagerUrl = QUrl("kotext://indexGeneratorManager");
const QUrl KoTextDocument::FrameCharFormatUrl = QUrl("kotext://frameCharFormat");
const QUrl KoTextDocument::FrameBlockFormatUrl = QUrl("kotext://frameBlockFormat");
const QUrl KoTextDocument::ShapeControllerUrl = QUrl("kotext://shapeController");
KoTextDocument::KoTextDocument(QTextDocument *document)
: m_document(document)
......@@ -143,6 +145,24 @@ KoChangeTracker *KoTextDocument::changeTracker() const
}
}
void KoTextDocument::setShapeController(KoShapeController *controller)
{
QVariant v;
v.setValue(controller);
m_document->addResource(KoTextDocument::ShapeController, ShapeControllerUrl, v);
}
KoShapeController *KoTextDocument::shapeController() const
{
QVariant resource = m_document->resource(KoTextDocument::ShapeController, ShapeControllerUrl);
if (resource.isValid()) {
return resource.value<KoShapeController *>();
}
else {
return 0;
}
}
void KoTextDocument::setLineNumberingConfiguration(KoOdfLineNumberingConfiguration *lineNumberingConfiguration)
{
lineNumberingConfiguration->setParent(m_document);
......
......@@ -43,6 +43,7 @@ class KUndo2Stack;
class KoTextEditor;
class KoOdfLineNumberingConfiguration;
class KoChangeTracker;
class KoShapeController;
/**
* KoTextDocument provides an easy mechanism to set and access the
......@@ -142,6 +143,12 @@ public:
/// Set the KoInlineTextObjectManager
void setInlineTextObjectManager(KoInlineTextObjectManager *manager);
/// Set the KoDocument's shapeController. This controller exists as long as KoDocument exists. It should only be used for deleting shapes.
void setShapeController(KoShapeController *controller);
/// Returns the shapeController
KoShapeController *shapeController() const;
QTextFrame* auxillaryFrame();
/**
......@@ -218,7 +225,8 @@ public:
ParaTableSpacingAtStart, /// this is used during layouting to specify if at the first paragraph margin-top should be applied.
IndexGeneratorManager,
FrameCharFormat,
FrameBlockFormat
FrameBlockFormat,
ShapeController
};
static const QUrl StyleManagerURL;
......@@ -238,6 +246,7 @@ public:
static const QUrl IndexGeneratorManagerUrl;
static const QUrl FrameCharFormatUrl;
static const QUrl FrameBlockFormatUrl;
static const QUrl ShapeControllerUrl;
private:
QTextDocument *m_document;
......
This diff is collapsed.
......@@ -2,6 +2,7 @@
* Copyright (C) 2009 Pierre Stirnweiss <pstirnweiss@googlemail.com>
* Copyright (C) 2009 Thomas Zander <zander@kde.org>
* Copyright (C) 2011 Boudewijn Rempt <boud@valdyas.org>
* Copyright (C) 2011-2012 C. Boemann <cbo@boemann.dk>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
......@@ -63,12 +64,6 @@ class KOTEXT_EXPORT KoTextEditor: public QObject
{
Q_OBJECT
public:
enum MoveOperation {
PreviousChar,
NextChar
};
enum ChangeListFlag {
NoFlags = 0,
ModifyExistingList = 1,
......@@ -248,9 +243,6 @@ public slots:
*/
void insertFrameBreak();
/// delete all inline objects in current cursor position or selection
bool deleteInlineObjects(bool backward = false);
/**
* paste the given mimedata object at the current position
* @param mimeData: the mimedata containing text, html or odf
......@@ -275,13 +267,6 @@ public slots:
KoShapeController *shapeController,
bool pasteAsText = false);
/**
* Delete one character in the specified direction.
* @param direction the direction into which we delete. Valid values are
* @param shapeController the canvas' shapeController
*/
void deleteChar(MoveOperation direction, KoShapeController *shapeController);
/**
* @param numberingEnabled when true, we will enable numbering for the current paragraph (block).
*/
......@@ -307,8 +292,6 @@ public slots:
bool atStart() const;
void beginEditBlock();
QTextBlock block() const;
QTextCharFormat blockCharFormat() const;
......@@ -329,20 +312,16 @@ public slots:
const QTextDocument *document() const;
//Starts a new custom command. Everything between these two is one custom command. These should not be called from whithin a KUndo2Command
// void beginCustomCommand();
// void endCustomCommand();
//Same as Qt, only to be used inside KUndo2Commands
KUndo2Command *beginEditBlock(QString title = QString());
void endEditBlock();
bool hasComplexSelection() const;
void insertBlock();
void insertBlock(const QTextBlockFormat &format);
void insertBlock(const QTextBlockFormat &format, const QTextCharFormat &charFormat);
// NOT part of the api, since QTextDocumentFragment translates to html, losing all formatting.
// so intentionally not exposed.
// void insertFragment(const QTextDocumentFragment &fragment);
/**
* Insert a table at the current cursor position.
* @param rows the number of rows in the created table.
......@@ -418,25 +397,16 @@ public slots:
void insertText(const QString &text);
void insertText(const QString &text, const QTextCharFormat &format);
void insertHtml(const QString &html);
// void joinPreviousEditBlock ();
void mergeBlockCharFormat( const QTextCharFormat &modifier);
void mergeBlockFormat( const QTextBlockFormat &modifier);
void mergeCharFormat(const QTextCharFormat &modifier);
bool movePosition(QTextCursor::MoveOperation operation, QTextCursor::MoveMode mode = QTextCursor::MoveAnchor, int n = 1);
void newLine();
int position() const;
void removeSelectedText();
void select(QTextCursor::SelectionType selection);
QString selectedText() const;
......@@ -447,15 +417,9 @@ public slots:
int selectionStart() const;
// intentionally commented out: these are unimplemented.
void setBlockFormat(const QTextBlockFormat &format);
// void setBlockCharFormat(const QTextCharFormat &format);
void setBlockFormat(const QTextBlockFormat &format);
void setCharFormat(const QTextCharFormat &format);
// void setTableFormat(const QTextTableFormat &format);
void setCharFormat(const QTextCharFormat &format);
void setPosition(int pos, QTextCursor::MoveMode mode = QTextCursor::MoveAnchor);
......@@ -472,6 +436,12 @@ signals:
void textFormatChanged();
protected:
/**
* Delete one character in the specified direction or a selection.
* @param previous should be true if act like backspace
*/
void deleteChar(bool previous, KUndo2Command *parent = 0);
void recursivelyVisitSelection(QTextFrame::iterator it, KoTextVisitor &visitor) const;
private:
......
This diff is collapsed.
......@@ -31,10 +31,13 @@
#include <KLocale>
#include <kdebug.h>
#include <QStack>
#include <QTextBlock>
#include <QTextDocument>
#include <QTimer>
class KUndo2Command;
class KoTextEditor::Private
{
public:
......@@ -53,8 +56,7 @@ public:
void documentCommandAdded();
void updateState(State newState, QString title = QString());
bool deleteInlineObjects(bool backwards = false);
void newLine();
void newLine(KUndo2Command *parent);
void clearCharFormatProperty(int propertyId);
void emitTextFormatChanged();
......@@ -62,7 +64,10 @@ public:
KoTextEditor *q;
QTextCursor caret;
QTextDocument *document;
KUndo2Command *headCommand;
QStack<KUndo2Command*> commandStack;
bool addNewCommand;
bool dummyMacroAdded;
int customCommandCount;
QString commandTitle;
State editorState;
......@@ -71,6 +76,47 @@ public:
bool editProtectionCached;
};
class KoTextVisitor
{
public:
KoTextVisitor(KoTextEditor *editor)
: m_abortVisiting(false)
, m_editor(editor)
{
}
virtual ~KoTextVisitor() {}
// called whenever a visit was prevented by editprotection
virtual void nonVisit() {}
virtual void visitFragmentSelection(QTextCursor )
{
}
// The default implementation calls visitFragmentSelection on each fragment.intersect.selection
virtual void visitBlock(QTextBlock block, const QTextCursor &caret)
{
for (QTextBlock::iterator it = block.begin(); it != block.end(); ++it) {
QTextCursor fragmentSelection(caret);
fragmentSelection.setPosition(qMax(caret.selectionStart(), it.fragment().position()));
fragmentSelection.setPosition(qMin(caret.selectionEnd(), it.fragment().position() + it.fragment().length()), QTextCursor::KeepAnchor);
if (fragmentSelection.anchor() >= fragmentSelection.position()) {
continue;
}
visitFragmentSelection(fragmentSelection);
}
}
bool abortVisiting() { return m_abortVisiting;}
void setAbortVisiting(bool abort) {m_abortVisiting = abort;}
KoTextEditor * editor() {return m_editor;}
private:
bool m_abortVisiting;
KoTextEditor *m_editor;
};
class BlockFormatVisitor
{
public:
......
This diff is collapsed.
......@@ -28,14 +28,13 @@
#include <QTextDocument>
ChangeAnchorPropertiesCommand::ChangeAnchorPropertiesCommand(KoTextAnchor *anchor, const KoTextAnchor &newAnchorData, KoShapeContainer *newParent, KUndo2Command *parent)
: KUndo2Command(parent)
: KUndo2Command("Change Anchor Properties", parent) //Don't translate
, m_anchor(anchor)
, m_oldAnchor(0)
, m_newAnchor(0)
, m_oldParent(anchor->shape()->parent())
, m_newParent(newParent)
, m_first(true)
, m_macroFirst(parent != 0)
{
copyLayoutProperties(anchor, &m_oldAnchor);
copyLayoutProperties(&newAnchorData, &m_newAnchor);
......@@ -64,19 +63,6 @@ void ChangeAnchorPropertiesCommand::redo()
textData = qobject_cast<KoTextShapeDataBase*>(m_newParent->userData());
}
// We need this weird construct if we are played within a macro then our first job
// is to call instantlyExecuteCommand which will "redo" us immidiately in what is the normal
// "first" time
if (m_macroFirst) {
m_macroFirst = false;
if (textData) {
KoTextEditor *editor = KoTextDocument(textData->document()).textEditor();
editor->instantlyExecuteCommand(this);
return;
}
//fall through as it's just a AnchorPage to AnchorPage change
}
KUndo2Command::redo();
copyLayoutProperties(&m_newAnchor, m_anchor);
......
......@@ -49,7 +49,6 @@ private:
KoShapeContainer *m_newParent;
QPointF m_oldAbsPos;
bool m_first;
bool m_macroFirst;
};
#endif // CHANGEANCHORPROPERTIESCOMMAND_H
......@@ -31,13 +31,12 @@ ChangeStylesCommand::ChangeStylesCommand(ChangeFollower *changeFollower
, const QList<KoParagraphStyle *> &origParagraphStyles
, const QSet<int> &changedStyles
, KUndo2Command *parent)
: KUndo2Command(parent)
: KUndo2Command("stylechangecommand",parent) //Don't translate
, m_changeFollower(changeFollower)
, m_origCharacterStyles(origCharacterStyles)
, m_origParagraphStyles(origParagraphStyles)
, m_changedStyles(changedStyles)
, m_first(true)
, m_macroFirst(parent != 0)
{
m_changeFollower->collectNeededInfo(m_changedStyles);
}
......@@ -48,16 +47,6 @@ ChangeStylesCommand::~ChangeStylesCommand()
void ChangeStylesCommand::redo()
{
// We need this weird construct if we are played within a macro then our first job
// is to call instantlyExecuteCommand which will "redo" us immediately in what is the normal
// "first" time
if (m_macroFirst) {
m_macroFirst = false;
KoTextEditor *editor = KoTextDocument(m_changeFollower->document()).textEditor();
editor->instantlyExecuteCommand(this);
return;
}
KUndo2Command::redo();
if (m_first) {
......
......@@ -49,7 +49,6 @@ private:
QList<KoParagraphStyle *> m_origParagraphStyles;
QSet<int> m_changedStyles;
bool m_first;
bool m_macroFirst;
};
#endif // CHANGESTYLESCOMMAND_H
......@@ -23,8 +23,10 @@
#include "ChangeStylesCommand.h"
#include "KoCharacterStyle.h"
#include "KoParagraphStyle.h"
#include "ChangeFollower.h"
#include <KoTextDocument.h>
#include <KoTextEditor.h>
#include <KLocale>
......@@ -48,13 +50,6 @@ ChangeStylesMacroCommand::~ChangeStylesMacroCommand()
// finally the new styles are applied to the documents through super::redo()
void ChangeStylesMacroCommand::redo()
{
if (m_first) {
foreach(ChangeFollower *cf, m_changeFollowers) {
new ChangeStylesCommand(cf, m_origCharacterStyles, m_origParagraphStyles, m_changedStyles, this);
}
m_first = false;
}
foreach(KoCharacterStyle *newStyle, m_changedCharacterStyles) {
int id = newStyle->styleId();
m_styleManager->characterStyle(id)->copyProperties(newStyle);
......@@ -69,7 +64,17 @@ void ChangeStylesMacroCommand::redo()
emit m_styleManager->styleAltered(m_styleManager->paragraphStyle(id));
}
KUndo2Command::redo(); // calls redo on all children
if (m_first) {
foreach(ChangeFollower *cf, m_changeFollowers) {
ChangeStylesCommand *cmd = new ChangeStylesCommand(cf, m_origCharacterStyles, m_origParagraphStyles, m_changedStyles, this);
//add and execute it's redo
KoTextDocument(cf->document()).textEditor()->addCommand(cmd);
}
m_first = false;
} else {
KUndo2Command::redo(); // calls redo on all children
}
}
void ChangeStylesMacroCommand::undo()
......
......@@ -194,8 +194,6 @@ void ChangeTrackedDeleteCommand::handleListItemDelete(KoTextEditor *editor)
editor->setPosition(editor->anchor() -1);
editor->movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor, block.length());
deleteSelection(editor);
// Insert a new Block and paste the copied contents
editor->insertBlock();
// Mark it as inserted content
QTextCharFormat format = editor->charFormat();
editor->registerTrackedChange(*editor->cursor(), KoGenChange::InsertChange, i18n("Key Press"), format, format, false);
......
......@@ -24,6 +24,8 @@
#include "KoTextDocument.h"
#include "KoInlineTextObjectManager.h"
#include <KDebug>
bool sortAnchor(KoTextAnchor *a1, KoTextAnchor *a2)
{
return a1->positionInDocument() > a2->positionInDocument();
......@@ -59,7 +61,9 @@ void DeleteAnchorsCommand::redo()
foreach (KoTextAnchor *anchor, m_anchors) {
QTextCursor cursor(m_document);
cursor.setPosition(anchor->positionInDocument());
cursor.deleteChar();
// cursor.beginEditBlock();
cursor.deleteChar(); //this works also when the DeleteCommand further deletes its selection, which contained this char. Odd
// cursor.endEditBlock();
}
}
KoInlineTextObjectManager *manager = KoTextDocument(m_document).inlineTextObjectManager();
......@@ -83,4 +87,3 @@ void DeleteAnchorsCommand::undo()
KUndo2Command::undo();
m_deleteAnchors = false;
}
This diff is collapsed.
/*
This file is part of the KDE project
* Copyright (C) 2009 Ganesh Paramasivam <ganesh@crystalfab.com>
* Copyright (C) 2012 C. Boemann <cbo@boemann.dk>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
......@@ -36,6 +37,10 @@ class KoShape;
class QTextCursor;
class DeleteVisitor;
class KoBookmark;
class KoTextEditor;
class DeleteCommand : public KoTextCommandBase
{
public:
......@@ -54,24 +59,28 @@ public:
virtual bool mergeWith(const KUndo2Command *command);
private:
friend class DeleteVisitor;
QWeakPointer<QTextDocument> m_document;
KoShapeController *m_shapeController;
QList<KUndo2Command *> m_shapeDeleteCommands;
QSet<KoInlineObject *> m_invalidInlineObjects;
QList<KoBookmark *>m_unmatchedBookmarks;
QSet<KoInlineObject *> m_bookmarksToRemove;
bool m_first;
bool m_undone;
DeleteMode m_mode;
int m_position;
int m_length;
QTextCharFormat m_format;
bool m_multipleFormatDeletion;
bool m_mergePossible;
virtual void doDelete();
virtual void deleteInlineObjects();
virtual void deleteTextAnchor(KoInlineObject *object);
virtual bool checkMerge(const KUndo2Command *command);
virtual void updateListChanges();
void doDelete();
void deleteBookmark(KoInlineObject *object);
void restoreUnmatchedBookmarks(KoTextEditor *editor);
void deleteTextAnchor(KoInlineObject *object);
bool checkMerge(const KUndo2Command *command);
void updateListChanges();
};
#endif // DELTECOMMAND_H
......@@ -78,16 +78,15 @@ void TextPasteCommand::redo()
if (!m_first) {
KUndo2Command::redo();
} else {
//kDebug() << "begin paste command";
editor->beginEditBlock();
editor->beginEditBlock(); //this is needed so Qt does not merge successive paste actions together
m_first = false;
if (editor->hasSelection()) { //TODO
// XXX: this was m_tool->m_actionShowChanges.isChecked -- but shouldn't we check
// whether we should record changes here, instead of showing?
if (textDocument.changeTracker()->recordChanges()) {
editor->addCommand(new ChangeTrackedDeleteCommand(ChangeTrackedDeleteCommand::NextChar, m_document.data(), m_shapeController));
editor->addCommand(new ChangeTrackedDeleteCommand(ChangeTrackedDeleteCommand::NextChar, m_document.data(), m_shapeController, this));
} else {
editor->addCommand(new DeleteCommand(DeleteCommand::NextChar, m_document.data(), m_shapeController));
editor->addCommand(new DeleteCommand(DeleteCommand::NextChar, m_document.data(), m_shapeController, this));
}
}
......@@ -114,10 +113,8 @@ void TextPasteCommand::redo()
}
#endif
//kDebug() << "pasting odf text";
KoTextPaste paste(editor, m_shapeController, rdfModel);
paste.paste(odfType, m_mimeData);
//kDebug() << "done with pasting odf";
#ifdef SHOULD_BUILD_RDF
if (m_rdf) {
......@@ -129,14 +126,10 @@ void TextPasteCommand::redo()
#endif
}
} else if (!m_pasteAsText && m_mimeData->hasHtml()) {
//kDebug() << "pasting html";
editor->insertHtml(m_mimeData->html());
//kDebug() << "done with pasting";
} else if (m_pasteAsText || m_mimeData->hasText()) {
//kDebug() << "pasting text";
editor->insertText(m_mimeData->text());
//kDebug() << "done with pasting";
}
editor->endEditBlock();
editor->endEditBlock(); //see above beginEditBlock
}
}
......@@ -119,7 +119,7 @@ void TestKoTextEditor::testRemoveSelectedText()
Q_ASSERT(editor.hasSelection());
// remove the table + the markers from the document
editor.removeSelectedText();
editor.deleteChar();
// check whether the bookmarks have gone.
Q_ASSERT(inlineObjectManager.inlineTextObjects().length() == 0);
......
......@@ -111,11 +111,13 @@
\sa ~KUndo2Command()
*/
KUndo2Command::KUndo2Command(const QString &text, KUndo2Command *parent)
KUndo2Command::KUndo2Command(const QString &text, KUndo2Command *parent):
m_hasParent(parent != 0)
{
d = new KUndo2CommandPrivate;
if (parent != 0)
if (parent != 0) {
parent->d->child_list.append(this);
}
setText(text);
}
......@@ -310,6 +312,11 @@ const KUndo2Command *KUndo2Command::child(int index) const
return d->child_list.at(index);
}
bool KUndo2Command::hasParent()
{
return m_hasParent;
}
#endif // QT_NO_UNDOCOMMAND
#ifndef QT_NO_UNDOSTACK
......
......@@ -78,9 +78,13 @@ public:
int childCount() const;
const KUndo2Command *child(int index) const;
bool hasParent();
private:
Q_DISABLE_COPY(KUndo2Command)
friend class KUndo2QStack;
bool m_hasParent;
};
#endif // QT_NO_UNDOCOMMAND
......
......@@ -132,7 +132,9 @@ void KoSemanticStylesheet::format(KoRdfSemanticItem *obj, KoTextEditor *editor,
editor->setPosition(startpos, QTextCursor::MoveAnchor);
editor->movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor, endpos - startpos);
QString oldText = editor->selectedText();
editor->removeSelectedText();
if (editor->hasSelection()) {
editor->deleteChar(); // deletes the selection
}
editor->setPosition(startpos, QTextCursor::MoveAnchor);
kDebug(30015) << "formating start:" << startpos << " end:" << endpos;
kDebug(30015) << "semantic item oldText:" << oldText;
......
......@@ -353,7 +353,7 @@ void RdfTest::testRemoveMarkers()
Q_ASSERT(editor.hasSelection());
// remove the table + the markers from the document
editor.removeSelectedText();
editor.deleteChar();
results = TestSemanticItem::allObjects(&rdfDoc);
......
......@@ -867,7 +867,7 @@ void TextTool::copy() const
void TextTool::deleteSelection()
{
m_textEditor.data()->deleteChar(KoTextEditor::NextChar, canvas()->shapeController());
m_textEditor.data()->deleteChar();
editingPluginEvents();
}
......@@ -1068,7 +1068,7 @@ void TextTool::keyPressEvent(QKeyEvent *event)
if (!textEditor->hasSelection() && event->modifiers() & Qt::ControlModifier) { // delete prev word.
textEditor->movePosition(QTextCursor::PreviousWord, QTextCursor::KeepAnchor);
}
textEditor->deleteChar(KoTextEditor::PreviousChar, canvas()->shapeController());
textEditor->deletePreviousChar();
editingPluginEvents();
}
......@@ -1090,7 +1090,7 @@ void TextTool::keyPressEvent(QKeyEvent *event)
}
// the event only gets through when the Del is not used in the app
// if the app forwards Del then deleteSelection is used
textEditor->deleteChar(KoTextEditor::NextChar, canvas()->shapeController());