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.
There are two different approaches you may consider.
Both leverage the
TextStore/Marker/MarkerOwner AboutToUpdate/DidUpdate
mechanisms.
If you have some easy mechanism already built (not using Marker
s) to check
what region of text must be read-only, then this maybe your easiest approach.
MarkerOwner
s 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!
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
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).
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!
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.
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.
Led has a tutorial showing just how to do this.
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.
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.
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.
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.
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.
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).
Led has a tutorial showing just how to do this.
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.
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.
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.
Led has a tutorial showing just how to do this.
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.
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.
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.
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);
}
Yes.
Led supports a number of different file formats, nearly all nearly totally platform independent.
Led can Read and Write:
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.
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?".
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?".
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.
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 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.
All the Led sample programs have pre-built configurations that show how to build the various sorts of UNICODE versions of Led. But briefly:
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.
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).
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 -
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).
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.
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.
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.
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.
qSupportLed22CompatAPI
flag).
qSupportLed23CompatAPI
in Precomp.pch (or stdafx.h, or MSVC60 settings dialog or whatever you prefer)
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.
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);
AddEmbedding (pItem, GetTextStore (), GetSelectionStart (),
GetDocument ().GetStyleDatabase ()
);
#include <Controls.h>
#include <ControlDefinitions.h>
to the top of the file (to address the fact that PopupPrivateData was undefined).
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.
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.
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.
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:
qUseMacTmpMemForAllocs
to 0
(i.e. shut the feature off) in PreComp.pchDebugNewValidateAllBlocks
.
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.
#include <cctype>
to the top of the file (to fix the error about isspace() not being defined).
fTabStopList ()
to:
fTabStopList (Led_TWIPS (1440/3))
fTabStopList.fPixelsPerTabStop = kCharsPerTab * GetFontMetricsAt (0).GetMaxCharacterWidth ();
To:
Tablet_Acquirer tablet_ (this);
Led_Tablet tablet = tablet_;
fTabStopList.fTWIPSPerTabStop = tablet->CvtToTWIPSH (kCharsPerTab * GetFontMetricsAt (0).GetMaxCharacterWidth ());
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);
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.
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).
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.
No instructions are available right now for this. Contact Sophist Solutions technical support if you need help with this.
Led 2.2 may work with other compiler versions, but no guarantees are made. Each compiler revision has changed a number of things/quirks.
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.
qSupportLed21CompatAPI
flag).
qSupportLed22CompatAPI
in Precomp.pch (or stdafx.h, or MSVC60 settings dialog or whatever you prefer)
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).
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).
See FAQ #31 for details.