home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
DP Tool Club 26
/
CD_ASCQ_26_1295.iso
/
vrac
/
tvme30.zip
/
MANUAL.DOC
< prev
next >
Wrap
Text File
|
1995-08-02
|
230KB
|
4,590 lines
Virtual Memory Text Editor Classes
For Turbo Vision
(Shareware Edition)
Eric Woodruff
16719 Lakeside Drive
Medical Lake WA 99022
Copyright (c) 1994, Eric Woodruff
All rights reserved
CompuServe ID: 72134,1150
Internet: 72134.1150@compuserve.com
Version: 3.00
Released: Wed 08/02/95
Compilers: Borland C++ 3.1 to 4.xx
Turbo Vision: 1.03 or 2.0
Description
===========
These classes are intended as a total replacement for the default
Turbo Vision editor classes TEditor, TMemo, TFileEditor, TEditWindow,
and TIndicator. While the basic Turbo Vision editor classes are a
good start for basic editing, I found them to be seriously lacking for
larger jobs. The biggest problems are a size limit of 64K, a tendency
to consume more memory than required, a lack of some necessary editing
features such as word wrapping and printing, limited undo/redo
capabilities, and I had a hard time in general deriving a new editor
class that would accomplish what I needed.
I had kicked around the idea of doing another editor for Turbo
Vision for ages and actually made a start by trying to make the
existing code use virtual memory. To be blunt, that was a total PITA
and I gave up after a couple of tries. After several months, I
finally came back to the project with a different approach altogether
and TVMEditor finally became reality.
The class definition and code used for the editor are radically
different and were written from scratch. However, I did try to keep
the class variable names, constants, #defines and, where possible, the
function names the same. I started out with the basic editing
functions found in the original TEditor and, as I am inclined to do,
found all kinds of other features that could be added or improved
upon. As this editor bears no relation to the original TEditor, be
aware that a number of variables and functions where dropped from the
class definitions because they no longer had purpose. I have also
made some of the functions inline or virtual as I deemed necessary and
there are a number of additions that aren't found in the original.
TVMEditWindow, TVMFileEditor, and TVMMemo, do not differ too much
from the originals although they benefit from several enhancements
that I will describe later on. Of the three, TVMMemo is the most
different in usage, but those differences greatly expand its
flexibility and capabilities.
Instantiating a TVMEditor-type object should not be all that
different from instantiating a TEditor-type object. The constructors
are fairly similar, but there are extra parameters available. Most of
those have default values and may not need to be specified anyway.
There is a demo program included, so it should give you a good idea of
how they can be used.
As I said to start with, these classes are complete replacements
for their original counterparts. They *cannot* be used in conjunction
with their original TEditor ancestors due to the duplication of some
constants' names and/or reassignment of values. The duplication of
names was intentionally done to provide some compatibility with any
existing code that uses TEditor.
Because of the restriction of mixing the old and new classes, I
have packed as much functionality and flexibility as possible into the
basic editor classes. I hope you will find as I have that the basic
editor classes will serve a multitude of applications without the need
to derive new classes from them except for very specialized purposes.
I have created editor classes that only overcome the limitations of
the originals that I could find. Others may still see limitations in
these ones that I do not. If you think something is lacking, let me
know and I will try to add the missing capability. However, bear in
mind that this is not intended to replace any commercial text editors
or word processors. It is simply intended to provide a solid base for
drop-in text editing that can be used in your applications for
whatever purpose you need.
In short, here are some of the new capabilities: Can use virtual
memory (EMS + disk or XMS + disk), implements buffer sharing for
instances editing the same file, can load more than 32,767 lines,
extended editing capabilities, separate global and local editor
options, enter matching, find matching, jump to specific/relative
line, bookmarks, soft tabs or hard tabs with variable size, a choice
of persistent or non-persistent marked block, all new search and
replace capabilities, basic and automatic word wrapping, paragraph
reformatting, reformat on window resize, and lots more. Complete
details can be found below for each class.
DISCLAIMER
==========
I have made every effort to test this code and insure that there
aren't any bugs. However, I'm not infallible. I'm pretty sure I've
got all the problems worked out but, as with any other software:
THIS SOFTWARE AND MANUAL ARE DISTRIBUTED "AS IS" AND WITHOUT
WARRANTIES AS TO PERFORMANCE OF MERCHANTABILITY OR ANY OTHER
WARRANTIES WHETHER EXPRESSED OR IMPLIED. BECAUSE OF THE VARIOUS
HARDWARE AND SOFTWARE ENVIRONMENTS INTO WHICH THIS PRODUCT MAY BE PUT,
NO WARRANTY OF FITNESS FOR A PARTICULAR PURPOSE IS OFFERED. THE USER
MUST ASSUME THE ENTIRE RISK OF USING THE SOFTWARE. I WILL NOT BE
RESPONSIBLE FOR ANY DAMAGE OR LOSS OF TIME, DATA, HARDWARE, OR
SOFTWARE YOU INCUR THROUGH USE OF THIS PRODUCT.
Copyrights
==========
I must state now that two of the classes used by this library,
TVMPoint and TVMScrollBar, are derived directly from copyrighted
Borland code and are only a little different from the original source.
The only changes made were to enforce usage of type long values for
the editor's expanded line range.
I make no claim of ownership or copyright to the code in those two
files (specifically TVMPOINT.CPP and TVMSBAR.CPP) and to comply with
Borland's licensing agreement *WILL NOT* distribute the source code in
those two files. However, *I HAVE* supplied the necessary
instructions to recreate those files. The changes involve some simple
replacements and a couple of additions and are easy to do. To
recreate the files, you will need the source files TPOINT.CPP and
TSCRLBAR.CPP from the original Turbo Vision 1.03 or 2.0 though. If
you do not have the source code to Turbo Vision 1.03, I have included
the necessary .OBJ files that can be used to rebuild the libraries.
All other source code associated with the package is of my own
creation and was designed and written entirely by me. I retain all
rights to all other files.
Borland C++ 3.1, Borland C++ 4.0 through 4.51, Turbo Vision 1.03,
Turbo Vision 2.0, and PowerPack for DOS are trademarks of Borland
International
The SemWare Editor (TSE) and QEdit are trademarks of the SemWare
Corporation
Files you should receive in TVME30.ZIP
======================================================================
HISTORY.DOC - History of changes to the TVMEditor library and
documentation for any last minute changes.
MANUAL.DOC - TVMEditor class library documentation (this file)
ORDER.DOC - Registration, technical support, and order form
KEYHELP.DOC - Keyboard command help text used for the memo demo
TVBC4BUG.DOC - Describes a Turbo Vision 1.03 bug that needs fixing
to make Turbo Vision 1.03 work properly with BC++
4.xx.
TVMEDIT.H - TVMEditor class library header file
TVMEDIT.??? - Library containing the editor functions:
TVMEDIT.BC3 - BC++ 3.1/TV 1.03
TVMEDIT.BC4 - BC++ 4.xx/TV 1.03
TVMEDIT.TV2 - BC++ 4.xx/TV 2.0
Rename one of these files to TVMEDIT.LIB before
compiling the demo.
LINK.H - __link() definition header file for the demo
TVEDIT.H - Application header file for the demo
TINTFILE.H - TInteger and TFilename class header for the demo
TVCOLR.??? - Color definitions header file (See notes later on)
HEAPVIEW.H - Header file for the heap viewer
TMSGVIEW.H - Header file for the message viewer window
HEAPVIEW.CPP - Heap viewer class for the demo
TFILENM.CPP - Filename input line for the demo
TINTEGER.CPP - Numeric input line for the demo
TMSGVIEW.CPP - Message viewer window to demonstrate the cmSetLine
command for the editor demo
MAPCOLOR.CPP - An alternate TView::mapColor() for the TVCOLR.H stuff
BLDRSC.CPP - Resource file builder for the demo
TVEDIT1.CPP - Demo editor routines
TVEDIT2.CPP - Demo editor routines
TVEDIT3.CPP - Demo editor routines
TMACRO.CPP - Demo editor simple event macro recorder/player
TV20DPMI.DEF - Default module resource definition file for TV 2.0
DPMI apps
DEMO.MAK - Make file for the demo executables and resource file
TVEDIT.EXE - The demo editor application
TVEDIT.RSC - The resource file for the demo editor
TVECLEAN.COM - TVMEditor EMS clean-up utility
If your copy is incomplete or out of date, you can always find a
full, up to date copy in the BCPPDOS forum on CompuServe in the Turbo
Vision library (Section 11).
Class Hierarchy Diagram
-----------------------
Below is a class hierarchy diagram for the new TVMEditor library
classes. Although similar in most cases, TVMMemo is now derived from
TVMFileEditor instead of TVMEditor. This gives it some additional
capabilities not present in the basic TVMEditor class. Also, TVMPoint
and TVMScrollBar have been added due to the expanded line capacity of
the editors.
┌─────────────┐
│ TView │
└┬───┬───┬───┬┘
/│\ /│\ /│\ /│\
│ │ │ │
┌─────────────────────┘ │ │ └──┐
│ ┌───────┘ │ │
┌─────┴─────┐ ┌──────┴───────┐ │ ┌───┴────┐ ┌─────────────┐
│ TVMEditor │ │ TVMIndicator │ │ │ TGroup │ │ TWindowInit │
└─────┬─────┘ └──────────────┘ │ └───┬────┘ └─────┬───────┘
/│\ │ /│\ /│\
│ ┌─────┘ │ │
┌──────┴────────┐ ┌───────┴──────┐ └──────┬──────┘(virtual)
│ TVMFileEditor │ │ TVMScrollBar │ │
└──────┬────────┘ └──────────────┘ ┌────┴────┐
/│\ │ TWindow │
│ └────┬────┘
┌────┴────┐ /│\
│ TVMMemo │ │
└─────────┘ ┌───────┴───────┐
│ TVMEditWindow │
└───────────────┘
┌──────────┐
│ TVMPoint │
└──────────┘
┌──────────────────┐
│ TVMFindDialogRec │
└──────────────────┘
┌─────────────────────┐
│ TVMReplaceDialogRec │
└─────────────────────┘
┌─────────────┐
│ TVMMemoData │
└─────────────┘
**
** ATTENTION!! PLEASE READ THIS!
**
** Please be aware of the fact that most of the constants and
** definitions below duplicate the existing names found in Borland's
** EDITORS.H file. I did this intentionally so that the names would
** be familiar and so that entirely new command values didn't have to
** be created. Many of the duplicate names have the same value
** assigned to them as in EDITORS.H but many others don't.
** As long as you don't define Borland's Uses_TEditor,
** Uses_TFileEditor, Uses_TEditWindow, Uses_TMemo, Uses_TIndicator,
** Uses_TReplaceDialogRec, or Uses_TFindDialogRec you shouldn't get
** any compiler errors.
** Instead, you should be using the equivalent Uses_TVMxxx
** definitions for TVMEDIT.H because these classes are all intended
** as a complete replacement for the Turbo Vision editor classes.
** The two should not be mixed. Given the advantages offered by this
** set of classes, there should be no reason to mix them anyway.
**
Definitions and Constants
-------------------------
-----------------
TVMEDITOR_VERSION
TVMVERSION_STRING
-----------------
These define the version number for the TVMEditor classes.
Currently, they are defined as 0x0300 and "3.00" respectively.
---------------------------------
const ushort kbCtrlLBrkt = 0x1A1B
---------------------------------
This constant defines the Ctrl+[ (left bracket) key code value for
the default Find Matching command key. There was no equivalent in
Turbo Vision's TKEYS.H file so it had to be defined here.
-----------------
ufXXXXX constants
-----------------
These constants serve the same purpose as in the original TEditor
classes. They indicate how much of the view should be drawn the next
time a screen update is performed (scrollbars and indicators, one or
more lines, or the entire view).
-----------------
smXXXXX constants
-----------------
These constants are used internally by the editor classes to keep
track of the current block marking mode (none, block key (^Kx),
Shift+Movement keys, mouse drag, whole line mouse drag).
-----------------
cmXXXXX constants
-----------------
These, of course, define all available commands for the editor
classes. The constants in the range 80 to 90 (cmSave to cmReSynch)
are in Turbo Vision's reserved command range of 0-99 and can be
disabled if necessary. Some of these already existed in the original,
but there are some new ones. Note that some of the constants are
conditionally defined only when using Turbo Vision 1.03. This is
because Turbo Vision 2.0 added these commands to its default set and
they no longer need to appear in TVMEDIT.H.
The constants in the range 500 and up are in Turbo Vision's
reserved command range of 256-999 and are not allowed to be disabled.
They represent the commands for editing text and other such
operations. A majority of the existing command names have new values
and are grouped with the new commands into two sets: Commands that are
destructive and commands that are non-destructive. Destructive
commands are ignored when the editor is in read-only mode to prevent
alterations to the text..
-----------------
edXXXXX constants
-----------------
These constants define the message types that can be handled by
the editorDialog() function. The first eight message types (0-7) will
be handled by the default editorDialog() function if you decide not to
define one of your own. Those commands are considered fatal or at
least worthy of mention to the user. Messages numbered 8 through 22
are optional and will be ignored by the default editorDialog()
function. Commands associated with those message types will be
unavailable to the user.
By making your own version of editorDialog() handle these events,
you can add the associated functionality to your application's editors
and memo fields. See the documentation for the TVMEditor data member
'editorDialog' and the section on Command Operation and Implementation
for more information.
-----------------
efXXXXX constants
-----------------
These constants define the available editor options in effect such
as Insert Mode, Auto Indent, Word Wrap, etc. efInsertMode through
efOverWriteBlocks are local options, efExpandTabs through efUseLFOnly
are global options, and efReadOnly through efUseCSH are classed as
"Other". Local options are inherited from the defaults structure when
a new editor is created. Global options are common to all editors.
The options marked as "Other" are inherited like local options, but
probably should not be user-modifiable. The intent of those options
is to set them at start up and leave them set. The efUseCSH option
bit is the exception as it can be toggled via a broadcast command to
enable or disable color syntax highlighting (requires the derived
editor class found in CSH 1.00).
The Enter Matching and Auto EOL options are also inherited at
construction and are local to each editor. The Search and Replace
efXXXXX constants are always considered global options. They affect
all editors that use them. A complete description of each option can
be found in the TVMEditor Local and Global Options section of this
manual.
---------------------------------
maxLineLength and maxSearchString
---------------------------------
maxLineLength defines the maximum length of an editor line. As in
the original, it is set to 256. maxSearchString defines the maximum
length of a search and/or replace string. As in the original, it is
set to 80.
-------------------------------------------
typedef ushort (*TVMEditorDialog)(int, ...)
ushort VMdefEditorDialog(int dialog, ...)
-------------------------------------------
These define the typedef for editorDialog() functions and the
function prototype for the default editorDialog() handler. The
default handler will display a simple error message dialog box for
errors below and including the value of the constant edGeneralMsg.
These are considered important because they generally indicate an
error condition of some sort. The message displayed is in the form:
TVMEditor Error #nn occurred
The number displayed can be matched up to one of the edXXXXX
constants in TVMEDIT.H
--------------------------------------------------------------------
enum SignsOfLife { slInitiate, slReporting, slHide, slShow, slDone }
--------------------------------------------------------------------
This enumerated type defines the different states that the
signsOfLife() function can be called to handle. slInitiate is used to
intialize the signs of life event. slReporting is called periodically
to issue the "signs of life" event. slHide and slShow are not
implemented by the default editors but they can be used by you to hide
or show any dialog box that may be on screen. An example of their use
may be to hide the signs dialog while you stop for user input or some
other such event and then resuming the operation that uses the signs.
slDone is used to let the Signs of Life function know that the
operation is complete and it can get rid of any dialog box or other
items it may be using.
---------------------------------------------------------------------
typedef void (*TVMSignsOfLife)(SignsOfLife, ushort, long, long);
void VMdefSignsOfLife(SignsOfLife, ushort, long, long);
---------------------------------------------------------------------
These define the typedef for signsOfLife() functions and the
function prototype for the default signsOfLife() handler. The default
handler will not do anything. You must define your own in order for
it to do something useful. A simple but effective Signs of Life
handler can be found in the demo program. See the manual section on
Signs of Life for more information on this feature.
---------------------------
extern "C" {
char *unique_name(char *s);
}
---------------------------
The unique_name() function was added to replace calls to the
tmpnam() standard language library function. This was done to prevent
disk access to the default drive during construction of the virtual
memory object. Regardless of where the file would reside, tmpnam()
always checked the default drive for existing filenames which proved
to be irritating if it was a floppy drive. The new function will not
access any drive and is capable of generating a unique eight character
filename that won't repeat for at least 3.55 years down to the
hundredth of a second. This is a standalone function unrelated to any
class. It may be used to generate a unique filename for any part of
your application if so desired. Just pass it a pointer to a buffer
that can take at least nine characters (8 for the filename and 1 for
the NULL terminator). It will return the pointer that you pass it.
-----------------------------
extern "C" {
void AllocateDescriptor(void)
}
-----------------------------
This function is only available when using the 32-bit protected
mode version of the library. It will allocate a descriptor for
TVMEditor::lowMemDesc and register an exit function to deallocate it
at program end. In 32-bit protected mode, accessing the BIOS keyboard
flags is not as simple as it is in real mode or 16-bit protected mode.
To simplify the process, this function was added. The TVMEditor
constructor will call this function whenever a new editor is
instantiated. If a descriptor has not already been allocated, it does
so. If one has been allocted, it simply returns. See the description
of TVMEditor::lowMemDesc for more information.
--------------------------
struct TVMFindDialogRec
struct TVMReplaceDialogRec
--------------------------
These two structures define the items found in the "Find" and
"Find and Replace" dialog boxes that can be used by the editorDialog()
function for the cmFind and cmReplace command events. As a rule, you
will not use them directly. The editor class itself will format them
with the necessary values and pass them to the editorDialog() function
for you to handle. The demo program contains an example of this. See
TVEDIT2.CPP.
The TVMPoint and TVMScrollBar Classes
-------------------------------------
These two classes are identical to their normal counterparts
TPoint and TScrollBar. The only difference is that they have been
reimplemented using type long values internally. This was done in
order to support the expanded line range of the editor classes. These
two classes are used when dealing with line oriented information
(vertical scrolling, line range limits, line number references,
column-row coordinates, etc).
You normally won't be using TVMPoint, but it is possible that you
might use a TVMScrollBar when adding a memo field to a dialog box. In
such cases, you construct it just as you would the normal TScrollBar
used for horizontal scrolling. Just pass it a TRect() defining its
boundaries.
The TVMIndicator Class
----------------------
╔══════════════════════════════════════════════════════════════════════════╗
║ * 999999:255 │A W250 H16 T !│Ovr│CAPS│Num│ScLk│<------message area------>║
╟──────────────────────────────────────────────────────────────────────────╢
│ │ │ │ │ │ │ │ │ │ │ │ │ └─── Message display area
│ │ │ │ │ │ │ │ │ │ │ │ └──────── Scroll Lock on
│ │ │ │ │ │ │ │ │ │ │ └──────────── Num Lock on
│ │ │ │ │ │ │ │ │ │ └───────────────── CAPS Lock on
│ │ │ │ │ │ │ │ │ └───────────────────── Overwrite/insert mode
│ │ │ │ │ │ │ │ └──────────────────────── Swap to virtual memory
│ │ │ │ │ │ │ └────────────────────────── Trailing spaces kept
│ │ │ │ │ │ └──────────────────────────── Current tab width
│ │ │ │ │ └────────────────────────────── Hard/soft tabs
│ │ │ │ └───────────────────────────────── Word wrap right margin
│ │ │ └─────────────────────────────────── Word wrap mode on
│ │ └───────────────────────────────────── Auto-indent mode on
│ └─────────────────────────────────────────── Cursor Line:Column
└─────────────────────────────────────────────────── * = Modified (0Fh),
R = Read-Only,
Blank = Not modified
This indicator will be inserted on a full width line either above
or below the text editing region within the borders of a
TVMEditWindow. It displays the various options in effect for the
associated editor. You can also use it for TVMMemo fields. In such
cases, you can create the bounds such that the indicator occupies a
full line as it does in a TVMEditWindow or shorten its right boundary
so that it displays only the column and row information similar to its
original TIndicator ancestor. The demo program has examples of both.
Indicator Flags
---------------
If the text is read-only, the Modified indicator will be a
flashing "R". It will flash to be more visible. That way, the user
won't try typing or deleting text and think it has locked up when
nothing happens. If not a read-only editor, the space will remain
blank until the text is modified. At that time, a star will appear
(0x0F character).
Note that there is room for a type long line value. TVMEditor and
its derived classes can handle more than 32,767 lines. Given the type
long value, the number of lines in a file is only limited by available
virtual memory. Columns are limited to a maximum of 255 as before.
When the Auto Indent Marker is displayed, pressing ENTER will
cause the cursor to line up under the first non-blank character of the
previous line. When not enabled, the cursor always goes to column 1
when ENTER is pressed.
The right margin value is used for word wrapping and line
centering. When the 'W' for Word Wrap Mode is not displayed, no word
wrapping is performed and the right margin only has an effect for the
Center Lines command. When Word Wrap is enabled, text will be word
wrapped at the specified right margin. The right margin can be set to
any value from 20 to 250 in the demo. Note that standard word wrap
mode is indicated by a lower case 'w'. In this mode, full paragraph
reformatting only occurs when manually done via the Ctrl+B keypress.
If automatic word wrapping is enabled (the efAutoWrap bit is set),
automatic word wrapping and paragraph reformatting will occur as you
type. In this mode, inserting text or deleting characters will
reformat text from the current cursor line forward as far as is
needed. In standard word wrap mode (efAutoWrap is not set), an
uppercase 'W' is displayed and wrapped text moves to the next line but
subsequent lines are left alone.
Hard Tab means that a physical 0x09 character is inserted into the
editor when the Tab key is hit. These tabs will cause the display to
change if the tab width is modified after loading the file. Soft tabs
are just an appropriate number of spaces inserted at the time the Tab
key is hit. After the tab type indicator, the number of spaces a tab
represents is displayed. This value can be set to any number from 2
to 16 in the demo. When Tab or Shift+Tab is hit, the cursor will be
moved to the appropriate tab stop. There is also a load-time option
that will convert hard tabs to spaces when the file is initially read
into the editor.
If Trailing Spaces is turned on, any trailing spaces and/or tabs
at the end of the lines will be retained. This is the way the
original TEditor worked. If turned off, any trailing spaces and tabs
will be stripped from the end of the line. There are other benefits
to having this turned on or off. See below for further information on
this feature.
The Swap Marker will appear as soon as the editor starts swapping
text to virtual memory. When blank, it indicates that the file is
entirely within the editor's conventional memory buffer. When the
0x12 character (looks like up and down arrowheads) is displayed, data
is being swapped to XMS. When the 0x17 character (looks like up and
down arrowheads with an underline) is displayed, data is being swapped
to EMS. For the protected mode libraries, the 0x17 symbol simply
means that swapping is occurring (there is no concept of EMS or XMS
memory in protected mode, it's just conventional memory). When the
0x1D character (looks like left and right arrowheads) is displayed,
data is being swapped to EMS/XMS and disk or disk alone if EMS/XMS was
not available for use. For the protected mode libraries, it means
that no more conventional memory could be allocated so it is using a
disk swap file. I used this marker so that I could see where data was
going during development.
Note that it is possible for a file to use enough EMS or XMS
memory that it eventually starts swapping to disk but a newly opened
file will display the marker indicating EMS/XMS usage. This is due to
the way that the editor class extends its memory block via a
Reallocate Pages/Block function call to the EMS/XMS handler. The same
thing applies to the protected mode versions.
Ins/Ovr indicates the current insert state of the editor. When
Ins is displayed, any typed text is inserted into the line at the
current position. When Ovr is displayed, typed text overwrite data at
the current cursor position. Also, while in overwrite mode, the
Tab/Shift+Tab keys function as positional keys and simply move the
cursor forward or backward by the given tab size. When in insert
mode, the appropriate hard or soft tab will be inserted or deleted.
When displayed, CAPS and Num indicate that the CAPS and/or NumLock
keys are toggled on. This is displayed purely for your information
and serves no other purpose but to remind you of their current state.
If the proper code is added to an overridden TApplication::idle()
function, these indicators can be updated immediately whenever the
CAPS or NumLock keys are pressed. This is done with a broadcast
message event. If the proper code is not present, these two
indicators will not get updated until something happens to cause a
redraw of the view (type text, switch windows, etc). The demo program
has an example of an overridden TApplication::idle() function.
The ScLk (Scroll Lock) indicator is used in a similar fashion.
For TVMFileEditor, it is purely informational. However, for the
TVMMemo class it does have meaning. When the ScLk indicator is
displayed (on), Tab and Shift+Tab will operate within the memo edit
window to insert or delete hard/soft tabs. When ScLk is not displayed
(off), Tab and Shift+Tab will change the focus from one item to the
next in the dialog box as it always has. Thus, with the TVMMemo
class, you do not have to use spacebar instead of the Tab key if you
don't want to.
The section marked <message area> currently has two possible
settings. <TwoKey> is displayed when the first key of a two-key
sequence is pressed (i.e. ^K of the two-key command <^KB>) and
<Literal> is displayed when the Literal command key is pressed
(default: ^P). The message disappears once the second key is pressed.
These messages appear to alert you to the fact that another key press
is needed to complete the command just selected. Pressing ESC while
one of these messages is displayed will effectively cancel the
command. The exception is Literal, which inserts the next keypress
received as a literal character. In that case, the ESC key code
character 0x1B is inserted. This is easily erased with a press of the
Backspace key. There are also functions available that allow you to
display your own temporary message or set a default message that is
displayed in place of the normal blank area.
Data and Function Members
-------------------------
---------------------------------------
TVMPoint Location
Boolean ShowReadOnly, UseMemoColor, Modified;
ushort Opts
short RightMargin, TabSize, Swapping
char Message[80]
---------------------------------------
These data members track the current values of each of the
indicator's different display fields. ShowReadOnly and UseMemoColor
relate to the extra parameters passed to the constructor.
----------------------
const char *DefaultMsg
----------------------
This pointer can be used to set up a default message for display
in the message area of the indicator. At construction, it will be set
to NULL (a blank message area). It can be changed using the
setDefaultMessage() member function to point to a different string
that indicates something meaningful to your applications such as a
mode or state that the editor object is in for longer than a key press
or two. An example of this might be a terminal object with a
scrollback mode. When in scrollback mode, the default message could
be set to something like <ScrollBack> to let the user know it is
enabled. Any temporary text stored to Message[] will be displayed
when needed, but once cleared, it returns to showing the default
message string pointed to by this data member. When you are done with
the default message, call setDefaultMessage(NULL) to go back to a
blank message area. An editor's indicator pointer is a protected data
member. However, you can still set a default message via the
TVMEditor access function setDefaultMessage. For example:
anEditor->setDefaultMessage("A message")
--------------------------------------------------------
TVMIndicator(const TRect &bounds, Boolean ShowRO = True,
Boolean IsForMemo = True);
--------------------------------------------------------
The constructor is like the old TIndicator with the exception of
the extra parameters ShowRO, and IsForMemo. The ShowRO parameter is
used to determine whether or not the "R" is displayed when the
associated editor's text is read-only. In situation where it can be
assumed that the text is read-only (in an informational dialog for
example), you can pass this parameter as False so that the flashing
"R" does not appear. By default, it will be True so that if the text
is read-only, the user will be notified by the indicator. The
IsForMemo parameter determines what color from the indicator's palette
will be used to draw the view. There are two separate colors for the
indicator. One is for edit windows and the other is for memo fields
in a dialog box. This was done because I found that the color used
for edit windows didn't always look good in a dialog box. By default
it is True so that the parameter doesn't have to be specified when you
create a TVMMemo's indicator for a dialog box. Since TVMEditWindow
creates the editor's indicator automatically, you probably won't have
to alter or specify this parameter at any time.
---------------------------------------
void setDefaultMessage(const char *msg)
---------------------------------------
As noted above, this function can be used to establish a default
message that is displayed in the message area. Such messages will not
be cleared until you call setDefaultMessage() again with a new message
or NULL to clear it. Note that temporary messages displayed with the
setMessage() command take precedence and will be displayed instead.
As soon as the temporary message is cleared, the default message is
shown again.
---------------------------------------------------------------
void setValue(const TVMPoint &aLocation, Boolean aModified,
ushort aOpts, short RMargin, short TabSz, short SwapStatus)
---------------------------------------------------------------
This function is called internally by the owning editor to update
the indicator with its current settings.
--------------------------------
void setMessage(const char *msg)
--------------------------------
This function is called internally by the owning editor to update
the indicator with a flag message such as <TwoKey> or <Literal>.
The TVMEditWindow Class
-----------------------
╔═[ ]═════════════════════ FILENAME ═════════════════════[ ]═╗
║ * 999999:255 │A W250 H16 T !│Ovr│CAPS│Num│ScLk│<indicator at top ...> ^
║ Text editing region below the indicator. ░
║ ░
║ ░
║ V
╚═<░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░>──┘
╔═[ ]═════════════════════ FILENAME ═════════════════════[ ]═╗
║ Indicator below the text editing region. ^
║ ░
║ ░
║ ░
║ * 999999:255 │A W250 H16 T !│Ovr│CAPS│Num│ScLk│<... or at the bottom > V
╚═<░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░>──┘
This is simply a window that contains a TVMFileEditor object and
its associated indicator and scrollbars. It differs from the standard
Turbo Vision TEditWindow in that you can pass it a Boolean specifying
the indicator position, a buffer size (in KILOBYTES not just bytes),
and a flag to optionally suppress the loading of the file text until a
later time. A suppressed load is useful in situations where you need
to do something special (change the swap file location or name, etc)
prior to the text being loaded. The window's handleEvent() will also
respond to a cmEditorPresent broadcast event by returning its 'this'
pointer in the TEvent event.message.infoPtr member. This is useful
for detecting the presence of an editor for other application
operations.
As in the original, the window constructor creates the indicator,
scrollbars, and editor. However, due to the fact that the editor can
handle over 32,767 lines, a specially created scrollbar (TVMScrollBar)
is inserted for the vertical scrollbar. It is identical to a normal
scrollbar, but can handle type long values.
Another minor difference between my edit window and the original
is that I turn on the ofTileable option bit and turn off the
ofBuffered option bit during construction. Disabling buffering of the
view saves quite a bit of memory when there are multiple editor
windows open. If screen flicker is a problem, you can always add the
line:
EditWin->options |= ofBuffered;
before inserting the edit window into the desktop. For the systems
that I have worked with (386's and up), this hasn't been a problem.
Data and Function Members
-------------------------
---------------------
TVMFileEditor *editor
---------------------
This is a pointer to the file editor object that is contained
within the edit window.
--------------------------------------------------------------------
TVMEditWindow(const TRect &bounds, const char *aFileName,
int aNumber = 0, Boolean IndAtTop = True, short bufSizeInK = 20,
Boolean SuppressLoad = False)
--------------------------------------------------------------------
This is the constructor for the TVMEditWindow class. As you can
see, the first three parameters match up to the original TEditWindow
class. Following those are three additional parameters that you may
or may not want to specify. Each has a default value, so it isn't
necessary to specify them unless you want to alter the default
behaviour.
IndAtTop If passed to the constructor as True (the default),
the edit window will insert the indicator line just
below the top window border. If passed as False, it
will insert the indicator just above the bottom
window border.
bufSizeInK This parameter specifies (in Kilobytes) how large
the conventional memory buffer will be for the
editor object. This buffer is used to hold the
recently used text and internal information
necessary for editing the file. By default, it is
20K. This provides enough of a buffer for editing
large files with reasonable speed and swap
efficiency. If you will be editing smaller files or
have ample virtual memory in the form of EMS or XMS
memory, then you can drop this amount down to
further reduce the amount of conventional memory
used by each editor instance.
SuppressLoad If passed in as False, the specified file will be
loaded immediately into the editor. If passed in as
True, the load operation will be suppressed until a
later time. This is useful for situations where you
might want to perform some special operation such as
altering the default swap file name, etc before
allowing the editor to load the text. In such cases,
a call to the EditWindow->editor->loadFileNow()
function will be required to make the editor load
the text.
-------------------------------------------
virtual const char *getTitle(short maxSize)
-------------------------------------------
This function returns the title of the window and, in effect, the
filename that the window's editor contains. If the window is for the
clipboard, it will return the title pointed to by the 'clipboardTitle'
data member. If the window contains an unnamed file, it will return
the title pointed to by the 'untitled' data member.
------------------------
virtual void close(void)
------------------------
Under normal circumstances, close() will simply call
TWindow::close() to shut down the window. However, if the window is
the clipboard, it simply hides itself.
---------------------------------------
virtual void handleEvent(TEvent &event)
---------------------------------------
This overridden handleEvent() function will recognize and act upon
the cmEditorPresent event to signal that there is an active editor on
the desktop. The window will only respond to the cmEditorPresent
event if it is not the issuer of the command and is not the clipboard.
The handleEvent() function will also issue a cmReformatAll event
to its editor when the cmZoom command is seen. That way, if the
window's editor has the efWrapOnResize option bit set, it will
reformat the text that it contains. Editors that have that option bit
disabled will ignore the event.
-------------------------------------------------
virtual void sizeLimits(TPoint &min, TPoint &max)
-------------------------------------------------
This function will limit the minimum size of any edit window to
six rows and twenty-five columns. This is done to prevent the window
from getting too small and obliterating its scrollbars.
The Editors
-----------
===========================================================
TVMEditor(const TRect &bounds, TScrollBar *aHScrollBar,
TVMScrollbar *aVScrollBar, TVMIndicator *aIndicator,
short bufSizeInK = 8)
TVMFileEditor(const TRect &bounds, TScrollBar *aHScrollBar,
TVMScrollbar *aVScrollBar, TVMIndicator *aIndicator,
const char *aFileName, short bufSizeInK = 20,
Boolean SuppressLoad = False)
TVMMemo(const TRect &bounds, TScrollBar *aHScrollBar,
TVMScrollbar *aVScrollBar, TVMIndicator *aIndicator,
short bufSizeInK = 1, const char *aFileName = NULL)
===========================================================
These are similar in nature to their standard Turbo Vision
counterparts. However, they are passed the size of the buffer
expressed in KILOBYTES (not just bytes). They are also passed a
TVMScrollBar to handle the added ability to have more than 32,767
lines in an editor. TVMFileEditor also has the option to suppress
loading of the text until a later time. You may also have noticed
that TVMMemo can be passed a filename. This will be discussed later
on. The following sections will describe each of the editor classes
in turn.
The TVMEditor Class
-------------------
TVMEditor is the root base class for TVMFileEditor and TVMMemo. A
full description of the available features is given below. All
features described for TVMEditor apply to TVMFileEditor and TVMMemo as
well.
Design and Implementation Notes
===============================
The new ideas and features found in the TVMEditor classes where
all taken from various sources (mainly QEdit and TSE (my two favorite
editors, both by SemWare) and the Borland C++ 3.1 IDE). I also saw a
number of messages in the BCPPDOS forum on CompuServe pertaining to
requested TEditor features. A majority, if not all, of the requested
features are now in there along with several excellent suggestions
from current users of the TVMEditor library.
For a number of the added features, I based the operating
characteristics on the above mentioned editors and my own personal
preferences. They should operate in a fairly similar manner to other
editors, but there may be slight deviations here and there. Word
wrapping and paragraph reformatting are two areas in which this is
particularly relevant. I've used editors that implement these in a
couple of different ways and I chose the methods I preferred.
Virtual Memory Support
======================
The editor was originally intended to only handle files in the
100K to 200K size range. As I designed and implemented the virtual
memory system that handles the text retrieval and storage, it evolved
from something that would handle those sizes into its current
incarnation that adapts to handle multi-megabyte files. I have tried
to make it as efficient as possible while still keeping its
conventional memory requirements to a reasonable minimum. As it
stands, you have the flexibility to specify how large or small the
conventional memory buffer is for each editor instance (as little as
1K or as large as 60K). Also, editors viewing the same file can share
a buffer reducing the amount of conventional memory required for each
editor after the first one by quite a bit. Virtual memory savings in
such a situation can also be quite substantial.
The virtual memory manager is in a class totally separate from the
editor classes. This allows the underlying manager to be written for
use with whatever type of memory it wants for storage (EMS, XMS, disk,
or a combination thereof) without having to alter the actual editor
class code or applications that use them. Changing virtual memory
managers for the end user is as simple as relinking with the
appropriate library or altering the preference option in the class
itself. You won't need a license to any third-party EMS/XMS
libraries. I built the necessary supporting code into the affected
functions with inline assembler.
A LIM 4.0 compliant memory manager such as 386MAX, QEMM,
EMM386.SYS, etc is required to use expanded memory for swapping. If
no such manager is present or it only supports a version less than LIM
4.0, the editor will start using XMS (if available) or disk space for
virtual memory when required.
An XMS 3.0 compliant memory manager such as 386MAX, QEMM,
HIMEM.SYS, etc is required to use extended memory for swapping. If no
such manager is present or it only supports a version less than XMS
3.0, the editor will start using EMS (if available) or disk space for
virtual memory when required. The XMS 3.0 Specification warns that at
least 256 bytes of stack space must be available for calls to the XMS
API functions. If problems are encountered, try increasing the value
of _stklen to provide a larger program stack.
For the 16-bit and 32-bit protected mode versions of the library,
memory is consumed until a user-definable limit is reached or until
the memory block cannot be reallocated to a larger size. At that
time, disk space will be used for additional memory as required.
The editors will not initiate virtual memory usage until the
contents overflows the conventional memory buffer. The contents of
the editor includes the actual text being edited, internal tracking
information, and undo/redo information. As stated, if there is no
available EMS or XMS memory, disk space is automatically used. If EMS
or XMS memory is available, the first type found is consumed as needed
until there is no more available (a reallocation attempt fails). At
that point, the editors will resort to using disk space to contain any
additional information. Note that each open editor will use one EMS
or XMS handle in the real mode versions. By altering the value of a
static data member of the virtual memory class used by the editors,
you can control what type of memory is used or given preference
(available from the registered version only).
In the protected mode versions of the library, EMS and XMS memory
are managed by the DPMI server as conventional memory. When compiled
for either 16-bit or 32-bit protected mode, the library will use a
different method of memory allocation. Virtual memory is allocated
via calls to GlobalAlloc(). Each editor will use one HGLOBAL type
handle. If conventional memory does run out, the editors will start
swapping to disk.
I obtained all of my information for EMS memory access from the
LIM 4.0 Specification document dated October, 1987 and, for XMS memory
access, from the XMS 3.0 Specification document dated January, 1991.
If you are interested, you can download the LIM 4.0 Specification
document from the LOTUSA forum (library 2, LIM40.ZIP) and the XMS 3.0
Specification document from the MSDOS forum (library 10, XMS30.TXT) on
CompuServe. They cover all the necessary details and available
function calls associated with each type of memory access.
A Note To The Impatient <g>
===========================
When working with a large file and you perform an operation such
as file insertion, large block edit operations such as delete,
reformat, case toggling, etc, or a large block undo/redo, it is
possible that the editor will appear to be doing nothing for an
extended period of time. This is especially true when EMS or XMS
memory is being used (or simply conventional memory in protected mode)
and when a disk cache is in use and the hard drive light isn't doing
anything. Such operations can take a minute or two to finish, so
don't think it's locked up when this happens. Give it a little time
to finish what it's doing. Also see the section on Signs of Life. It
was for this reason that I added this feature.
NOTE FOR DEBUGGING WITH EDITOR OBJECTS USING EMS
------------------------------------------------
Both the BC++ 3.1 IDE and Turbo Debugger (TD286.EXE in BC++ 3.1
and TD.EXE in BC++ 4.xx) may steal all available EMS memory at
start-up. Therefore, if you debug any application with the preference
set to use EMS memory, the editors will more than likely start
swapping to disk immediately or to XMS if any is still available.
During development, I used XMS memory or the protected mode libraries
most of the time. As a rule, there is usually some XMS memory
available so the editors can make use of that until it runs out. In
16-bit and 32-bit protected mode, there is also plenty of memory
available.
You can increase the amount of memory available to the real mode
editors though. Set the environment variable DPMIMEM to limit the
amount of EMS/XMS memory that TD uses:
SET DPMIMEM=MAXMEM xxxx
where 'xxxx' is the amount of memory in kilobytes.
Features List
=============
The basic TVMEditor and derived classes support the following
features:
* First and foremost, they support virtual memory and can therefore
load extremely large files. The theoretical limit is between 32
and 128 Meg (but don't hold me to it <g>). The maximum editable
size is determined by the conventional memory buffer size you
specify for the editor in the constructor. The virtual memory
manager will optimize its page size for that buffer. The page
size (1024, 2048, or 4096 bytes) multiplied by 32,767 yields
the maximum editable size.
* Because they can load large files, they also supports more than
32,767 lines in a file. The total number of lines is now limited
only by the amount of free virtual memory.
* They have all the basic editing features found in the original and
numerous extensions have been made to the basic movement and
editing keys. See below for a full list. Most key sequences are
the same but some are different. Most have been standardized
and/or grouped based on what I have seen other editors use.
* There is an added capability to alter or extend the keyboard
command sets without overriding convertEvent(). The arrays used
to hold the key sequences and their associated commands can be
swapped with a simple function call. By default, there is the
normal single key command set and four two-key command sets with
room to add up to four additional two-key command sets. If you
don't like the default command key mappings, you can change them
to suit your preferences.
* Additional editor option settings have been added and they have
been grouped into a global scope for use by all editors and a
local scope for use by each editor instance. Global options
affect all editors and local options affect only the editor they
belong to. Each new editor will inherit the currently defined
global options upon being opened.
* Line jump: Go to a specific line, +/- a number of lines, previous
line, last edited line, and 3 user-definable bookmarks.
* Hard and soft tabs with variable tab size. Also has the option to
convert hard tabs to soft tabs (spaces) at load time.
* Support for Enter Matching on (, [, {, ', ", and <. It can be
enabled or disabled for any or all of them through local option
settings.
* There is also support for Find Matching on (), [], {}, and <>
pairs starting on either character in the pair going in either
direction across multiple lines. Find Matching can also be done
for " and ' but the matching search will go in the forward
direction only and will be limited to the same line.
* The selected block of text can be persistent or non-persistent in
nature. A persistent block allows you to mark text and move away
from it without losing it. Either block type can be marked via
several different key sequences or the mouse. A marked block can
start and end at any point within a line and may also start and
end on the same line so as to mark only a few characters or words.
Block extension is also supported via Shift+Clicking the mouse.
* Improved search and replace options: Forward or backward within
selected text or the whole file, search from cursor or entire
scope (from one end of the file or selected text to the other).
Search rates range from less than 150K to more than 650K per
second depending upon the PC in use and the location of the
virtual memory (EMS/XMS or disk).
* Supports word wrapping, paragraph reformatting, character case
switching, line centering, and text alignment as needed. If no
block is selected, the current line is used as the block for
certain commands. This is useful when you only want to operate on
one or two lines.
* Additional Move Block and Copy Block functions were added that do
not require the clipboard. These are useful in situations where a
clipboard may not be available (i.e. a TVMMemo). Also, secondary
keypresses were defined so that the clipboard commands could be
used while debugging an application in the DOS IDE which tends to
trap the Ctrl/Shift+Ins/Del keypresses.
* Supports unlimited Undo/Redo.
* Supports color syntax highlighting when used in conjunction with
the derived editor class found in the Color Syntax Highlighter
add-on (currently CSH 1.00).
Default Editor Command Key Mappings
===================================
Below are the default command key mappings. For a lot of the
commands, there is a primary and secondary key sequence defined. The
editor gives no preference to either, and does not care which one you
use. The secondary key sequences generally represent a different
approach to getting around in the editor. The primary key sequences
are, in most cases, the most common method of issuing movement and
text editing commands.
The default key sequences associated with the commands, even if
they aren't the most likeable, should be familiar enough that most
people who have used an editor before can use this one. The command
key sets can be replaced to suit your personal preferences if so
desired. It's easy to do and doesn't require deriving a new editor
class. You define an array of command keys and command values and
call a function to replace a specific key map (more on that later).
Function Primary Secondary
---------------------------------------------------------------------
Movement:
Cursor Left <LtArrow> <^S>
Cursor Right <RtArrow> <^D>
Word Left <^LtArrow> <^A>
Word Right <^RtArrow> <^F>
Start of Line <Home> <^QS>
End of Line <End> <^QD>
Up Line <UpArrow> <^E>
Down Line <DnArrow> <^X>
Top of Window <^Home> <^QE>
Bottom of Window <^End> <^QX>
Roll Window Up <^W>
Roll Window Down <^Z>
Page Up <PgUp> <^R>
Page Down <PgDn> <^C>
Top of Text <^PgUp> <^QR>
Bottom of Text <^PgDn> <^QC>
Text Insertion/Deletion:
Delete Char at Cursor <Del> <^G>
Delete Char Left (Bkspc) <Backspace> <^H>
Delete Current Line <^Y>
Delete to Start of Line <^QH>
Delete to End of Line <^QY>
Delete Word Right <^T>
Delete Word Left <^Backspace>
Start a New Line <Enter> <^M>
Insert New Line <^N>
Tab Right (Hard/Soft) <Tab> <^I>
Tab Left (Delete Tab) <Shift+Tab>
Insert Literal Char <^P>
Restore Contents of Line <^QL>
Function Primary Secondary
---------------------------------------------------------------------
!Undo <Alt ->
!Redo <Alt =>
Block Commands:
@Mark Block Beginning <Shift+Movement Keys, Drag Mouse> <^KB>
@Mark Block End <Release Shift Key/Mouse Button> <^KK>
Hide Block <^KH>
*Copy Block to Cursor <^KC>
*Move Block to Cursor <^KV>
Delete Block <Ctrl-Delete> <^KY>
-Indent Block <^KI>
-Unindent Block <^KU>
Read Block from File <^KR>
Write Block to File <^KW>
~Print Block <^KP>
-Toggle Case in Block <^OO>
-Force Uppercase in Block <^OU>
-Force Lowercase in Block <^OL>
-+Center Lines in Block <^OC>
-Align Text in Block <^OA>
-Reformat Paragraph <^B>
Clipboard Commands:
Copy Block to Clipboard <Ctrl-Insert> <^JC>
Cut Block to Clipboard <Shift-Delete> <^JK>
Paste from Clipboard <Shift-Insert> <^JP>
The secondary clipboard key sequences were added for situations
where the primary key sequences can't be used (i.e. debugging in the
DOS IDE)
@ = With a block marked, Shift+Click and drag the mouse or use ^KB/^KK
to move the starting or ending position.
* = Non-clipboard move and copy.
+ = Lines are centered based on right margin value
- = Command works with current line only if no block is defined.
(Reformat Paragraph has special rules.)
~ = To print the entire file issue the command cmPrintFile (See demo
menu File | Print construction in BLDRSC.CPP)
! = Note to Super PCKwik users:
If you are using the keyboard accelerator, the default hot keys
for Repeat Rate Slower and Faster are <Alt -> and <Alt =>.
Either change them or hold down the Shift key while pressing
them to access Undo or Redo.
Function Primary Secondary
---------------------------------------------------------------------
Text Search/Replace:
Find Matching <^[> (Ctrl+Left Bracket)
Search for Text <^QF>
Search and Replace Text <^QA>
Repeat Last Srch/Replace <^L>
Search/Replace Options:
Case Sensitive Forward Global From Cursor
Whole Words Only Backward Selected Text Entire Scope
Prompt On Replace
Positional/BookMark
Set Bookmark 1-3 <^K><1-3>
Jump to line or +/- cnt <^JG>
Jump to Start of Block <^JB>
Jump to End of Block <^JE>
Jump to Bookmark 1-3 <^J><1-3>
Jump to Prev Position <^JV>
Jump to Last Change Line <^JL>
Mode Toggles & Other Options:
Insert/Overwrite Mode <Ins> <^OV>
Auto-Indent Mode <^OI>
Word Wrap <^OW>
Automatic Word Wrapping <^OM>
Word Wrap on Win. Resize <^OR>
Tab Style (Hard/Soft) <^OT>
Trailing Spaces <^OS>
Two-Key Commands By First Key
-----------------------------
^K - Block Mode Commands ^Q - Quick Keys
------------------------------ ------------------------------
Mark Block Beginning <^KB> Start of Line <^QS>
Mark Block End <^KK> End of Line <^QD>
Hide Block <^KH> Top of Window <^QE>
Copy Block to Cursor <^KC> Bottom of Window <^QX>
Move Block to Cursor <^KV> Top of Text <^QR>
Delete Block <^KY> Bottom of Text <^QC>
Indent Block <^KI> Delete to Start of Line <^QH>
Unindent Block <^KU> Delete to End of Line <^QY>
Read Block from File <^KR> Restore Contents of Line <^QL>
Write Block to File <^KW> Search for Text <^QF>
Print Block <^KP> Search/Replace Text <^QA>
Set Bookmark 1-3 <^K><1-3>
^J - Jump/Secondary Clipboard ^O - Options/Other
------------------------------ ------------------------------
Jump to Line or +/- cnt <^JG> Toggle Case in Block <^OO>
Jump to Start of Block <^JB> Force Uppercase in Block <^OU>
Jump to End of Block <^JE> Force Lowercase in Block <^OL>
Jump to Bookmark 1-3 <^J><1-3> Center Lines in Block <^OC>
Jump to Prev Position <^JV> Align Text in Block <^OA>
Jump to Last Change Line <^JL> Insert Mode <^OV>
Copy Block to Clipboard <^JC> Auto-Indent Mode <^OI>
Cut Block to Clipboard <^JK> Word Wrap <^OW>
Paste from Clipboard <^JP> Automatic Word Wrapping <^OM>
Word Wrap on Win. Resize <^OR>
Tab Style (Hard/Soft) <^OT>
Trailing Spaces <^OS>
Local Editor Options
====================
This section describes the various local options available to the
editor classes. Some of these have a representation on the indicator
line if one is present. All of these modes are local to each editor.
For example, in one editor view you may have a document file loaded
with word wrapping and insert mode enabled, but in another editor
view, you may have a source code file loaded with word wrapping and
insert mode turned off. As you switch between editors, these modes
come into effect for that view only and won't alter any mode for other
editing views that may be loaded.
Insert Mode (efInsertMode)
--------------------------
As always, when insert mode is on, any typed text will be inserted
into the current line. When insert mode is off, typed text overwrite
anything currently under the cursor. The current mode is displayed as
"Ins" or "Ovr" on the indicator line.
Auto Indent Mode (efAutoIndent)
-------------------------------
When auto indent mode is on, the cursor will line up under the
first non-blank character of the preceding line whenever the ENTER key
is pressed. When off, the cursor will always return to column 1 when
the ENTER key is pressed. Auto indent is useful for aligning blocks
of text. An "A" appears on the indicator line when it is on.
Word Wrap Mode - Enabled/Standard (efWordWrap)
Automatic Word Wrap (efAutoWrap)
----------------------------------------------
When entering text, it is nice to have the cursor automatically
advance to the next line when it passes the right margin. All of the
TVMEditor classes support word wrapping. A word wrap will occur only
when the cursor passes the right margin and a non-white space
character is typed. There must also be at least one full word
followed by a space prior to the right margin for word wrapping to
occur. When text is word wrapped, the cursor, the word being typed,
and any text following the cursor will be moved onto a new line. If
Auto Indent is on, the wrapped portion will also be indented by the
appropriate amount to align it with the line above.
Note that when automatic wrapping (efAutoWrap) is disabled, a
character other than a space or tab must be typed while the cursor is
past the right margin for the word wrap to occur. If you type in a
line and then go back to some point prior to the end of the line and
start typing again, the end of the line may be pushed out past the
right margin. That part won't get moved to a new line until you type
in some text that exceeds the right margin to cause a word wrap, press
ENTER, or issue the paragraph reformat command. Likewise, when you
delete text, line shorter than the right margin will not be joined
with text from subsequent lines.
When efAutoWrap is enabled, automatic word wrapping and paragraph
reformatting will occur as you insert or delete text. This option bit
makes the editor function more like a word processor. Inserting text
at any point in a line causes text past the right margin to word wrap.
Deleting text causes words from subsequent lines to be appended to the
shorter lines as required to bring them as close to the right margin
as possible. It's best to play around with these two options to see
which you prefer best.
When standard word wrapping is on (efWordWrap only), a lowercase
"w" will appear on the indicator line. When automatic wrapping is
enabled (efWordWrap | efAutoWrap), an uppercase 'W' appears on the
indicator line. In either case, the letter is followed by the
editor's current right margin setting. The right margin value is
controlled separately using another option setting. If both option
bits are turned off, no letter is displayed and no wrapping will
occur.
Wrap (Reformat) On Window Resize (efWrapOnResize)
-------------------------------------------------
The editor also supports complete text reformatting when the view
changes size. This is useful for file viewers which need to wrap the
text they contain to fit within the window if the user resizes it.
Note that this option is best used in conjuntion with the EOLMarker
data member to prevent text from being reformatted incorrectly (i.e.
title lines).
Trailing Space Retention (efTrailingSpaces)
-------------------------------------------
Trailing space is defined as any number of spaces or tabs that are
after the last non-blank character of a line. When trailing space
retention is disabled, the editor will effectively give you a free
roaming cursor. For example, if you use a movement key to go past the
end of the line, it will pad the line with spaces. Likewise, if you
move from a long line up or down onto a shorter one, the short line
will be padded with spaces up to the cursor so as to maintain its
current horizontal position. These trailing spaces will be stripped
from the line as the cursor moves off of it as will any trailing
spaces added by the space bar and/or tab key.
With trailing space retention enabled, you no longer have a free
roaming cursor. Horizontal cursor movement will be limited to the
extent of the text that is currently in the line. To add spaces to
the end of a line, you must press the space bar or tab key. If you
try to use the right arrow key to move past the end of the line, the
cursor will automatically advance to the first column of the next
line. Likewise, if you move from a long line up or down onto a
shorter line, the cursor will jump from its current horizontal
position to the position after the last non-blank character of the
short line. When enabled, a "T" will appear on the indicator line.
The editing and movement will be similar to the original TEditor which
always retained trailing spaces and did not provide for a free roaming
cursor.
For the most part, disabling the trailing space retention is most
useful while editing source code. As you move up and down the file,
the cursor will maintain its horizontal position no matter how much
the lines vary in length. Enabling trailing space retention is mostly
used for document type files where you may wish to keep trailing
spaces on a line for formatting purposes.
Note that saved files may shrink in size when edited with trailing
space retention disabled. The loss in size is due to the removal of
trailing spaces during editing. Likewise, a file may grow in size
when saved if the file is edited with trailing space retention
enabled.
Hard Tab/Soft Tab (efUseHardTabs)
---------------------------------
The hard or soft tab option controls what will happen whenever the
tab key is pressed and Insert Mode is enabled. While in overwrite
mode, the tab key serves as a positional command and will simply move
the cursor forward or backward. An "H" for hard tabs or an "S" for
soft tabs followed by the current tab size is always displayed on the
indicator line.
For hard tabs, the actual 0x09 tab character is inserted into the
document. Thus, if the tab size is changed while editing the
document, the display will change to reflect this new tab size. For
soft tabs, the appropriate number of spaces are inserted into the
current line to advance the cursor to the next tab stop. Changes in
the tab size while editing the document will have no visible effect on
the display unless hard tabs were already present in the document.
Undo/Redo (efCanUndo)
---------------------
When Undo/Redo is enabled, you are able to undo edits and commands
performed on the text. Redo will, of course, put the changes back if
you change your mind or undo too much. The Undo/Redo capacity is only
limited by available virtual memory (EMS/XMS + disk space). It is
possible to undo all changes to a file right back to when it was first
loaded and then redo every single step. However, if you edit text
after a redo, any undo information after the last redo point will be
lost because it is reused to record the undo information for the edits
that where just done.
Each undo/redo step is grouped based on the command executed. For
example, if you type in some words on a line and then change your
mind, Undo will revert the line to the state it was in before you
typed all those words. Likewise, if you reformat a section of text
and realize you've included too much, Undo will undo the entire
reformat command and return the text to the state it was in before it
was issued. This could involve a few lines or several paragraphs.
Redo works exactly the same way.
Some people might not consider Undo/Redo a local option. This is
entirely up to you. To remove it from the local options is as simple
as not offering it as a selection in the checkboxes that control these
features. When it is local, undo/redo can be enabled and disabled as
many times as you like. Keeping it as a local option has its
advantages as you will now see.
When Undo/Redo is enabled, the virtual memory manager will take
some virtual memory to keep track of this information. Thus there is
some virtual memory overhead when enabled. It will keep consuming
virtual memory for each edited line until you actually close the
editor. With plenty of EMS, XMS, disk space, or a combination
thereof, it should not be a problem. If you need or want to conserve
virtual memory, you can disable Undo/Redo.
When disabled, the virtual memory manager will recycle any unused
portions of virtual memory and place any new edited text in the
discarded regions. This will reduce the total amount of virtual
memory used over the course of the editing session. It will take
steps to insure that if you enable Undo/Redo after it has been off, it
will not go into these recycled regions. It is therefore possible to
leave Undo/Redo disabled until you need it, enable it for a while, and
then disable it again if so desired. Such a situation might arise
while reformatting paragraphs. It is easy to reformat from the wrong
starting point and reformat too much text. This is when Undo is a
very helpful feature to have.
Just remember that if you disable Undo/Redo after it has been on,
you may not be able to undo or redo changes when it is re-enabled
again due to the recycling that goes on behind the scenes. As a rule,
Undo/Redo will only work with changes made from the point it was
enabled onward.
Persistent, Non-persistent, and Overwriteable Marked Blocks
-----------------------------------------------------------
efNonPersistentBlocks and efAllowOverwrite (which combine to form
the efOverwriteBlocks constant) allow the editor to use non-persistent
and, if selected, overwriteable blocks. A persistent block (used when
efNonPersistentBlocks is not set) allows the user to mark a text block
and then move away from it. The user can go anywhere in the file and
the block of text will remain marked until deselected by the user or a
command that makes use of the block. A non-persistent block will
deselect automatically if the user tries to move away from the block
after stopping block selection. Typing a key or hitting Delete while
the text is marked will delete the selected text if the Allow
Overwrite option bit is set.
If non-persistent blocks are enabled and overwriteable blocks are
disabled, inserting text, deleting text, or moving the cursor will
simply deselect any currently highlighted block. Alternately,
efAllowOverwrite can be enabled along with efNonPersistentBlocks to
delete the selected block under those conditions. Overwriteable
blocks are not possible with persistent blocks because you can move
the cursor away from the block. Inserting text in that case would
delete the block and insert the new text at the wrong location (this
behaviour conforms to the way the BC++ 3.1 IDE uses these options).
Enter Matching (efParen through efMatchAll)
-------------------------------------------
Borrowing a feature from my favorite editors (QEdit and TSE), I
have enabled enter matching in the editor classes. What this means is
that for the left-hand characters (, [, {, ", ', and <, the editor can
automatically enter the appropriate matching right-hand character ),
], }, ", ', or >.
This mode can be individually enabled or disabled for each
character via local option settings. It is most useful while entering
program source code or equations so that you don't forget a
parenthesis or bracket.
Of course, Enter Matching would not be complete without its
counterpart Find Matching so I added that feature too. By placing the
cursor on either character of a (), [], {}, or <> pair and issuing the
Find Matching command, the cursor will jump to the matching character.
When there is a missing or extra matching character, the cursor will
either not go anywhere or will end up on an unexpected match. For
each of the listed pairs, the search will go in either direction based
on the starting character you are positioned on and can span multiple
lines.
Find Matching can also be executed for the single and double quote
marks. However, because the character cannot be used to determine in
which direction to go, all such matchings will go in the forward
direction and are restricted to the current line only.
Tab Size, Indent Size, Right Margin
-----------------------------------
Tab size controls how many spaces a tab represents when the text
is displayed or printed. For soft tabs, it will determine how many
spaces are inserted or deleted whenever the Tab or Shift+Tab key is
hit. It should be a value from 2 to 16.
Indent size controls how many characters will be inserted or
removed from each line of the block when the Indent/Unindent commands
are issued. It should be a value from 1 to 16. The Indent/Unindent
commands are useful for shifting large blocks of text left or right in
the editor all at the same time.
The right margin value is associated with word wrapping and line
centering. It should be a value from 20 to 250. Word wrapping will
occur as described above with the specified right margin. Line
centering will center text between column 1 and the right margin
setting.
Note that all of the above commands have *suggested* legal ranges
but the editor itself cannot and will not enforce those ranges. It is
up to the programmer to limit the values properly when altering them
in source code or with the appropriate edits when they are entered
using a dialog box from within an application.
Global Editor Options
=====================
The following options will control all editors. Note that there
are global counterparts to each of the above described local options.
These serve as the defaults for each new editor object as they are
created. At instantiation, the new editor object will set each of its
local options to the value of their global counterparts. Any
modification to the editor's local options will not be reflected in
the global options. Likewise, subsequent changes to the global
options will not be reflected in any existing editor object's local
options. For example, if you have word wrapping turned off in the
global options and later decide to enable it, any existing editor
objects will retain their own setting for word wrapping. Any new
editor objects opened will inherit the new setting.
For the following options, there are no local counterparts.
Tab Expansion at Load Time (efExpandTabs)
-----------------------------------------
If enabled, any existing hard tabs in a file will be expanded to
the appropriate number of spaces when the text is loaded into the
editor. This applies to the initial opening of the file or text
inserted into the file with the Read Block command.
This is useful if, like me, you prefer soft tabs to hard tabs.
Just be aware that if the current tab size setting is not the same as
it was when the file was created, some text may not line up correctly
in the loaded file. Examples of this might be columnar data that was
randomly formatted by separating some columns with spaces and others
with tabs. The loaded text may end up looking a little ragged. Such
files can always be loaded with the appropriate tab size and then you
can adjust the editor's local tab size to suit your preferences.
Backup File Creation (efBackupFiles)
------------------------------------
Pretty much speaks for itself. When enabled, the original file
will be renamed with an extension of your choice (see below) as a
backup. When disabled, no such backup file is created.
The TVMFileEditor class performs "safe saves" regardless of this
setting. It will never save directly to the real filename. It saves
the text to a temporary file first and renames it afterwards if all
went well. If there is a problem or error during the save, the
original file is untouched and can be retrieved without problems.
Use Line Feed (LF) Only When Saved (efUseLFOnly)
------------------------------------------------
If this option is disabled, files are saved with each line
separated by a carriage return-line feed pair (CR/LF). This is the
normal setting for text files on PC-based systems. If you enable this
option, files will be saved with lines separated by a single line feed
(LF). This is the way UNIX text files are stored.
Files Are Read Only (efReadOnly)
Set Read Only On Load (efSetROonLoad)
-------------------------------------
With the Read Only option enabled (efReadOnly), text is loaded
into the editor as read-only. Any commands that could modify the text
within the editor are filtered out. You are limited to moving around
the file and copying sections of it to the clipboard, printing it, or
saving marked blocks to a file. The only thing that can modify the
file on disk is to issue a Save As command and then save the file to
the name it is currently using.
If you set this global option to True and then create a clipboard,
it will initially keep the read-only flag set. If you were to view
the clipboard on the desktop, it would display the read-only
indicator. However, as soon as you cut or copy something into it, it
is smart enough to turn this bit off for itself and allow the
insertion of text. You don't need to do anything special or check for
such a situation.
The Set Read Only On Load option (efSetROonLoad), causes the file
editor to look at the Read Only file attribute. If set, the editor
will automatically set its own efReadOnly bit to prevent alterations
to a file that is marked as Read Only on the disk.
Color Syntax Highlighting (efUseCSH)
------------------------------------
The basic TVMEditor package does not use this option bit. It is
reserved for the Color Syntax Highlighter add-on (currently CSH 1.00).
The derived editor class uses this option to determine whether its
text is drawn in the plain standard color or whether it should use the
syntax highlighter to color its text. See the CSH documentation for
more information on this feature.
Automatic End Of Line Marker (efAutoEOLMark)
--------------------------------------------
The efAutoEOLMark is placed with the Enter Matching options
although it does not affect how they work. The Auto End Of Line
Marker option is used in conjunction with the TVMEditor class member
EOLMarker. Whenever ENTER is hit and this option is enabled, the
EOLMarker character will be inserted. Subsequent paragraph reformats,
automatic word wraps, and wrap on resizes will prevent text from being
appended to the line after that point. For an idea of how this
affects the editor, compile the demo with the '-DAUTOEOL' command line
option. It sets the necessary editor options and enables a visible
end of line marker that is used whenever the ENTER key is hit.
Signs Of Life Initialization and Reporting Intervals
----------------------------------------------------
These two options control when Signs of Life are initiated and how
often they are reported. See the section on Signs of Life for more
information.
Default File Extension and Default Backup Extension
---------------------------------------------------
These two options control what default extensions are used by the
editor classes. Currently, TVMFileEditor only makes use of the
default file extension for Read and Write Block operations and the
default backup extension when saving a file. The default file
extension can be used to store a default extension for use with an
Open or Save As dialog box. See the demo program for an example of
this.
Default Swap File Path
----------------------
The default swap file path specifies the drive and directory in
which all editor objects will store their swap file if one is created.
Be sure that there will be enough room on the given drive to hold
them. The swap file is only created when necessary and is removed
when the editor object is destroyed. A RAM drive is the ideal place
to send the swap files provided it is large enough to contain files
for the maximum number of editors that you may have open at once.
Note that if created, a swap file can grow to be larger than the
original file depending upon the amount of editing done. This is due
to the extra information virtualized along with the actual text. If
you set the swap file path variable to an empty string, the swap files
will be stored on the current drive in the current directory.
Default Print Device
--------------------
The default print device specifies where printed text is sent.
By default, it is set to LPT1, but it can be changed to LPT2, COM1,
COM2, a filename, etc. This allows the default
TVMFileEditor::PrintBuffer() function to be a little more flexible by
allowing the user to specify the output device. It was also written
using low level, unbuffered, binary writes so that it stops printing
when there is an error and ESC is pressed in the critical error
handler. The fprintf() function didn't always do this properly
because it buffered the output.
Search and Replace Options
==========================
The search and replace features have been expanded to include more
useful options. They are described below.
NOTE: If you are using the search/replace options and the search
fails when you didn't expect it to, check the option settings.
It might be due to a setting that is not correct such as trying
to search a selected block of text when none is selected, an
incorrect scope setting, or an incorrect direction setting.
Find String and Replace String
------------------------------
As before, these strings represent the text to search for and the
text to be used for replacements.
Options: Case Sensitive, Whole Words Only, Prompt On Replace
------------------------------------------------------------
If Case Sensitive is selected, the case of the text is considered
when searching for the find string. If left unselected, the search
will be case insensitive.
If Whole Words Only is selected, the search is limited to finds
that have a non-word character on either side. The word characters
are determined by a call to the virtual function isWordChar(). If
left unselected, the search will include finds that occur within other
words.
Prompt on Replace is only available when doing a Search and
Replace operation. If selected, at each find you will be prompted to
decide whether or not the replacement should be made. If left
unselected, changes are made without your consent.
Direction: Forward or Backward
------------------------------
Specifies which way the search will proceed.
Scope: Global or Selected Text
------------------------------
Due to the selected text block being persistent in nature, there
is now a search and replace option that can limit the operations to
that block. If scope is set to Global, then the entire file is
searched regardless of whether or not a block is selected. Note that
a Selected Text search will work even if the non-persistent block
options are set. This is done by temporarily disabling those options
and then resetting them afterwards.
Origin: From Cursor or Entire Scope
-----------------------------------
Origin specifies where the search will begin. If From Cursor is
selected, the search will proceed from the current cursor position
forward or backward depending upon the Direction setting. If Entire
Scope is selected, the cursor is first moved to the appropriate end of
the file or block depending on the selected scope and the search
direction. The search will then proceed either forward or backward
depending upon the Direction setting.
Note that if you use the Repeat Search command (default: ^L), it
will automatically go into From Cursor mode and proceed in the
appropriate direction until the end of the selected scope is reached.
Command Operation and Implementation
====================================
Most of the commands available in the editor speak for themselves
as to their purpose. For those that don't, those that have special
rules, or those that need some clarification as to their operation,
the following sections will describe them in more detail.
Roll Window Up and Roll Window Down
===================================
These commands will keep the cursor in its current horizontal and
vertical position in the edit window, and will scroll the text up or
down by one line.
Tab Left and Tab Right
======================
I've mentioned it elsewhere, but thought I might as well do it
again. When insert mode is off, the Tab and Shift+Tab key presses
will serve as positional commands instead of text insertion/deletion
commands. They will simply move the cursor backwards or forwards by
the appropriate tab width. This was done to prevent accidental
erasure of large chunks of text while insert mode is off. Also be
aware that if trailing space retention is enabled, when you press Tab
with insert mode off the cursor will not proceed past the end of the
line.
Insert Literal Character
========================
This command will take the next key press and insert it as a
literal character into the file. When ^P (the default key assignment)
is pressed, the message <Literal> appears on the indicator line to
show you that another key press is expected. This is useful for
inserting control codes into the text that normally cannot be entered
such as ESC (Ctrl+P, ESC), end of file (Ctrl+P, Ctrl+Z), form feed
(Ctrl+P, Ctrl+L), or the graphics characters used for special symbols
and drawing (Ctrl+P, then hold down ALT and type a 3 digit number on
the numeric keypad).
Copy Block to Cursor and Move Block to Cursor
=============================================
These are non-clipboard versions of the copy, cut, and paste
commands. They will function even if there is no clipboard defined.
This is useful for applications that use memo fields but not the file
editor. Copy Block and Move Block can still be used. Be warned that
when moving or copying extremely large blocks of text in large files,
these two functions tend to cause the virtual memory system to thrash.
In such cases it is better to use the clipboard. Move Block and Copy
Block will ignore requests to move text anywhere inside the marked
block.
Indent Block and Unindent Block
===============================
The only special thing to note is that indent will not let lines
exceed 255 characters and that unindent will continue to unindent
blocks until there is nothing left on a line. For example, if you
unindented a block of lines to get rid of the spaces before the lines
and then unindented again it would start chopping off the text in the
lines too.
Align Text
==========
This command will align one or more lines of text (depending on
whether or not a block is marked) with the first non-blank line above
the starting point. There can be one or more blank lines above the
starting point. It will keep looking for a non-blank line until it
hits the top of the file. If a non-blank line can't be found, no
alignment will occur.
After the alignment operation, the cursor will automatically
advance to the next line ready for another operation. This makes it
easy to align several lines, one after the other, without selecting
the block first.
Paragraph Reformatting (Wrap Paragraph)
=======================================
This command will reformat text into paragraphs between the left
and right margins. This is done by aligning text with the effective
left margin, extending short lines up to the right margin, and word
wrapping long lines at the right margin.
During reformatting, the following definitions apply:
Space, white space, blanks
--------------------------
Any string of one or more characters consisting only of
spaces, tabs, or the form feed character. This is what separates
the "words" during reformatting. A line with a single form feed
character in the first position is also considered a blank line.
This is done to prevent the reformatting code from incorporating
the form feed character into the line above it as a "word".
Word
----
Be aware that what is considered a word here may not be for
commands such as Word Left or Word Right. For the reformatting
process, a word is considered to be any string of one or more
characters separated by white space as defined above.
Indent or Outdent
-----------------
During reformatting, a line is considered indented if it has
more white space before the first word than lines following it.
A line is considered to be outdented if it has less white space
before the first word than lines following it.
The indent or outdent of the line where reformatting starts
is important because it determines when the end of a paragraph
is reached in cases where following paragraphs are not separated
by blank lines. The indent or outdent of the second line is
important because it determines the effective left margin for the
rest of the paragraph.
Examples:
A. This line is indented.
The line above is indented when compared to this one.
B. This line is outdented.
The line above is outdented when compared to this one.
C. This line is indented equally to the next line.
These lines are indented equally when compared to each
other.
Effective Left Margin
---------------------
The amount of white space up to but not including the first
non-space character of a line. This is the amount of indentation
that will be placed on each line of the paragraph as they are
formatted. It is determined for each paragraph by looking at the
amount of white space on the line immediately following the one
where reformatting will start.
Paragraph
---------
Blocks of text that are either separated by one or more
blank lines or, in the absence of blank lines between them, have
a starting line that is indented or outdented an equal amount to
other paragraphs.
Reformatting Rules
------------------
There are a number of rules that the editor will follow when
reformatting text. These rules may not interest you or may not give
an entirely clear picture of what happens under all circumstances. To
get a good feel for how paragraph reformatting truly works, it is best
to just play with it and see what happens under odd or unique
circumstances. The following paragraphs will try to explain what goes
on. Even if you don't want to know the gory details, at least read
the "PLEASE NOTE" section below. There are situations in which no
reformatting will occur or the end of a paragraph cannot be determined
with certainty and it may end up reformatting more than you intended.
When executed, the reformatting starts at the current cursor line
and will continue until a blank line, the end of the file, the end of
the selected text block (if any), or a line with an indent or outdent
equal to that of the starting line is reached. The cursor will be
place on the line immediately following the last line of the
paragraph. Note that if a selected text block is defined, the cursor
will be moved to the first line of the block and the editor will
reformat as many paragraphs as it can find until the end of the block
is reached. If no block is selected, only the paragraph the cursor is
in will be reformatted starting at the current cursor line and
continuing until one of the above mentioned end conditions is met.
The starting line is considered to be the first line of the
paragraph and will not have its indentation changed. The effective
left margin is determined by using the indentation on the line
immediately after the starting line. Subsequent lines will be
indented or outdented to match the effective left margin.
As the text is reformatted, long lines are word wrapped if they
exceed the right margin and short lines are extended with words from
subsequent lines until they are as close as possible to the right
margin. As words are added to a line, a single separating space is
included before the appended word. Leading and trailing spaces for
appended words are stripped out. When I was taught to type, I was
told that two spaces after every period was the standard and I've
followed that "rule" ever since. Therefore, if a period is
encountered prior to adding a word, two spaces are inserted before
adding the next word to the line. Reformatting continues until one of
the above mentioned end conditions is met.
PLEASE NOTE:
============
If a line contains no spaces at all or just some indentation
followed by a string of non-space characters and it exceeds the right
margin, that line will not be wrapped. However, it will be indented
to conform to the effective left margin. An example might by a drawn
box border or one that continuously underlines (i.e. -----) the text
above it. This generally isn't a problem and usually only occurs if
you choose to start reformat text in the wrong place.
If the effective left margin is past the specified right margin,
no word wrapping will occur. As an example, if the right margin is
set at 72 and the first word does not start until column 74 when
determining the effective left margin, no word wrapping will occur.
There must also be at least one full word followed by a space prior to
the right margin for word wrapping to occur.
THIS ONE IS IMPORTANT! If you start reformatting on a line that
has no indentation or one that has an equal amount of indentation as
subsequent lines, the editor is only able to determine the end of the
paragraph by encountering a blank line, the end of the file, or the
end of a defined block. The matching indent/outdent criteria will be
ignored so that it doesn't stop reformatting immediately on the next
line.
As an example, if you were to start reformatting from the second
line of the preceding paragraph instead of the first, this paragraph
and the ones following it would be merged into it because the
indentation on the next line (third line) matches the starting line
(second line). Reformatting won't stop until the blank line is hit.
Load a copy of this file into the editor and try it out if this isn't
clear. As I said before, playing with this command is the best way to
see how it reacts.
This problem can also occur if you are not diligent about making
all of your paragraph's first lines use a standard amount of
indentation. Remember, if paragraphs aren't separated by a blank
line, reformatting will continue until a line is reached that has an
indent or outdent *EQUAL* to that of the starting line.
If you absolutely need to reformat a paragraph or a portion of one
in which the above situation could occur, there is an easy way to
avoid it. The way to do it is with a selected block of text. Simply
block select the portion of text you wish to have reformatted just
like you would if you were going to move it or copy it to the
clipboard. Once marked, simply issue the reformat command and it will
format the text from the top of the block and stop when it reaches the
last line of the block.
Marking a block is also the way to get the reformat command to
work on multiple paragraphs in one shot. Simply block select all the
paragraphs to reformat and issue the command. However, be warned that
if the selected block's first line has an indent equal to the second
line, you will still run into the above described situation. Not to
worry though. If you make a mistake, the Undo command can always back
you out of a botched reformat (provided that you have Undo/Redo turned
on first! <g>).
Clipboard Commands
==================
As noted, secondary keys have been defined for these operations so
that they can be used while debugging programs in the BC++ 3.1 DOS
IDE. Many is the time I've seen people on the BCPPDOS forum ask why
the clipboard commands didn't work. The reason is that the IDE traps
them and the application being debugged never sees them. With the
secondary commands, this is no longer a problem. Besides which, it
was impossible to debug the clipboard commands when I couldn't access
them <g>.
One unique characteristic of the clipboard that I have made use of
is that when new text is cut or copied to the clipboard, any marked
text is deleted but any unmarked text is left untouched. Knowing
this, it is possible to open the clipboard on the desktop, copy or cut
a block of text to the clipboard, then change to the clipboard and
hide the block. You can then move the cursor to the end of the
clipboard text, go back to another window, and cut or copy another
piece of text to the clipboard. This has the effect of appending the
next block to the text already in the clipboard. You can repeat this
process as often as you need to merge several pieces of text into the
clipboard. Finally, you can go into the clipboard and save it as a
different file or select the entire contents as a block and paste it
into other files.
Set Bookmark and Jump to Bookmark
=================================
By default, I've used <^K1>, <^K2>, <^K3>, <^J1>, ,<^J2>, and
<^J3> as the keys to access these commands. One important thing to
note is that if you are still holding down the Ctrl key when you press
1, 2, or 3, the editor will not see the command. This is because the
computer won't generate scan codes for Ctrl+1, Ctrl+2, and Ctrl+3.
Let go of the Ctrl key before pressing the 1, 2, or 3. For that
matter, you should be letting go of Ctrl for the second key of any
two-key commands unless otherwise noted. It isn't required on the
second key press.
Events Commands
================================ ====================
Save Modified File Prompt Read Block
Save Untitled File Prompt Write Block
Save File As Prompt Find
Replace Text Verification Prompt Find and Replace
Search Failed Prompt Change Local Options
Goto Line
Just like the original TEditor classes, the TVMEditor classes use
an editorDialog() function defined by you to handle user interaction
for commands that require some form of acknowledgement or input. The
above listed events and commands require some form of interaction with
the user before they can be formally completed.
TVMEditor::editorDialog is a static function pointer in the
TVMEditor class that points to your function or a default function
supplied by me. To be fully implemented, you must define and replace
the function pointer that TVMEditor::editorDialog points to with a
pointer to your own handler.
In addition to the above listed events and commands, there are
several diagnostic or informative messages that editorDialog() will
handle too. Most of these can be safely ignored, but the first eight
message types cannot be ignored. They refer to such things as swap
file failure, file save failure, etc. If you do not replace the
default function with your own, these will be handled by the default
function with a simple message box that displays the error number that
occurred. A complete list of possible values can be seen in TVMEDIT.H
(the edXXXXX constants). The doEditDialog() function in TVEDIT2.CPP
of the demo program shows you how to handle each of the events. You
may use this one if you like or create your own that handles a subset
of the events.
Note that the above listed commands will not be accessible unless
you replace the default editorDialog() function to handle them as show
in TVEDIT2.CPP. Remember that TVMMemo now has access to all of these
features as well, so if you write an application that uses TVMMemo but
not TVMFileEditor, you will still need to define an editorDialog()
function to handle the commands you want TVMMemo to have access to.
For example, you might let it have access to Goto Line, Find, Find and
Replace, and leave out the other commands so that they are ignored.
Signs Of Life
=============
Okay, it sounds strange, but that's exactly what it is. On
really large files, the delay in returning control to the user in
conjunction with in-memory swapping (EMS/XMS for real mode or
conventional memory for protected mode) gives no indication that
anything is really happening. It is possible that you might think it
has locked up when it really hasn't. Basically, enabling Signs of
Life entails adding code to call a user specifiable function that
gives you some feedback during potentially long operations such as
file load/save, block operations, search/replace, etc so that you know
the editor is still alive and kicking. Even with the additional
function call overhead, there is extremely little drop in performance
and you have complete control over how often the function is called.
The supplied demo editor contains a simple but effective Signs of Life
handler in the TVEDIT3.CPP module.
How It Works
------------
In general, your Signs of Life function has to handle certain
events. Those events are defined as follows:
slInitiate Get ready to start showing signs of life. This may
include creating a dialog box and inserting it into
the desktop and initializing any necessary counters,
spinners, progress bars, etc that you may want to
use. Signs of life are only initiated after the
command in progress has processed a number of lines
specified in the global options structure.
slReporting This is the "heartbeat" event. It is issued every so
often based on a setting in the global option
structure. Each time your handler is called with
this event code, it should do something to show
"signs of life". This might be something like
turning a spinner, showing count information, or
updating a progress bar.
slHide The default editors do not make use of either slHide
slShow or slShow. However, they are here in case you need
them. The intended use of slHide and slShow are to
temporarily suspend signs of life and perhaps hide
the progress dialog box while the user is prompted
for some other input or is asked to confirm some part
of the operation. Once the interruption is over,
slShow can be used to redisplay the dialog box and
continue on as normal.
slDone This is always called when the event is finished to
terminate the signs of life display. It is in this
event that you would dispose of any dialog box or
other items that you may have inserted into the
desktop.
Installing your Signs of Life handler is as simple as assigning
its address to the TVMEditor::signsOfLife data member:
TVMEditor::signsOfLife = doSignsOfLife;
The function prototype would be something like:
void doSignsOfLife(SignsOfLife lifeSign, ushort cmnd,
long count, long total);
The parameters passed to it are:
SignsOfLife lifeSign One of the above slXXXXX definitions.
ushort cmnd The command being executed. The basic
editors will issue signs of life during the
following command events:
cmMoveBlock cmClear
cmCopyBlock cmUndo
cmReadFile cmFind
cmWriteBlock cmFindMatching
cmPrintBlock cmWrapPara
All commands handled by the alterText()
function.
cmCopyBlock is also used to denote
insertion to/from the clipboard.
cmReadFile reports its progress in bytes
read and total bytes instead of lines
processed and total lines.
cmUndo serves the undo and the redo
operations.
See TVMEditor::alterText() for the commands
that it handles.
NOTE: If you see a deletion taking place at
the start of a clipboard operation,
don't panic! It's just from the
cmClear issued to erase any marked
block currently in the clipboard.
long count This is the current number of lines
processed (or bytes for cmReadFile) out of
the total number specified in the 'total'
parameter.
long total This is the total number of lines (or
bytes) that are to be processed. Using
this information with the 'count'
parameter, it is possible to show progress
either by displaying the actual numbers or,
if you want to get sophisticated, by
displaying a progress bar.
Controlling Signs of Life
-------------------------
The GlobalEditorOptions structure contains these two fields:
short initThreshold;
short reportInterval;
These two values indicate when signs of life should be issued by
the editor. What this means is that after initThreshold lines, the
editor will place an slInitiate call to the signsOfLife() function to
let the user know it is still working and hasn't locked up. After
that, it will place an slReporting call (the "heartbeat") every
reportInterval lines. Whenever signs of life has been started and the
operation completes, a final call is placed to signsOfLife() with a
value of slDone and 'count' and 'total' are equal to the same value.
NOTE: If either of the above variables is set to zero, Signs of
Life reporting will be disabled and the editors will perform
the entire operation with no indication of progress.
As stated above, the cmReadFile command reports its progress in
bytes. This is because it has no way of telling how many lines are in
a file until it has completely finished processing it. However, it
does count up how many lines it has inserted as it reads the file so
that it knows when to start and how often to call the signsOfLife()
function.
Data and Function Members
-------------------------
----------------------------------------------------------------------
struct GlobalEditorOptions
{
ushort Operation, // Default operating modes
EnterMatch; // Default Enter Matching characters
short TabSize, // Default tab size
IndentSize, // Default block indent size
RightMargin; // Default right margin
// NOTE: Any changes in the structure ABOVE this point should also
// be taken into account for structure LocalEditorOptions
// below. The rest of this structure is for global items
// only.
// Search options
ushort Search;
// Signs of Life.
// These two values indicate when signs of life should be issued
// by the editor. What this means is that after initThreshold
// lines, the editor will place a call to the signsOfLife()
// function to let the user know it is still working and hasn't
// locked up. After that, it will place a call to it every
// reportInterval lines.
short initThreshold;
short reportInterval;
// Default filename extensions. These are currently only used by
// TVMFileEditor.
char DefaultExt[4], BackupExt[4];
// Default drive/dir for swap files. This can be used by virtual
// memory systems needing a swap file for each editor instance.
char DefaultSwapDir[MAXPATH];
// Print Device (LPT1, LPT2, COM1, COM2, filename, etc).
char PrintDevice[MAXPATH];
}
----------------------------------------------------------------------
The GlobalEditorOptions structure contains options used by all
editor object instances along with the defaults for the local options
structure when a new one is first created.
--------------------------------------------------------
struct LocalEditorOptions
{
ushort Operation, // Operating modes
EnterMatch; // Enter Matching characters
short TabSize, // Tab size
IndentSize, // Block indent size
RightMargin; // Right margin
}
--------------------------------------------------------
The LocalEditorOptions structure contains options that are local
to each instance and can be changed for each one without affecting any
of the other objects.
-----------------------------------------
static TVMEditorDialog _NEAR editorDialog
-----------------------------------------
This is a pointer to a function that you can define to handle
commands and events that require some form of user interaction or
acknowledgement. The function it points to takes a single type short
parameter and a variable number of additional arguments. The type
short parameter is one of the edXXXXX constants described earlier in
this file. A complete list can be found in TVMEDIT.H. An example of
this handler can be found in the demo program in TVEDIT2.CPP.
---------------------------------------
static TVMSignsOfLife _NEAR signsOfLife
---------------------------------------
This is a pointer to a function that you can define to issue
"signs of life" during long operations performed by the editor such as
file insertions, printing, saving, loading, etc. An example of this
handler can be found in the demo program in TVEDIT3.CPP. Also, see
the section above on Signs of Life.
----------------------------------
static TVMEditor * _NEAR clipboard
----------------------------------
This is a pointer used by all editors to access the clipboard. By
default, it is NULL (no clipboard defined). If you would like your
application to have a clipboard, simply create a TVMEditor object and
store its address in this data member.
Any TVMEditor can be the clipboard. It just needs to be assigned
to this variable. If you simply want an editor object as the
clipboard, use TVMEditor to construct one. If you would like a
viewable clipboard (like the one in the demo program), use
TVMEditWindow to create an edit window object and set 'clipboard'
equal to the address of the edit window's 'editor' data member:
TVMEditWindow *clipWindow = new TVMEditWindow(...);
TVMEditor::clipboard = clipWindow->editor;
See the demo program in TVEDIT1.CPP for a more detailed example.
-----------------------------------
static const char * _NEAR charLeft
static const char * _NEAR charRight
-----------------------------------
These two pointers simply define the left and right-hand Enter
Matching and Find Matching characters. By default, the characters
defined are (, [, {, ', ", and < for the left-hand characters and the
appropriate match for the right-hand characters.
------------------------------------
static const char * _NEAR TwoKeyMsg
static const char * _NEAR LiteralMsg
------------------------------------
These two pointers are used to define the default Two Key and
Literal command flag messages. Whenever the first key of a two-key
command or the Literal command key is pressed, the text pointed to
will be displayed on the indicator line if one is present. By default,
the messages are set to <Two Key> and <Literal>.
---------------------------
static char _NEAR EOLMarker
---------------------------
This is the line length inhibitor character (also referred to as
the End Of Line marker or hard return). Set this character to the one
you want wrapPara() to use when determining if a line should not be
lengthened. By default it is '\xFF'. You can make this a visible
character if you want to (the left chevron (\xAE) would be a good
one). To enable auto insertion of TVMEditor::EOLMarker whenever a
cmNewLine command is seen (i.e. hitting ENTER), set the efAutoEOLMark
in Opts.EnterMatch (or GlobalOpts.EnterMatch for global usage by
default). The default TVMFileEditor::PrintBuffer will strip EOLMarker
characters automatically before printing to save you from having to do
it.
The wrapPara() function skips lengthening of lines ending in this
character. This is a form of "hard return" that lets it know when a
line should be excluded from reformatting past that point. This is
most useful in Wrap On Resize enabled editors with title lines or
section headings which should not be extended. It can also be used in
conjunction with automatic word wrapping so that whenever the user
hits ENTER, a "hard return" is inserted. In all other cases, the
editor wraps text at the right margin and reformats it as necessary.
The inhibitors prevent it from wrapping too much text in situations
that might otherwise cause it to wrap more than you want it to. For
an idea of what this does, compile the demo with the switch
'-DAUTOEOL'. This sets the necessary option bits in the global
options structure and enables a visible EOL marker (\xAE).
-------------------------------------------
static GlobalEditorOptions _NEAR GlobalOpts
-------------------------------------------
This is the global options structure shared by all editor
instances. The values in this structure are used as the defaults for
each new editor's local options. It also contains some of the default
search and replace options, the default file extensions, and default
swap path.
------------------------------------------------
static ushort _NEAR searchDirection
static ushort _NEAR searchScope
static ushort _NEAR searchOrigin
static char _NEAR findStr[maxFindStrLen]
static char _NEAR replaceStr[maxReplaceStrLen]
------------------------------------------------
These data members contain the other search and replace options.
They are also shared by all editor instances.
--------------------------------
static unsigned short lowMemDesc
--------------------------------
This static public data member holds the descriptor used to
access the BIOS keyboard flags in 32-bit protected mode. In real mode
and 16-bit protected mode, this data member is not defined. Since it
is public, your application is also free to make use of it if you need
to. If you are sure that an editor has been instantiated (either in
the desktop or a clipboard during start-up), you don't need to check
its contents to verify that a valid descriptor has been assigned. If
you have some doubts about whether or not a descriptor has been
assigned yet, you can place a call to the AllocateDescriptor()
function at some point to establish a value manually. Calling it will
not harm any currently assigned descriptor. If one has already been
established, the function simply returns. You can tell if a
descriptor has been assigned because lowMemDesc will be non-zero.
----------------------
TVirtualMemory *Buffer
----------------------
This is a pointer to the virtual memory buffer object. The
virtual memory manager is a separate entity to allow the modification
of the underlying virtual memory engine (switch from EMS + disk to XMS
+ disk, use an alternate method for protected mode, etc). Also,
multiple editors can share the same buffer object to conserve memory.
Note that if no EMS or XMS memory is available, it will go straight to
disk for its virtual memory.
This is a public member of TVMEditor and some of its functions can
be accessed directly by you. This allows direct storage and retrieval
of text on a line-by-line basis. This makes it easy to work with the
text, especially for memo fields.
---------------------------
Boolean isValid, LineEdited
---------------------------
isValid is used to signal whether or not it is okay to continue
using the editor object after construction. This can be used in
conjunction with validView() to see whether or not it should be
inserted into the desktop.
LineEdited is True when the line that the cursor is on has been
modified. It is used to determine whether or not text should be
stored in a new virtual memory location and undo information recorded
using the original data. When False, the line has not been edited and
no such operations are performed when the cursor moves to a different
location.
-----------------------
LocalEditorOptions Opts
-----------------------
This structure holds the local options for the editor instance.
------------------------
TScrollBar *hScrollBar
TVMScrollBar *vScrollBar
TVMIndicator *indicator
------------------------
These three pointers refer to the horizontal and vertical
scrollbars and the indicator line passed to the constructor. If set
to NULL, then the associated item will not be used for the given
editor instance.
----------------------------
char Text[maxLineLength + 1]
----------------------------
This is an intermediate editing buffer for the line that the
cursor is sitting on. Changes are made to this line and, when
LineEdited is True, this text is used to replace the old text before
the cursor moves to a different location. If LineEdited is False,
then any information in this buffer is discarded when moving the
cursor to a new line.
-----------------------------
TVMPoint delta, limit, curPos
-----------------------------
The TVMPoint 'delta' is used to hold the horizontal and vertical
offsets into the buffer text when updating the screen. It represents
the top line and left-most column shown in the view.
The TVMPoint 'limit' is used to hold the current horizontal and
vertical limits for the buffer. Currently, the horizontal limit is
used only by the horizontal scrollbar. The vertical limit is always
updated as lines are added or deleted in the buffer. It controls the
vertical scrollbar limit and also gives an upper boundary to commands
that operate on the entire file.
The TVMPoint 'curPos' is used to record the cursor's current
horizontal and vertical position within the text buffer.
------------------------
short selStartC, selEndC
------------------------
The selStartC and selEndC data members are used to remember the
currently marked block's start line column and end line column. If
either selStart or selEnd (the line markers) is zero, then any non-
zero value in selStartC and/or selEndC is undefined. Note that if
selStart is equal to selEnd and selStartC is equal to selEndC, the the
block starts and end at the same point and will not be visible on
screen. A marked block must be at least one column wide but may be
limited to a portion of a single line.
--------------------------------------------------
long selStart, selEnd, drawLine, findLine, setLine
--------------------------------------------------
The selStart and selEnd data members are used to remember the
currently marked text block (if any). When either or both are zero,
then no marked block is currently defined. When both are non-zero,
they represent the starting and ending lines of the block.
The drawLine data member is used only when refreshing the entire
screen display. It defines the line that is currently at the top of
the window.
The findLine and setLine data members are also used when
refreshing the screen display. findLine is used by the search and
replace options to signal which line is currently holding the found
text (if any). setLine is used by the cmSetLine command to signal
which line was just moved to. They are used by the screen draw
routines to highlight the necessary text in a different color.
------------------------------------------------
SignsOfLife sl_Type
long sl_Count, sl_ReportMark, sl_Bytes, sl_Total
------------------------------------------------
These are used internally to track if and when signs of life
should be issued during lengthy operations. You are free to use these
in derived classes if you need to to set up signs of life in your own
operations that may need them.
---------------
short curPosx_t
---------------
This data member keeps track of the cursor position within the
temporary Text[] buffer. Due to hard tabs, this cursor position and
the curPos.x display cursor position may not be identical in value. A
physical hard tab character will represent only one character in
Text[]. However, that single character can represent any number of
displayed spaces based on the current TabSize setting in the local
options data structure.
--------------
short keyState
--------------
This data member is used to track the two-key command state. When
zero, the next key press is interpreted using the single key command
map. When non-zero, it indicates that a special key such as Ctrl+K
has been pressed. It's value represents the map to look at when
locating a command for the second key press of a two-key command. For
example, when Ctrl+K is pressed, keyState will change from zero to a
number that represents the location of the Ctrl+K key's map of valid
second key presses. That map will be used when interpreting the very
next key press to see if it matches one of the commands in that map.
When the second key press matches a command key in the next map,
that command is executed and keyState returns to zero. If the second
key press does not match a command key in the next map, it is ignored
and keyState will return to zero. See changeKeyMap() for more
detailed information on how all of this works.
----------------------------
uchar lockCount, updateFlags
----------------------------
The lockCount data member is used internally by some routines to
prevent unnecessary screen updates. When non-zero, the screen draw is
suppressed. This variable is only modified by the lock() and unlock()
member functions.
The updateFlags data member determines which parts of the screen
will be drawn when lockCount is equal to zero. One or more of the
ufXXXXX constant bits is set based on the operation that requires the
screen update.
---------------
short selecting
---------------
This data member will be set to one of the smXXXXX constants
described earlier and indicates the current block marking state of the
editor.
-----------------
Boolean FirstLoad
-----------------
This is an internal flag used by the editor and the virtual memory
buffer to signal that the first text load operation is about to occur.
When True, the virtual memory buffer will take steps to avoid
unnecessary thrashing as the text is loaded for the first time and
also will not record undo/redo information during that time. When set
to False after the first load, the buffer object will revert to its
normal LRU mechanisms and will record undo/redo information if any
text is edited.
----------------------
Boolean hasChangedSize
----------------------
This flag is used in conjunction with the efWrapOnResize option
bit to determine if the editor has changed its bounds. If True and
Wrap On Resize is enabled, the editor calls reformatAll() to reformat
the text that it contains. If this flag were not present, resizing an
editor would cause a rewrap every single time you moved the window
(each character you widened or shortened the view up, down, left, or
right). Not only would this cause it to eat virtual memory in vast
quantities, it would be an extremely slow process. By altering the
changeBounds() code to set this flag and checking it in setState()
only after the resize has completed, it only has to reformat and
redraw once saving lots of virtual memory and lots of time in the
process. Note that if the editor contains a large amount of text,
there may still be a delay between the end of the resize operation and
when control is returned to you.
-------------------------------------------------------
long lastChg, prevLine, Bookmark1, Bookmark2, Bookmark3
-------------------------------------------------------
These data members represent the cursor line position history
values. lastChg records the number of the last changed line, prevLine
records the line that the cursor was on prior to the last movement,
and the bookmarks represent the lines tagged by the Bookmark command
when set by the user.
-------------------------------------------------------
TVMEditor(const TRect &bounds, TScrollBar *aHScrollBar,
TVMScrollBar *aVScrollBar, TVMIndicator *aIndicator,
short bufSizeInK = 8)
-------------------------------------------------------
This is the constructor for the TVMEditor class. As you can see,
the first four parameters match up to the original TEditor class with
the exceptions of the vertical scrollbar being a TVMScrollBar and the
indicator being a TVMIndicator. Following those is the additional
parameter bufSizeInK that you may or may not want to specify. This
parameter specifies (in Kilobytes) how large the conventional memory
buffer will be for the editor object. This buffer is used to hold the
recently used text and internal information necessary for editing the
file. By default, it is 8K. Derived classes can adjust this upwards
or downwards based on their needs.
If you do not want one of the optional scrollbars or the
indicator, pass a NULL in that parameter's position. The default
editor operating modes are set as follows:
All local options Initialized from the global options
structure settings
growMode gfGrowHix | gfGrowHiY
options ofSelectable is OR'ed with existing
setting
eventMask evMouseDown | evKeyDown | evCommand |
evBroadcast
selecting smNone
keyState 0 (Normal single key command map)
Bookmarks etc. 0 (Undefined)
curPos etc. Line 1, column 1
If there is not enough memory to get underway, the editorDialog()
function is called to notify the user and isValid is set to False.
Otherwise, initialization will continue and isValid will be set to
True. In 32-bit protected mode, the constructor will also call
AllocateDescriptor() to assign a descriptor to the lowMemDesc data
member.
-------------------------------------
virtual Boolean valid(ushort command)
-------------------------------------
This function returns True if the virtual memory buffer and
TVMEditor object initialized correctly. If they did not, then it
returns False. The return value is controlled by the setting of the
isValid data member.
---------------------------
virtual void shutDown(void)
---------------------------
This is used internally by TObject::destroy() to insure that the
derived and related objects are all destroyed properly.
TVMEditor::shutDown will also disable commands like cmCopy, cmCut,
cmFind, etc so that they appear dimmed and unselectable on the menus.
If another edit window is open on the desktop, that one will
immediately enable them when it receives the focus. Otherwise, they
will stay disabled until another edit window is created.
----------------------------------------
virtual void convertEvent(TEvent &event)
----------------------------------------
This virtual function is used by handleEvent() to provide basic
editing operations by converting various key events into command
events. To keep backward compatibility with the original TEditor,
this function is still virtual. It was done this way in the original
as a means of extending or changing the default key bindings. This
required you to derive a new TEditor class and (just my opinion here
<g>) was rather awkward to implement. The underlying code for
TVMEditor is similar to the original, but I have altered it in two
major ways and also added a new function that does away with the need
to derive a new editor class to extend the key code conversions.
Due to the way some of Turbo Vision's kbXXXXX constants are
defined and the way the matching code worked in the original TEditor,
some keys such as BackSpace, Tab, and Enter would equate to an
equivalent Ctrl key combination (Ctrl+H, Ctrl+I, and Ctrl+M). This
prevented those Ctrl keys for being used for other commands. I
altered this behaviour and explicitly scan for an exact keycode match
before scanning for the other keycodes. This will allow BackSpace,
Tab, Enter, Ctrl+H, Ctrl+I, and Ctrl+M to function as individual keys
unrelated to each other and the Ctrl keys are free to do something
else if you want them to. In the default maps, Ctrl+H, Ctrl+I, and
Ctrl+M, are defined so that they still perform BackSpace, Tab, and
Enter to emulate the original until you decide to change them.
As mentioned before, extending or completely redefining the
command key mappings is as simple as a single function call. There is
no longer a need to derive a new editor class in an attempt to solve
the problem with more code. See the changeKeyMap() function
definition for information on how all this works.
---------------------------------------
virtual void handleEvent(TEvent &event)
---------------------------------------
This virtual function provides event handling for the TVMEditor
object. By default, this function calls TView::handleEvent() and then
tries to convert all unhandled keyboard events to command events by
calling convertEvent().
You can override this function to provide new commands and other
event handling features to the TVMEditor classes. I have packed as
many basic editing features as I could into the general TVMEditor and
its derived classes. These new features were ones that I found
lacking or missing in the original. The basic classes should stand up
quite well on their own except for specialized situations in which
there is no other alternative but to derive a new editor class.
----------------------------------------
virtual TPalette &getPalette(void) const
----------------------------------------
This returns the default TVMEditor palette. The palette has been
extended by one entry to include a highlighting color used whenever a
cmSetLine command is received. The extra color is defined and
implemented via the TVCOLR.H file and alternate TView::mapColor()
routine. You must also have defined an appropriate
TApplication::getPalette() member function to contain the extra colors
used by the editor classes.
----------------------------------------------------
virtual void setState(ushort aState, Boolean enable)
----------------------------------------------------
This overrides TView::setState() in order to hide and display the
scrollbars as well as perform some other behind the scenes operations
whenever an editor object gains or loses the focus.
If you wish to alter the commands that are enabled or disabled at
a given point in time, override updateCommands() instead. That
function gets called whenever the command states should be updated.
---------------------------------
virtual void updateCommands(void)
---------------------------------
This virtual function is called whenever the command states should
be updated. It is used to enable and disable commands such as cmCut,
cmCopy, cmUndo, cmRedo, cmReplace, etc. Several commands, such as
those just listed are only available under certain conditions such as
having a marked text block, having undo/redo enabled, being in an
editor that isn't read-only, etc. Others, such as cmFind,
cmLocalEditorOpt, cmGotoLine, etc are enabled all the time because
they do not depend on other options for their use.
----------------------------------------------
virtual void changeBounds(const TRect &bounds)
----------------------------------------------
This virtual function changes the view's bounds, adjusts the delta
value, and redraws the display when necessary to keep the editor view
within its parent view's boundaries. It also sets the hasChangedSize
flag for editors that use the efWrapOnResize option. The actual
reformat call occurs in setState() when sfDragging is finally disabled
at the end of the resize operation.
-----------------------
virtual void draw(void)
-----------------------
This overrides TView::draw() to draw the editor display. It
places a call to the drawLines() function which does all the work. If
you want an editor class to handle a different drawing method,
override the drawLines() function instead of draw().
----------------------------------------------------------
virtual void drawLines(short y, short count, long lineNbr)
----------------------------------------------------------
This function is used to draw 'count' lines starting at line
number 'lineNbr' in the buffer. The display is updated starting at
line 'y' on the screen. If the data members findLine or setLine are
non-zero, the appropriate display line will be highlighted in a
different color to draw attention to the specified line's text. It
also takes care of highlighting a selected block of text. If a find
item appears in the selected block, the color is inverted so that it
stands out as it would in normal text.
If you need to alter the way in which an editor object draws
itself, this is the function to override. The draw() function simply
places a call to drawLines(). This function is also called to draw
partial screen updates (i.e. one or a few lines only). By overriding
this function, you can be sure that you will have control of all
screen updates.
--------------------------------------
virtual void setXIndex(short newPos)
virtual void setScrIndex(short newPos)
--------------------------------------
The function setXIndex() will synchronize the physical display
column (curPos.x) with the index into the edit line Text[]
(curPosx_t). The function setScrIndex() will do the opposite. It
synchronizes the index into the edit line Text[] with the physical
display column. They also insure that curPos.x is not in the middle
of a hard tab's whitespace. Due to hard tabs, curPos.x and curPosx_t
may have different values. These functions are used when moving
around within a line and onto other lines.
These functions have been made virtual to allow you to embed
special codes in the text or to alter the cursor positioning in some
custom fashion should you ever need that capability.
------------------------------------------------------
virtual const char *getSwapFileName(void)
virtual Boolean setSwapFileName(const char *aFileName)
------------------------------------------------------
These two functions can be used to get and set the virtual memory
buffer's swap filename. getSwapFileName() simply returns a 'const
char *' to the swap filename. setSwapFileName() takes a 'const char
*' to the new name and returns True if it was set. If False is
returned, it means that the buffer is swapping text to a disk file
already and the name cannot be changed. This can be prevented for
TVMFileEditor() and TVMEditWindow() with the SuppressLoad constructor
parameter.
----------------------------------
virtual Boolean isWordChar(int ch)
----------------------------------
This virtual function returns True if ch is in the set of defined
word characters. By default, a word character is any alphanumeric
character (as returned by the isalnum() function) or the underscore
character.
This function was not virtual in the original TEditor but I made
it this way for TVMEditor. This makes it easy to derive a new
TVMEditor with a custom word character set. If you decided to derive
a new editor used strictly for editing a special type of data file,
you could override this function and define a word character set that
was unique to that type of file. For example, you might want to make
it consider alphabetic characters only and ignore other characters
when determining word boundaries.
--------------------------------------------------
virutal void doneBuffer(Boolean releaseMem = True)
--------------------------------------------------
This function simply deletes all text in the buffer and
reinitializes the editor to its start-up state. Note that unlike the
original TEditor, this function is not used during shutdown. It was
simply added as a quick way to delete all text in the buffer and reset
some of the internal variables. The releaseMem parameter determines
whether or not any allocated virtual memory is released back to the
system. If not specified or passed in as True, the function will
deallocate any EMS/XMS in used and remove the swap file if one was
created. Passing in a False for this parameter will retain the
virtual memory. Under normall circumstances, the function should be
allowed to release all memory so that it is freed for use by other
editors. If you wish to retain the purged information for undo/redo
purposes, pass in False.
TVMFileEditor overrides this function to give you the option of
reloading the text. See its description for further details.
-------------------------------------------------
inline void setOption(ushort efConst, Boolean On)
-------------------------------------------------
This inline function provides a simple means of altering the
editor's local option settings. Simply pass it one or more of the
efXXXXX local option constants (ORed together if necessary) and True
to enable them or False to disable them.
----------------------------
inline Boolean canUndo(void)
----------------------------
This inline function returns True if undo/redo is enabled for the
editor or False if it is not.
-----------------------------------------
inline void cursorPos(short &x, long &y)
inline void textLimits(short &x, long &y)
-----------------------------------------
Cursor position and limits shouldn't be modified directly so they
are protected data members. These two inline functions will let you
know what they are currently set to. The x parameters refer to the
horizontal coordinates and the y parameters refer to the vertical
coordinates.
---------------------------------
inline const char *lineText(void)
---------------------------------
It is more expedient in an iterative, line-by-line operation to
call the virtual memory buffer text retrieval functions directly and
work with the Text[] line buffer. This returns a const char * to
Text[] for those cases. An example might be a compile operation. By
using the LRU text retrieval mechanisms of TVirtualMemory, the file
can be scanned from one end to the other fairly quickly. There are
other non-LRU functions in the TVirtualMemory class, but because they
return an address directly into a virtual memory page, they bypass the
LRU mechanisms and generally cause thrashing under such conditions
which slows performance.
----------------------------------
inline Boolean cursorVisible(void)
----------------------------------
This inline function returns True if the cursor is visible on the
screen or False if it is not. Unlike the original TEditor class, this
version will check both the horizontal and vertical cursor
coordinates.
------------------------
inline void lock(void)
inline void unlock(void)
------------------------
The function lock() increments the lockCount variable and prevents
screen updates from occurring. Its counterpart, unlock(), will
decrement the lockCount variable and, if it is zero, perform a screen
update.
--------------------------------
inline Boolean isClipboard(void)
--------------------------------
This inline function returns True if the associated editor is the
clipboard. If the editor is not the clipboard, it returns False. To
be the clipboard, the address of the TVMEditor object must be assigned
to TVMEditor::clipboard.
----------------------------------------------
inline void setDefaultMessage(const char *msg)
----------------------------------------------
This inline function simply allows you to set the default message
for its associated indicator when you are not doing it from inside a
TVMEditor derived class.
--------------------------------------------------------------
static Boolean changeKeyMap(short index, const ushort *newMap)
--------------------------------------------------------------
This is a static function that allows you to change key maps. The
key maps are shared by all editors. Therefore, if you change a key
map it will affect all open editors. A key map is simply a list of
keys and commands. The format of the key maps has been changed and is
not the same as it was for TEditor. They now all have the following
format:
<key1>, <command1>, <key> = Key to press
<key2>, <command2>, <command> = cmXXXX command value
. or 0xFFnn for a secondary
. array.
.
<keyN>, <commandN>,
0 Arrays MUST be terminated by a zero
for the key entry!
Examples:
// Default single key command mappings.
const ushort singleKeys[] =
{
kbCtrlK, 0xFF01, // Block lead in key
kbCtrlQ, 0xFF02, // Quick lead in key
kbCtrlJ, 0xFF03, // Jump/Secondary clipboard lead
// in key
kbCtrlO, 0xFF04, // Option/Other lead in key
kbLeft, cmCharLeft, // Movement
kbCtrlS, cmCharLeft,
kbRight, cmCharRight,
kbCtrlD, cmCharRight,
.
.
.
.
kbCtrlB, cmWrapPara,
kbAltMinus, cmUndo,
kbAltEqual, cmRedo,
0
};
// Default: Ctrl K, 0xFF01
const ushort blockKeys[] =
{
'B', cmStartSelect,
'K', cmEndSelect,
'H', cmHideSelect,
'C', cmCopyBlock,
'V', cmMoveBlock,
'Y', cmClear,
'I', cmIndentBlock,
'U', cmUnindentBlock,
'R', cmReadFile,
'W', cmWriteBlock,
'P', cmPrintBlock,
'1', cmSetBookmark1,
'2', cmSetBookmark2,
'3', cmSetBookmark3,
0
};
etc.
The addresses of these arrays are then stored in another array
like this:
const ushort *VMkeyMap[9] = { singleKeys, blockKeys, quickKeys,
jumpKeys, optKeys, NULL,
NULL, NULL, NULL };
This is the keyboard command map array. The zeroeth element's
array is always scanned first. To access the other elements' arrays,
a lead-in keypress is needed within that array. This lead-in key
causes a flag to be set (keyState) which sends the editor to look in a
different array for the next keypress after the lead-in.
The lead-in keys are defined in the singleKeys array by having the
command value 0xFFnn where nn is the element number of VMkeyMap[]
which will be accessed for the next keypress. For example, Ctrl+K, H
has "kbCtrlK, 0xFF01" defined for Ctrl K in singleKeys and "'H',
cmHideSelect" defined in the blockKeys array for the 'H' keypress.
Ctrl+K signals the editor to look in the blockKeys array on the next
keypress and, if H is pressed, it will execute the cmHideSelect
command.
When the second key of a two-key command is pressed, you should
let go of the Ctrl key unless it is specifically needed. Some
sequences such as Ctrl+K, 1 will not work if Ctrl is held down while
pressing the "1". That is because Ctrl+1 does not have a scan code on
the normal PC keyboard and therefore won't generate a keyboard event.
These maps can be replaced by calling the changeKeyMap() function
so as to define your own preferences. There is extra space in the
VMkeyMap array to hold up to four additional unique lead-in keys'
maps. This should save you from having to override convertEvent()
every time a new keyboard layout is needed or a new lead-in command
key is needed. Note that the maps pointed to can be up to 64K in size
so there is no real limit on how many commands can be placed in a
single array.
To use this function, simply pass in the index number of the array
you wish to replace (0-8) and a 'const ushort *' to the new command
key map. changeKeyMap() will return True if the map was replaced or
False if it wasn't. Currently, it will only return False if you
specify an invalid index (a number other than 0 to 8). Note that if
you wish to alter the first key of any of the existing two-key
commands (Ctrl+K, Ctrl+Q, Ctrl+J, or Ctrl+O) or add a new two-key
starter, you will also need to replace the singleKeys array. Also be
aware of the fact that it is up to you to insure that there are no
kbXXXX values attached to more than one command in the same array. If
you do have a key attached to more than one command in the same array,
the editor will only see the first command it encounters.
Examples:
const ushort MyBlockKeys[] =
{
.
.
.
};
// Change second key presses for the Ctrl+K block keys.
TVMEditor::changeKeyMap(1, &MyBlockKeys[0]);
const ushort MySingleKeys[] =
{
kbCtrlX, 0xFF01, // Block lead in key changed
// to Ctrl+X
kbCtrlQ, 0xFF02,
kbCtrlJ, 0xFF03,
kbCtrlO, 0xFF04,
kbAltY, 0xFF05, // A new lead in key.
kbLeft, cmCharLeft,
kbCtrlS, cmCharLeft,
kbRight, cmCharRight,
kbCtrlD, cmCharRight,
.
.
.
.
kbCtrlB, cmWrapPara,
kbAltMinus, cmUndo,
kbAltEqual, cmRedo,
0
};
const ushort MyAltYKeys[] =
{
.
.
.
};
// Changes Ctrl+K to Ctrl+X and adds Alt+Y
TVMEditor::changeKeyMap(0, &MySingleKeys[0]);
// Defines the second key press actions for Alt+Y
TVMEditor::changeKeyMap(5, &MyAltYKeys[0]);
To restore a key map to its default settings, simply specify the
index number and NULL for the newMap pointer. For index values
greater than 4, the VMKeyMap[] element will be set to NULL and for
index values of 4 or less, the VMKeyMap[] element will be reset to
point to the original key map.
// Return the key maps to their original states.
TVMEditor::changeKeyMap(0, NULL); // Point to default
// singleKeys again
TVMEditor::changeKeyMap(5, NULL); // Set to NULL again
------------------------------------------------
void setCmdState(ushort command, Boolean enable)
------------------------------------------------
This function enables or disables the specified command depending
on whether 'enable' is True of False and whether or not the editor is
active. If the editor is not the focused view, the command is always
disabled.
------------------------------------------------------------
void setSelect(short fromX, long fromY, short toX, long toY,
Boolean goTop = False)
------------------------------------------------------------
The setSelect() function simply marks the range of text starting
at 'fromX, fromY' and going to 'toX, toY' as the currently selected
block. If goTop is False, the cursor is placed at the end of the
block. If True, the cursor is placed at the top of the block.
--------------------------------------------------------------------
void TVMEditor::putCursorAt(short x, long y, Boolean center = False)
--------------------------------------------------------------------
The putCursorAt() function will position the cursor at the given
coordinates. This should be used in place of the setCursor() function
inherited from TView which only moves the hardware cursor around the
screen. If 'center' is True, the cursor will be placed as close as
possible to the center of the screen. If False, no such attempt is
made.
------------------------------
void scrollTo(short x, long y)
------------------------------
This function moves column X and line Y to the upper left corner
of the editor's view.
--------------------------------
void trackCursor(Boolean center)
--------------------------------
This function will force the display into a position such that the
cursor is visible. If 'center' is True, the cursor will be placed as
close to the center of the view as possible in both the horizontal and
vertical directions.
-------------------------
void update(uchar aFlags)
-------------------------
This function is used to alter the updateFlags data member. If
lockCount is zero, it will also refresh the display by calling
doUpdate().
-------------------
void doUpdate(void)
-------------------
This function will update the view's display based on the setting
of the updateFlags data member. If it is zero, nothing happens.
Otherwise, it will update the command set, draw the scrollbars and
indicator, and optionally draw a part or all of the editor's view.
----------------------
long getTextSize(void)
----------------------
This function returns the total number of characters in the editor
buffer. A function by the same name also exists in the TVirtualMemory
class. These can be used to find out how much memory needs to be
allocated for text retrieval (i.e. for TVMMemo). The difference
between the TVMEditor and TVirtualMemory copy is that
TVirtualMemory::getTextSize() returns the total size calculated using
NULL terminated lines where as TVMEditor::getTextSize() will account
for the extra carriage return on each line when the efUseLFOnly option
bit is not set.
--------------------
short pad(short pos)
--------------------
This function will add trailing spaces to Text[] if needed. When
the cursor moves to a new line, it is padded with spaces so that the
cursor maintains its horizontal position. This provides the editor
with a free-roaming cursor. The trailing spaces are removed before
the line is stored if the efTrailingSpaces option is not set. If
efTrailingSpaces is set, then the spaces are not added because in that
case, trailing spaces in the input file or those added in editing are
permanently retained. In this mode the cursor can't be moved beyond
the rightmost character of a line with the right arrow key. This
function will return the line length with padding (if any).
------------------------------------
short trim(char *sline, char *chptr)
------------------------------------
This function will strip trailing whitespace (in this case spaces
and tabs only) from the end of the line. The length of the string
after stripping is returned. If *ch is not NULL, it is filled in with
the character that the NULL terminator replaced. This is done so that
the whitespace can be added back in by the caller if necessary with a
simple sline[pos] = ch. It is used this way internally by some of the
commands.
------------------------------------------------------
void moveChar(short move, Boolean isSelecting = False)
------------------------------------------------------
This function will move the cursor by 'move' columns to the right
or left. Trailing spaces are added to the right as needed (and when
allowed) to provide a free-roaming cursor. The isSelecting parameter
determines whether or not the block marking mode will start, continue,
or finish.
------------------------------------------------------
void moveWord(short move, Boolean isSelecting = False)
------------------------------------------------------
This function will move the cursor one word to the left when
'move' is equal to -1 or one word to the right when 'move' is equal to
1. If the cursor goes past the beginning or the end of the line, it
will automatically jump to the word on the previous or next line. The
isSelecting parameter determines whether or not the block marking mode
will start, continue, or finish.
-----------------------------------------------------
void moveLine(long move, Boolean isSelecting = False)
-----------------------------------------------------
This function will move the cursor up or down by 'move' lines. If
possible, the cursor will maintain its physical screen position
relative to the top and bottom of the window when a scroll occurs.
The isSelecting parameter determines whether or not the block marking
mode will start, continue, or finish.
--------------------------------------------
Boolean insertChar(char ch, Boolean insChar)
--------------------------------------------
This function will take the character passed to it and either
insert it at the current cursor location or overwrite the character at
the current cursor location. The cursor position is moved one
character to the right.
------------------------------------
void insertTab(Boolean centerCursor)
------------------------------------
This function will insert the appropriate tab representation into
the editor line when insert mode is on. When insert mode is off, it
simply moves the cursor by the appropriate amount of space. It is
passed the value True or False in centerCursor. This value is then
passed to trackCursor() just before returning to insure that the
cursor is visible on the screen.
-------------------
void insertCR(void)
-------------------
This function handles the insertion of a carriage return. When
the cursor is in the first column of the line, a blank line is
inserted above the current line. If the cursor is somewhere else, the
current line is split into two separate parts at the current cursor
location. The cursor always moves down one line. If a line is split,
the second half will be indented accordingly if auto indent mode is
enabled.
---------------------------------
void deleteChar(Boolean DelRight)
---------------------------------
This function will delete a character for Backspace or DEL. If
DelRight is True, the character at the current cursor location is
deleted and the remaining text is pulled backwards to fill the gap.
If DelRight is False, the character immediately to the left of the
cursor is deleted and the remaining text is pulled backwards to fill
the gap.
When the cursor is in the first column of the line and Backspace
is pressed, the line will be joined to the previous one. If the
cursor is in the last column and DEL is pressed, the line following
the current one is appended to it.
------------------------------------
void deleteTab(Boolean centerCursor)
------------------------------------
This function is simply the reverse of insertTab(). When insert
mode is on, it deletes the appropriate tab width. When insert mode is
off, it simply moves the cursor to the left by the appropriate tab
width. The trackCursor() function is called afterwards to insure that
the cursor is still visible.
---------------------
void deleteLine(void)
---------------------
This function deletes the current cursor line as referenced by the
value in curPos.y.
--------------------------
Boolean hasSelection(void)
--------------------------
This function returns True if there is a currently marked block of
text. If there is no currently marked text block, it returns False.
A block is considered marked when the start and end lines are non-zero
and, if the start and end lines are the same, the start and end
columns are not equal.
----------------------------------
void adjustBlock(short difference)
----------------------------------
This function adjusts the block start and end points whenever one
or more characters are inserted or deleted from a line. This was
added so that the persistent block would maintain a reasonable start
and end point as text is edited instead of remaining fixed at a point
that may no longer be valid.
----------------------
void deleteBlock(void)
void moveBlock(void)
void copyBlock(void)
----------------------
These three functions control the non-clipboard delete, move, and
copy operations. The deleteBlock() function simply erases the
currently selected block of text. The moveBlock() function will
attempt to move the currently selected block of text to the current
cursor location. If the cursor is anywhere inside the selected block,
the move operation will be ignored. This is because moving the text
to a point anywhere within the selected text will not make it go
anywhere. The copyBlock() function will copy the currently selected
block of text to the current cursor location.
------------------------------------
Boolean insertFrom(TVMEditor *insEd)
Boolean clipCopy(void)
Boolean clipCut(void)
Boolean clipPaste(void)
------------------------------------
These four functions constitute the clipboard control functions
for the editor. clipCopy() copies the selected text to the clipboard,
clipCut() will copy it to the clipboard and delete it from the current
editor, and clipPaste() will paste the clipboard's currently selected
block of text into the current editor. All three functions make use
of the insertFrom() function by calling clipboard->insertFrom(this)
for cut or copy and insertFrom(clipboard) for paste. insertFrom()
simply takes the selected block of text from the insEd editor and
starts inserting it into the editor that called it at the current
cursor location. If the insertion was successful, it returns True.
It will return False under any of the following conditions: insEd is
NULL, the editor is trying to insert text into itself, the editor is
trying to insert text from a linked editor into the same shared
virtual memory buffer (same as inserting into itself), there is no
selected text in insEd, or the receiving editor is Read Only.
----------------------------------------
Boolean insertAtCursor(const char *text)
----------------------------------------
This function can be used to insert a string of text at the
current cursor location. It works by calling the insertChar()
function for each character in the string. Note that the tab and new
line characters are processed properly and each will insert the proper
amount of spaces or new lines in the text. Word wrapping will also
occur properly as the text is inserted if the word wrap option bits
are set. If the insertion was successful, True is returned. If there
was a problem inserting the text, False is returned.
-------------------------------------------------------------------
ushort getSelectedTextSize(char LineTerm)
ushort getSelectedText(char *buffer, ushort length, char LineTerm,
Boolean *NotDone)
-------------------------------------------------------------------
getSelectedTextSize() returns the size of the selected text block.
This function repeatedly calls getSelectedText() to determine the
actual size of the selected text. This is useful for determining
storage requirements prior to actually doing the retrieval. If the
selected text exceeds 60K, the function return the maximum value 60K
(61440 bytes). All you need to do in order to receive a valid count
is pass in the line termination character that will be used with the
actual getSelectedText() function call (NULL, line feed, or carriage
return).
getSelectedText() is similar in nature to TVMMemo::RetrieveMemo()
but it is in the base TVMEditor class and is used to retrieve the
block of selected text to a user-specified buffer. Pass it a pointer
to the buffer, the maximum length (up to 61440 bytes) and the line
termination method to use ('\r' = CR/LF, '\n' = LF only, '\x0' =
NULL). The function returns the actual number of bytes stored to the
buffer including line terminators. If 'Boolean *NotDone' is not NULL,
the function will return True in that location if all the selected
text was returned or False if not. If False, the function will adjust
the selected block so that a subsequent call will return the next
block. This can be repeated until 'NotDone' is returned as True. If
'*buffer' is NULL, the function returns the byte count for the text
that would fit in the given length but does not copy any data.
----------------------
Boolean wrapLine(void)
----------------------
This function controls word wrapping of the current line (as
referenced by the curPos.y value). If word wrapping is enabled in the
local options, this is called automatically whenever a word wrap is
required. It is also called by wrapPara() when reformatting blocks of
text.
Rules for word wrapping:
1. Called by the insertChar() function if cursor is past the
specified right margin and the inserted character is not a
space or tab.
2. Called by wrapPara() when reformatting paragraphs.
3. Note that if characters are inserted such that text after the
cursor exceeds the right margin before the cursor does, the
line will still not be wrapped until the cursor passes the
right margin or until the line is reformatted as part of a
Paragraph Reformat command.
4. If the first word starts past the right margin, then no word
wrapping will be performed for that line.
5. The first word, space, or tab after the right margin is the
wrapping point.
6. If a word spans the margin, the wrapping point is the first
space or tab prior to that word. If that word is the first
word of the line, then no wrapping will occur.
7. Text after the wrap point is moved to a new line with the
cursor. Leading spaces are stripped and the line is indented
if required.
-------------------
void wrapPara(void)
-------------------
This function controls the reformatting of text blocks (referred
to as paragraphs for lack of a better term). This is a text editor
and not a word processor, so soft returns are not used to mark
wrapping points and this function is only called when the user
requests it via the keyboard command (^B by default) or if auto
wrapping is enabled (efAutoWrap is set). It is possible to use
EOLMaker to set points in the text where reformatting should stop,
thus providing a form of "hard return". However, when auto wrapping
is enabled, wrapPara() reacts differently when called to perfom an
automatic wrap and will stop reformatting when it detects any change
in indentation. This prevents the reformatting of too much text that
can occur when the manaul (^B) paragraph reformat command is issued.
See the section entitled Paragraph Reformatting for more details on
how this works.
Rules for reformatting:
1. Reformatting starts at the current cursor line.
2. Reformatting continues until a blank line, the end of the file,
the end of a selected block, or a line with an indent or
outdent equal to the starting line is encountered.
3. If the indentation of the first and second lines is the same,
reformatting will continue until a blank line, the end of the
file, or the end of a selected block is encountered (whichever
occurs first).
4. The indentation for lines after the first is determined by
getting the indentation for the second line. All lines after
the first will be indented or outdented by that same amount.
5. Reformatting is done by repeatedly word wrapping long lines and
appending words to short ones from subsequent lines until an
exit condition is met. Lines that have their text completely
assimilated into another line are deleted.
6. Word wrapping will not occur for lines that start past the
right margin or for lines where there is no place to legally
break a line (i.e. no spaces or tabs between words).
Such lines may still be indented.
7. Regardless of where a block starts or ends, the paragraph
reformat command will always work with whole lines only.
----------------------
void reformatAll(void)
----------------------
This function can be called to unconditionally reformat the
entire document. It is also used to support the efWrapOnResize option
bit. Note that depending upon the size of the document, this function
may take a little while to perform its task.
---------------------
void doAutoWrap(void)
---------------------
This function exists to perform the automatic text wrapping. It
is called after any cmDelXXXXX command and is also called from the
insertChar() function. If required, the text from the line that the
cursor is on and as many subsequent lines as needed are reformatted.
See the wrapPara() function for the reformatting rules.
-----------------------------------------------
void alterText(long from, long to, ushort cmnd)
-----------------------------------------------
This single function takes care of the following editor commands:
cmForceUpper - Force text in the current line or marked block to
upper case.
cmForceLower - Force text in the current line or marked block to
lower case.
cmToggleCase - Switch the case of the text in the current line or
marked block from upper to lower case or vice versa.
cmIndentBlock - Indent the current line or all lines in the marked
block by the size specified in the local options'
IndentSize data member.
cmUnindentBlock - Unindent the current line or all lines in the marked
block by the size specified in the local options'
IndentSize data member.
cmCenterLines - Center the current line or all lines in the marked
block between column 1 and the current right margin
as specified in the local options.
cmAlignText - Align the current line or all lines in the marked block
with the first non-blank line above the starting point.
For cmIndentBlock and cmUnindentBlock, it will either indent or
outdent the selected lines by the amount specified by the IndentSize
member of the local options structure. If cmUnindentBlock encounters
a hard tab, it will break it into spaces and only remove the necessary
number of positions from it. All characters (whitespace or text) are
included when unindenting, so it is possible to truncate the text at
the beginning of the line.
cmCenterLines will center the text on the selected lines between
column 1 and the current RightMargin value in the local options
structure. Trailing spaces will be truncated regardless of the Retain
Trailing Spaces setting so that the text can be properly centered.
cmAlignText will align the selected lines with the first non-blank
line above the starting point. If a non-blank line isn't found, then
no alignment will be performed. Alignment consists of adjusting the
amount of whitespace at the start of the line to match the lines
above.
Note that regardless of where a block starts or ends, the indent,
centering, and alignment commands will always work with whole lines
only. The case toggling commands can work with any type of marked
block including ones that start and/or end at points other than the
beginning or end of lines.
User Defined Text Alterations
-----------------------------
By passing the alterText() function a command value other than
those listed above, you can perform your own custom edits. If the
'cmnd' value is not recognized, a call is placed to the editorDialog()
function with a value of edAlterText followed by the command, a
pointer to the line's text, and starting and ending column values
which denote what part of the line should be affected by the command.
This gives you a "hook" that can be used to alter text in different
ways that may not be a standard part of the editor. If the
editorDialog() function returns cmCancel, nothing is changed. If it
returns cmOK, then the altered text is stored.
----------------------------------
void SearchDialog(Boolean Replace)
void doSearchReplace(void)
Boolean search(void)
----------------------------------
These three functions control the search and replace features for
the editors. SearchDialog() will create either a Find Dialog if the
Replace parameter is False or a Replace Dialog if the Replace
parameter is True. The user is then prompted for the necessary
information and, if the user chooses to do so, the operation is then
performed.
The doSearchReplace() function controls the top level operation of
a search or replace, it calls search() to look for the specified text
and then prompts the user if necessary and takes care of replacements.
The search() function controls the low level aspects of the
search. It determines where to start and stop, when a match has been
found, and movement through the buffer while searching.
-----------------------
void FindMatching(void)
-----------------------
This function controls the Find Matching feature of the editor.
It simply takes the character under the cursor and, if it is a
matchable character, will try to find its companion. If its companion
cannot be found, the cursor will stay where it is at and nothing will
happen. If a match is found (whether it is correct or not), the
cursor will jump to the new location. If it is not where you expected
it, you have a mismatch somewhere between the starting and ending
location. See the section entitled Enter Matching under the Local
Editor Options descriptions for more information.
The TVMFileEditor Class
-----------------------
Features List
=============
The basic TVMFileEditor and derived classes support the following
additional features:
* Recognizes Print File, Print Block, and Save All commands.
* A single virtual memory buffer will be shared between two or
more editors when they are all looking at the same file.
* Buffer clearing and file reload via a single call to the
doneBuffer() function.
* By adding the necessary code to your editorDialog() function
and issuing a broadcast cmReSynch event, you can have the
file editors automatically reload their file from disk if it is
no longer current after such things as shelling to the DOS
prompt.
* If the efSetROonLoad bit is set, the editor will check the Read
Only access flag on the file and, if set, will make the editor
Read Only as well to prevent altering the file.
The TVMFileEditor class is almost identical to its normal Turbo
Vision counterpart. However, this file editor supports read block,
write block, print block, and printing of the entire file. I felt
that these were more of an I/O nature than a basic editing feature.
The base TVMEditor class will convert the keyboard commands to cmXXXX
commands, but will not act on them. Only TVMFileEditor will. The
Print member function is only defined for TVMFileEditor and is
virtual. It can therefore be overridden if required. The default
function provides basic printing ability. The only formatting
performed is to send hard tabs to the device specified in the global
options as the appropriate number of spaces (defined via the local Tab
Size option) when the file or a selected block is printed.
A big plus to using TVMFileEditors that are looking at the same
file is that they will share a common virtual memory buffer. That
way, changes made in one editor will also be reflected in other linked
editors. This will also conserve conventional memory. Editors that
share a common buffer will use about 96% LESS conventional memory than
the first one opened for the file. The amount of virtual memory saved
will also be substantial. Each editor that is sharing the buffer
won't have any allocated for it because there is one common buffer
object between them.
Each editor will still retain its own local options and will
function independently of the others. Changes to the text in one
editor will be reflected on screen in the others only when you move
between them. Also, you will not be prompted to save a modified file
if you close a linked window. You are only prompted when you close
the very last window that is viewing the modified file.
Data and Function Members
-------------------------
----------------------
char fileName[MAXPATH]
----------------------
This contains the name of the text file being edited. The name is
displayed on the top border of TVMEditWindow objects.
------------------------------------------------------------
TVMFileEditor(const TRect &bounds, TScrollBar *aHScrollBar,
TVMScrollbar *aVScrollBar, TVMIndicator *aIndicator,
const char *aFileName, short bufSizeInK = 20,
Boolean SuppressLoad = False)
------------------------------------------------------------
This is the constructor for the TVMFileEditor class. As you can
see, the first five parameters match up to the original TFileEditor
class with the exceptions of the vertical scrollbar being a
TVMScrollBar and the indicator being a TVMIndicator. Following those
is the additional parameter bufSizeInK that you may or may not want to
specify. This parameter specifies (in Kilobytes) how large the
conventional memory buffer will be for the editor object. This buffer
is used to hold the recently used text and internal information
necessary for editing the file. By default, it is 20K. Derived
classes can adjust this upwards or downwards based on their needs. If
you do not want one of the optional scrollbars or the indicator, pass
a NULL in that parameter's position. The last parameter,
SuppressLoad, will function just as it does for TVMEditWindow. When
True, it suppresses the loading of text until you call the
loadFileNow() function for the editor.
-------------------------------------
virtual Boolean valid(ushort command)
-------------------------------------
This overridden valid() function will insure that a modified
editor is not closed without first prompting the user to either save
it or discard it. You will not be prompted to save a modified file if
it is sharing a buffer with another editor. Only the last remaining
editor attached to the buffer will prompt you to save it upon closing.
---------------------------------------
virtual void handleEvent(TEvent &event)
virtual void shutDown(void)
virtual void updateCommands(void)
---------------------------------------
These three functions are overridden to handle the extra commands
recognized by the TVMFileEditor class. Because multiple ownership is
a possibility, the cmUpdateTitle command is handled by
TVMFileEditor::handleEvent() instead of TVMEditWindow::handleEvent().
This event is sent to each owner by the buffer object whenever the
filename changes for one of its owners.
----------------------------------------------------------------------
virtual void doneBuffer(Boolean releaseMem = True, Boolean reloadFile)
----------------------------------------------------------------------
This function calls TVMEditor::doneBuffer() and, if reloadFile is
True, will reload the file it contains from disk. An example of when
this is used is the cmReSynch command. The TVMFileEditor class will
recognize the cmReSynch command as an evBroadcast event. When
received, it will check the date and time stamp of its associated file
on disk (if one exists). If the date and/or time stamp is different,
it will call the editorDialog() function with a value of edReSynch and
a pointer to the filename. You can make the editorDialog() function
query the user as to whether or not the file should be reloaded or
simply return cmYes to force a reload. Not handling the event or
returning a value other than cmYes will prevent the file from being
reloaded. This is useful after a shell to DOS in which the text files
may be altered by an external source. It is also useful for automatic
resynchronization of a file editor. An example might be if you
translate the file on disk in some manner and need to insure that an
open editor window always reflects the most recent contents. Two
public unsigned int members (FileDate and FileTime) were added to the
TVirtualMemory class to support the date and time stamp checking.
They were added there due to the buffer sharing ability.
--------------------------------------------
virtual void PrintBuffer(long from, long to)
--------------------------------------------
This is the default print function for TVMFileEditor objects. It
simply takes each line, formats it for tabs if necessary, and sends it
to the printer. If the EOLMarker character is being used, any
occurances of it will also be stripped out before printing the line.
This function is virtual, so it can be overridden in a derived class
if necessary to provide more print features.
----------------------
void loadFileNow(void)
----------------------
This loads the file *after* construction when SuppressLoad was set
to True. This is used in cases where the swap file is placed on
another drive and/or directory and the swap filename needs to be
changed. By suppressing the load at construction, the swap filename
can be changed with the guarantee that it is not already open. In
such situations, a call to loadFileNow() must be issued after setting
the swap filename so that the file text is placed in the buffer for
you to edit.
-------------------------
void readFile(char *name)
-------------------------
This reads text into the current editor buffer from the named file
for a cmReadFile command. The first inserted line is above the
current line. All inserted text is marked as the active block upon
return from this function.
---------------------------------------------------------
long readText(char *name, long line, Boolean InitialLoad)
---------------------------------------------------------
This function is the main data loading function. It starts
inserting text at the specified line number and will return the number
of the last line inserted. For lines that exceed the maximum width,
it will split them into two or more pieces. A warning is issued if
this occurs by calling the editorDialog() function with the value
edLinesSplit. The InitialLoad parameter is used when the object is
first created so that the virtual memory buffer fills all conventional
memory pages before swapping starts.
-------------------------------------------------
Boolean writeFile(long from, long to, char *name,
Boolean updateTimeStamp = False)
-------------------------------------------------
This function will write the lines 'from' through 'to' out to the
specified filename. It is used for the main file save commands as
well as the write block commands. To provide the most safety during
the save, all text is written to a temporary file. If the save
succeeds, the temporary file is then renamed to the real filename. If
it fails, the original file will be left completely intact. If
enabled, this routine will also rename the original file to have the
backup filename extension upon successful completion. The
updateTimeStamp parameter is set to True when saving the loaded file
so that the internal date and time stamp values are updated for the
cmReSynch event.
The TVMMemo Class
-----------------
The basic TVMMemo class supports the following additional
features:
* Derived from TVMFileEditor instead of TVMEditor so it supports
TVMFileEditor's ability to print text and read/write blocks of
text to/from files.
* It has less memory overhead when used in a dialog box than its
predecessor.
* It has better text storage and retrieval mechanisms.
* You can use Scroll Lock to toggle how Tab and Shift+Tab are
handled inside a dialog box's memo fields.
* When using setData() and getData() for loading and retrieving
text, the TVMMemo::valid() member function will check the total
length of the text it contains to insure that it will fit inside
the destination buffer before a call to getData() would be
allowed. This provides some protection from inadvertent memory
overwrite.
* Lines inside the buffer are separated in a more natural format
for easier parsing by the programmer. Lines will be separated
by NULLs, line feeds, or carriage return-line feed pairs.
TVMMemo is similar to its standard Turbo Vision counterpart but it
is a lot more flexible in usage. A majority of that flexibility comes
from being derived from TVMFileEditor instead of TVMEditor. It is a
TVMFileEditor object with getData(), setData(), and dataSize() members
for insertion into a dialog box. As such, all functions available to
the basic TVMFileEditor are available to the TVMMemo including all
formatting commands, the clipboard functions if one is defined, search
and replace, local option modification, undo/redo, read block, write
block, print block, and line jump when an appropriate editorDialog()
function equipped for those events is defined. The demo program has
examples of this functionality. In addition, the TVMMemo can handle a
small, fixed buffer size and start swapping if the text exceeds that
buffer size. Thus, multiple memo fields containing large amounts of
text can be used together in one or more open dialog boxes without
exhausting available conventional memory.
Note that unlike TVMFileEditor, the TVMMemo class does not have a
filename associated with it. However, it can implement buffer sharing
between other memos or file editors. As stated earlier, you can pass
a filename to TVMMemo for it to load into the buffer, but this is
associated only with its extended text storage and retrieval
mechanisms. If used, the memo will be loaded with the text from this
file when constructed.
If you haven't looked at the code for the original TMemo, you will
not have noticed that when stored to a resource file, the memo will
store any text it contains in the resource file too. Thus with
TVMMemo, you can have it load a file into its buffer, stream it to a
resource file and it will take the loaded text right along with it.
When the memo is restored from the resource file, it will also restore
the text it contains. This feature can be extremely useful for
storing large informational dialog boxes in resource files that may
not have been included as part of a context sensitive help file.
Currently, this is the only reason for specifying a filename in the
constructor. The name is discarded after loading. The memo will
respond to the cmSave/cmSaveAs commands if necessary, but if you will
be saving data to a file in this manner, it would probably be better
to use a true TVMFileEditor.
I always found it annoying that the TMemo class let Tab and
Shift+Tab change focus from one dialog item to the next. The only
alternative was to use spaces in place of tabs. I altered this habit
by using the Scroll Lock key as a toggle. When Scroll Lock is off,
the Tab and Shift+Tab keys will act as they always have. When Scroll
Lock is turned on, Tab and Shift+Tab are handled by the memo field.
Therefore, you can now insert and delete tabs of the appropriate size
with a single press of the Tab or Shift+Tab key instead of using the
space bar or backspace key. If you leave Scroll Lock on, the mouse
can still be used to move you from field to field. Optionally, you
can simply toggle Scroll Lock on and off as you need it. When the
memo field is constructed or restored from a resource file, Scroll
Lock is toggled off automatically. The indicator (if you create one
for the memo field) will always display the current state of the
Scroll Lock key.
The TVMMemoData structure used to load the memo field is very
different. In order to minimize memory usage when creating and
executing the dialog, TVMMemoData simply has a 'char *' to a buffer
instead of an INT_MAX sized char array (or a one byte char array for
Turbo Vision 2.0). This allows for a number of different methods of
allocating memory and using it to initialize the memo fields. One
small allocation per memo field can be made or one large allocation
for all memos can be made. You can also pass the address of an
existing character array or buffer to the memo field as well. That
way, you don't have to allocate any dynamic memory at all. A comment
field within a record's data structure might be such a case.
Standard TVMMemo Usage
======================
When using setData(), you will use the TVMMemoData structure to
specify the maximum length that the buffer can hold (in characters)
and also how many characters are currently stored in the buffer
including line terminating characters. Lines within the buffer can be
separated by NULLs, line feeds only, or carriage return/line feed
pairs. The load and retrieve functions will interpret the buffer and
break up the lines accordingly. When text is retrieved, lines will be
terminated according to what was found at load time. Note that all
lines must conform to the same termination standard. Mixing line
terminators within the same buffer may result in garbled or
inappropriately separated lines.
If you only insert a single NULL terminated line into the buffer,
the line terminator will be set to the NULL character. If you would
like the lines to be terminated with "\n" or "\r\n" when retrieved,
then either append those characters to the line before inserting it or
call the setLineTerminator() function before retrieving text from the
memo field. If a memo starts out with a completely empty buffer, the
line termination character will default to '\r' for carriage
return+line feed.
The default valid() function used for TVMMemo will sum up the
length of all lines in the memo field whenever the dialog box is
closed and data is to be returned. If the memo contains too much
data, it will not allow the dialog box to close. That way, you are
protected from accidental memory overwrite. To close the dialog, you
must either cancel it or shorten the text in the memo field so that it
will fit in the specified buffer. Upon return from getData(), the
bytesCopied member of the TVMMemoData structure will contain the
number of bytes within the buffer including all line termination
characters.
Non-standard TVMMemo Usage
==========================
You may also call the functions to load and retrieve the text
yourself manually. To do this when other fields are present in the
dialog box (i.e. input lines, checkboxes, etc), you simply set the
length parameter of the TVMMemoData structure to zero and use the
LoadMemo() function to load data before executing the dialog box and
the RetrieveMemo() function to get the data after executing it. When
a memo field is all by itself in a dialog box (except for push
buttons), you may not need to use the setData() or getData() at all
if you are manually storing and retrieving text with LoadMemo() and
RetrieveMemo(). In general, setData() and getData() are simpler to
implement and should be used if at all possible
The LoadMemo() and RetrieveMemo() functions can be used to load
and retrieve large amounts of text to/from a memo field or can be used
in situations where the true size of the memo field may be unknown
until runtime. Note that even though you are controlling the loading
and retrieval of text for the memo field, you can still use setData()
and getData() for any other items in the dialog box including other
memo fields. Setting the 'length' parameter of TVMMemoData to zero
will tell the TVMMemo::setData() and TVMMemo::getData() functions for
that memo field not to do anything when called. It is then up to you
to load and retrieve the text that it contains.
Data and Function Members
-------------------------
------------------------------------------------------------------
struct TVMMemoData
{
// Maximum length. Up to 60K or use 0 to signal use of
// LoadMemo/RetrieveMemo.
ushort length;
// NOTE: This is a pointer now, not an array!
char *buffer;
// The amount of data to store by setData(). This is how many
// characters are parsed when loading data into the editor.
// Also:
// The amount of data returned by getData(). This is how much
// text was retrieved from the memo editor into the buffer.
ushort copyCount;
}
------------------------------------------------------------------
This is the field structure to use for a dialog box's data
structure. To use it, you need to set 'length' to the maximum length
of the TVMMemo field (or zero if you will be loading the memo
yourself). If you use setData() and getData(), you will also need to
set the pointer to the address of the text so that it can be loaded
automatically. For setData(), you will need to set copyCount to the
number of characters currently in the buffer. After a call to
getData(), copyCount will contain the new number of characters in the
buffer.
-------------
ushort Length
-------------
The maximum allowable length for this memo field. This is set to
a non-zero value by setData() when necessary and is used by valid() to
see if the text will fit in the user-supplied buffer for getData().
If set to zero either by default at construction or by setData(), then
no such checking is performed and it is assumed that the programmer
has taken control of loading and retrieving the text.
-------------------
char LineTerminator
-------------------
Line terminator for the load and retrieve functions. This simply
holds a character that will determine how lines are terminated when
text is retrieved from the buffer by getData() or RetrieveMemo(). It
will be either NULL, line feed, or carriage return (for carriage
return-line feed).
-------------------------------------
static const char * _NEAR MemoTooLong
-------------------------------------
This points to the text for the "Memo too long" message displayed
by the valid() function. It is displayed via a call to editorDialog()
with the parameters edGeneralMsg and the address in this pointer.
-------------------------------------------------------
TVMMemo(const TRect &bounds, TScrollBar *aHScrollBar,
TVMScrollbar *aVScrollBar, TVMIndicator *aIndicator,
short bufSizeInK = 1, const char *aFileName = NULL)
-------------------------------------------------------
This is the constructor for the TVMMemo class. As you can see,
the first four parameters match up to the original TMemo class with
the exceptions of the vertical scrollbar being a TVMScrollBar and the
indicator being a TVMIndicator. Following those is the additional
parameter bufSizeInK that you may or may not want to specify. This
parameter specifies (in Kilobytes) how large the conventional memory
buffer will be for the editor object. This buffer is used to hold the
recently used text and internal information necessary for editing the
file. By default, it is 1K. Derived classes can adjust this upwards
based on their needs. If you do not want one of the optional
scrollbars or the indicator, pass a NULL in that parameter's position.
The last parameter is the optional filename that can be used to
pre-load text into the memo field. The only purpose for this
parameter at the present time is for creating message dialogs like the
one in the demo program's resource file.
When constructed, the TVMMemo object will adjust the
Opts.RightMargin value to be 'bounds.b.x - bounds.a.x - 4' if it is
larger than that value. If this is acceptable, you don't have to do
anything to set it yourself. Also, when constructed or restored from
a resource file, the TVMMemo object will turn off the Scroll Lock
keyboard flag to emulate the original behaviour of TMemo concerning
the handling of Tab and Shift+Tab key presses.
---------------------------------------
virtual void handleEvent(TEvent &event)
---------------------------------------
This is similar to the original TMemo handleEvent(), but it has
the added ability to pass Tab and Shift+Tab key presses on to the
editor if Scroll Lock is toggled on.
-------------------------------------
virtual Boolean valid(ushort command)
-------------------------------------
This will check the length of the memo when necessary to insure
that it will fit in the user-supplied buffer referenced in setData()
and getData(). Note that the length check is not performed if the
length parameter of the TVMMemoData structure was set to zero or if
you are totally bypassing setData()/getData() for the dialog box.
NOTE: If you have an extremely large amount of text in the memo
field, it might take a little while for valid() to sum up the total
size of the memo text. If it seems to hang when you select OK to exit
the dialog, give it a minute or two. It may just be totalling the
size of a very large amount of text. This generally isn't a problem
as it does stop counting as soon as the limit is exceeded. The main
factors will be the speed of the PC and the location of the virtual
memory.
-------------------------------
virtual void getData(void *rec)
-------------------------------
The getData() function casts the *rec parameter to a TVMMemoData *
called 'data' and handles retrieving the memo text and storing it into
the user-supplied buffer. If data->length is non-zero, it retrieves
text into the user-supplied data->buffer. If data->length is zero, it
is the programmer's responsibility to retrieve the data. The
data->copyCount member will contain the actual number of bytes copied
to the buffer when data->length is non-zero. Because valid() will not
return True unless the text will fit in the buffer, you can be sure
that you have it all. However, if you derive a new TVMMemo class,
override valid(), and forget to call the base TVMMemo::valid(), this
might not be the case. So, you should always remember to call the
base TVMMemo::valid() function in any overridden valid() function for
a derived TVMMemo class. This is true of most classes in Turbo Vision
that have a valid() member function.
-------------------------------
virtual void setData(void *rec)
-------------------------------
The setData() function casts the *rec parameter to a TVMMemoData *
called 'data' and handles loading the text from the user-supplied
buffer into the memo field. If data->length is non-zero, it loads
data from the specified buffer pointed to by data->buffer. If
data->length is zero, it is the programmer's responsibility to load
the memo with text.
-----------------------------
virtual ushort dataSize(void)
-----------------------------
This simply returns the size of a TVMMemoData structure.
-----------------------------------------------------
virtual Boolean LoadMemo(ushort length, char *buffer,
Boolean FirstPart)
-----------------------------------------------------
This function is called by setData() to copy the text from the
user-supplied buffer into the memo field for use in the dialog box.
It can also be called by you to manually load text into the memo
field. This is generally needed only when special loading techniques
are to be used for your data. This function is also virtual, so you
can override it if necessary to handle your own specialized needs.
If used, you must call LoadMemo() with the FirstPart parameter set
to True for the very first call. If there are any subsequent calls
(if you are loading data in pieces for example), it should be set to
False. On the first call, LoadMemo() needs to be told to determine
how the lines are terminated. If it can't decide what the lines end
with, it will use the default line terminator as set in the
constructor or via a setLineTerminator() function call. This will
only happen if it cannot find any normal line termination characters
(NULL, line feed, or carriage return). The first one of the
previously listed characters it finds will determine how lines are
loaded into the memo and how they are terminated when you retrieve the
text from it.
On any call to LoadMemo(), *buffer will point to the text that
needs loading and length will be the actual length of the data in the
buffer (including the line termination characters). The text to be
loaded should be in the form of complete lines separated by NULLs,
line feeds, or carriage return-line feed pairs. Currently, this
function always returns True.
--------------------------------------------------------
virtual ushort RetrieveMemo(ushort length, char *buffer,
Boolean FirstPart, Boolean *NotDone = NULL)
--------------------------------------------------------
This function is called by getData() to move the text from the
memo field into the user-supplied buffer. It can also be called by
you to manually retrieve text from the memo. This is generally needed
only when special retrieval techniques are to be used for your data.
This function is also virtual, so you can override it if necessary to
handle your own specialized needs.
If used, you must call RetrieveMemo() with the FirstPart parameter
set to True for the very first call. If there are any subsequent
calls (if you are retrieving data in pieces for example), it should be
set to False. On the first call, RetrieveMemo() needs to be told to
start from line 1 of the memo text. On subsequent calls, it will
start retrieving text from where it left off on the last call.
On any call to RetrieveMemo(), *buffer will point to the place to
store the retrieved text and length will be the actual length of the
buffer. The retrieved text will be in the form of complete lines
separated by NULLs, line feeds, or carriage return-line feed pairs
(whatever was found when it was loaded into the memo field by
LoadMemo() or specified via the setLineTerminator() function).
Note that only whole lines are returned by this function, and that
the buffer may not be filled to capacity. RetrieveMemo() will return
the actual number of bytes copied into the buffer. You can also
specify the address of a Boolean variable and pass it to the function
as the 'NotDone' parameter. If RetrieveMemo() is unable to return all
the remaining text from the memo in the specified buffer, it will set
this variable to True. While NotDone is True, you can be sure that
there is more text to retrieve. When NotDone is False upon return
from the function, it means that there is no more text in the memo to
be retrieved. You can also tell that all text has been retrieved when
a call to RetrieveMemo() returns zero for the number of bytes copied.
-------------------------------------
Boolean setLineTerminator(char lTerm)
-------------------------------------
Use this function to explicitly specify what line termination
character you want to use in RetrieveMemo(). This must be called
after loading text into the memo field and before any text is
retrieved from it. Pass it '\x0', '\n' (line feed only), or '\r' (for
CR+LF) to set the line terminator type. This is useful for buffers
that are (or could be) blank when constructed and executed. By
default, such memo fields default to using '\r' (CR+LF) as the line
terminator.
TVECLEAN.COM
------------
While developing programs that use EMS memory for the editors, it
is possible that if the program crashes or you stop it from exiting
normally while using the debugger (program reset), the EMS memory
allocated to any open editors will not be freed. This memory will be
unavailable until the machine is rebooted or you run TVECLEAN.COM.
TVECLEAN.COM simply searches for any EMS memory handles with a
name in the form "nnTVMEDT" and frees them. This is a simple way to
free the memory without having to reboot the PC. The "nn" will be the
handle number in hex. This is how TVMEditor objects name their EMS
handles.
Note that there is no counterpart program for XMS memory.
Unfortunately, the XMS driver does not allow the naming of its
handles. Therefore, there is no way to tell who owns the memory. If
your program crashes or you stop if from exiting normally under the
debugger, any allocated XMS memory remains unavailable until you
reboot the PC.
TVCOLR.H
--------
This library makes use of a method I developed for extending the
colors of Turbo Vision classes without the problems usually associated
with such a task. It involves the simple inclusion of a single header
file and an alternate TView::mapColor() routine. These new colors can
be modified through a TColorDialog if so desired and, once defined,
will not interfere with any current or future color additions you make
using this method.
This method requires adding color attributes to the default
application palette. If you are familiar with my TVCOLR.ZIP or
TVCLR2.ZIP, then you won't have anything at all to learn. To use it,
you override the TApplication::getPalette() member function for your
application (an example can be seen in the demo program), #include
<tvcolr.h> in the files that need it, and add the supplied alternate
MAPCOLOR.CPP to your project. Just be sure that MAPCOLOR.CPP gets
linked in before TV.LIB (or TVNO.LIB and TVO.LIB if using overlays).
Complete details of this method can be found in TVCOLR.ZIP (for
Turbo Vision 1.03) or TVCLR2.ZIP (for Turbo Vision 2.0) in library 11
(Turbo Vision) in the BCPPDOS forum on CompuServe. I have submitted
the entire TVCOLR concept to the public domain, so it is free and can
be used in any of your own projects. If you don't have access to
CompuServe, simply make a note on the registration form when ordering
and I'll send you a copy of TVCOLR.ZIP or TVCLR2.ZIP with your
registered version. I think it's an easy way to extend the color
palettes used by Turbo Vision (but I designed it so... <g>).