/* This file is part of the KDE libraries Copyright (C) 2002 John Firebaugh Copyright (C) 2001 Christoph Cullmann Copyright (C) 2001 Joseph Wenninger This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License version 2 as published by the Free Software Foundation. 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 "kateundo.h" #include "katedocument.h" #include "kateview.h" #include "katecursor.h" /** * Private class, only for KateUndoGroup, no need to use it elsewhere */ class KateUndo { public: /** * Constructor * @param type undo item type * @param line line affected * @param col start column * @param len length of change * @param text text removed/inserted */ KateUndo (KateUndoGroup::UndoType type, uint line, uint col, uint len, const TQString &text); /** * Destructor */ ~KateUndo (); public: /** * Invalid examples: insert / remove 0 length text * I could probably fix this in KateDocument, but it's more work there * (and probably better here too) * @return validity */ bool isValid(); /** * merge an undo item * Saves a bit of memory and potentially many calls when undo/redoing. * @param u undo item to merge * @return success */ bool merge(KateUndo* u); /** * undo this item at given doc * @param doc document */ void undo (KateDocument *doc); /** * redo this item at given doc * @param doc document */ void redo (KateDocument *doc); /** * The cursor before the action took place */ KateTextCursor cursorBefore() const; /** * The cursor after the action took place */ KateTextCursor cursorAfter() const; /** * type of item * @return type */ inline KateUndoGroup::UndoType type() const { return m_type; } /** * line of changes * @return line */ inline uint line () const { return m_line; } /** * startcol of changes * @return column */ inline uint col () const { return m_col; } /** * length of changes * @return length */ inline uint len() const { return m_len; } /** * text inserted/removed * @return text */ inline const TQString& text() const { return m_text; }; private: /** * type */ KateUndoGroup::UndoType m_type; /** * line */ uint m_line; /** * column */ uint m_col; /** * length */ uint m_len; /** * text */ TQString m_text; }; KateUndo::KateUndo (KateUndoGroup::UndoType type, uint line, uint col, uint len, const TQString &text) : m_type (type), m_line (line), m_col (col), m_len (len), m_text (text) { } KateUndo::~KateUndo () { } bool KateUndo::isValid() { if (m_type == KateUndoGroup::editInsertText || m_type == KateUndoGroup::editRemoveText) if (len() == 0) return false; return true; } bool KateUndo::merge(KateUndo* u) { if (m_type != u->type()) return false; if (m_type == KateUndoGroup::editInsertText && m_line == u->line() && (m_col + m_len) == u->col()) { m_text += u->text(); m_len += u->len(); return true; } else if (m_type == KateUndoGroup::editRemoveText && m_line == u->line() && m_col == (u->col() + u->len())) { m_text.prepend(u->text()); m_col = u->col(); m_len += u->len(); return true; } return false; } void KateUndo::undo (KateDocument *doc) { if (m_type == KateUndoGroup::editInsertText) { doc->editRemoveText (m_line, m_col, m_len); } else if (m_type == KateUndoGroup::editRemoveText) { doc->editInsertText (m_line, m_col, m_text); } else if (m_type == KateUndoGroup::editWrapLine) { doc->editUnWrapLine (m_line, (m_text == "1"), m_len); } else if (m_type == KateUndoGroup::editUnWrapLine) { doc->editWrapLine (m_line, m_col, (m_text == "1")); } else if (m_type == KateUndoGroup::editInsertLine) { doc->editRemoveLine (m_line); } else if (m_type == KateUndoGroup::editRemoveLine) { doc->editInsertLine (m_line, m_text); } else if (m_type == KateUndoGroup::editMarkLineAutoWrapped) { doc->editMarkLineAutoWrapped (m_line, m_col == 0); } } void KateUndo::redo (KateDocument *doc) { if (m_type == KateUndoGroup::editRemoveText) { doc->editRemoveText (m_line, m_col, m_len); } else if (m_type == KateUndoGroup::editInsertText) { doc->editInsertText (m_line, m_col, m_text); } else if (m_type == KateUndoGroup::editUnWrapLine) { doc->editUnWrapLine (m_line, (m_text == "1"), m_len); } else if (m_type == KateUndoGroup::editWrapLine) { doc->editWrapLine (m_line, m_col, (m_text == "1")); } else if (m_type == KateUndoGroup::editRemoveLine) { doc->editRemoveLine (m_line); } else if (m_type == KateUndoGroup::editInsertLine) { doc->editInsertLine (m_line, m_text); } else if (m_type == KateUndoGroup::editMarkLineAutoWrapped) { doc->editMarkLineAutoWrapped (m_line, m_col == 1); } } KateTextCursor KateUndo::cursorBefore() const { if (m_type == KateUndoGroup::editInsertLine || m_type == KateUndoGroup::editUnWrapLine) return KateTextCursor(m_line+1, m_col); else if (m_type == KateUndoGroup::editRemoveText) return KateTextCursor(m_line, m_col+m_len); return KateTextCursor(m_line, m_col); } KateTextCursor KateUndo::cursorAfter() const { if (m_type == KateUndoGroup::editRemoveLine || m_type == KateUndoGroup::editWrapLine) return KateTextCursor(m_line+1, m_col); else if (m_type == KateUndoGroup::editInsertText) return KateTextCursor(m_line, m_col+m_len); return KateTextCursor(m_line, m_col); } KateUndoGroup::KateUndoGroup (KateDocument *doc) : m_doc (doc),m_safePoint(false) { m_items.setAutoDelete (true); } KateUndoGroup::~KateUndoGroup () { } void KateUndoGroup::undo () { if (m_items.count() == 0) return; m_doc->editStart (false); for (KateUndo* u = m_items.last(); u; u = m_items.prev()) u->undo(m_doc); if (m_doc->activeView()) { for (uint z=0; z < m_items.count(); z++) if (m_items.at(z)->type() != KateUndoGroup::editMarkLineAutoWrapped) { m_doc->activeView()->editSetCursor (m_items.at(z)->cursorBefore()); break; } } m_doc->editEnd (); } void KateUndoGroup::redo () { if (m_items.count() == 0) return; m_doc->editStart (false); for (KateUndo* u = m_items.first(); u; u = m_items.next()) u->redo(m_doc); if (m_doc->activeView()) { for (uint z=0; z < m_items.count(); z++) if (m_items.at(z)->type() != KateUndoGroup::editMarkLineAutoWrapped) { m_doc->activeView()->editSetCursor (m_items.at(z)->cursorAfter()); break; } } m_doc->editEnd (); } void KateUndoGroup::addItem (KateUndoGroup::UndoType type, uint line, uint col, uint len, const TQString &text) { addItem(new KateUndo(type, line, col, len, text)); } void KateUndoGroup::addItem(KateUndo* u) { if (!u->isValid()) delete u; else if (m_items.last() && m_items.last()->merge(u)) delete u; else m_items.append(u); } bool KateUndoGroup::merge(KateUndoGroup* newGroup,bool complex) { if (m_safePoint) return false; if (newGroup->isOnlyType(singleType()) || complex) { // Take all of its items first -> last KateUndo* u = newGroup->m_items.take(0); while (u) { addItem(u); u = newGroup->m_items.take(0); } if (newGroup->m_safePoint) safePoint(); return true; } return false; } void KateUndoGroup::safePoint (bool safePoint) { m_safePoint=safePoint; } KateUndoGroup::UndoType KateUndoGroup::singleType() { KateUndoGroup::UndoType ret = editInvalid; for (KateUndo* u = m_items.first(); u; u = m_items.next()) { if (ret == editInvalid) ret = u->type(); else if (ret != u->type()) return editInvalid; } return ret; } bool KateUndoGroup::isOnlyType(KateUndoGroup::UndoType type) { if (type == editInvalid) return false; for (KateUndo* u = m_items.first(); u; u = m_items.next()) if (u->type() != type) return false; return true; } // kate: space-indent on; indent-width 2; replace-tabs on;