// $Revision: 1.3 $ // Copyright (c) 1994-1995 Taligent, Inc. All rights reserved. #ifndef TaligentSamples_SCRAMBLETEXTCOMMAND #include "ScrambleTextCommand.h" #endif #ifndef Taligent_RANDOMNUMBER #include #endif #ifndef Taligent_BREAKWORD #include #endif #ifndef Taligent_ARRAYOF #include #endif #ifndef Taligent_ASSERTIONS #include #endif MCollectibleDefinitionsMacro(TScrambleTextCommand, 0); TScrambleTextCommand::TScrambleTextCommand() : TReplaceTextCommand() { } TScrambleTextCommand::~TScrambleTextCommand() { } // Get the currently selected text first and scramble it, then // use this to replace the text. Support for discontiguous selections // isn't really available yet, so we just use the first range of // the current selection. void TScrambleTextCommand::HandleDoBegin(MTextSelection& selection) { TStandardText text; TTextRange range; selection.GetFirstRange(range); { TTextRepresentationReadEntry entry(&selection); entry.GetTextForReading()->Extract(range, text); } ScrambleText(text); SetText(text); TReplaceTextCommand::HandleDoBegin(selection); } // Break the text into runs of words and punctuation and put the ranges into an // array. Shuffle the array, build new text from the shuffled ranges, then replace // the provided text. void TScrambleTextCommand::ScrambleText(TText& text) { TTextChunkIterator* iter = TTextChunkIterator::CreatePreferredWordSelectionIterator(&text); Assertion(iter != NIL); TDeleterFor deleter(iter); TTextRange range; if (!iter->First(range)) { return; } TArrayOf ranges; TTextRange currentRange = range; while (iter->Next(range)) { bool joinRange = true; for (TTextOffset i = range.GetBegin(), e = range.GetEnd(); (i < e) && joinRange; i++) { // UniChar c = text[TTextIndex(i)]; joinRange = TUnicode::IsPunctuation(c) || TUnicode::IsASpace(c); } if (joinRange) { currentRange.SetEnd(currentRange.GetEnd() + range.GetLength()); } else { ranges.Append(new TTextRange(currentRange)); currentRange = range; } } ranges.Append(new TTextRange(currentRange)); long limit = ranges.Count(); if (limit > 1) { long maxindex = limit - 1; TUniformRandomInteger random; // can't restrict random numbers to a range... unsigned long mask = 1; while (mask < maxindex) { mask = (mask << 1) + 1; } CollectionIndex i; for (i = 0; i < limit; i++) { CollectionIndex x; do { x = random.Next() & mask; } while (x > maxindex); if (i != x) { TTextRange* r = ranges.FastAt(i); ranges.FastAtPut(i, ranges.FastAt(x)); ranges.FastAtPut(x, r); } } TStandardText scrambledText; for (i = 0; i < limit; i++) { scrambledText.Insert(text, ranges[i]); } text = scrambledText; } ranges.DeleteAll(); }