Stroika Library 3.0d25
 
Loading...
Searching...
No Matches
StandardStyledTextInteractor.cpp
1/*
2 * Copyright(c) Sophist Solutions, Inc. 1990-2026. All rights reserved
3 */
4#include "Stroika/Frameworks/StroikaPreComp.h"
5
6#include "Stroika/Foundation/DataExchange/BadFormatException.h"
9#include "Stroika/Frameworks/Led/StyledTextEmbeddedObjects.h"
10#include "Stroika/Frameworks/Led/StyledTextIO/StyledTextIO_HTML.h"
11#include "Stroika/Frameworks/Led/StyledTextIO/StyledTextIO_RTF.h"
12
13#include "StandardStyledTextInteractor.h"
14
15#if qStroika_Frameworks_Led_IncludeLedNativeFileFormatSupportInStandardStyledTextInteractor
16#include "Stroika/Frameworks/Led/StyledTextIO/StyledTextIO_LedNative.h"
17#endif
18
19using std::byte;
20
21using namespace Stroika::Foundation;
22
23using Memory::MakeSharedPtr;
24
25using namespace Stroika::Frameworks;
26using namespace Stroika::Frameworks::Led;
27using namespace Stroika::Frameworks::Led::StyledTextIO;
28
29/*
30 ********************************************************************************
31 ************************** StandardStyledTextIOSrcStream ***********************
32 ********************************************************************************
33 */
34StandardStyledTextIOSrcStream::StandardStyledTextIOSrcStream (TextStore* textStore, const shared_ptr<AbstractStyleDatabaseRep>& textStyleDatabase,
35 size_t selectionStart, size_t selectionEnd)
36 : fTextStore (textStore)
37 , fStyleRunDatabase (textStyleDatabase)
38 , fCurOffset (selectionStart)
39 , fSelStart (selectionStart)
40 , fSelEnd (selectionEnd)
41{
42 RequireNotNull (textStore);
43 Require (textStyleDatabase.get () != nullptr);
44 Require (fSelStart >= 0);
45 Require (fSelEnd >= 0);
46 fSelEnd = min (fSelEnd, textStore->GetEnd ());
47}
48
49#if qStroika_Frameworks_Led_SupportGDI
50StandardStyledTextIOSrcStream::StandardStyledTextIOSrcStream (StandardStyledTextImager* textImager, size_t selectionStart, size_t selectionEnd)
51 : StandardStyledTextIOSrcStream{textImager->PeekAtTextStore (), textImager->GetStyleDatabase (), selectionStart, selectionEnd}
52{
53}
54#endif
55
56size_t StandardStyledTextIOSrcStream::readNTChars (Led_tChar* intoBuf, size_t maxTChars)
57{
58 AssertNotNull (intoBuf);
59 size_t bytesToRead = min (maxTChars, fSelEnd - fCurOffset);
60 Assert (bytesToRead <= maxTChars);
61 fTextStore->CopyOut (fCurOffset, bytesToRead, intoBuf);
62 fCurOffset += bytesToRead;
63 return bytesToRead;
64}
65
66size_t StandardStyledTextIOSrcStream::current_offset () const
67{
68 return fCurOffset - fSelStart;
69}
70
71void StandardStyledTextIOSrcStream::seek_to (size_t to)
72{
73 Require (to >= 0);
74 to += fSelStart;
75 to = min (to, fSelEnd);
76 fCurOffset = to;
77 Ensure (fCurOffset >= fSelStart);
78 Ensure (fCurOffset <= fSelEnd);
79}
80
81size_t StandardStyledTextIOSrcStream::GetTotalTextLength () const
82{
83 Assert (fSelEnd >= fSelStart);
84 return (fSelEnd - fSelStart);
85}
86
87vector<StyledInfoSummaryRecord> StandardStyledTextIOSrcStream::GetStyleInfo (size_t from, size_t len) const
88{
89 size_t effectiveFrom = from + fSelStart;
90#if qStroika_Foundation_Debug_AssertionsChecked
91 size_t effectiveTo = effectiveFrom + len;
92#endif
93 Require (effectiveFrom >= fSelStart);
94 Require (effectiveFrom <= fSelEnd);
95#if qStroika_Foundation_Debug_AssertionsChecked
96 Require (effectiveTo >= fSelStart);
97 Require (effectiveTo <= fSelEnd);
98#endif
99 return fStyleRunDatabase->GetStyleInfo (effectiveFrom, len);
100}
101
102#if qStroika_Frameworks_Led_SupportGDI
103vector<SimpleEmbeddedObjectStyleMarker*> StandardStyledTextIOSrcStream::CollectAllEmbeddingMarkersInRange (size_t from, size_t to) const
104{
105 size_t effectiveFrom = from + fSelStart;
106 size_t effectiveTo = to + fSelStart;
107 Require (effectiveFrom >= fSelStart);
108 Require (effectiveFrom <= fSelEnd);
109 Require (effectiveTo >= fSelStart);
110 Require (effectiveTo <= fSelEnd);
111
112 MarkersOfATypeMarkerSink2Vector<SimpleEmbeddedObjectStyleMarker> result;
113 AssertNotNull (fTextStore);
114 fTextStore->CollectAllMarkersInRangeInto (effectiveFrom, effectiveTo, TextStore::kAnyMarkerOwner, result);
115 return result.fResult;
116}
117#endif
118
119StandardStyledTextIOSrcStream::Table* StandardStyledTextIOSrcStream::GetTableAt (size_t /*at*/) const
120{
121 return nullptr;
122}
123
124void StandardStyledTextIOSrcStream::SummarizeFontAndColorTable (set<SDKString>* fontNames, set<Color>* colorsUsed) const
125{
126 if (fontNames != nullptr or colorsUsed != nullptr) {
127 size_t totalTextLength = GetTotalTextLength ();
128 vector<StyledInfoSummaryRecord> styleRuns;
129 if (totalTextLength != 0) {
130 styleRuns = GetStyleInfo (0, totalTextLength);
131 }
132 for (auto i = styleRuns.begin (); i != styleRuns.end (); ++i) {
133 if (fontNames != nullptr) {
134 fontNames->insert ((*i).GetFontName ());
135 }
136 if (colorsUsed != nullptr) {
137 colorsUsed->insert ((*i).GetTextColor ());
138 }
139 }
140 }
141}
142
143size_t StandardStyledTextIOSrcStream::GetEmbeddingMarkerPosOffset () const
144{
145 return fSelStart;
146}
147
148/*
149 ********************************************************************************
150 ************************* StandardStyledTextIOSinkStream ***********************
151 ********************************************************************************
152 */
153StandardStyledTextIOSinkStream::StandardStyledTextIOSinkStream (TextStore* textStore, const shared_ptr<AbstractStyleDatabaseRep>& textStyleDatabase,
154 size_t insertionStart)
155 : fTextStore{textStore}
156 , fStyleRunDatabase{textStyleDatabase}
157 , fOriginalStart{insertionStart}
158 , fInsertionStart{insertionStart}
159{
160 RequireNotNull (textStore);
161 Require (textStyleDatabase.get () != nullptr);
162}
163
164StandardStyledTextIOSinkStream::~StandardStyledTextIOSinkStream ()
165{
166 try {
167 Flush ();
168 }
169 catch (...) {
170 // ignore, cuz cannot fail out of DTOR
171 }
172}
173
174size_t StandardStyledTextIOSinkStream::current_offset () const
175{
176 return fInsertionStart - fOriginalStart;
177}
178
179void StandardStyledTextIOSinkStream::AppendText (const Led_tChar* text, size_t nTChars, const FontSpecification* fontSpec)
180{
181 RequireNotNull (text);
182 AssertNotNull (fTextStore);
183
184 // If caching, append the text to an array. Coun't on the array to have efficient
185 // growing properties (does for MSVC50 - grows by factor of two, so log-n append times).
186 fCachedText.insert (fCachedText.end (), text, text + nTChars);
187
188 /*
189 * Keep track of the style changes that need to be applied later. If there is NO spec specified, use the one from
190 * the previous section. Check for 'nTChars == 0' - don't append empty info-summary records.
191 */
192 if (nTChars != 0) {
193 if (fontSpec == nullptr) {
194 if (fSavedStyleInfo.size () == 0) {
195 fSavedStyleInfo.push_back (StyledInfoSummaryRecord (fStyleRunDatabase->GetStyleInfo (fOriginalStart, 0)[0], nTChars));
196 }
197 else {
198 fSavedStyleInfo.back ().fLength += nTChars;
199 }
200 }
201 else {
202 fSavedStyleInfo.push_back (StyledInfoSummaryRecord (*fontSpec, nTChars));
203 }
204 }
205 fInsertionStart += nTChars;
206}
207
208void StandardStyledTextIOSinkStream::ApplyStyle (size_t from, size_t to, const vector<StyledInfoSummaryRecord>& styleRuns)
209{
210 Require (from <= to);
211 if (GetCachedTextSize () != 0) {
212 Flush ();
213 }
214 fStyleRunDatabase->SetStyleInfo (fOriginalStart + from, to - from, styleRuns);
215}
216
217FontSpecification StandardStyledTextIOSinkStream::GetDefaultFontSpec () const
218{
219 return GetStaticDefaultFont ();
220}
221
222#if qStroika_Frameworks_Led_SupportGDI
223void StandardStyledTextIOSinkStream::InsertEmbeddingForExistingSentinel (SimpleEmbeddedObjectStyleMarker* embedding, size_t at)
224{
225 RequireNotNull (embedding);
226 if (GetCachedTextSize () != 0) {
227 Flush ();
228 }
229 size_t effectiveFrom = fOriginalStart + at;
230 Led_tChar testSentinel;
231 AssertNotNull (fTextStore);
232 fTextStore->CopyOut (effectiveFrom, 1, &testSentinel);
233 if (testSentinel != kEmbeddingSentinelChar) {
234 Execution::Throw (DataExchange::BadFormatException::kThe);
235 }
236 Stroika::Frameworks::Led::InsertEmbeddingForExistingSentinel (embedding, *fTextStore, effectiveFrom, fStyleRunDatabase.get ());
237}
238
239void StandardStyledTextIOSinkStream::AppendEmbedding (SimpleEmbeddedObjectStyleMarker* embedding)
240{
241 RequireNotNull (embedding);
242 AssertNotNull (fTextStore);
243 if (GetCachedTextSize () != 0) {
244 Flush ();
245 }
246 AddEmbedding (embedding, *fTextStore, fInsertionStart, fStyleRunDatabase.get ());
247 ++fInsertionStart;
248}
249#endif
250
251void StandardStyledTextIOSinkStream::AppendSoftLineBreak ()
252{
253 // Bogus implementation - usually overriden...
254 AppendText (LED_TCHAR_OF ("\n"), 1, nullptr);
255}
256
257void StandardStyledTextIOSinkStream::InsertMarker (Marker* m, size_t at, size_t length, MarkerOwner* markerOwner)
258{
259 Require (at <= current_offset ());
260 RequireNotNull (m);
261 RequireNotNull (markerOwner);
262 AssertNotNull (fTextStore);
263 if (GetCachedTextSize () != 0) {
264 Flush ();
265 }
266 {
267 TextStore::SimpleUpdater u (*fTextStore, fOriginalStart + at, fOriginalStart + at + length);
268 fTextStore->AddMarker (m, fOriginalStart + at, length, markerOwner);
269 }
270}
271
272void StandardStyledTextIOSinkStream::Flush ()
273{
274 if (GetCachedTextSize () != 0) {
275 AssertNotNull (fTextStore);
276 size_t dataSize = fCachedText.size ();
277 size_t whereToInsert = fInsertionStart - dataSize;
278 fTextStore->Replace (whereToInsert, whereToInsert, Traversal::Iterator2Pointer (fCachedText.begin ()), dataSize);
279 fCachedText.clear ();
280
281 // Flush the cached style info
282 fStyleRunDatabase->SetStyleInfo (whereToInsert, dataSize, fSavedStyleInfo.size (), Traversal::Iterator2Pointer (fSavedStyleInfo.begin ()));
283 fSavedStyleInfo.clear ();
284 }
285 Ensure (fSavedStyleInfo.size () == 0);
286}
287
288void StandardStyledTextIOSinkStream::PushContext (TextStore* ts, const shared_ptr<AbstractStyleDatabaseRep>& textStyleDatabase, size_t insertionStart)
289{
290 Require (GetCachedTextSize () == 0); // must flush before setting/popping context
291
292 Context c;
293 c.fTextStore = fTextStore;
294 c.fStyleRunDatabase = fStyleRunDatabase;
295 c.fInsertionStart = fInsertionStart;
296 c.fOriginalStart = fOriginalStart;
297 fSavedContexts.push_back (c);
298 fTextStore = ts;
299 fStyleRunDatabase = textStyleDatabase;
300 fInsertionStart = insertionStart;
301 fOriginalStart = insertionStart;
302}
303
304void StandardStyledTextIOSinkStream::PopContext ()
305{
306 Require (GetCachedTextSize () == 0); // must flush before setting/popping context
307 Require (not fSavedContexts.empty ());
308 fTextStore = fSavedContexts.back ().fTextStore;
309 fStyleRunDatabase = fSavedContexts.back ().fStyleRunDatabase;
310 fInsertionStart = fSavedContexts.back ().fInsertionStart;
311 fOriginalStart = fSavedContexts.back ().fOriginalStart;
312 fSavedContexts.pop_back ();
313}
314
315#if qStroika_Frameworks_Led_SupportGDI
316
317#if qStroika_Platform_Windows
318const TCHAR kLedPrivateClipTypeName[] = _T ("Led Rich Text Format");
319const Led_ClipFormat Led::kLedPrivateClipFormat = static_cast<Led_ClipFormat> (::RegisterClipboardFormat (kLedPrivateClipTypeName));
320const TCHAR kRTFClipTypeName[] = _T ("Rich Text Format");
321const Led_ClipFormat Led::kRTFClipFormat = static_cast<Led_ClipFormat> (::RegisterClipboardFormat (kRTFClipTypeName));
322const TCHAR kHTMLClipTypeName[] = _T ("HTML"); /// MAYBE A BAD NAME - SEE IF ANY WINDOWS STANDARD NAME???
323const Led_ClipFormat Led::kHTMLClipFormat = static_cast<Led_ClipFormat> (::RegisterClipboardFormat (kHTMLClipTypeName));
324#endif
325
326/*
327 ********************************************************************************
328 *************************** StandardStyledTextInteractor ***********************
329 ********************************************************************************
330 */
331StandardStyledTextInteractor::CommandNames StandardStyledTextInteractor::sCommandNames = StandardStyledTextInteractor::MakeDefaultCommandNames ();
332
333StandardStyledTextInteractor::StandardStyledTextInteractor ()
334 : fEmptySelectionStyleSuppressMode (false)
335 , fEmptySelectionStyle (GetStaticDefaultFont ())
336{
337}
338
339StandardStyledTextInteractor::CommandNames StandardStyledTextInteractor::MakeDefaultCommandNames ()
340{
341 StandardStyledTextInteractor::CommandNames cmdNames;
342 cmdNames.fFontChangeCommandName = Led_SDK_TCHAROF ("Font Change");
343 return cmdNames;
344}
345
346void StandardStyledTextInteractor::HookLosingTextStore ()
347{
348 TextInteractor::HookLosingTextStore ();
349 StandardStyledTextImager::HookLosingTextStore ();
350 HookLosingTextStore_ ();
351}
352
353void StandardStyledTextInteractor::HookLosingTextStore_ ()
354{
355 // Remove all embeddings...
356 vector<SimpleEmbeddedObjectStyleMarker*> embeddings = CollectAllEmbeddingMarkersInRange (0, GetLength ());
357 for (size_t i = 0; i < embeddings.size (); ++i) {
358 SimpleEmbeddedObjectStyleMarker* e = embeddings[i];
359 AssertNotNull (e); // all embeddings returned must be non-null
360 DISABLE_COMPILER_MSC_WARNING_START (28182)
361 if (e->GetOwner () == this) {
362 PeekAtTextStore ()->RemoveMarker (e);
363 delete e;
364 }
365 DISABLE_COMPILER_MSC_WARNING_END (28182)
366 }
367}
368
369void StandardStyledTextInteractor::HookGainedNewTextStore ()
370{
371 TextInteractor::HookGainedNewTextStore ();
372 StandardStyledTextImager::HookGainedNewTextStore ();
373 HookGainedNewTextStore_ ();
374}
375
376void StandardStyledTextInteractor::HookGainedNewTextStore_ ()
377{
378}
379
380/*
381@METHOD: StandardStyledTextInteractor::SetDefaultFont
382@DESCRIPTION: <p>Override @'TextImager::SetDefaultFont' to provide a moderately sensible interpretation
383 of that method.</p>
384 <p>Note that this definition is significantly different than in Led 3.0. To get
385 the Led 3.0 behavior, you should call InteractiveSetFont ()</p>
386 */
387void StandardStyledTextInteractor::SetDefaultFont (const IncrementalFontSpecification& defaultFont)
388{
389 size_t selStart = GetSelectionStart ();
390 size_t selEnd = GetSelectionEnd ();
391 if (selStart == selEnd) {
392 size_t selLength = selEnd - selStart;
393 FontSpecification newEmptySelectionStyle = fEmptySelectionStyle;
394 newEmptySelectionStyle.MergeIn (defaultFont);
395 SetStyleInfo (selStart, selLength, defaultFont);
396 SetEmptySelectionStyle (newEmptySelectionStyle);
397 Refresh ();
398 }
399 StandardStyledTextImager::SetDefaultFont (defaultFont);
400}
401
402/*
403@METHOD: StandardStyledTextInteractor::InteractiveSetFont
404@DESCRIPTION: <p>Applies the given incremental font
405 specification to the current selection. If the selection is empty - it stores the specification in
406 a special variable used to represent the font of the empty selection. Then when the user types, the
407 newly typed characters are in that font.</p>
408 <p>This function is meant to implement the underlying semantics of the standard word-processor
409 font/style selection menu.</p>
410 <p>As such, it is also entered by name in the command UNDO list. If you do <em>not</em> want your
411 font changes treated that way, use @'StandardStyledTextImager::SetStyleInfo'.</p>
412 <p>Note that this functionality USED to be provided by @'StandardStyledTextInteractor::SetDefaultFont'
413 (before Led 3.1a4) - but that is now obsolete. @'TextImager::SetDefaultFont' just sets a default font
414 object associated with the imager, and that has little or no effect when used with this class.
415 */
416void StandardStyledTextInteractor::InteractiveSetFont (const IncrementalFontSpecification& defaultFont)
417{
418 InteractiveModeUpdater iuMode (*this);
419 RequireNotNull (PeekAtTextStore ()); // Must specify TextStore before calling this, or any routine that calls it.
420
421 BreakInGroupedCommands ();
422
423 UndoableContextHelper undoContext (*this, GetCommandNames ().fFontChangeCommandName, false);
424 {
425 /*
426 * NB: The SetStyleInfo() call will notify markers via AboutTo/DidUpdate, so long as that code
427 * percieves there is any change. But if the selection is empty, no style runs will change!
428 *
429 * Similarly, if there is no selection, SetEmptySelectionStyle () will take care of the notification
430 * of change.
431 */
432 size_t selLength = undoContext.GetUndoRegionEnd () - undoContext.GetUndoRegionStart ();
433 FontSpecification newEmptySelectionStyle = fEmptySelectionStyle;
434 newEmptySelectionStyle.MergeIn (defaultFont);
435 SetStyleInfo (undoContext.GetUndoRegionStart (), selLength, defaultFont);
436 SetEmptySelectionStyle (newEmptySelectionStyle);
437 Refresh ();
438 }
439 undoContext.CommandComplete ();
440}
441
442IncrementalFontSpecification StandardStyledTextInteractor::GetContinuousStyleInfo (size_t from, size_t nTChars) const
443{
444 if (nTChars == 0 and from == GetSelectionStart ()) {
445 vector<StyledInfoSummaryRecord> summaryInfo;
446 summaryInfo.push_back (StyledInfoSummaryRecord (fEmptySelectionStyle, 0));
447 return (GetContinuousStyleInfo_ (summaryInfo));
448 }
449 else {
450 return StandardStyledTextImager::GetContinuousStyleInfo (from, nTChars);
451 }
452}
453
454void StandardStyledTextInteractor::DidUpdateText (const UpdateInfo& updateInfo) noexcept
455{
456 TextInteractor::DidUpdateText (updateInfo);
457 StandardStyledTextImager::DidUpdateText (updateInfo);
458 /*
459 * SPR#1171 - note that we cannot call SetEmptySelectionStyle () here because it is TOO aggressive.
460 * changes occur all the time (including setting the font in an empty selection to italics or something
461 * which trigger a DidUpdate call. Easier and safer to just do the SetEmptySelectionStyle () in the few
462 * places where I notice its needed.
463 */
464}
465
466bool StandardStyledTextInteractor::ShouldEnablePasteCommand () const
467{
468 if (TextInteractor::ShouldEnablePasteCommand ()) {
469 return true;
470 }
471 if (Led_ClipboardObjectAcquire::FormatAvailable (kLedPrivateClipFormat)) {
472 return true;
473 }
474 if (Led_ClipboardObjectAcquire::FormatAvailable (kRTFClipFormat)) {
475 return true;
476 }
477
478 const vector<EmbeddedObjectCreatorRegistry::Assoc>& types = EmbeddedObjectCreatorRegistry::Get ().GetAssocList ();
479 for (size_t i = 0; i < types.size (); ++i) {
480 EmbeddedObjectCreatorRegistry::Assoc assoc = types[i];
481 bool clipAvailForAll = true;
482 for (size_t j = 0; j < assoc.fFormatTagCount; ++j) {
483 if (not Led_ClipboardObjectAcquire::FormatAvailable (assoc.GetIthFormat (j))) {
484 clipAvailForAll = false;
485 break;
486 }
487 }
488 if (clipAvailForAll) {
489 return true;
490 }
491 }
492 return false;
493}
494
495bool StandardStyledTextInteractor::CanAcceptFlavor (Led_ClipFormat clipFormat) const
496{
497 if (TextInteractor::CanAcceptFlavor (clipFormat)) {
498 return true;
499 }
500 if (clipFormat == kLedPrivateClipFormat) {
501 return true;
502 }
503 if (clipFormat == kRTFClipFormat) {
504 return true;
505 }
506
507 const vector<EmbeddedObjectCreatorRegistry::Assoc>& types = EmbeddedObjectCreatorRegistry::Get ().GetAssocList ();
508 for (size_t i = 0; i < types.size (); ++i) {
509 EmbeddedObjectCreatorRegistry::Assoc assoc = types[i];
510
511 // This may sometimes false-posative - since we may (in priciple) require several other formats at the
512 // same time. But this will at least return true whenever we CAN accept the format...
513 // Maybe we should redesign/reimplement this API for a future release? LGP 960416
514 for (size_t j = 0; j < assoc.fFormatTagCount; ++j) {
515 if (assoc.GetIthFormat (j) == clipFormat) {
516 return true;
517 }
518 }
519 }
520 return false;
521}
522
523void StandardStyledTextInteractor::HookStyleDatabaseChanged ()
524{
525 StandardStyledTextImager::HookStyleDatabaseChanged ();
526 if (PeekAtTextStore () != nullptr) {
527 // if no TextStore - no problem - TextInteractor::HookGainedTextStore () will recreate these.
528 SetExternalizer (MakeDefaultExternalizer ());
529 SetInternalizer (MakeDefaultInternalizer ());
530 }
531}
532
533shared_ptr<FlavorPackageInternalizer> StandardStyledTextInteractor::MakeDefaultInternalizer ()
534{
535 return MakeSharedPtr<StyledTextFlavorPackageInternalizer> (GetTextStore (), GetStyleDatabase ());
536}
537
538shared_ptr<FlavorPackageExternalizer> StandardStyledTextInteractor::MakeDefaultExternalizer ()
539{
540 return MakeSharedPtr<StyledTextFlavorPackageExternalizer> (GetTextStore (), GetStyleDatabase ());
541}
542
543/*
544@METHOD: StandardStyledTextInteractor::ProcessSimpleClick
545@ACCESS: protected
546@DESCRIPTION: <p>Override @'TextInteractor::ProcessSimpleClick' to handle embeddings.</p>
547*/
548bool StandardStyledTextInteractor::ProcessSimpleClick (Led_Point clickedAt, unsigned clickCount, bool extendSelection, size_t* dragAnchor)
549{
550 RequireNotNull (dragAnchor);
551 size_t clickedOnChar = GetCharAtWindowLocation (clickedAt);
552 Led_Rect charRect = GetCharWindowLocation (clickedOnChar);
553
554 // Only if click is on an embedding character cell, and fully within it (not in case just past it as at when at
555 // end of line) - then we look at if it needs special processing
556 //
557 // Actually - better to check that the click isn't too near the edges of the embedding,
558 // cuz then its hard to click and make an insertion point in between two embeddings.
559 // So only do this click-selects somewhere near the middle of the embedding.
560 Led_Rect tstClickRect = charRect;
561 const DistanceType kHMargin = 3;
562 tstClickRect.left += kHMargin;
563 tstClickRect.right -= kHMargin;
564
565 if (tstClickRect.Contains (clickedAt)) {
566 vector<SimpleEmbeddedObjectStyleMarker*> embeddingList = CollectAllEmbeddingMarkersInRange (clickedOnChar, clickedOnChar + 1);
567 Assert (embeddingList.size () == 0 or embeddingList.size () == 1);
568
569 if (embeddingList.size () == 1) {
570 SimpleEmbeddedObjectStyleMarker* embedding = embeddingList[0];
571 AssertMember (embedding, SimpleEmbeddedObjectStyleMarker);
572 switch (clickCount) {
573 case 1: {
574 if (not extendSelection) {
575 SetSelection (clickedOnChar, clickedOnChar + 1);
576 // select the entire embedding, and then process the rest as usual...
577 if (clickCount == 1) {
578 // In this case - it really doesn't matter if we pick the LHS or RHS of the embedding
579 // as the drag anchor...
580 *dragAnchor = clickedOnChar;
581 }
582 return embedding->HandleClick (clickedAt, 1);
583 }
584 } break;
585
586 case 2: {
587 // If we dbl-click on an embedding, then be sure it is still selected, and then try to open it.
588 if (not extendSelection) {
589 SetSelection (clickedOnChar, clickedOnChar + 1);
590 // DO OPEN? Anyhow - even if no open, the treating the object as a word makes good sense...
591 if (clickCount == 1) {
592 // In this case - it really doesn't matter if we pick the LHS or RHS of the embedding
593 // as the drag anchor...
594 *dragAnchor = clickedOnChar;
595 }
596 return embedding->HandleClick (clickedAt, 2);
597 }
598 } break;
599
600 default: {
601 // others are ignored
602 } break;
603 }
604 }
605 }
606 return TextInteractor::ProcessSimpleClick (clickedAt, clickCount, extendSelection, dragAnchor);
607}
608
609void StandardStyledTextInteractor::WhileSimpleMouseTracking (Led_Point newMousePos, size_t dragAnchor)
610{
611 size_t clickedOnChar = GetCharAtWindowLocation (newMousePos);
612 size_t oldSelStart = GetSelectionStart ();
613 size_t oldSelEnd = GetSelectionEnd ();
614
615 /*
616 * If the drag anchor is coincident with the LHS or RHS of the clicked on character and the selection length
617 * is one (we clicked on an embedding) - then just eat that mousetracking - and prevent the selection from
618 * changing.
619 */
620 if ((clickedOnChar == dragAnchor or clickedOnChar + 1 == dragAnchor) and (oldSelEnd - oldSelStart == 1)) {
621 vector<SimpleEmbeddedObjectStyleMarker*> embeddingList = CollectAllEmbeddingMarkersInRange (clickedOnChar, clickedOnChar + 1);
622 if (embeddingList.size () == 1) {
623 [[maybe_unused]] SimpleEmbeddedObjectStyleMarker* embedding = embeddingList[0];
624 AssertMember (embedding, SimpleEmbeddedObjectStyleMarker);
625 return;
626 }
627 }
628 TextInteractor::WhileSimpleMouseTracking (newMousePos, dragAnchor);
629}
630
631void StandardStyledTextInteractor::InteractiveReplace (const Led_tChar* withWhat, size_t withWhatCharCount, UpdateMode updateMode)
632{
633 UpdateMode useUpdateMode = updateMode == eImmediateUpdate ? eDelayedUpdate : updateMode;
634 Assert (not fEmptySelectionStyleSuppressMode);
635 fEmptySelectionStyleSuppressMode = true;
636 try {
637 TextInteractor::InteractiveReplace (withWhat, withWhatCharCount, useUpdateMode);
638 fEmptySelectionStyleSuppressMode = false;
639 }
640 catch (...) {
641 fEmptySelectionStyleSuppressMode = false;
642 throw;
643 }
644 if (updateMode == eImmediateUpdate) {
645 Update ();
646 }
647}
648
649void StandardStyledTextInteractor::SetSelection (size_t start, size_t end)
650{
651 bool changed = (GetSelectionStart () != start) or (GetSelectionEnd () != end);
652 TextInteractor::SetSelection (start, end);
653 if (changed) {
654 StandardStyledTextInteractor::SetSelection_ (start, end);
655 }
656}
657
658void StandardStyledTextInteractor::SetSelection_ ([[maybe_unused]] size_t start, [[maybe_unused]] size_t end)
659{
660 // SetEmptySelectionStyle () assumes selection already set - uses set one - assure that we're called
661 // at the right time and that it already HAS been set
662 Require (start == GetSelectionStart ());
663 Require (end == GetSelectionEnd ());
664 if (not fEmptySelectionStyleSuppressMode) {
665 SetEmptySelectionStyle ();
666 }
667}
668
669/*
670@METHOD: StandardStyledTextInteractor::GetEmptySelectionStyle
671@DESCRIPTION: <p>Return the style applied to newly typed text (or interactively entered text) at the current
672 selection. This font defaults to the same as the surrounding text. But can be changed under user-control,
673 in order to implement the usual semantics of a font / style menu.</p>
674 <p>See @'StandardStyledTextInteractor::SetEmptySelectionStyle'.</p>
675*/
676FontSpecification StandardStyledTextInteractor::GetEmptySelectionStyle () const
677{
678 return fEmptySelectionStyle;
679}
680
681/*
682@METHOD: StandardStyledTextInteractor::SetEmptySelectionStyle_OVLD
683@DESCRIPTION: <p>Same as @'StandardStyledTextInteractor::SetEmptySelectionStyle' but always grabs style info
684 from the surrounding text (called from @'StandardStyledTextInteractor::SetSelection_').</p>
685 <p>See @'StandardStyledTextInteractor::GetEmptySelectionStyle'.</p>
686*/
687void StandardStyledTextInteractor::SetEmptySelectionStyle ()
688{
689 size_t start = 0;
690 size_t end = 0;
691 GetSelection (&start, &end);
692 if (fLeftSideOfSelectionInteresting) {
693 if (start < GetTextStore ().GetEnd ()) {
694 fEmptySelectionStyle = GetStyleInfo (start);
695 }
696 }
697 else {
698 fEmptySelectionStyle = GetStyleInfo (FindPreviousCharacter (end));
699 }
700 if (end == GetEnd ()) {
701 SetStyleInfo (GetEnd (), 1, fEmptySelectionStyle);
702 }
703}
704
705/*
706@METHOD: StandardStyledTextInteractor::SetEmptySelectionStyle
707@DESCRIPTION: <p>Set the @'FontSpecification' applied to newly typed text (or interactively entered text) at the current
708 selection. This font defaults to the same as the surrounding text. But can be changed under user-control,
709 in order to implement the usual semantics of a font / style menu.</p>
710 <p>Note: if the selection is currently empty, this routine will make appropriate AboutToUpdate/DidUpdate calls to
711 notifie anyone interested of the change (so - for example - the cached font metrics of text can change).</p>
712 <p>See @'StandardStyledTextInteractor::GetEmptySelectionStyle'.</p>
713*/
714void StandardStyledTextInteractor::SetEmptySelectionStyle (FontSpecification newEmptyFontSpec)
715{
716 if (fEmptySelectionStyle != newEmptyFontSpec) {
717 /*
718 * If we change the empty style selection, this change can affect menus etc (since they show
719 * the currently selected font which - with an empty selection is really just 'fEmptySelectionStyle').
720 *
721 * Also - this can change the size of the current row of text (when you change the font of the empty style to make
722 * it big - even if you type no characters - the row immediately gets bigger).
723 */
724 size_t selStart = 0;
725 size_t selEnd = 0;
726 GetSelection (&selStart, &selEnd);
727 if (selStart == selEnd) {
728 {
729 // not sure if we really need this scoping operator - just added to assure preserving semeantics - for now - LGP 2003-03-16
730 TextStore::SimpleUpdater updater (GetTextStore (), selStart, selEnd, false);
731 fEmptySelectionStyle = newEmptyFontSpec;
732 }
733 if (selEnd == GetEnd ()) {
734 SetStyleInfo (GetEnd (), 1, fEmptySelectionStyle);
735 }
736 }
737 }
738}
739
740bool StandardStyledTextInteractor::InteractiveReplaceEarlyPostReplaceHook (size_t withWhatCharCount)
741{
742 Assert (GetSelectionStart () >= withWhatCharCount);
743 if (withWhatCharCount == 1) {
744 // If we just typed a single extra char - apply our fEmptySelectionStyle to that extra char typed. Return true iff
745 // that caused a font-style change.
746 size_t charAt = FindPreviousCharacter (GetSelectionStart ()); // start of char we just added
747 FontSpecification prevStyle = GetStyleInfo (charAt);
748 if (prevStyle != fEmptySelectionStyle) {
749 SetStyleInfo (charAt, withWhatCharCount, IncrementalFontSpecification (fEmptySelectionStyle));
750 return true;
751 }
752 }
753 return false;
754}
755
756vector<SimpleEmbeddedObjectStyleMarker*> StandardStyledTextInteractor::CollectAllEmbeddingMarkersInRange (size_t from, size_t to) const
757{
758 /*
759 * Walk through all the markers in existence, and throw away all but our
760 * SimpleEmbeddedObjectStyleMarker markers. This is an inefficient approach. It would be far
761 * faster to keep a linked, or doubly linked list of all these guys.
762 * But this approach saves a bit of memory, and til we see this as a problem, lets just
763 * live with it.
764 */
765 MarkersOfATypeMarkerSink2Vector<SimpleEmbeddedObjectStyleMarker> result;
766 GetTextStore ().CollectAllMarkersInRangeInto (from, to, TextStore::kAnyMarkerOwner, result);
767 return result.fResult;
768}
769
770InteractiveReplaceCommand::SavedTextRep* StandardStyledTextInteractor::InteractiveUndoHelperMakeTextRep (size_t regionStart, size_t regionEnd,
771 size_t selStart, size_t selEnd)
772{
773 if (regionStart == regionEnd) {
774 // optimization, cuz these are smaller
775 return new EmptySelStyleTextRep{this, selStart, selEnd};
776 }
777 else {
778 return TextInteractor::InteractiveUndoHelperMakeTextRep (regionStart, regionEnd, selStart, selEnd);
779 }
780}
781
782/*
783 ********************************************************************************
784 ************************* StyledTextFlavorPackageInternalizer ******************
785 ********************************************************************************
786 */
787using StyledTextFlavorPackageInternalizer = StandardStyledTextInteractor::StyledTextFlavorPackageInternalizer;
788StyledTextFlavorPackageInternalizer::StyledTextFlavorPackageInternalizer (TextStore& ts, const shared_ptr<AbstractStyleDatabaseRep>& styleDatabase)
789 : inherited (ts)
790 , fStyleDatabase (styleDatabase)
791{
792}
793
794void StyledTextFlavorPackageInternalizer::InternalizeFlavor_FILEGuessFormatsFromName (filesystem::path fileName, Led_ClipFormat* suggestedClipFormat,
795 optional<CodePage> suggestedCodePage)
796{
797 inherited::InternalizeFlavor_FILEGuessFormatsFromName (fileName, suggestedClipFormat, suggestedCodePage);
798
799#if qStroika_Platform_Windows
800 if (suggestedClipFormat != nullptr and *suggestedClipFormat == kBadClipFormat) {
801 TCHAR drive[_MAX_DRIVE];
802 TCHAR dir[_MAX_DIR];
803 TCHAR fname[_MAX_FNAME];
804 TCHAR ext[_MAX_EXT];
805 ::_tsplitpath_s (fileName.native ().c_str (), drive, dir, fname, ext);
806 if (::_tcsicmp (ext, Led_SDK_TCHAROF (".rtf")) == 0) {
807 *suggestedClipFormat = kRTFClipFormat;
808 }
809 else if (::_tcsicmp (ext, Led_SDK_TCHAROF (".htm")) == 0) {
810 *suggestedClipFormat = kHTMLClipFormat;
811 }
812 else if (::_tcsicmp (ext, Led_SDK_TCHAROF (".html")) == 0) {
813 *suggestedClipFormat = kHTMLClipFormat;
814 }
815 else if (::_tcsicmp (ext, Led_SDK_TCHAROF (".led")) == 0) {
816 *suggestedClipFormat = kLedPrivateClipFormat;
817 }
818 }
819#endif
820}
821
822void StyledTextFlavorPackageInternalizer::InternalizeFlavor_FILEGuessFormatsFromStartOfData (Led_ClipFormat* suggestedClipFormat,
823 optional<CodePage> suggestedCodePage,
824 const byte* fileStart, const byte* fileEnd)
825{
826 inherited::InternalizeFlavor_FILEGuessFormatsFromStartOfData (suggestedClipFormat, suggestedCodePage, fileStart, fileEnd);
827 if (suggestedClipFormat != nullptr) {
828 if (*suggestedClipFormat == kBadClipFormat) {
829 {
830 StyledTextIOSrcStream_Memory source (fileStart, fileEnd - fileStart);
831 StyledTextIOReader_RTF reader (&source, nullptr);
832 if (reader.QuickLookAppearsToBeRightFormat ()) {
833 *suggestedClipFormat = kRTFClipFormat;
834 return;
835 }
836 }
837
838 {
839 StyledTextIOSrcStream_Memory source (fileStart, fileEnd - fileStart);
840 StyledTextIOReader_HTML reader (&source, nullptr);
841 if (reader.QuickLookAppearsToBeRightFormat ()) {
842 *suggestedClipFormat = kHTMLClipFormat;
843 return;
844 }
845 }
846
847#if qStroika_Frameworks_Led_IncludeLedNativeFileFormatSupportInStandardStyledTextInteractor
848 {
849 StyledTextIOSrcStream_Memory source (fileStart, fileEnd - fileStart);
850 StyledTextIOReader_LedNativeFileFormat reader (&source, nullptr);
851 if (reader.QuickLookAppearsToBeRightFormat ()) {
852 *suggestedClipFormat = kLedPrivateClipFormat;
853 return;
854 }
855 }
856#endif
857 }
858 }
859}
860
861bool StyledTextFlavorPackageInternalizer::InternalizeBestFlavor (ReaderFlavorPackage& flavorPackage, size_t from, size_t to)
862{
863 Require (from <= GetTextStore ().GetEnd ());
864 Require (to <= GetTextStore ().GetEnd ());
865 Require (from <= to);
866
867 if (InternalizeFlavor_RTF (flavorPackage, from, to)) {
868 return true;
869 }
870 else if (InternalizeFlavor_HTML (flavorPackage, from, to)) {
871 return true;
872 }
873#if qStroika_Frameworks_Led_IncludeLedNativeFileFormatSupportInStandardStyledTextInteractor
874 else if (InternalizeFlavor_Native (flavorPackage, from, to)) {
875 return true;
876 }
877#endif
878#if qStroika_Platform_Windows
879 // A bit of a hack. MSIE 3.0 generates both FILE and DIB objects on the clip
880 // for when we drag out pictures. This allows us to grab the dibs in that case.
881 // I just hope it doesn't cause too much trouble for other cases. For Led 2.2, we
882 // must completely rewrite this code and find a better way to choose what to
883 // grab out of a clip package...
884 // LGP 961101
885 else if (flavorPackage.GetFlavorAvailable (CF_DIB) and InternalizeFlavor_OtherRegisteredEmbedding (flavorPackage, from, to)) {
886 return true;
887 }
888#endif
889 else if (InternalizeFlavor_FILE (flavorPackage, from, to)) {
890 return true;
891 }
892 else if (InternalizeFlavor_OtherRegisteredEmbedding (flavorPackage, from, to)) {
893 return true;
894 }
895 else if (InternalizeFlavor_TEXT (flavorPackage, from, to)) {
896 return true;
897 }
898 return false;
899}
900
901#if qStroika_Frameworks_Led_IncludeLedNativeFileFormatSupportInStandardStyledTextInteractor
902bool StyledTextFlavorPackageInternalizer::InternalizeFlavor_Native (ReaderFlavorPackage& flavorPackage, size_t from, size_t to)
903{
904 if (flavorPackage.GetFlavorAvailable (kLedPrivateClipFormat)) {
905 size_t length = flavorPackage.GetFlavorSize (kLedPrivateClipFormat);
906 Memory::StackBuffer<char> buf{Memory::eUninitialized, length};
907 length = flavorPackage.ReadFlavorData (kLedPrivateClipFormat, length, buf);
908
909 size_t start = from;
910 size_t end = to;
911 Assert (end >= start);
912
913 GetTextStore ().Replace (start, end, LED_TCHAR_OF (""), 0); // clear current selection before insert
914 {
915 // Be sure these guys in scope like this so caches get flusehd before we update cursor position
916 StyledTextIOSrcStream_Memory source (buf, length);
917 unique_ptr<StandardStyledTextIOSinkStream> sink (mkStandardStyledTextIOSinkStream (start));
918 StyledTextIOReader_LedNativeFileFormat textReader (&source, sink.get ());
919 textReader.Read ();
920 sink->Flush (); // would be called implcitly in DTOR, but call like this so exceptions get propagates...
921 }
922 return true;
923 }
924 else {
925 return false;
926 }
927}
928#endif
929
930bool StyledTextFlavorPackageInternalizer::InternalizeFlavor_RTF (ReaderFlavorPackage& flavorPackage, size_t from, size_t to)
931{
932 if (flavorPackage.GetFlavorAvailable (kRTFClipFormat)) {
933 size_t length = flavorPackage.GetFlavorSize (kRTFClipFormat);
934 if (length == 0) {
935 // Bizare - but Word2000 seems to sometimes return a zero-length RTF entity when you insert a BitMap ActiveX control into the WP, and
936 // try to copy it... LGP 2000/04/26
937 return false;
938 }
939 Memory::StackBuffer<char> buf{Memory::eUninitialized, length};
940 length = flavorPackage.ReadFlavorData (kRTFClipFormat, length, buf.data ());
941
942 size_t start = from;
943 size_t end = to;
944 Assert (end >= start);
945
946 GetTextStore ().Replace (start, end, LED_TCHAR_OF (""), 0); // clear current selection before insert
947 {
948 // Be sure these guys in scope like this so caches get flusehd before we update cursor position
949 StyledTextIOSrcStream_Memory source{buf.data (), length};
950 unique_ptr<StandardStyledTextIOSinkStream> sink{mkStandardStyledTextIOSinkStream (start)};
951 StyledTextIOReader_RTF textReader{&source, sink.get ()};
952 textReader.Read ();
953 sink->Flush (); // would be called implcitly in DTOR, but call like this so exceptions get propagates...
954 }
955 return true;
956 }
957 else {
958 return false;
959 }
960}
961
962bool StyledTextFlavorPackageInternalizer::InternalizeFlavor_HTML (ReaderFlavorPackage& flavorPackage, size_t from, size_t to)
963{
964 if (flavorPackage.GetFlavorAvailable (kHTMLClipFormat)) {
965 size_t length = flavorPackage.GetFlavorSize (kHTMLClipFormat);
966 Memory::StackBuffer<char> buf{Memory::eUninitialized, length};
967 length = flavorPackage.ReadFlavorData (kHTMLClipFormat, length, buf.data ());
968
969 size_t start = from;
970 size_t end = to;
971 Assert (end >= start);
972
973 GetTextStore ().Replace (start, end, LED_TCHAR_OF (""), 0); // clear current selection before insert
974 {
975 // Be sure these guys in scope like this so caches get flusehd before we update cursor position
976 StyledTextIOSrcStream_Memory source{buf.data (), length};
977 unique_ptr<StandardStyledTextIOSinkStream> sink{mkStandardStyledTextIOSinkStream (start)};
978 StyledTextIOReader_HTML textReader{&source, sink.get ()};
979 textReader.Read ();
980 sink->Flush (); // would be called implcitly in DTOR, but call like this so exceptions get propagates...
981 }
982 return true;
983 }
984 else {
985 return false;
986 }
987}
988
989bool StyledTextFlavorPackageInternalizer::InternalizeFlavor_OtherRegisteredEmbedding (ReaderFlavorPackage& flavorPackage, size_t from, size_t to)
990{
991 const vector<EmbeddedObjectCreatorRegistry::Assoc>& types = EmbeddedObjectCreatorRegistry::Get ().GetAssocList ();
992 for (size_t i = 0; i < types.size (); ++i) {
993 EmbeddedObjectCreatorRegistry::Assoc assoc = types[i];
994 bool clipAvailForAll = (assoc.fFormatTagCount != 0);
995 for (size_t j = 0; j < assoc.fFormatTagCount; ++j) {
996 if (not flavorPackage.GetFlavorAvailable (assoc.GetIthFormat (j))) {
997 clipAvailForAll = false;
998 break;
999 }
1000 }
1001 if (clipAvailForAll) {
1002 SimpleEmbeddedObjectStyleMarker* objMarker = (assoc.fReadFromFlavorPackage) (flavorPackage);
1003 {
1004 size_t pasteStart = from;
1005 size_t pasteEnd = to;
1006 Assert (pasteEnd >= pasteStart);
1007
1008 GetTextStore ().Replace (pasteStart, pasteEnd, &kEmbeddingSentinelChar, 1); // clear current selection and put in embedding character
1009
1010 {
1011 // add marker, and do DID_UPDATE stuff so cached metrics and rowheights get refreshed...
1012 TextStore::SimpleUpdater updater (GetTextStore (), pasteStart, pasteStart + 1);
1013 GetTextStore ().AddMarker (objMarker, pasteStart, 1, fStyleDatabase.get ());
1014 }
1015 }
1016
1017 return true;
1018 }
1019 }
1020 return false;
1021}
1022
1023/*
1024@METHOD: StandardStyledTextInteractor::StyledTextFlavorPackageInternalizer::mkStandardStyledTextIOSinkStream
1025@DESCRIPTION: <p>Hook function so that the various Externalize_XXX methods in
1026 @'StandardStyledTextInteractor::StyledTextFlavorPackageInternalizer' can use a dynamicly typed
1027 SinkStream. So - for example - the externalize methods include paragraph info.</p>
1028*/
1029StandardStyledTextIOSinkStream* StyledTextFlavorPackageInternalizer::mkStandardStyledTextIOSinkStream (size_t insertionStart)
1030{
1031 return new StandardStyledTextIOSinkStream (PeekAtTextStore (), fStyleDatabase, insertionStart);
1032}
1033
1034/*
1035 ********************************************************************************
1036 ************************* StyledTextFlavorPackageExternalizer ******************
1037 ********************************************************************************
1038 */
1039using StyledTextFlavorPackageExternalizer = StandardStyledTextInteractor::StyledTextFlavorPackageExternalizer;
1040StyledTextFlavorPackageExternalizer::StyledTextFlavorPackageExternalizer (TextStore& ts, const shared_ptr<AbstractStyleDatabaseRep>& styleDatabase)
1041 : inherited (ts)
1042 , fStyleDatabase (styleDatabase)
1043{
1044}
1045
1046void StyledTextFlavorPackageExternalizer::ExternalizeFlavors (WriterFlavorPackage& flavorPackage, size_t from, size_t to)
1047{
1048 size_t start = from;
1049 size_t end = to;
1050 Require (start >= 0);
1051 Require (end <= GetTextStore ().GetEnd ());
1052 Require (start <= end);
1053
1054 /*
1055 * Enumerate in fidelity order flavors to copy...
1056 */
1057
1058 // Directly write out singly selected embedding
1059 {
1060 MarkersOfATypeMarkerSink2Vector<SimpleEmbeddedObjectStyleMarker> embeddings;
1061 GetTextStore ().CollectAllMarkersInRangeInto (from, to, TextStore::kAnyMarkerOwner, embeddings);
1062 if ((embeddings.fResult.size () == 1) and (start + 1 == end)) {
1063 /*
1064 * If we have some embedding like a pict or whatever selected, no reason
1065 * to copy to clip anything else.
1066 */
1067 ExternalizeFlavor_SingleSelectedEmbedding (flavorPackage, embeddings.fResult[0]);
1068#if 0
1069 // WELL, this trick (of returning here) is ALMOST right.
1070 // At least for the time being, some 'unknown' embeddings get externalized in
1071 // some format NOBODY - including LED will recognize (eg rtf pictures).
1072 // This isn't fatal, except
1073 // in a few rare cases. For example, when we try to
1074 return;
1075#endif
1076 }
1077 }
1078
1079 // not sure we should do if single selected???? -LGP 961014
1080 // If NOT, we must be careful about case of unknown RTF embeddings!!! - See SPR# 0397
1081 ExternalizeFlavor_RTF (flavorPackage, start, end);
1082
1083 ExternalizeFlavor_TEXT (flavorPackage, start, end);
1084}
1085
1086void StyledTextFlavorPackageExternalizer::ExternalizeBestFlavor (WriterFlavorPackage& flavorPackage, size_t from, size_t to)
1087{
1088 ExternalizeFlavor_RTF (flavorPackage, from, to);
1089}
1090
1091#if qStroika_Frameworks_Led_IncludeLedNativeFileFormatSupportInStandardStyledTextInteractor
1092void StyledTextFlavorPackageExternalizer::ExternalizeFlavor_Native (WriterFlavorPackage& flavorPackage, size_t from, size_t to)
1093{
1094 Require (from <= to);
1095 Require (to <= GetTextStore ().GetEnd ());
1096 unique_ptr<StandardStyledTextIOSrcStream> source (mkStandardStyledTextIOSrcStream (from, to));
1097 StyledTextIOWriterSinkStream_Memory sink;
1098 StyledTextIOWriter_LedNativeFileFormat textWriter (source.get (), &sink);
1099 textWriter.Write ();
1100 flavorPackage.AddFlavorData (kLedPrivateClipFormat, sink.GetLength (), sink.PeekAtData ());
1101}
1102#endif
1103
1104void StyledTextFlavorPackageExternalizer::ExternalizeFlavor_RTF (WriterFlavorPackage& flavorPackage, size_t from, size_t to)
1105{
1106 Require (from <= to);
1107 Require (to <= GetTextStore ().GetEnd ());
1108 unique_ptr<StandardStyledTextIOSrcStream> source{mkStandardStyledTextIOSrcStream (from, to)};
1109 StyledTextIOWriterSinkStream_Memory sink;
1110 StyledTextIOWriter_RTF textWriter{source.get (), &sink};
1111 textWriter.Write ();
1112 flavorPackage.AddFlavorData (kRTFClipFormat, sink.GetLength (), sink.PeekAtData ());
1113}
1114
1115void StyledTextFlavorPackageExternalizer::ExternalizeFlavor_SingleSelectedEmbedding (WriterFlavorPackage& flavorPackage,
1116 SimpleEmbeddedObjectStyleMarker* embedding)
1117{
1118 RequireNotNull (embedding);
1119 embedding->ExternalizeFlavors (flavorPackage);
1120}
1121
1122/*
1123@METHOD: StandardStyledTextInteractor::StyledTextFlavorPackageExternalizer::mkStandardStyledTextIOSrcStream
1124@DESCRIPTION: <p>Hook function so that the various Internalize_XXX methods in
1125 @'StandardStyledTextInteractor::StyledTextFlavorPackageExternalizer' can use a dynamicly typed
1126 SinkStream. So - for example - the internalize methods include paragraph info.</p>
1127*/
1128StandardStyledTextIOSrcStream* StyledTextFlavorPackageExternalizer::mkStandardStyledTextIOSrcStream (size_t selectionStart, size_t selectionEnd)
1129{
1130 return new StandardStyledTextIOSrcStream (PeekAtTextStore (), fStyleDatabase, selectionStart, selectionEnd);
1131}
1132
1133/*
1134 ********************************************************************************
1135 ***************************** EmptySelStyleTextRep *****************************
1136 ********************************************************************************
1137 */
1138using EmptySelStyleTextRep = StandardStyledTextInteractor::EmptySelStyleTextRep;
1139
1140EmptySelStyleTextRep::EmptySelStyleTextRep (StandardStyledTextInteractor* interactor, size_t selStart, size_t selEnd)
1141 : inherited{selStart, selEnd}
1142 , fSavedStyle{interactor->fEmptySelectionStyle}
1143{
1144}
1145
1146size_t EmptySelStyleTextRep::GetLength () const
1147{
1148 return 0;
1149}
1150
1151void EmptySelStyleTextRep::InsertSelf (TextInteractor* interactor, size_t at, size_t nBytesToOverwrite)
1152{
1153 RequireNotNull (interactor);
1154 interactor->Replace (at, at + nBytesToOverwrite, LED_TCHAR_OF (""), 0);
1155
1156 StandardStyledTextInteractor* si = dynamic_cast<StandardStyledTextInteractor*> (interactor);
1157 RequireNotNull (si); // cannot DO with one type, and UNDO with another!
1158
1159 si->SetEmptySelectionStyle (fSavedStyle);
1160}
1161#endif
#define AssertNotNull(p)
Definition Assertions.h:336
#define RequireNotNull(p)
Definition Assertions.h:350
#define AssertMember(p, c)
Definition Assertions.h:315
Logically halfway between std::array and std::vector; Smart 'direct memory array' - which when needed...
virtual size_t GetFlavorSize(Led_ClipFormat clipFormat) const =0
void Throw(T &&e2Throw)
like the builtin C++ 'throw', but stamps in the current Activity context and does helpful,...
Definition Throw.inl:54