Warning, file /office/calligra/libs/text/KoTextEditor_p.h 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) 2009 Pierre Stirnweiss <pstirnweiss@googlemail.com> 0003 * Copyright (C) 2009 Thomas Zander <zander@kde.org> 0004 * Copyright (C) 2015 Soma Schliszka <soma.schliszka@gmail.com> 0005 * 0006 * This library is free software; you can redistribute it and/or 0007 * modify it under the terms of the GNU Library General Public 0008 * License as published by the Free Software Foundation; either 0009 * version 2 of the License, or (at your option) any later version. 0010 * 0011 * This library is distributed in the hope that it will be useful, 0012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 0013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0014 * Library General Public License for more details. 0015 * 0016 * You should have received a copy of the GNU Library General Public License 0017 * along with this library; see the file COPYING.LIB. If not, write to 0018 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 0019 * Boston, MA 02110-1301, USA. 0020 */ 0021 0022 #ifndef KOTEXTEDITOR_P_H 0023 #define KOTEXTEDITOR_P_H 0024 0025 #include "KoTextEditor.h" 0026 0027 #include "KoTextDocument.h" 0028 #include "styles/KoParagraphStyle.h" 0029 #include "styles/KoStyleManager.h" 0030 #include "changetracker/KoChangeTracker.h" 0031 0032 #include <klocalizedstring.h> 0033 #include <kundo2magicstring.h> 0034 0035 #include <QStack> 0036 #include <QTextBlock> 0037 #include <QTextDocument> 0038 #include <QTextTableCell> 0039 #include <QTimer> 0040 0041 class KUndo2Command; 0042 0043 class Q_DECL_HIDDEN KoTextEditor::Private 0044 { 0045 public: 0046 enum State { 0047 NoOp, 0048 KeyPress, 0049 Delete, 0050 Format, 0051 Custom 0052 }; 0053 0054 explicit Private(KoTextEditor *qq, QTextDocument *document); 0055 0056 ~Private() {} 0057 0058 void documentCommandAdded(); 0059 void updateState(State newState, const KUndo2MagicString &title = KUndo2MagicString()); 0060 0061 void newLine(KUndo2Command *parent); 0062 void clearCharFormatProperty(int propertyId); 0063 0064 void emitTextFormatChanged(); 0065 0066 KoTextEditor *q; 0067 QTextCursor caret; 0068 QTextDocument *document; 0069 QStack<KUndo2Command*> commandStack; 0070 bool addNewCommand; 0071 bool dummyMacroAdded; 0072 int customCommandCount; 0073 KUndo2MagicString commandTitle; 0074 0075 State editorState; 0076 0077 bool editProtected; 0078 bool editProtectionCached; 0079 }; 0080 0081 class KoTextVisitor 0082 { 0083 public: 0084 /// The ObjectVisitingMode enum marks how was the visited object selected. 0085 enum ObjectVisitingMode { 0086 Partly, /// The visited object (table, cell, ...) is just @b partly selected. (Eg. just one cell is selected in the visited table) 0087 Entirely, /// The visited object (table, cell, ...) is @b entirely selected. 0088 }; 0089 0090 explicit KoTextVisitor(KoTextEditor *editor) 0091 : m_abortVisiting(false) 0092 , m_editor(editor) 0093 { 0094 } 0095 0096 virtual ~KoTextVisitor() {} 0097 // called whenever a visit was prevented by editprotection 0098 virtual void nonVisit() {} 0099 0100 virtual void visitFragmentSelection(QTextCursor &) 0101 { 0102 } 0103 0104 /** 0105 * This method allows to perform custom operation when the visitor reaches a QTextTable 0106 * @param visitedTable pointer to the currently visited table object 0107 * @param visitingMode flag, marks if the table is just partly visited or entirely 0108 */ 0109 virtual void visitTable(QTextTable *visitedTable, ObjectVisitingMode visitingMode) 0110 { 0111 Q_UNUSED(visitedTable); 0112 Q_UNUSED(visitingMode); 0113 } 0114 0115 /** 0116 * This method allows to perform custom operation when the visitor reaches a QTextTableCell 0117 * @param visitedCell pointer to the currently visited cell object 0118 * @param visitingMode flag, marks if the cell is just partly visited or entirely 0119 */ 0120 virtual void visitTableCell(QTextTableCell *visitedCell, ObjectVisitingMode visitingMode) 0121 { 0122 Q_UNUSED(visitedCell); 0123 Q_UNUSED(visitingMode); 0124 } 0125 0126 // The default implementation calls visitFragmentSelection on each fragment.intersect.selection 0127 virtual void visitBlock(QTextBlock &block, const QTextCursor &caret) 0128 { 0129 for (QTextBlock::iterator it = block.begin(); it != block.end(); ++it) { 0130 QTextCursor fragmentSelection(caret); 0131 fragmentSelection.setPosition(qMax(caret.selectionStart(), it.fragment().position())); 0132 fragmentSelection.setPosition(qMin(caret.selectionEnd(), it.fragment().position() + it.fragment().length()), QTextCursor::KeepAnchor); 0133 0134 if (fragmentSelection.anchor() >= fragmentSelection.position()) { 0135 continue; 0136 } 0137 0138 visitFragmentSelection(fragmentSelection); 0139 } 0140 } 0141 0142 bool abortVisiting() { return m_abortVisiting;} 0143 void setAbortVisiting(bool abort) {m_abortVisiting = abort;} 0144 KoTextEditor * editor() const {return m_editor;} 0145 private: 0146 bool m_abortVisiting; 0147 KoTextEditor *m_editor; 0148 }; 0149 0150 class BlockFormatVisitor 0151 { 0152 public: 0153 BlockFormatVisitor() {} 0154 virtual ~BlockFormatVisitor() {} 0155 0156 virtual void visit(QTextBlock &block) const = 0; 0157 0158 static void visitSelection(KoTextEditor *editor, const BlockFormatVisitor &visitor, const KUndo2MagicString &title = kundo2_i18n("Format"), bool resetProperties = false, bool registerChange = true) { 0159 int start = qMin(editor->position(), editor->anchor()); 0160 int end = qMax(editor->position(), editor->anchor()); 0161 0162 QTextBlock block = editor->block(); 0163 if (block.position() > start) 0164 block = block.document()->findBlock(start); 0165 0166 // now loop over all blocks that the selection contains and alter the text fragments where applicable. 0167 while (block.isValid() && block.position() <= end) { 0168 QTextBlockFormat prevFormat = block.blockFormat(); 0169 if (resetProperties) { 0170 if (KoTextDocument(editor->document()).styleManager()) { 0171 KoParagraphStyle *old = KoTextDocument(editor->document()).styleManager()->paragraphStyle(block.blockFormat().intProperty(KoParagraphStyle::StyleId)); 0172 if (old) 0173 old->unapplyStyle(block); 0174 } 0175 } 0176 visitor.visit(block); 0177 QTextCursor cursor(block); 0178 QTextBlockFormat format = cursor.blockFormat(); 0179 if (registerChange) 0180 editor->registerTrackedChange(cursor, KoGenChange::FormatChange, title, format, prevFormat, true); 0181 block = block.next(); 0182 } 0183 } 0184 }; 0185 0186 class CharFormatVisitor 0187 { 0188 public: 0189 CharFormatVisitor() {} 0190 virtual ~CharFormatVisitor() {} 0191 0192 virtual void visit(QTextCharFormat &format) const = 0; 0193 0194 static void visitSelection(KoTextEditor *editor, const CharFormatVisitor &visitor, const KUndo2MagicString &title = kundo2_i18n("Format"), bool registerChange = true) { 0195 int start = qMin(editor->position(), editor->anchor()); 0196 int end = qMax(editor->position(), editor->anchor()); 0197 if (start == end) { // just set a new one. 0198 QTextCharFormat format = editor->charFormat(); 0199 visitor.visit(format); 0200 0201 if (registerChange && KoTextDocument(editor->document()).changeTracker() && KoTextDocument(editor->document()).changeTracker()->recordChanges()) { 0202 QTextCharFormat prevFormat(editor->charFormat()); 0203 0204 int changeId = KoTextDocument(editor->document()).changeTracker()->getFormatChangeId(title, format, prevFormat, editor->charFormat().property( KoCharacterStyle::ChangeTrackerId ).toInt()); 0205 format.setProperty(KoCharacterStyle::ChangeTrackerId, changeId); 0206 } 0207 0208 editor->cursor()->setCharFormat(format); 0209 return; 0210 } 0211 0212 QTextBlock block = editor->block(); 0213 if (block.position() > start) 0214 block = block.document()->findBlock(start); 0215 0216 QList<QTextCursor> cursors; 0217 QVector<QTextCharFormat> formats; 0218 // now loop over all blocks that the selection contains and alter the text fragments where applicable. 0219 while (block.isValid() && block.position() < end) { 0220 QTextBlock::iterator iter = block.begin(); 0221 while (! iter.atEnd()) { 0222 QTextFragment fragment = iter.fragment(); 0223 if (fragment.position() > end) 0224 break; 0225 if (fragment.position() + fragment.length() <= start) { 0226 ++iter; 0227 continue; 0228 } 0229 0230 QTextCursor cursor(block); 0231 cursor.setPosition(fragment.position() + 1); 0232 QTextCharFormat format = cursor.charFormat(); // this gets the format one char after the position. 0233 visitor.visit(format); 0234 0235 if (registerChange && KoTextDocument(editor->document()).changeTracker() && KoTextDocument(editor->document()).changeTracker()->recordChanges()) { 0236 QTextCharFormat prevFormat(cursor.charFormat()); 0237 0238 int changeId = KoTextDocument(editor->document()).changeTracker()->getFormatChangeId(title, format, prevFormat, cursor.charFormat().property( KoCharacterStyle::ChangeTrackerId ).toInt()); 0239 format.setProperty(KoCharacterStyle::ChangeTrackerId, changeId); 0240 } 0241 0242 cursor.setPosition(qMax(start, fragment.position())); 0243 int to = qMin(end, fragment.position() + fragment.length()); 0244 cursor.setPosition(to, QTextCursor::KeepAnchor); 0245 cursors.append(cursor); 0246 formats.append(format); 0247 0248 QTextCharFormat prevFormat(cursor.charFormat()); 0249 if (registerChange) 0250 editor->registerTrackedChange(cursor,KoGenChange::FormatChange,title, format, prevFormat, false); //this will lead to every fragment having a different change untill the change merging in registerTrackedChange checks also for formatChange or not? 0251 0252 ++iter; 0253 } 0254 block = block.next(); 0255 } 0256 QVector<QTextCharFormat>::Iterator iter = formats.begin(); 0257 foreach(QTextCursor cursor, cursors) { 0258 cursor.setCharFormat(*iter); 0259 ++iter; 0260 } 0261 } 0262 }; 0263 0264 #endif //KOTEXTEDITOR_P_H