Stroika Library 3.0d16
 
Loading...
Searching...
No Matches
Command.cpp
1/*
2 * Copyright(c) Sophist Solutions, Inc. 1990-2025. All rights reserved
3 */
4#include "Stroika/Frameworks/StroikaPreComp.h"
5
6#include "IdleManager.h"
7#include "TextInteractor.h"
8
9#include "Command.h"
10
11using namespace Stroika::Foundation;
12
13using namespace Stroika::Frameworks;
14using namespace Stroika::Frameworks::Led;
15
17
18#if qStroika_Frameworks_Led_SupportGDI
19
20/*
21 ********************************************************************************
22 *************************************** Command ********************************
23 ********************************************************************************
24 */
25/*
26@METHOD: Command::GetName
27@DESCRIPTION: <p>Returns the name associated with a command. This is used for UI purposes in constructing the
28 text of the Undo command name.</p>
29*/
30const SDKChar* Command::GetName () const
31{
32 return Led_SDK_TCHAROF ("");
33}
34
35bool Command::UpdateSimpleTextInsert (size_t /*insertAt*/, Led_tChar /*c*/)
36{
37 return false;
38}
39
40/*
41 ********************************************************************************
42 ******************************** CommandHandler ********************************
43 ********************************************************************************
44 */
45bool CommandHandler::PostUpdateSimpleTextInsert (size_t /*insertAt*/, Led_tChar /*c*/)
46{
47 IdleManager::NonIdleContext nonIdleContext;
48 return false;
49}
50
51size_t CommandHandler::GetUndoRedoWhatMessageText (char* buf, size_t bufSize)
52{
53 const char kCantUndo[] = "Can't Undo";
54 const char kUndo[] = "Undo";
55 const char kReUndo[] = "Redo";
56 if (CanUndo ()) {
57 bufSize = min (bufSize, strlen (kUndo));
58 memcpy (buf, kUndo, bufSize);
59 }
60 else if (CanRedo ()) {
61 bufSize = min (bufSize, strlen (kReUndo));
62 memcpy (buf, kReUndo, bufSize);
63 }
64 else {
65 bufSize = min (bufSize, strlen (kCantUndo));
66 memcpy (buf, kCantUndo, bufSize);
67 }
68 return bufSize;
69}
70
71/*
72 ********************************************************************************
73 ************************* SingleUndoCommandHandler *****************************
74 ********************************************************************************
75 */
76SingleUndoCommandHandler::SingleUndoCommandHandler ()
77 : CommandHandler{}
78 , fLastCmd{nullptr}
80 , fDoingCommands{false}
81#endif
82{
83}
84
85void SingleUndoCommandHandler::Post (Command* newCommand)
86{
87#if qStroika_Foundation_Debug_AssertionsChecked
88 Require (not fDoingCommands);
89#endif
90 IdleManager::NonIdleContext nonIdleContext;
91 delete fLastCmd;
92 fLastCmd = newCommand;
93}
94
95bool SingleUndoCommandHandler::PostUpdateSimpleTextInsert (size_t insertAt, Led_tChar c)
96{
97 IdleManager::NonIdleContext nonIdleContext;
98 if (fLastCmd != nullptr) {
99 return fLastCmd->UpdateSimpleTextInsert (insertAt, c);
100 }
101 return false;
102}
103
104void SingleUndoCommandHandler::BreakInGroupedCommands ()
105{
106}
107
108void SingleUndoCommandHandler::BreakInGroupedCommandsIfDifferentCommand (const SDKString& /*cmdName*/)
109{
110}
111
112void SingleUndoCommandHandler::DoUndo (TextInteractor& interactor)
113{
114 Require (CanUndo ());
115
116 RequireNotNull (fLastCmd);
117 Require (GetDone ());
118
119 IdleManager::NonIdleContext nonIdleContext;
120
121#if qStroika_Foundation_Debug_AssertionsChecked
122 Require (not fDoingCommands);
123 fDoingCommands = true;
124 try {
125#endif
126 fLastCmd->UnDo (interactor);
127#if qStroika_Foundation_Debug_AssertionsChecked
128 }
129 catch (...) {
130 fDoingCommands = false;
131 throw;
132 }
133 fDoingCommands = false;
134#endif
135}
136
137void SingleUndoCommandHandler::DoRedo (TextInteractor& interactor)
138{
139 Require (CanRedo ());
140 RequireNotNull (fLastCmd);
141 Require (not GetDone ());
142
143 IdleManager::NonIdleContext nonIdleContext;
144
145#if qStroika_Foundation_Debug_AssertionsChecked
146 Require (not fDoingCommands);
147 fDoingCommands = true;
148 try {
149#endif
150 fLastCmd->ReDo (interactor);
151#if qStroika_Foundation_Debug_AssertionsChecked
152 }
153 catch (...) {
154 fDoingCommands = false;
155 throw;
156 }
157 fDoingCommands = false;
158#endif
159}
160
161void SingleUndoCommandHandler::Commit ()
162{
163 delete fLastCmd;
164 fLastCmd = nullptr;
165}
166
167bool SingleUndoCommandHandler::CanUndo ()
168{
169 return fLastCmd != nullptr and GetDone ();
170}
171
172bool SingleUndoCommandHandler::CanRedo ()
173{
174 return fLastCmd != nullptr and not GetDone ();
175}
176
177bool SingleUndoCommandHandler::GetDone () const
178{
179 return (fLastCmd != nullptr and fLastCmd->GetDone ());
180}
181
182const SDKChar* SingleUndoCommandHandler::GetUndoCmdName ()
183{
184 if (CanUndo ()) {
185 return fLastCmd->GetName ();
186 }
187 else {
188 return Led_SDK_TCHAROF ("");
189 }
190}
191
192const SDKChar* SingleUndoCommandHandler::GetRedoCmdName ()
193{
194 if (CanRedo ()) {
195 return fLastCmd->GetName ();
196 }
197 else {
198 return Led_SDK_TCHAROF ("");
199 }
200}
201
202/*
203 ********************************************************************************
204 ***************************** MultiLevelUndoCommandHandler *********************
205 ********************************************************************************
206 */
207MultiLevelUndoCommandHandler::MultiLevelUndoCommandHandler (size_t maxUndoLevels, size_t maxCmdsPerLevel)
208 : CommandHandler{}
209 , fMaxUndoLevels{maxUndoLevels}
210 , fMaxCmdsPerLevel{maxCmdsPerLevel}
211 , fUndoCursor{0}
212 , fCommands{}
213 , fCommandGroupCount{0}
214 , fUndoneGroupCount{0}
216 , fDoingCommands{false}
217#endif
218{
219}
220
221MultiLevelUndoCommandHandler::~MultiLevelUndoCommandHandler ()
222{
223 Commit (); // just to avoid memory leak...
224}
225
226void MultiLevelUndoCommandHandler::Post (Command* newCommand)
227{
228 RequireNotNull (newCommand);
229#if qStroika_Foundation_Debug_AssertionsChecked
230 Require (not fDoingCommands);
231#endif
232
233 IdleManager::NonIdleContext nonIdleContext;
234
235 // When we've undone some things, and DO another, commit those UNDONE commands. We have no
236 // UI for keeping multiple threads of undos alive...
237 Assert (fUndoCursor <= fCommands.size ());
238 Commit_After (fUndoCursor);
239 Assert (fCommandGroupCount >= fUndoneGroupCount);
240 fCommandGroupCount -= fUndoneGroupCount;
241 fUndoneGroupCount = 0;
242
243 Assert (fCommandGroupCount <= fMaxUndoLevels);
244
245 if (fMaxUndoLevels == 0) {
246 // prevent memory leak/crash if no undo allowed
247 delete newCommand;
248 return;
249 }
250
251 bool partOfNewCommand = (fCommands.size () == 0 or (fCommands.back () == nullptr));
252
253 // If prev item was a nullptr, then we are starting new cmd group
254 // cleanp/commit and old ones if we've hit the limit...
255 if (partOfNewCommand) {
256 if (fCommandGroupCount == fMaxUndoLevels) {
257 size_t lastItemInFirstGroup = 0;
258 for (; lastItemInFirstGroup <= fUndoCursor; ++lastItemInFirstGroup) {
259 if (fCommands[lastItemInFirstGroup] == nullptr) {
260 Assert (lastItemInFirstGroup != 0); // cannot have break here!
261 // must be a break in here someplace - delete back from here...
262 break;
263 }
264 }
265 Assert (lastItemInFirstGroup <= fUndoCursor); // didn't fall through loop
266 Commit_Before (lastItemInFirstGroup);
267 fUndoCursor = fCommands.size ();
268 }
269 else {
270 ++fCommandGroupCount;
271 }
272 }
273 else {
274 AssertNotNull (fCommands.back ());
275 }
276
277 // at this point, we may have added more commands in this group than we should have (fMaxCmdsPerLevel)...
278 // maybe we'll ignore this for now - sooner or later I will implement merging commands together as
279 // a speed hack!!!
280 // LGP 960119
281 // won't be as important once we implement merging adjacent typing commands which can be merged...
282 // LGP 960328
283
284 try {
285 fCommands.push_back (newCommand);
286 }
287 catch (...) {
288 // if we don't have enuf memory to add this to our list, we'd better dispose of the
289 // command. Having the command Posted() makes it our responsability to free
290 delete newCommand;
291
292 // Actually - at this point, fCommandGroupCount maybe wrong (if partOfNewCommand)
293 // rather than fixing it, since we are so low on memory, we may as well just commit
294 // all our commands
295 Commit ();
296
297 throw;
298 }
299 fUndoCursor = fCommands.size ();
300}
301
302bool MultiLevelUndoCommandHandler::PostUpdateSimpleTextInsert (size_t insertAt, Led_tChar c)
303{
304 IdleManager::NonIdleContext nonIdleContext;
305 if (fUndoCursor != fCommands.size ()) {
306 // cannot update last command with undo info if we've undone anything on stack
307 return false;
308 }
309 Command* lastCmd = (fCommands.size () == 0) ? nullptr : fCommands.back ();
310 if (lastCmd != nullptr) {
311 return lastCmd->UpdateSimpleTextInsert (insertAt, c);
312 }
313 return false;
314}
315
316void MultiLevelUndoCommandHandler::BreakInGroupedCommands ()
317{
318 size_t commandListLen = fCommands.size ();
319 /*
320 * Unless we are at the end of a sequence of commands, don't do a break (cuz it would
321 * cause a committing of commands needlessly - and there must already be a break
322 * here).
323 */
324 if (commandListLen != 0 and (fUndoCursor == commandListLen)) {
325 if (fCommands[fUndoCursor - 1] != nullptr) { // last actual command in array
326 fCommands.push_back (nullptr);
327 fUndoCursor = fCommands.size ();
328 }
329 }
330}
331
332void MultiLevelUndoCommandHandler::BreakInGroupedCommandsIfDifferentCommand (const SDKString& cmdName)
333{
334 if (fCommands.size () != 0 and fCommands.back () != nullptr and fCommands.back ()->GetName () != cmdName) {
335 BreakInGroupedCommands ();
336 }
337}
338
339void MultiLevelUndoCommandHandler::DoUndo (TextInteractor& interactor)
340{
341 Require (CanUndo ());
342
343 IdleManager::NonIdleContext nonIdleContext;
344
345 BreakInGroupedCommands ();
346
347 size_t start;
348 size_t end;
349 [[maybe_unused]] bool result = GetLastCmdRangeBefore (&start, &end);
350 Assert (result);
351
352#if qStroika_Foundation_Debug_AssertionsChecked
353 Require (not fDoingCommands);
354 fDoingCommands = true;
355 try {
356#endif
357 for (int i = static_cast<int> (end); i >= static_cast<int> (start); --i) {
358 fCommands[i]->UnDo (interactor);
359 }
360#if qStroika_Foundation_Debug_AssertionsChecked
361 }
362 catch (...) {
363 fDoingCommands = false;
364 throw;
365 }
366 fDoingCommands = false;
367#endif
368
369 fUndoCursor = start;
370 ++fUndoneGroupCount;
371 Assert (fUndoneGroupCount <= fCommandGroupCount);
372}
373
374void MultiLevelUndoCommandHandler::DoRedo (TextInteractor& interactor)
375{
376 Require (CanRedo ());
377
378 IdleManager::NonIdleContext nonIdleContext;
379
380 size_t start;
381 size_t end;
382 [[maybe_unused]] bool result = GetLastCmdRangeAfter (&start, &end);
383 Assert (result);
384
385#if qStroika_Foundation_Debug_AssertionsChecked
386 Require (not fDoingCommands);
387 fDoingCommands = true;
388 try {
389#endif
390 for (size_t i = start; i <= end; ++i) {
391 fCommands[i]->ReDo (interactor);
392 }
393#if qStroika_Foundation_Debug_AssertionsChecked
394 }
395 catch (...) {
396 fDoingCommands = false;
397 throw;
398 }
399 fDoingCommands = false;
400#endif
401
402 fUndoCursor = end + 1; // point AFTER last cmd
403 Assert (fUndoCursor <= fCommands.size ());
404 if (fCommands[fUndoCursor] == nullptr) {
405 // if pointing to breaker, then point just past it, so new posted commands
406 // come after that
407 ++fUndoCursor;
408 Assert (fUndoCursor <= fCommands.size ());
409 }
410 Assert (fUndoneGroupCount <= fCommandGroupCount);
411 Assert (fUndoneGroupCount >= 1);
412 --fUndoneGroupCount;
413}
414
415void MultiLevelUndoCommandHandler::Commit ()
416{
417 for (size_t i = 0; i < fCommands.size (); ++i) {
418 delete fCommands[i];
419 }
420 fCommands.clear ();
421 fUndoCursor = 0;
422 fUndoneGroupCount = 0;
423 fCommandGroupCount = 0;
424}
425
426bool MultiLevelUndoCommandHandler::CanUndo ()
427{
428 return (fCommandGroupCount > fUndoneGroupCount);
429}
430
431bool MultiLevelUndoCommandHandler::CanRedo ()
432{
433 return (fUndoneGroupCount > 0);
434}
435
436const SDKChar* MultiLevelUndoCommandHandler::GetUndoCmdName ()
437{
438 if (CanUndo ()) {
439 size_t start;
440 size_t end;
441 [[maybe_unused]] bool result = GetLastCmdRangeBefore (&start, &end);
442 Assert (result);
443 // arbitrarily pick name from any of the commands in group
444 return fCommands[start]->GetName ();
445 }
446 else {
447 return Led_SDK_TCHAROF ("");
448 }
449}
450
451const SDKChar* MultiLevelUndoCommandHandler::GetRedoCmdName ()
452{
453 if (CanRedo ()) {
454 size_t start;
455 size_t end;
456 [[maybe_unused]] bool result = GetLastCmdRangeAfter (&start, &end);
457 Assert (result);
458 // arbitrarily pick name from any of the commands in group
459 return fCommands[start]->GetName ();
460 }
461 else {
462 return Led_SDK_TCHAROF ("");
463 }
464}
465
466/*
467@METHOD: MultiLevelUndoCommandHandler::SetMaxUnDoLevels
468@DESCRIPTION: <p>See @'MultiLevelUndoCommandHandler::GetMaxUnDoLevels'</p>
469
470*/
471void MultiLevelUndoCommandHandler::SetMaxUnDoLevels (size_t maxUndoLevels)
472{
473 if (fCommandGroupCount >= maxUndoLevels) {
474 Commit ();
475 }
476 fMaxUndoLevels = maxUndoLevels;
477}
478
479bool MultiLevelUndoCommandHandler::GetLastCmdRangeBefore (size_t* startIdx, size_t* endIdx) const
480{
481 RequireNotNull (startIdx);
482 RequireNotNull (endIdx);
483
484 *startIdx = 0;
485 *endIdx = 0;
486
487 size_t commandListLen = fCommands.size ();
488
489 if (commandListLen == 0) {
490 return false;
491 }
492 Assert (fUndoCursor >= 0);
493 if (fUndoCursor == 0) {
494 return false;
495 }
496
497 size_t i = fUndoCursor - 1; // start looking at item just BEFORE cursor
498 if (fCommands[i] == nullptr) {
499 if (i == 0) {
500 return false;
501 }
502 --i;
503 }
504 *endIdx = i;
505
506 for (; i > 0; --i) {
507 if (fCommands[i] == nullptr) {
508 *startIdx = i + 1;
509 return true;
510 }
511 }
512 return true;
513}
514
515bool MultiLevelUndoCommandHandler::GetLastCmdRangeAfter (size_t* startIdx, size_t* endIdx) const
516{
517 RequireNotNull (startIdx);
518 RequireNotNull (endIdx);
519
520 *startIdx = 0;
521 *endIdx = 0;
522
523 Assert (fUndoCursor != kBadIndex); // if triggered must do some fixing...
524
525 size_t commandListLen = fCommands.size ();
526 size_t listPastEnd = commandListLen;
527 Assert (fUndoCursor <= listPastEnd);
528 if (fUndoCursor == listPastEnd) {
529 return false;
530 }
531 else {
532 size_t i = fUndoCursor;
533 if (fCommands[i] == nullptr) {
534 ++i;
535 }
536 *startIdx = i;
537
538 for (; i < listPastEnd; ++i) {
539 if (fCommands[i] == nullptr) {
540 *endIdx = i - 1;
541 return true;
542 }
543 }
544 Assert (listPastEnd > 0);
545 *endIdx = listPastEnd - 1;
546 return true;
547 }
548}
549
550void MultiLevelUndoCommandHandler::Commit_After (size_t after)
551{
552 Require (after >= 0);
553 size_t commandsLen = fCommands.size ();
554 if (commandsLen != 0) {
555 for (long i = static_cast<long> (commandsLen) - 1; i >= long (after); --i) {
556 Assert (i >= 0);
557 delete fCommands[i];
558 fCommands.erase (fCommands.begin () + i);
559 }
560 }
561}
562
563void MultiLevelUndoCommandHandler::Commit_Before (size_t before)
564{
565 // delete items before 'before' - and INCLUDING THAT ITEM. So this MUST BE CALLED ON
566 // A NON_EMPTY LIST!
567 Require (before >= 0);
568 Require (before <= fCommands.size ());
569 size_t countToCommit = (before) + 1;
570 while (countToCommit != 0) {
571 delete fCommands[0];
572 fCommands.erase (fCommands.begin ());
573 --countToCommit;
574 }
575}
576
577/*
578 ********************************************************************************
579 **************************** SnoopingCommandHandler ****************************
580 ********************************************************************************
581 */
582
583SnoopingCommandHandler::SnoopingCommandHandler (CommandHandler* realHandler)
584 : fRealHandler (realHandler)
585{
586}
587
588void SnoopingCommandHandler::Post (Command* newCommand)
589{
590 IdleManager::NonIdleContext nonIdleContext;
591 Snoop (newCommand);
592 if (fRealHandler != nullptr) {
593 fRealHandler->Post (newCommand);
594 }
595}
596
597void SnoopingCommandHandler::BreakInGroupedCommands ()
598{
599 if (fRealHandler != nullptr) {
600 fRealHandler->BreakInGroupedCommands ();
601 }
602}
603
604void SnoopingCommandHandler::BreakInGroupedCommandsIfDifferentCommand (const SDKString& cmdName)
605{
606 if (fRealHandler != nullptr) {
607 fRealHandler->BreakInGroupedCommandsIfDifferentCommand (cmdName);
608 }
609}
610
611void SnoopingCommandHandler::DoUndo (TextInteractor& interactor)
612{
613 IdleManager::NonIdleContext nonIdleContext;
614
615 if (fRealHandler != nullptr) {
616 fRealHandler->DoUndo (interactor);
617 }
618}
619
620void SnoopingCommandHandler::DoRedo (TextInteractor& interactor)
621{
622 IdleManager::NonIdleContext nonIdleContext;
623
624 if (fRealHandler != nullptr) {
625 fRealHandler->DoRedo (interactor);
626 }
627}
628
629void SnoopingCommandHandler::Commit ()
630{
631 if (fRealHandler != nullptr) {
632 fRealHandler->Commit ();
633 }
634}
635
636bool SnoopingCommandHandler::CanUndo ()
637{
638 if (fRealHandler == nullptr) {
639 return false;
640 }
641 else {
642 return fRealHandler->CanUndo ();
643 }
644}
645
646bool SnoopingCommandHandler::CanRedo ()
647{
648 if (fRealHandler == nullptr) {
649 return false;
650 }
651 else {
652 return fRealHandler->CanRedo ();
653 }
654}
655
656const SDKChar* SnoopingCommandHandler::GetUndoCmdName ()
657{
658 if (fRealHandler == nullptr) {
659 return Led_SDK_TCHAROF ("");
660 }
661 else {
662 return fRealHandler->GetUndoCmdName ();
663 }
664}
665
666const SDKChar* SnoopingCommandHandler::GetRedoCmdName ()
667{
668 if (fRealHandler == nullptr) {
669 return Led_SDK_TCHAROF ("");
670 }
671 else {
672 return fRealHandler->GetRedoCmdName ();
673 }
674}
675
676/*
677 ********************************************************************************
678 ************************* InteractiveReplaceCommand ****************************
679 ********************************************************************************
680 */
681
682/*
683@METHOD: InteractiveReplaceCommand::InteractiveReplaceCommand
684@DESCRIPTION: <p>This constructor takes an @'InteractiveReplaceCommand::SavedTextRep'
685 for BEFORE and AFTER. It also takes as argument - an 'at' parameter - specifying where the NEW/OLD text (for DO and UNDO) will get inserted.
686 For the length overwritten - we use the size from the SavedTextRep itself. This CTOR also takes a command name to be saved with the
687 command (not used intenrally - but saved as an attribute so menu handling code can report what is to be UNDONE).</p>
688*/
689InteractiveReplaceCommand::InteractiveReplaceCommand (SavedTextRep* beforeRegion, SavedTextRep* afterRegion, size_t at, const SDKString& cmdName)
690 : inherited (true)
691 , fBeforeRegion (beforeRegion)
692 , fAfterRegion (afterRegion)
693 , fAt (at)
694 , fCmdName (cmdName)
695{
696 RequireNotNull (fBeforeRegion);
697 RequireNotNull (fAfterRegion);
698}
699
700InteractiveReplaceCommand::~InteractiveReplaceCommand ()
701{
702 delete fBeforeRegion;
703 delete fAfterRegion;
704}
705
706void InteractiveReplaceCommand::Do (TextInteractor& /*interactor*/)
707{
708 Assert (false); // illegal to call - command must be PRE-DONE
709}
710
711void InteractiveReplaceCommand::UnDo (TextInteractor& interactor)
712{
713 AssertNotNull (fBeforeRegion);
714 AssertNotNull (fAfterRegion);
715 fBeforeRegion->InsertSelf (&interactor, fAt, fAfterRegion->GetLength ());
716 fBeforeRegion->ApplySelection (&interactor);
717
718 inherited::UnDo (interactor);
719}
720
721void InteractiveReplaceCommand::ReDo (TextInteractor& interactor)
722{
723 AssertNotNull (fBeforeRegion);
724 AssertNotNull (fAfterRegion);
725 fAfterRegion->InsertSelf (&interactor, fAt, fBeforeRegion->GetLength ());
726 fAfterRegion->ApplySelection (&interactor);
727
728 inherited::ReDo (interactor);
729}
730
731bool InteractiveReplaceCommand::UpdateSimpleTextInsert (size_t insertAt, Led_tChar c)
732{
733 AssertNotNull (fBeforeRegion);
734 AssertNotNull (fAfterRegion);
735
736 PlainTextRep* afterPTR = dynamic_cast<PlainTextRep*> (fAfterRegion);
737 if (afterPTR != nullptr) {
738 return afterPTR->AppendCharToRep (insertAt, c);
739 }
740
741 return false;
742}
743
744const SDKChar* InteractiveReplaceCommand::GetName () const
745{
746 return fCmdName.c_str ();
747}
748
749/*
750 ********************************************************************************
751 ******************** InteractiveReplaceCommand::SavedTextRep *******************
752 ********************************************************************************
753 */
754void InteractiveReplaceCommand::SavedTextRep::ApplySelection (TextInteractor* imager)
755{
756 RequireNotNull (imager);
757 imager->SetSelection (fSelStart, fSelEnd);
758}
759
760/*
761 ********************************************************************************
762 ******************** InteractiveReplaceCommand::PlainTextRep *******************
763 ********************************************************************************
764 */
765InteractiveReplaceCommand::PlainTextRep::PlainTextRep (size_t selStart, size_t selEnd, const Led_tChar* text, size_t textLen)
766 : inherited (selStart, selEnd)
767 , fText (nullptr)
768 , fTextLength (textLen)
769{
770 if (textLen != 0) {
771 fText = new Led_tChar[textLen];
772 memcpy (fText, text, textLen * sizeof (Led_tChar));
773 }
774}
775
776InteractiveReplaceCommand::PlainTextRep::~PlainTextRep ()
777{
778 delete[] fText;
779}
780
781size_t InteractiveReplaceCommand::PlainTextRep::GetLength () const
782{
783 return fTextLength;
784}
785
786void InteractiveReplaceCommand::PlainTextRep::InsertSelf (TextInteractor* interactor, size_t at, size_t nBytesToOverwrite)
787{
788 RequireNotNull (interactor);
789 interactor->Replace (at, at + nBytesToOverwrite, fText, fTextLength);
790}
791
792/*
793@METHOD: InteractiveReplaceCommand::PlainTextRep::AppendCharToRep
794@DESCRIPTION: <p>Utility used internally to implement optimized undo code.</p>
795*/
796bool InteractiveReplaceCommand::PlainTextRep::AppendCharToRep (size_t insertAt, Led_tChar c)
797{
798 if (fSelStart == insertAt and fSelEnd == insertAt) {
799 // could be more efficient and avoid copy - but this is already a big improvemnt over old algorithm - so lets not complain just yet...
800 Led_tChar* newText = new Led_tChar[fTextLength + 1];
801 (void)::memcpy (newText, fText, fTextLength * sizeof (Led_tChar));
802 newText[fTextLength] = c;
803 fTextLength++;
804 delete[] fText;
805 fText = newText;
806 ++fSelStart;
807 fSelEnd = fSelStart;
808 return true;
809 }
810 else {
811 return false;
812 }
813}
814#endif
#define AssertNotNull(p)
Definition Assertions.h:333
#define qStroika_Foundation_Debug_AssertionsChecked
The qStroika_Foundation_Debug_AssertionsChecked flag determines if assertions are checked and validat...
Definition Assertions.h:48
#define RequireNotNull(p)
Definition Assertions.h:347
conditional_t< qTargetPlatformSDKUseswchar_t, wchar_t, char > SDKChar
Definition SDKChar.h:71