/// This method test the undo functionality of the text void ReplaceSelectionCommandTest::testUndo() { TextEditorWidget* widget = new TextEditorWidget(); TextEditorController* ctrl = widget->controller(); TextDocument *doc = widget->textDocument(); TextBuffer* buf = doc->buffer(); // check if we can set the txt ctrl->replaceSelection("test"); testEqual( buf->text(), "test" ); // test basic, undo/redo ctrl->undo(); testEqual( buf->text(), "" ); // test coalesce ctrl->replaceSelection("emma"); ctrl->replaceSelection(" sarah",true); ctrl->replaceSelection(" david",true); testEqual( buf->text(), "emma sarah david" ); ctrl->undo(); testEqual( buf->text(), "emma" ); ctrl->redo(); testEqual( buf->text(), "emma sarah david"); // test ranged replacement doc->textUndoStack()->clear(); buf->setText("Blommers"); testEqual( buf->text(), "Blommers" ); // now replace 'mm' by nothing TextRangeSet sel( doc ); sel.addRange(3,5); ctrl->replaceRangeSet( sel, "" ); testEqual( buf->text(), "Bloers" ); ctrl->undo(); testEqual( buf->text(), "Blommers" ); ctrl->redo(); testEqual( buf->text(), "Bloers" ); delete widget; }
/// execute the given selection command /// @param controller the controller to execute the selection for void SelectionCommand::execute( TextEditorController* controller ) { // save the selection state TextDocument* document = controller->textDocument(); TextRangeSet* currentSelection = dynamic_cast<TextRangeSet*>( controller->textSelection() ); TextRangeSet* sel = new TextRangeSet(*currentSelection); // start with the current selection bool resetAnchors = !keepSelection_; // handle the select operation switch( unit_ ) { // character movement case MoveCaretByCharacter: sel->moveCarets(amount_); break; // This results in clearing the selection if a selection is present or it results in a movement of the caret. // When clearing a selection the caret is placed next to the selection (which side depends on the direction) case MoveCaretsOrDeselect: if( keepSelection_ ) { sel->moveCarets(amount_); } else { sel->moveCaretsOrDeselect(amount_); } break; case MoveCaretByWord: sel->moveCaretsByCharGroup(amount_, document->config()->whitespaceWithoutNewline(), document->config()->charGroups() ); break; case MoveCaretByLine: TextSelection::moveCaretsByLine( controller, sel, amount_ ); break; case MoveCaretToLineBoundary: sel->moveCaretsToLineBoundary( amount_, document->config()->whitespaceWithoutNewline() ); break; case MoveCaretToDocumentBegin: sel->toSingleRange(); sel->range(0).setCaret(0); break; case MoveCaretToDocumentEnd: sel->toSingleRange(); sel->range(0).setCaret( controller->textDocument()->length() ); break; case MoveCaretByPage: { // make sure the first line of the window is scrolled TextRenderer* renderer = controller->textRenderer(); TextEditorWidget* widget = controller->widget(); int firstVisibleLine = renderer->firstVisibleLine(); int linesPerPage = renderer->viewHeightInLines(); sel->beginChanges(); TextSelection::moveCaretsByPage( controller, sel, amount_ ); if( !keepSelection_ ) { sel->resetAnchors(); // we must reset anchors here because de process-changes will merge carets } sel->endChanges(); firstVisibleLine += linesPerPage * amount_; widget->scrollTopToLine( firstVisibleLine ); break; } case MoveCaretToExactOffset: sel->toSingleRange(); sel->range(0).setCaret(amount_); break; case SelectAll: sel->toSingleRange(); sel->setRange(0, document->buffer()->length() ); resetAnchors = false; // do not reset the anchors break; case SelectWord: sel->expandToWords(document->config()->whitespaces(), document->config()->charGroups()); resetAnchors = false; // do not reset the anchors break; case SelectWordAt: sel->selectWordAt( amount_, document->config()->whitespaces(), document->config()->charGroups() ); resetAnchors = false; break; case ToggleWordSelectionAt: sel->toggleWordSelectionAt( amount_, document->config()->whitespaces(), document->config()->charGroups() ); resetAnchors = false; break; case SelectFullLine: sel->expandToFullLines( amount_); resetAnchors = false; break; case AddCaretAtOffset: sel->addRange( amount_, amount_ ); resetAnchors = false; // do not reset the anchors break; case AddCaretByLine: TextSelection::addRangesByLine( controller, sel, amount_ ); break; case ResetSelection: // when there's a selection ESCAPE clears the selection if( sel->hasSelection() ) { sel->clearSelection(); } else if( sel->rangeCount() > 1 ) { sel->toSingleRange(); } resetAnchors = false; // keep selection break; } if( resetAnchors ) { sel->resetAnchors(); } // no change? if( currentSelection->equals( *sel ) ) { delete sel; return; // 0 } controller->changeAndGiveTextSelection( sel, commandId() ); }