File indexing completed on 2024-04-28 11:45:28
0001 /* 0002 SPDX-FileCopyrightText: 2011 Dominik Haumann <dhaumann@kde.org> 0003 SPDX-FileCopyrightText: 2009-2010 Bernhard Beschow <bbeschow@cs.tu-berlin.de> 0004 SPDX-FileCopyrightText: 2002 John Firebaugh <jfirebaugh@kde.org> 0005 SPDX-FileCopyrightText: 2001 Christoph Cullmann <cullmann@kde.org> 0006 SPDX-FileCopyrightText: 2001 Joseph Wenninger <jowenn@kde.org> 0007 0008 SPDX-License-Identifier: LGPL-2.0-or-later 0009 */ 0010 0011 #include "kateundo.h" 0012 0013 #include "katedocument.h" 0014 #include "kateundomanager.h" 0015 #include "kateview.h" 0016 0017 #include <ktexteditor/cursor.h> 0018 #include <ktexteditor/view.h> 0019 0020 KateUndo::KateUndo(KTextEditor::DocumentPrivate *document) 0021 : m_document(document) 0022 { 0023 } 0024 0025 KateEditInsertTextUndo::KateEditInsertTextUndo(KTextEditor::DocumentPrivate *document, int line, int col, const QString &text) 0026 : KateUndo(document) 0027 , m_line(line) 0028 , m_col(col) 0029 , m_text(text) 0030 { 0031 } 0032 0033 KateEditRemoveTextUndo::KateEditRemoveTextUndo(KTextEditor::DocumentPrivate *document, int line, int col, const QString &text) 0034 : KateUndo(document) 0035 , m_line(line) 0036 , m_col(col) 0037 , m_text(text) 0038 { 0039 } 0040 0041 KateEditWrapLineUndo::KateEditWrapLineUndo(KTextEditor::DocumentPrivate *document, int line, int col, int len, bool newLine) 0042 : KateUndo(document) 0043 , m_line(line) 0044 , m_col(col) 0045 , m_len(len) 0046 , m_newLine(newLine) 0047 { 0048 } 0049 0050 KateEditUnWrapLineUndo::KateEditUnWrapLineUndo(KTextEditor::DocumentPrivate *document, int line, int col, int len, bool removeLine) 0051 : KateUndo(document) 0052 , m_line(line) 0053 , m_col(col) 0054 , m_len(len) 0055 , m_removeLine(removeLine) 0056 { 0057 } 0058 0059 KateEditInsertLineUndo::KateEditInsertLineUndo(KTextEditor::DocumentPrivate *document, int line, const QString &text) 0060 : KateUndo(document) 0061 , m_line(line) 0062 , m_text(text) 0063 { 0064 } 0065 0066 KateEditRemoveLineUndo::KateEditRemoveLineUndo(KTextEditor::DocumentPrivate *document, int line, const QString &text) 0067 : KateUndo(document) 0068 , m_line(line) 0069 , m_text(text) 0070 { 0071 } 0072 0073 bool KateUndo::isEmpty() const 0074 { 0075 return false; 0076 } 0077 0078 bool KateEditInsertTextUndo::isEmpty() const 0079 { 0080 return len() == 0; 0081 } 0082 0083 bool KateEditRemoveTextUndo::isEmpty() const 0084 { 0085 return len() == 0; 0086 } 0087 0088 bool KateUndo::mergeWith(const KateUndo * /*undo*/) 0089 { 0090 return false; 0091 } 0092 0093 bool KateEditInsertTextUndo::mergeWith(const KateUndo *undo) 0094 { 0095 // we can do a hard cast, we ensure we are only called with the same types on the outside 0096 Q_ASSERT(type() == undo->type()); 0097 const KateEditInsertTextUndo *u = static_cast<const KateEditInsertTextUndo *>(undo); 0098 if (m_line == u->m_line && (m_col + len()) == u->m_col) { 0099 m_text += u->m_text; 0100 return true; 0101 } 0102 0103 return false; 0104 } 0105 0106 bool KateEditRemoveTextUndo::mergeWith(const KateUndo *undo) 0107 { 0108 // we can do a hard cast, we ensure we are only called with the same types on the outside 0109 Q_ASSERT(type() == undo->type()); 0110 const KateEditRemoveTextUndo *u = static_cast<const KateEditRemoveTextUndo *>(undo); 0111 if (m_line == u->m_line && m_col == (u->m_col + u->len())) { 0112 m_text.prepend(u->m_text); 0113 m_col = u->m_col; 0114 return true; 0115 } 0116 0117 return false; 0118 } 0119 0120 void KateEditInsertTextUndo::undo() 0121 { 0122 KTextEditor::DocumentPrivate *doc = document(); 0123 0124 doc->editRemoveText(m_line, m_col, len()); 0125 } 0126 0127 void KateEditRemoveTextUndo::undo() 0128 { 0129 KTextEditor::DocumentPrivate *doc = document(); 0130 0131 doc->editInsertText(m_line, m_col, m_text); 0132 } 0133 0134 void KateEditWrapLineUndo::undo() 0135 { 0136 KTextEditor::DocumentPrivate *doc = document(); 0137 0138 doc->editUnWrapLine(m_line, m_newLine, m_len); 0139 } 0140 0141 void KateEditUnWrapLineUndo::undo() 0142 { 0143 KTextEditor::DocumentPrivate *doc = document(); 0144 0145 doc->editWrapLine(m_line, m_col, m_removeLine); 0146 } 0147 0148 void KateEditInsertLineUndo::undo() 0149 { 0150 KTextEditor::DocumentPrivate *doc = document(); 0151 0152 doc->editRemoveLine(m_line); 0153 } 0154 0155 void KateEditRemoveLineUndo::undo() 0156 { 0157 KTextEditor::DocumentPrivate *doc = document(); 0158 0159 doc->editInsertLine(m_line, m_text); 0160 } 0161 0162 void KateEditMarkLineAutoWrappedUndo::undo() 0163 { 0164 KTextEditor::DocumentPrivate *doc = document(); 0165 0166 doc->editMarkLineAutoWrapped(m_line, m_autowrapped); 0167 } 0168 0169 void KateEditRemoveTextUndo::redo() 0170 { 0171 KTextEditor::DocumentPrivate *doc = document(); 0172 0173 doc->editRemoveText(m_line, m_col, len()); 0174 } 0175 0176 void KateEditInsertTextUndo::redo() 0177 { 0178 KTextEditor::DocumentPrivate *doc = document(); 0179 0180 doc->editInsertText(m_line, m_col, m_text); 0181 } 0182 0183 void KateEditUnWrapLineUndo::redo() 0184 { 0185 KTextEditor::DocumentPrivate *doc = document(); 0186 0187 doc->editUnWrapLine(m_line, m_removeLine, m_len); 0188 } 0189 0190 void KateEditWrapLineUndo::redo() 0191 { 0192 KTextEditor::DocumentPrivate *doc = document(); 0193 0194 doc->editWrapLine(m_line, m_col, m_newLine); 0195 } 0196 0197 void KateEditRemoveLineUndo::redo() 0198 { 0199 KTextEditor::DocumentPrivate *doc = document(); 0200 0201 doc->editRemoveLine(m_line); 0202 } 0203 0204 void KateEditInsertLineUndo::redo() 0205 { 0206 KTextEditor::DocumentPrivate *doc = document(); 0207 0208 doc->editInsertLine(m_line, m_text); 0209 } 0210 0211 void KateEditMarkLineAutoWrappedUndo::redo() 0212 { 0213 KTextEditor::DocumentPrivate *doc = document(); 0214 0215 doc->editMarkLineAutoWrapped(m_line, m_autowrapped); 0216 } 0217 0218 KateUndoGroup::KateUndoGroup(KateUndoManager *manager, 0219 const KTextEditor::Cursor cursorPosition, 0220 KTextEditor::Range selection, 0221 const QVector<KTextEditor::ViewPrivate::PlainSecondaryCursor> &secondary) 0222 : m_manager(manager) 0223 , m_undoSelection(selection) 0224 , m_redoSelection(-1, -1, -1, -1) 0225 , m_undoCursor(cursorPosition) 0226 , m_undoSecondaryCursors(secondary) 0227 , m_redoCursor(-1, -1) 0228 { 0229 } 0230 0231 KateUndoGroup::~KateUndoGroup() 0232 { 0233 qDeleteAll(m_items); 0234 } 0235 0236 void KateUndoGroup::undo(KTextEditor::ViewPrivate *view) 0237 { 0238 if (m_items.isEmpty()) { 0239 return; 0240 } 0241 0242 m_manager->startUndo(); 0243 0244 for (int i = m_items.size() - 1; i >= 0; --i) { 0245 m_items[i]->undo(); 0246 } 0247 0248 if (view != nullptr) { 0249 if (m_undoSelection.isValid()) { 0250 view->setSelection(m_undoSelection); 0251 } else { 0252 view->removeSelection(); 0253 } 0254 view->clearSecondaryCursors(); 0255 view->addSecondaryCursorsWithSelection(m_undoSecondaryCursors); 0256 0257 if (m_undoCursor.isValid()) { 0258 view->setCursorPosition(m_undoCursor); 0259 } 0260 } 0261 0262 m_manager->endUndo(); 0263 } 0264 0265 void KateUndoGroup::redo(KTextEditor::ViewPrivate *view) 0266 { 0267 if (m_items.isEmpty()) { 0268 return; 0269 } 0270 0271 m_manager->startUndo(); 0272 0273 for (int i = 0; i < m_items.size(); ++i) { 0274 m_items[i]->redo(); 0275 } 0276 0277 if (view != nullptr) { 0278 if (m_redoSelection.isValid()) { 0279 view->setSelection(m_redoSelection); 0280 } else { 0281 view->removeSelection(); 0282 } 0283 view->clearSecondaryCursors(); 0284 view->addSecondaryCursorsWithSelection(m_redoSecondaryCursors); 0285 0286 if (m_redoCursor.isValid()) { 0287 view->setCursorPosition(m_redoCursor); 0288 } 0289 } 0290 0291 m_manager->endUndo(); 0292 } 0293 0294 void KateUndoGroup::editEnd(const KTextEditor::Cursor cursorPosition, 0295 KTextEditor::Range selectionRange, 0296 const QVector<KTextEditor::ViewPrivate::PlainSecondaryCursor> &secondaryCursors) 0297 { 0298 m_redoCursor = cursorPosition; 0299 m_redoSecondaryCursors = secondaryCursors; 0300 m_redoSelection = selectionRange; 0301 } 0302 0303 void KateUndoGroup::addItem(KateUndo *u) 0304 { 0305 // kill empty items 0306 if (u->isEmpty()) { 0307 delete u; 0308 return; 0309 } 0310 0311 // try to merge, do that only for equal types, inside mergeWith we do hard casts 0312 if (!m_items.isEmpty() && m_items.last()->type() == u->type() && m_items.last()->mergeWith(u)) { 0313 delete u; 0314 return; 0315 } 0316 0317 // default: just add new item unchanged 0318 m_items.append(u); 0319 } 0320 0321 bool KateUndoGroup::merge(KateUndoGroup *newGroup, bool complex) 0322 { 0323 if (m_safePoint) { 0324 return false; 0325 } 0326 0327 if (newGroup->isOnlyType(singleType()) || complex) { 0328 // Take all of its items first -> last 0329 KateUndo *u = newGroup->m_items.isEmpty() ? nullptr : newGroup->m_items.takeFirst(); 0330 while (u) { 0331 addItem(u); 0332 u = newGroup->m_items.isEmpty() ? nullptr : newGroup->m_items.takeFirst(); 0333 } 0334 0335 if (newGroup->m_safePoint) { 0336 safePoint(); 0337 } 0338 0339 m_redoCursor = newGroup->m_redoCursor; 0340 m_redoSecondaryCursors = newGroup->m_redoSecondaryCursors; 0341 m_redoSelection = newGroup->m_redoSelection; 0342 // m_redoSelections = newGroup->m_redoSelections; 0343 0344 return true; 0345 } 0346 0347 return false; 0348 } 0349 0350 void KateUndoGroup::safePoint(bool safePoint) 0351 { 0352 m_safePoint = safePoint; 0353 } 0354 0355 void KateUndoGroup::flagSavedAsModified() 0356 { 0357 for (KateUndo *item : std::as_const(m_items)) { 0358 if (item->isFlagSet(KateUndo::UndoLine1Saved)) { 0359 item->unsetFlag(KateUndo::UndoLine1Saved); 0360 item->setFlag(KateUndo::UndoLine1Modified); 0361 } 0362 0363 if (item->isFlagSet(KateUndo::UndoLine2Saved)) { 0364 item->unsetFlag(KateUndo::UndoLine2Saved); 0365 item->setFlag(KateUndo::UndoLine2Modified); 0366 } 0367 0368 if (item->isFlagSet(KateUndo::RedoLine1Saved)) { 0369 item->unsetFlag(KateUndo::RedoLine1Saved); 0370 item->setFlag(KateUndo::RedoLine1Modified); 0371 } 0372 0373 if (item->isFlagSet(KateUndo::RedoLine2Saved)) { 0374 item->unsetFlag(KateUndo::RedoLine2Saved); 0375 item->setFlag(KateUndo::RedoLine2Modified); 0376 } 0377 } 0378 } 0379 0380 void KateUndoGroup::markUndoAsSaved(QBitArray &lines) 0381 { 0382 for (int i = m_items.size() - 1; i >= 0; --i) { 0383 KateUndo *item = m_items[i]; 0384 item->updateUndoSavedOnDiskFlag(lines); 0385 } 0386 } 0387 0388 void KateUndoGroup::markRedoAsSaved(QBitArray &lines) 0389 { 0390 for (int i = m_items.size() - 1; i >= 0; --i) { 0391 KateUndo *item = m_items[i]; 0392 item->updateRedoSavedOnDiskFlag(lines); 0393 } 0394 } 0395 0396 KTextEditor::Document *KateUndoGroup::document() 0397 { 0398 return m_manager->document(); 0399 } 0400 0401 KateUndo::UndoType KateUndoGroup::singleType() const 0402 { 0403 KateUndo::UndoType ret = KateUndo::editInvalid; 0404 0405 for (const KateUndo *item : m_items) { 0406 if (ret == KateUndo::editInvalid) { 0407 ret = item->type(); 0408 } else if (ret != item->type()) { 0409 return KateUndo::editInvalid; 0410 } 0411 } 0412 0413 return ret; 0414 } 0415 0416 bool KateUndoGroup::isOnlyType(KateUndo::UndoType type) const 0417 { 0418 if (type == KateUndo::editInvalid) { 0419 return false; 0420 } 0421 0422 return std::all_of(m_items.begin(), m_items.end(), [type](const KateUndo *item) { 0423 return (item->type() == type); 0424 }); 0425 }