Led Class Library 3.0 / Recipes

Overview

So you want to accomplish something in Led, but aren't sure how to go about it? Before you panic, or despair, check out this list. Most common things you might want to accomplish are covered here. And if you find something you want to be able to do, but don't find it covered here, please send mail to info-led@sophists.com, and we will make sure you get a prompt answer, and this FAQ/Recipe file is updated.


001. I want to be notified of (and maybe prevent) updates to the text. I want to make regions of text (but not all the text) read-only.

Answer:

There are two different approaches you may consider. Both leverage the TextStore/Marker/MarkerOwner AboutToUpdate/DidUpdate mechanisms.

Use only MarkerOwner overrides

If you have some easy mechanism already built (not using Markers) to check what region of text must be read-only, then this maybe your easiest approach.

MarkerOwners get a callback MarkerOwner::AboutToUpdateText() when text is about to be updated. You can simply override this method of some MarkerOwner class, and if the update touches a read-only region, then 'throw' some private class of your own choosing (more later on the catcher).

Which MarkerOwner class to use? You can reate your own subclass of MarkerOwner. If you do this - be sure to add your MarkerOwner to the TextStore - TextStore::AddMarkerOwner() - (typically just after creating the TextStore), and remove it when you are done - TextStore::RemoveMarkerOwner() - (before destroying the TextStore).

Alternatively - you can simply subclass from some existing MarkerOwner - most likely your editor (subclass of TextImager) class. This class is already automatically added and removed from the TextStore - saving you that trouble. If you take this approach - and override its MarkerOwner::AboutToUpdateText() - be sure to remember to call the inherited method!

Use Marker objects

If you don't already have some data structure to keep track of what regions of text are marked as read-only, then this is probably the best way. Use a subclass of a Led Marker object to keep track of the read-only region.

Your subclass of the Marker class will override just one method - the Marker::AboutToUpdateText method. E.g.:

	class	ReadOnlyTextException { };
	class	MyReadOnlyMarker : public Marker {
		public:
			override	void	AboutToUpdateText (const UpdateInfo& /*updateInfo*/)
				{
					throw ReadOnlyTextException ();
				}
	};

This approach seems pretty easy. The only slight hitch is that you must keep track of these markers yourself to some small extent. Led doesn't know what areas you want to be readonly and which ones you do not. You must create these markers yourself and add them to the TextStore (with some MarkerOwner - perhaps just your editor). And you must delete them all yourself before you destroy the editor.

One good way todo this would be to create your own MarkerOwner subclass (adding it to the TextStore and removing it as covered above). Then make that the owner of these newly created markers (when you call TextStore::AddMarker ()) to add the new read-only markers). Then - before removing the MarkerOwner class you created - call a method of it to cleanup itself - and it could collect all ITS Markers and remove and destroy them.

For example:

	class	MyReadOnlyMarkerOwner : public MarkerOwner {
		public:
			MyReadOnlyMarkerOwner (TextStore& ts):
				fTextStore (ts)
				{
					fTextStore.AddMarkerOwner (this);
				}
			~MyReadOnlyMarkerOwner ()
				{
					DeleteAllReadOnlyMarkers ();
					fTextStore.RemoveMarkerOwner (this);
				}
			override TextStore* PeekAtTextStore () const
				{
					return &fTextStore;
				}
			void	AddReadOnlyRegion (size_t from, size_t to)
				{
					fTextStore.AddMarker (new MyReadOnlyMarker (), from, to-from, this);
				}
			void	DeleteAllReadOnlyMarkers ()
				{
					vector	delMes	=	fTextStore.CollectAllMarkersInRange_OrSurroundings (0, fTextStore.GetEnd (), this);
					fTextStore.RemoveMarkers (&*delMes.begin (), delMes.size ());
					for (vector::const_iterator i = delMes.begin (); i != delMes.end (); ++i) {
						delete *i;
					}
				}
		private:
			TextStore&	fTextStore;
	};
With both approaches - catch the exception

Both of these approaches involving throwing an exception from inside of Led when the user tries to modify the read-only text. You should provide a top-level catcher for this exception (see the Led sample application LedIt! for an example of how todo this) to catch the new exception you have defined. Otherwise - depending on your platform, you may get unfriendly messages displayed to the user when he attempts to edit the readonly text (for example - something like 'unknown exception caught' would not be an unlikely result).


002. I want to be notified when a text view scrolls

Answer:

Either override TextImager::InvalidateScrollBarParameters () or TextInteractor_::UpdateScrollBars (). Which you should use depends a bit on when you want to be notified.

InvalidateScrollBarParameters () is called whenever anything which could invalidate the scrollbars happens. This could be several times per user action. So if you react here, be wary of flicker.

Because of this, the more likely, probably preferred way is to override UpdateScrollBars (). This is called on a 'clever' basis, so that minimal screen updating is done. Basically, it takes advantage of the InvalidateScrollBarParameters () to mark the scrollbar contents as 'dirty' - and schedules a 'cleanup' of the scrollbar (by calling UpdateScrollBars ()) when all the changes are done, and before the user gets a chance to notice.

See the code for details. But the bottom line is - you probably want to override UpdateScrollBars ().

NB: Don't forget to call the inherited version when you do an override!


003. I want to be notified when the selection changes

Answer:

Simply override the TextImager method NotificationOf_SelectionChanged ().

This can be used, for example, to invalidate the menu bar state, or to update some other interface elements which depend on the current selection.


004. I want multiple synchronized views onto the same text (like with split windows)

Answer:

Just create multiple TextImagers (whatever subclass you want), and make them refer to a common TextStore. Typically, in a Document-View class library, you would associate the TextStore with the Document. And then allow creating multiple views associated with the given document (each referring to the same text store).

Also, if you want them also to share the same style run information, and object embeddings, they must be made to share a common StyleDatabase, as well. Similarly for ParagraphInfoDatabases. Note - one implication of this - is that you can have dramatically different views onto the same text - if you like. You can have views onto the same text with different, or shared style information. And you can even have your own custom TextImager views onto the text, simultaneous with more standard views.

When modifications are made to the text (via the textstore), it notifies all TextImagers (and other MarkerOwners) of the update, which is how they know to redisplay themselves.

To see an example of this, try the LedLineIt! Windows applet. Open a text file. Then create a 'New Window' with the 'Window/New Window' command. This produces a separately scrollable view onto the same text buffer. Edits in one are instantly reflected in the other.


005. Led's RTF reader ignores tags it doesn't understand. How to I make it preserve those tags, and re-insert them into the output when I write a file back out?

Answer:

Led has a tutorial showing just how to do this.


006. Can I make a non word wrapped editor?

Answer:

Yes. There are two straightforward ways, depending on your goals.

If you want to always have your editor be non-word-wrapped, and you want maximum performance, and don't need support for different font information on each line, then consider using SimpleTextImager. This is what LedLineIt! does. See that application as a demonstration.

If you cannot use SimpleTextImager for some reason, just use a standard WordWrappedTextImager, and set the WrapWidth to be very large. This simulates "no word wrapping". But its more memory and performance costly than a SimpleTextImager. On the other hand - it DOES allow for you to use different line heights for different rows.


007. Is Led thread-safe?

Answer:

Led has no support for threads whatsoever. This doesn't mean that Led cannot be used in a multithreaded library or application. It simply means that Led must be treated like any other non-thread-safe class library, and you must protect access to Led via your own semaphores, to prevent multiple simultaneous accesses.

I'm not definitely committed to adding threading support to Led in the future. But my current thinking is that if I were, the way in which I would add it is as a conditionally compiled ability to serialize access to TextStores. Most of the other Led data structures are such that there should be little multithreading problems with them. Its mostly just TextStores, and the markers contained therein which need to be locked out. So I may add a semaphore to each TextStore, and any places outside the TextStore module which accessed markers (like the LineBasedTextImager marker subclasses) would lock the same semaphore.

This design approach would do very little, or nothing to allow Led itself to be distributed over a number of processors. But - importantly - it might make it easier to write mutlithreaded code updating/accessing Led data-structures, which operate in parallel with the normal screen display/updating Led performs.

Anyone with opinions about how this ought to work, please send email to info-led@sophists.com.


008. How do I implement web-browser-style hyperlinks?

We're building a high performance multimedia browser and don't want to build it in HTML. So we just want to be able to identify hyperlinks, change the cursor and text appearance appropriately, receive some kind of message when a link is generated.
Answer:

Well, for the most part, I'd say what you want should be quite easy in Led.

There are two different approaches you may want to consider. You choice will probably depend on the eventual UI behavior you want.

URLs as embedded objects

If you want to treat URLs as embeddings (the entire URL is an atomic object), this functionality should come quite easily. You can try the behavior of the LedIt! sample program. Select a URL in MSIE, and drag it into LedIt!. Notice how you get a selectable atomic object in LedIt!? Notice how you can double click on them to open them, or right click on them (say properties) to edit the associated URL or description?

If this is the sort of URL support you want in your editor, there is basically nothing todo. If you want some behavior close to this - but not identical - then you should have little trouble looking into this behavior, and subclassing to provide whatever variation you want.

URLs as colored regions of text

This behavior is closer to what a web browser typically provides. The main difference between this behavior and the one Led provides built-in is that here you can more easily select the text of the URL, instead of following it as a link (active object).

Keeping track of regions of text as special objects (hyperlinks) is easy using markers. You can make those markers subclasses of StyledTextImager::StyleMarker, in which case they can easily override their display (e.g. color them, as is typically done for html anchors, or what I do currently for embedded URLs in LedIt!, or whatever you want).

Then, you can adjust the cursor to a special value when tracking over these hyperlinks by overriding the appropriate class-library-specific routine (on MFC: OnSetCursor (); for the Mac it is AdjustCursorSelf()). In this override, you just test if the cursor is over your special embedding, and if so, set your cursor accordingly. Else do the default.

Then, you can easily implement hyperlinking by simply overriding TextInteractor::ProcessSimpleClick (), and checking for a click inside one of your hyperlink objects (Led makes this easy - see StandardStyledTextInteractor::ProcessSimpleClick for an example).

Now, there are some slightly tricky points. But these are inevitable in your design (to the extent to which I understand it). If you are trying to do something like what Netscape (or any other Web browser does), then you will see there is a natural tension/ambiguity about whether certain gestures are supposed to select text, or follow a hyperlink. Led is flexible enough to make it fairly straightforward for you to implement whatever UI design choice you make. But I'm not aware of any particular design choice on how to handle this ambiguity which works perfectly.


009. How do I implement a bookmarking facility with Led?

Answer:

I recommend that you construct your own class:


      class   BookMark : public Marker {
            public:
                  string  fName;  // or whatever info you want associated with the bookmark (other than position)
      };
Add the bookmark where you like in the text (with TextStore::AddMarker). And keep track of an array of them in your document (or view, wherever appropriate). Don't forget to Remove() and delete all the bookmarks when you are through!

Note also that Led will NOT take care of persisting these bookmarks. That is up to your classes (and obviously depends on the file format you are working with).


010. How do I do syntax coloring?

IE, styled text, but not under user control, but with markup auto-calculated via some external algorithm.
Answer:

Led has a tutorial showing just how to do this.


011. How do I implement keyboard macros? Recording of what the commands the user did?

Answer:

I haven't (yet) got a really good answer to this. But here is a start.

First, we can take advantage of the Undo mechanism. It gives us a good hook to capture the actions of the user at a pretty high level.

There is a class SnoopingCommandHandler that we can use to 'wrap' access to our REAL command handler, and record events as they go by. It has a Snoop method you override, and which will be called with each action in-turn.

So then when you want to start recording, you install your subclass of SnoopingCommandHandler and when you are done recording, you re-install the OLD one.

Now the only catch is, how do you interpret the Command* argument to Snoop. This is what I must think out further. You can do a dynamic_cast to figure out which sort of command is being done, and peek at its internals, and take your own 'notes' as to what the action was. But this is somewhat inelegant, and would only work for some commands (the ones you've bother to reverse-engineer, and directly support). But you can do it now, with Led the way it is.

A better approach would be if all the command objects could themselves be externalized. Depending on customer demand, I may add support for this to a future Led release. If these command objects could be externalized, you could store their externalized forms in a vector, and re-apply them (and store them in a file), as you liked.

Right now, they are RAM-based objects, and cannot be counted on living past the end of the Snoop call.

Those of you needing this feature, I'd like to hear back your reactions, what solutions / workarounds you've found, and/or how much you need this 'externalization of Command objects' feature.


012. Do Led arrays, marker positions etc start at zero? Or at one? What is qLedFirstIndex?

Answer:

In very early versions of Led, indexing was done base 1. That is to say, that the first marker position in a buffer, etc, was 1, not zero.

As of Led 2.2, I introduced a #define qLedFirstIndex which could be used to allow a programmer to use Led either with one-based indexing or zero-based indexing. This was mostly as a transitioning tool.

That is now obsolete. Led now directly uses STL instead of many of the Led-specific templated container classes it used to use. And it entirely assumes indexing is done zero-based, as is standard practice in the C++ world.


013. Does Led support MBCS? What do I need to do to handle other character sets?

Answer:

Which MBCS character set? That's a key question.

Here's the history. Led 1.0 was developed for SJIS, for a Japanese product. So as of 1.0, it fully supported Japanese editing. That means, all the basics of Led use wrapper functions on navigating through strings.

Since 1.0, Led has not continued supporting SJIS.

If there is any particular MBCS character set you want to support, here is what you must do:

The above are all fairly minor. The biggest issue is that Led's basic design doesn't well support mixed strings of different character sets. Nor dynamically noticing what the default character set is for a computer, and just using the rules for that.

Instead - Led's solution to the internationalization problem is to support UNICODE. See the UNICODE FAQ (#24) for more details.


014. How do I use Led with an AppWizard-generated application? How do I convert an app which used CRichTextEdit to use Led?

Answer:

Led has a tutorial showing just how to do this.


015. How long does it take to learn Led?

Answer:

The answer to this question depends heavily on what it is you are trying to do with Led, and to what level of detail you want to learn Led. It also depends enormously on what experience you bring to bear dealing with C++-based class libraries.

Led makes extensive use of powerful C++ features like multiple inheritance, templates, constructor/destructor based resource allocation, and so on. If these concepts are familiar to you already, you will have a huge leg-up on understanding Led.

Also, a significant part of Led is devoted to dovetailing with the particular class libraries you are using (MFC or PowerPlant). The better your understanding of these libraries, the better prepared you will be to understand how to use Led.

For a reasonably savvy programmer, expect it to take two days to get a good sense of how Led works, and to build some of the sample code, and try some of the tutorials. Expect one week to learn all you need to know to accomplish most common sorts of Led-based applications. And about two weeks to become intimately familiar with Led - to the point where you can easily extend it, and customize it to meet your needs.

Please understand these are rough guidelines. Your mileage my vary. But if your mileage does vary, I'd like to hear about it it. Send mail to info-led@sophists.com with any feedback you have on how long it took you to learn Led (and any hints on what could be done to make the learning easier), for the benefit of other future users.


016. Linker Errors? What modules are needed? What modules depend on what?

Answer:
Nearly all of Led requires: Line editing editors also require: Word Processor: At least one of (depending on which you use - both if you use both) Frequently used by apps - to get these optional facilites: Use if it applies to your platform:

017. Why is my Led-based application so slow? LedIt! and the other shareware sample programs seem much faster? What is qDebug? What is qHeavyDebugging?

Answer:

Led is very heavily instrumented with debugging code. As a programmer, this is for your benefit. It means that if you improperly use one of Led's APIs, you will be notified immediately, at the point of incorrect use, and immediately shown what assumptions you have violated. This can make it much easier for you to detect, and correct bugs in your usage of the Led class library.

But all the extra instrumentation, and internally consistency checking takes time. Not enough to be noticable on smaller files, but enough to become a problem on files larger than 10-20K.

Some of Led's instrumentation is more oriented towards finding bugs in the code of programs using Led. Some is more oriented towards finding bugs in Led itself (though these two DO overlap in a gray area).

Because different Led users have different needs, as of Led 3.0, Led's debugging support is now controlled by two different variables.

All of Led's debugging is turned off/on by the qDebug compile time flag.

It is recommended that while you are developing, you leave the Led debugging code turned on. And that you turn it off for release builds. You may also need to turn it off for at least some of your stress testing. This is your choice, and best determined by experience.

You can turn off some of Led's more time consuming, and less valuable error checking with the qHeavyDebugging compile time flag. Though this flag is off by default. But it is turned ON in the sample Led applications (e.g. LedIt!, LedLineIt! etc). So if you've cloned those application projects - you may want to turn this off.


018. Will Led work with version XYZ of compiler ABC? MSVC? Metrowerks Code Warrior? Gnu CC? Borland C++? Others?

Answer:

IDEs, and compilers are constantly changing. Led only fully supports, and is tested with the latest versions of the supported compilers and IDEs at the time of Led's release. But I leave in bug workarounds for recent (the last year or two's versions) versions. In the case of MSVC - I actively support MSVC 6.0.

Led 3.0 was built and tested against:

To use earlier versions of these compilers, consider either reviewing the bug workaround defines in earlier versions of Led (say 2.3). Or manually figuring out for yourself what bugs in the old compilers need to be worked around with Led, and make defines accordingly in LedConfig.h.

Led users are actively encouraged to develop using Led and the latest available compilers, and IDEs.

To use OTHER compilers, from other vendors, I just don't know. Led is written in portable C++ code. So in principle, it should work fine with any compiler. The reality, however, is that different compilers have different quirks and bugs. This is exacerbated by Led's aggressive usage of modern C++ features like templates that are not extremely well supported among compilers.

I support these compilers because they represent the overwhelming majority of C++ programming users. If there is any demand, Sophist Solutions may support additional compilers.


019. Can I tell the Led control to draw it's contents at given coordinates on a device context (Win32), GrafPort (MacOS), or drawable (X-Windows)?

Answer:

Yes. This can be done directly using any Led text editor class.

More simply, you don't even need to use a Led control (with a window object). You can use Led's TrivialImager template or TrivialWordWrappedImager to wrap any of Led's TextImager classes, and draw directly into a tablet/grafport, any text you like.

For example, you could use the

	void	SomeAppDrawCall (Led_Tablet t, const Led_Rect& r, bool printing)
	{
	    TrivialImager<SimpleTextStore,SimpleTextImager< (t, r, LED_TCHAR_OF ("Hi mom")).Draw ();
	}
	void	SomeAppDrawCall_WordWrapped (Led_Tablet t, const Led_Rect& r, bool printing)
	{
	    TrivialWordWrappedImager<SimpleTextStore, WordWrappedTextImager> (t, r, LED_TCHAR_OF ("Hi mom")).Draw ();
	}
	

Or - even more simply - you could use the GetTextExtent template, or the DrawTextBox API. These roughly mimic the Mac TextBox () routine or the windows DrawTextEx (). For example, you could use the

	void	DrawTextCenteredAndWrapped (Led_Tablet t, const Led_Rect& r)
	{
		Led_tString	x	=	LED_TCHAR_OF ("Hi mom");
		Led_Size		s	=	GetTextExtent<WordWrappedTextImager,SimpleTextImager,SimpleTextStore>  (t, x, r, true);
		Led_Rect		smallerRect=	r;
		Led_Distance	oldRWidth	=	r.GetWidth ();
		smallerRect.left += (oldRWidth - s.h) / 2;
		smallerRect.right -= (oldRWidth - s.h) / 2;
		Led_Distance	oldRHeight	=	r.GetHeight ();
		smallerRect.top += (oldRHeight - s.v) / 2;
		smallerRect.bottom -= (oldRHeight - s.v) / 2;
		DrawTextBox<WordWrappedTextImager,SimpleTextImager,SimpleTextStore> (t, x, smallerRect, true);
	}
	


020. Is the data saved truly platform independent (Mac/Windows)? What formats does Led support? Microsoft Rich Text Format?

Answer:

Yes.

Led supports a number of different file formats, nearly all nearly totally platform independent.

Led can Read and Write:

And Led can Read-Only these formats:

021. Do customers experience many problems on either platform?

Answer:

My customer feedback has always been extremely positive. I offer a 30-day money back guarantee, to help deal with customers for whom Led doesn't meet their needs or expectations.

I should point out that I do 90% of my work/testing on the Windows platform. This is simply because that's where 90% of my customers are targeting. The Macintosh and UNIX platforms are somewhat less well tuned (especially in the form of sample code) than the Windows version, just because of the smaller market size those platforms have.

The only place where I can think of where this lack of full support for the Mac and UNIX shows through at all, is that the sample application (LedIt!) for windows has a ruler UI, where the Mac and UNIX sample applications do not. But the underlying class library supports the ruler functionality perfectly on all platforms.


022. How do I implement soft page breaks in Led?

Answer:

First, I'm not 100% sure what is mean by soft page breaks. I'll begin by defining what I think is meant. And then go on to say how I think it can be best implemented in Led.

I believe a soft page break is a visual display on the screen, which marks where the page would be broken if the given document were printed. This is not a user specified location (see hard page breaks). But rather - its location is computed on the fly depending on the text above (and fonts etc).

A soft page break is usually drawn visually as a light gray horizontal line, extending across the window.

Implementing soft page breaks is somewhat tricky, because you must compute things about the text using a very different Led_Tablet than the one used for imaging on the screen. Luckily - Led has full support for maintaining multiple concurrent views onto the text, which makes this much easier.

So the first step is to create another 'View' (duplicate of your Led TextImager subclass) which has set as its Led_Tablet the Printer DC (or grafport if you use a Mac). Then - you must create a vector of page break locations associated with this view (via a subclass of the view class probably). Then - write a routine which walks through the entire buffer of text and calculates line-heights and break points (this is really quite easy if you know anything about Led - see the existing printing code in Led - perhaps - as an example).

Now - one trick is that this could be quite expensive (time wise). And must be recomputed on the fly, as the text changes. Here is where Led's support for multiple views onto the same data comes is really handy.

You just write code - either using multithreading, or an idle task, which computes maybe a single page at a time of page-break information. Keep extra instance variables that tell how far you've navigated through the text computing page breaks, so your idle task knows where to start/end each time. And override the DidUpdateText() method, so that you can invalidate these soft page break cached values.

So - as you edit - in the background - your alternate mirror view is recomputing page break information, and maintaining cached row-height information for both the current screen version of the text and the printer version simultaneously.

Then - all you must do is modify your Draw() method for your main, drawing view (or perhaps its EraseBackground () method), to draw the dotted 'soft-page-break' separator line as appropriate.

Note - this is probably a solid day or two's work for a good engineer who is already very familiar with Led. A future version of Led may incorporate classes to make this nearly trivial. See spr#0607 for more details. And also maybe the FAQ entry on "How do I implement hard-page-breaks in Led?".


023. How do I implement hard-page-breaks in Led?

Answer:

First, let me say that I'm not quite sure what is meant by a 'hard page break'. But this is what I think is meant:

A hard page break is one which is user-inserted. That is - its an object the user inserts into a stream of text to tell the computer that when printing this page, be sure to force a page break at this point, regardless of whether all the whitespace on the page has been used up (vertically).

This is related vaguely to the question of "soft page breaks" dealt with in another FAQ (22). But this is much easier to support.

A soft page break can be easily implemented as a Marker object which subclasses from SimpleEmbeddedObjectStyleMarker. Override the appropriate methods of this class to make the embedding as wide as a page (roughly - a little less). And make its height variable: depending on the situation.

When the embedding is queried its height from a context which is printing, it will respond a VERY big number, so as to force a page break. And in this context, its draw method does NOTHING. Thus, it breaks the page, when its encountered printing.

When the embedding is encountered displaying to the screen, it returns a modest few pixels in height, and as I said - a large width (almost a screenful wide). Then its draw when imaging to the screen is - whatever you'd like - but typically a light gray - perhaps dashed horizontal line.

I have not personally tried this, but at least one Led customer has, and successfully. It is fairly easy todo.

There are some other related issues you may want to tackle as well. Reading and writing these markers to and from RTF files is often desirable, and not currently directly supported by Led. But again - this is an easy thing to add to your own Led RTF reader/writer subclasses.

Note - A future version of Led may incorporate this functionality in support classes. See spr#0609 in the ChangeLog for more details. And also maybe the FAQ entry (22) on "How do I implement soft page breaks in Led?".


024. Does Led support UNICODE?

Answer:

Led 3.0 now fully supports UNICODE (Windows only). Macintosh and UNIX will be supported in an upcoming release.

Led supports two different ways of getting UNICODE support.

Full UNICODE
In the Win32 SDK, you can define the command line flag -D_UNICODE, and then you are building a UNICODE application. Led fully supports this. And all Led's sample programs can be built this way (the MSVC projects have a built-in configuration for this).

However - this approach does have a serious limitation. Programs built with -D_UNICODE will not work on Win9x. They will only work on WinNT 4.0, Win2000, Windows XP or later. Note - this is NOT a Led limitation; but rather a limitation of the Win32 SDK and Microsoft's implementation.

Led provides what is informally dubbed 'Internal UNICODE' support to address this limitation.

Internal UNICODE

Internal UNICODE support means that you're application is not considered a UNICODE application. But (nearly) all of Led's internal data structures are UNICODE based, and Led calls only the UNICODE APIs which work properly on ALL the various varieties of Win32 platforms (save Win32s if anybody even remembers that :-)).

When Led is built for 'Internal UNICODE', it decides at runtime whether its running on Win95/Win98 or WinNT, and it applies the appropriate OS bug workarounds for imaging UNICODE text on each platform (well - NT is fine but the others badly broken).

For people who want the internationalization capabilities you get from UNICODE, but must continue to work with Win9x - Led's 'Internal UNICODE' support is the choice for you.

Turning it on

All the Led sample programs have pre-built configurations that show how to build the various sorts of UNICODE versions of Led. But briefly:

For more information

To understand better how Led implements UNICODE internally, and how you can build applications or libraries that can easily target either "Full" or "Partial" UNICODE, or some other character set, see Led_tChar or Led_SDK_Char for more details.


025. In the text "hello" with the text 'he' is marked with a special marker and 'llo' is marked with another tag, how do I specify when I start typing which marker is the one to be expanded?

Answer:

First start by reviewing the documentation about Marker?s.

The short answer - is the one with "llo".

Markers are defined by points BETWEEN characters. And so when you position the cursor between two characters, and have a marker at that same position, the characters typed at that position go into the FOLLOWING marker.

This is not always convenient. Its convenient about 95% of the time. For the rest of the time - override AboutToUpdate/DidUpdate () methods - either on the marker - or MarkerOwner - to adjust the bounds of markers you want to behave differently.

As an example of this sort of thing - consider looking at StandardStyledTextInteractor. Note that in LedIt! - you can click on a text boundary between bold (on the left) and plain (on the right). And Led will pick up the style on the left side and extend it to the right (counter to how I explained markers behave naturally).


026. How do I implement showing hidden characters in Led? Like end-of-paragraph markers, tabs, etc?

Answer:

New in Led 3.0, there are APIs which allow you to easily control this display feature.

Note that these routines are built on a new, general purpose facility in Led -


027. Why am I getting an assertion error in the ChunkedArrayTextStore or ChunkedArrayMarkerOwnerHook destructors? What happens if I forget to remove some Markers from a TextStore?

Answer:

The piece of code which adds a Marker object to a Led TextStore is the one responsible for REMOVING it from that TextStore. Led respects this rule. It should rarely cause this assertion error. If it does - its probably because some Led module which creates markers itself has not yet been destroyed, even though the TextStore its pointing into now has been.

For example, if you created a MarkerCover<> associated with a particular TextStore - and then destroyed the TextStore without first disassociated (or destroying) the MarkerCover - you could run into this problem.

Just as likely - you will find that you've created your OWN markers for some purpose - and perhaps forgot to remove them from the TextStore?

The ChunkedArrayTextStore's representation is not terribly easy to walk through in the debugger. If you find yourself debugging a situation in which you are getting this assertion error, and you cannot easily see what kind of markers your forgetting to delete - you may wish to REPLACE your usage of ChunkedArrayTextStore with that of SimpleTextStore.

SimpleTextStore is much easier to understand, and much easier to walk its data structures to look at the stored Marker objects. Its only drawback is that its much slower (but for debugging a problem like this - that is rarely an issue).


028. Why is it slow adding text to Led, very small chunks at a time? How can I make my Led-based application add text and markers faster?

Answer:

First - review FAQ #17 about qDebug and qHeavyDebugging as this is the most likely cause of performance problems. But if your past that - this may be an issue.

Every time you make any modification to the Led text, a huge number of checks and tests are done to preserve consistency among various databases of attributes and caches.

Just how many of these various attributes and caches Led is maintaining depends greatly on what Led features you are using.

In LedLineIt! - there are few: mostly just the line-ending Partition objects. In LedIt! - there are many more: including the StandardStyledTextImager::StyleDatabaseRep, and the WordProcessor::ParagraphDatabaseRep.

All this code for maintaining these databases is highly tuned and very fast. But no matter how fast the code is, it is boundless how much text you can have under Led's control, and how much you may want to be adding at any particular time. When you push this envelope - and want to get the best performance possible, you may want to take advantage of a few tricks.

In order to allow Led to avoid recomputing cached values and checking consistency too often - you want to try to arrange for writing fewer, larger chunks of text to Led's TextStore at time, rather than more smaller chunks.

This can generally be accomplished rather easily by providing a layer of code between where your text is coming from and the Led TextStore, and caching up successive addition requests, and then finally flushing them all at once.

That is what is done internally in the class StandardStyledTextInteractor::StandardStyledTextIOSinkStream - for example. That's why Led's RTF file reading is so fast. RTF consists of many very small chunks of text, mixed with attributes. This class acts as an intermediary, and writes all the text at once (or much of it in big chunks).

You may be able to directly use this 'StandardStyledTextInteractor::StandardStyledTextIOSinkStream' class, or the similar WordProcessor::WordProcessorTextIOSinkStream. If not - you can at least look at how they work, and replicate the design pattern in your own code.


029. Does Led have any memory leaks? How does qAllowBlockAllocation affect memory leaks?

Answer:

Led has no known memory leaks. But there is a feature Led uses internally - which can trigger false-positives from memory leak detectors. That is - Led's use of the Led_BlockAllocated < T > template. This template is an important performance tool Led uses internally. You shouldn't disable it lightly. But you may wish to temporarily disable it while checking for memory leaks by shutting of the qAllowBlockAllocation compile-time configuration variable.


030. How do I make Led recalculate linebreaks? I have some code which goes through the paragraph db and changes margin values but linebreaks aren't updated.

Answer:

AboutToUpdate/DidUpdate - is the short answer.

Look at:
StandardStyledTextInteractor::AddEmbedding_ () or SimpleTextStore::Replace () for simple examples how how to handle this.

The slightly longer answer is that you must somehow arrange for MultiRowTextImager...InvalidateCache () and related methods to get called. The best way to do that is the AboutToUpdate()/DidUpdate mechnism - explained above.


031. How do I upgrade between Led 2.3 and Led 3.0 How do I adapt my existing applications?

Answer:

Led is being actively developed, and is constantly evolving. Features are being added. Existing features are re-engineered to make them faster, more flexible, or to make them fit better with other new, emerging technologies (ActiveX, new C++ features, STL, etc).

For the most part, this is good. But it does require incompatible changes to Led's APIs, occasionally. Considerable effort is made, however, to minimize the impact of these changes. Where possible, one release worth of backward compatibility is conditionally compiled into Led classes. You can turn on this backward compatibility by defining the qSupportLed23CompatAPI flag.

Led isn't the only thing programmers have to deal with which is constantly evolving. IDEs, and compilers are constantly changing as well. As is covered in FAQ #18, Led only fully supports, and is tested with the latest versions of the supported compilers and IDEs at the time of Led's release.

Step by step upgrade instructions:
  • Cleanly convert to use of Led 2.3. For help on this, you may review (see FAQ #32 for help on this).
    That means don't depend on any 2.2 or earlier compatibility within Led 2.3, such as the qSupportLed22CompatAPI flag).
  • Convert your project files to new IDE
    See FAQ #18 for details on supported compilers/IDEs.
  • define qSupportLed23CompatAPI in Precomp.pch (or stdafx.h, or MSVC60 settings dialog or whatever you prefer)
  • Try to build (compile) your project.
  • If you are building from the Mac, and using a project based on an old version of PowerPlant, you will have gotten lots of errors in your build (e.g. Char16 undefined). Define PP_Uses_Old_Integer_Types to 1 in Precomp.pch to work around this. Later - once things compile - you should fix your application to use the new typenames, and eliminate this define from Precomp.pch.
  • (LedIt! only)If you have the define qExtraWordWrapDebugging specified (usually in the project settings for CPP), then change this to qHeavyDebugging
  • (LedIt! Win32 only)If you have any calls to GetMargins ()/SetMargins (), make sure the use the type Led_TWIPS instead of Led_Distance. For example, in LedItView::GetParaFormatSelection () - change the lines:
    	Led_Distance	lhsMargin		=	0;
    	Led_Distance	rhsMargin		=	0;
    	Led_Distance	firstIndent	=	0;
    
    to:
    	Led_TWIPS	lhsMargin		=	Led_TWIPS (0);
    	Led_TWIPS	rhsMargin		=	Led_TWIPS (0);
    	Led_TWIPS	firstIndent	=	Led_TWIPS (0);
    
  • (LedIt! Win32 only) Because of quirks (bugs) with the MSVC include files and MFC, and because of the fact that some Led header files #include <windows.h> (perhaps indirectly) - you may need to include <afxwin.h> before the Led includes in LedItDocument.cpp (and perhaps others of your files).
  • (LedIt! Win32 only) If you override InternalizeBestFlavor () - you must change your code significantly. It maybe you can simply DELETE your override, as it may no longer be needed. If it is needed, you must override the MakeDefaultInternalizer() method instead, and create your own subclass of WordProcessor::WordProcessorFlavorPackageInternalizer (or whatever was being built by your base class) and subclass that (which is where you now override the InternalizeBestFlavor). If you use WordProcessorCommonCommandHelper_CLASSLIB - as described below - this is done for you automatically. In the case of the LedItView::InternalizeBestFlavor override, it can simply be deleted.
    NB: for pasting of OLE embeddings to work with LedIt! 2.3 sample code - you must do one of these.
  • (LedIt! Win32 only) Calls to AddEmbedding () require an extra argument - the StyleDatabase. So for example, in the LedItView::OnInsertObject () call to AddEmbedding () - append the final argument GetDocument ().GetStyleDatabase () as in:
    	AddEmbedding (pItem, GetTextStore (), GetSelectionStart (),
    		GetDocument ().GetStyleDatabase ()
    	);
    
  • (LedIt! Win32 only) To fix the LedIt! sample code, fix RulerToolbar.cpp: RulerBar::Update delete calls to Led_CvtToTWIPSH and Led_CvtFromTWIPSH () (replace the calls with their argument). In call RulerBar::FillInParaFormat ()- replace Led_CvtFromTWIPSH with Led_TWIPS where we append to the vector 'v' and make the type of vector v vector. And a few other places replace Led_CvtFromTWIPSH () with its Led_TWIPS conversion.
  • (LedIt! MacOS only) In FilteredFilePicker.cpp add includes:
    Change:
    	#include	<Controls.h>
    	#include	<ControlDefinitions.h>
    
    to the top of the file (to address the fact that PopupPrivateData was undefined).
  • (MacOS only) In LedLineItApplication.cpp, LedLineItApplication::HandleMacOSException ()
    Change:
    	LedLineItDocument*	theDoc	=	NULL;
    	while (iterator.Next (theDoc)) {
    		Led_AssertMember (theDoc, LedLineItDocument);
    		theDoc->PurgeUnneededMemory ();
    	}
    
    to:
    	LDocument*	theDoc	=	NULL;
    	while (iterator.Next (theDoc)) {
    		Led_AssertMember (theDoc, LedLineItDocument);
    		LedLineItDocument*	d	=	dynamic_cast<LedLineItDocument*> (theDoc);
    		d->PurgeUnneededMemory ();
    	}
    

    NB: For LedIt! on MacOS - you must make the virtually identical fix - except for removing the string "Line" is obvious places, making LedLineIt become LedIt.

  • (MacOS only) In LedLineItDocument.cpp, LedLineItDocument::DoPrint ()
    Change:
    	thePrintout->SetPrintRecord(mPrintRecordH);
    
    to:
    	thePrintout->SetPrintSpec (mPrintSpec);
    

    NB: For LedIt! on MacOS - you must make the virtually identical fix - except for removing the string "Line" is obvious places, making LedLineIt become LedIt.

  • (MacOS only)Add/Remove files to/from project for new PowerPlant compatability
    Add: And Remove:

    This really has nothing todo with Led changes, but that the sample applications for the Mac which came with Led 2.3 were built with an older PowerPlant, and these changes are to reflect and accomodate he PowerPlant changes.

  • (MacOS only)React to operator new () changes in MetroWerks runtime.

    The Mac Led demo applications pull some tricks with the MetroWerks runtime library to make the memory allocations come from 'temporary memory'. These hacks have changed since the last CodeWarrior release

    To disable the hacks done with LedItPP 2.3 and LedLineItPP 2.3:

    That should allow your code to compile and work properly - though without the 'temporary memory' hacks. To re-enable those hacks - see how they are now done in the Led 3.0 LedIt! or LedLineItPP sample programs.

  • (LedLineIt! MacOS only) In LedLineItView.cpp
    Add the include
    #include	<cctype>
    
    to the top of the file (to fix the error about isspace() not being defined).
  • (LedLineIt! only) In LedLineItView.cpp, LedLineItView::CTOR ()- fTabStopList (of type SimpleTabStopList) now takes a required argument. Change:
    	fTabStopList ()
    
    to:
    	fTabStopList (Led_TWIPS (1440/3))
    
  • (LedLineIt! only) SimpleTabStopList::fPixelsPerTabStop ==> fTWIPSPerTabStop
    Change:
    	fTabStopList.fPixelsPerTabStop = kCharsPerTab * GetFontMetricsAt (0).GetMaxCharacterWidth ();
    
    To:
    	Tablet_Acquirer	tablet_ (this);
    	Led_Tablet		tablet	=	tablet_;
    	fTabStopList.fTWIPSPerTabStop = tablet->CvtToTWIPSH (kCharsPerTab * GetFontMetricsAt (0).GetMaxCharacterWidth ());
    
  • (LedLineIt! only) Changed signature of TextInteractor::OnTypedNormalCharacter ()
    In LedLineItView.cpp, change
    	void	LedLineItView::OnTypedNormalCharacter (Led_tChar theChar)
    	{
    		inherited::OnTypedNormalCharacter (theChar);
    
    To:
    	void	LedLineItView::OnTypedNormalCharacter (Led_tChar theChar, bool optionPressed, bool shiftPressed, bool commandPressed, bool controlPressed, bool altKeyPressed)
    	{
    		inherited::OnTypedNormalCharacter (theChar, optionPressed, shiftPressed, commandPressed, controlPressed, altKeyPressed);
    
  • Consider using new TextInteractorCommonCommandHelper_XXX or WordProcessorCommonCommandHelper code to implement new shared code for supporting commands. See the LedIt! sample code for an example. But basically, you copy the struct LedItViewCMDINFO and LedItViewCommandInfo declarations. Then inherit from WordProcessorCommonCommandHelper_MFC . (or _PP if you are using PowerPlant).

    This isn't strictly necessary, but can be helpful since it provides pre-canned implementations of a number of useful commands (such as Select All).

    Please look at the sample code in LedLineItMFC, LedLineItPP, or LedIt for an example of how to integrate those helper classes into your code.

  • Summary:

    Note that these steps were tried successfully when applied to the versions of LedIt and LedLineItMFC, which shipped as part of Led 2.3. The applications compiled and worked fine (with Led 3.0).


    032. How do I upgrade from very old versions of Led to Led 2.3?

    Answer:

    Sophist Solutions doesn't directly support converting from versions older than Led 2.3 to the current version of Led. Depending on how much coding you've done with Led, you maybe better off just jumping into the conversion blindly, or by incrementally upgrading to each version in succession.

    Without suggesting that upgrading to each successive version is the best way, we can still provide some instructions (based on previous FAQ's) on how to go about this.

    Converting to Led 2.1 from Led 2.0 or earlier:

    No instructions are available right now for this. Contact Sophist Solutions technical support if you need help with this.

    Converting to Led 2.2 from Led 2.1:
    Step by step upgrade instructions:
  • Cleanly convert to use of Led 2.1.
    That means don't depend on any 20 or earlier compatibility within Led 2.1, such as the 20 .hh files).
  • Convert your project files to new IDE
    Led 2.2 requires Metrowerks Code Warrior Pro 1 (CW1Pro) on the Mac, and MSVC 50 for Windows.

    Led 2.2 may work with other compiler versions, but no guarantees are made. Each compiler revision has changed a number of things/quirks.

  • define qSupportLed21CompatAPI in Precomp.pch (or stdafx.h, or MSVC50 settings dialog or whatever you prefer)
  • Add PartitioningTextImager.cpp, TextInteractorMixins.cpp, and WordProcessor.cpp to the project file.

    You should find that your application now builds properly using Led 2.2.

    Once you have verified that your application works properly with Led 2.2 in backwards compatibility mode, you should turn off that qSupportLed21CompatAPI flag, and trying building again.

    For the most part, compiler diagnostic messages should make clear what changes you need to make. That, coupled with reviewing what the qSupportLed21CompatAPI define turned off/on.

    You can also review the Led ChangeLog to see in detail what changed from Led 2.1 to Led 2.2. Search for <OLDCODENOTE> for changes which I judged likely to affect Led 2.1 programs being upgraded to Led 2.2.

    The only subtle change you should be aware of in turning off qSupportLed21CompatAPI is that this changes qLedFirstIndex to zero. If your code has lots of assumptions about Led being one-based, you may choose to manually define qLedFirstIndex yourself. But you would probably be best off updating your code to be zero based, as that may be all that Led supports in the future.

    Converting to Led 2.3 from Led 2.2:
    Step by step upgrade instructions:
  • Cleanly convert to use of Led 2.2 (see above).
    That means don't depend on any 2.1 or earlier compatibility within Led 2.2, such as the qSupportLed21CompatAPI flag).
  • Convert your project files to IDE which Led 2.3 was built/tested against:
  • In your project file, replace LineBasedTextImager.cpp with LineBasedPartition.cpp
  • In your project file, replace StyledTextInteractor.cpp (if it exists) with StandardStyledTextImager.cpp and StandardStyledTextInteractor.cpp
  • If your project contains "Auxiliary Packages" in the include path (or some subdirectory), then change that string to "AuxiliaryPackages" (no space). Similarly in the link information, for extra libraries.
  • define qSupportLed22CompatAPI in Precomp.pch (or stdafx.h, or MSVC60 settings dialog or whatever you prefer)
  • Try to build (compile) your project.
  • If you find that you get the link error:
    	LedLibrary.lib(Led_MFC.obj) : error LNK2001: unresolved external symbol "public: static char const * const  RTFIO::RTFOLEEmbedding::kEmbeddingTag" (?kEmbeddingTag@RTFOLEEmbedding@RTFIO@@2QBDB)
    .\Debug/LedLineIt.exe : fatal error LNK1120: 1 unresolved externals
    	
    then you must either include StyledTextIO.cpp into your project, or - more likely - define qSupportOLEControlEmbedding to be 0 (OFF).
  • If you find that you get the compiler error:
    l:\leditmfc22test23\sources\leditview.cpp(1122) : error C2440: 'initializing' : cannot convert from 'class std::vector<class SimpleEmbeddedObjectStyleMarker *,class std::allocator<class SimpleEmbeddedObjectStyleMarker *> >' to 'class Led_Array'
            No constructor could take the source type, or constructor overload resolution was ambiguous
    	
    Then change the source code from using Led_Array<>; Instead use vector<>.
    	Led_Array<SimpleEmbeddedObjectStyleMarker*>	embeddings	=	CollectAllEmbeddingMarkersInRange (selStart, selEnd);
    	if (embeddings.GetLength () == 1) {
    	
    then becomes
    	vector<SimpleEmbeddedObjectStyleMarker*>	embeddings	=	CollectAllEmbeddingMarkersInRange (selStart, selEnd);
    	if (embeddings.size () == 1) {
    	
  • You should find that your application now builds properly using Led 2.3.

    Once you have verified that your application works properly with Led 2.3 in backwards compatibility mode, you should turn off that qSupportLed22CompatAPI flag, and trying building again.

    For the most part, compiler diagnostic messages should make clear what changes you need to make. That, coupled with reviewing what the qSupportLed22CompatAPI define turned off/on.

    You can also review the Led ChangeLog to see in detail what changed from Led 2.2 to Led 2.3. Search for <OLDCODENOTE> for changes which I judged likely to affect Led 2.2 programs being upgraded to Led 2.3.

    Note that these steps were tried successfully when applied to the versions of LedItMFC and LedLineItMFC, which shipped as part of Led 2.2. The applications compiled and worked fine (with Led 2.3).

    Converting to Led 3.0 from Led 2.3:

    See FAQ #31 for details.


    Return to Led Page Return to Led Class Library Documentation Index
    Last Updated 2001-10-19