Home page Home page Home page Home page
Pixel Header R1 C1 Pixel
Pixel Header R2 C1 Pixel
Pixel Header R3 C1 Pixel
By Sprezz | Monday, 11 June 2018 12:41 | 0 Comments
We seem to have had a flurry of UTF-8 queries lately at Sprezz Towers and, as there isn't a lot of information published about this, we thought it might be useful to comment a little about this subject.

For many years, OpenInsight (OI) didn't support UTF-8 and this led to difficulties with people who needed to store foreign language characters; which also just happened to be system delimiters for OI. So, for example:

Delimiter ANSI Character
@Rm 255 ÿ
@Fm 254 þ
@Vm 253 ý
@Svm 252 ü
@Tm 251 û
@Stm 250 ú

Quite the challenge if you're working with European languages.

To get around this issue, Rev introduced something called CHARMAP - a special system wide property that essentially relied upon the developer choosing characters they didn't want to use lower down in the ANSI table and using those to store the affected characters. Then at display time, swapping the lower characters back to the higher.

For example, if you wanted to be able to store ý (and what red-blooded occupant of Český Heršlág wouldn't?), you might decide that you're never going to need to use ™ (ANSI 153) and so instruct the CHARMAP to map 253 to 153. You'd enter Český Heršlág and OI would store Česk™ Heršlág - then when you asked it to display the town name, OI would convert the ™ back to ý before displaying it.

Clunky, but effective.

With UTF-8 we no longer have this problem, ý is actually stored as the multi byte string 00FD and so it doesn't stand a chance of being confused with ANSI 253 (although ironically it is just ANSI 253 with an ANSI 0 stuck in front). BUT, UTF-8 doesn't read minds. It doesn't know that when we ask it to display an ANSI 153 we really mean 00FD. And OI doesn't know that either - you might have intended to store a trademark symbol. So, if you are planning on moving data that previously used CHARMAP into a UTF-8 environment, you need to do some groundwork to avoid tying yourself (and anybody else trying to help you) into a series of complicated knots.

  • Use the SETNOOFDELIMITERS routine to set the value to be used to 0
  • For every data row in the application
    • Read the row
      • Use Loop/Remove to grab the individually delimited pieces of data
      • Convert your CHARMAPPED characters back to their original value
      • Recast the string as UTF-8 using the ANSI_UTF8 function
      • Add back into the new string you are building
    • When complete, write this string back over the original row. This means it will look strange in ANSI I because it will contain multi-byte characters, but it will work properly in the UTF-8 OI app.
  • Fire up your UTF-8 enabled OI app
  • Remove anything to do with CHARMAP
  • Attach your data and all will be well with the world

Hopefully this information will help you in the smooth transition of your data from ANSI to UTF-8.

And if you're new to the ways of UTF-8 don't forget this handy article for programming in UTF-8.
By Sprezz | Wednesday, 9 May 2018 16:39 | 0 Comments
Recently Don Bakke at SRP published a very helpful blog entry highlighting just how much more productive it is possible to be in OI X – and he is SO right. Over the years, as more and more properties were added to the Presentation Server, the Form Designer struggled to keep up. So internally the Presentation Server had its list of properties and the Form Designer – being a separate executable – had its own list of properties which wasn’t really ever added to. The knock-on effect from this was that if you wanted to achieve certain things using the new properties you HAD to cut code, and cutting code takes time, it adds to the maintenance burden and it introduces a potential point of failure.

This post is going to highlight the new properties in just the Windows control that remove some of the coding burden from the OpenInsight developer. To make it easy to follow we’ll deal with the properties in the order in which they’re found in the property panel in the Form Designer. When properties are trivial we’ll describe them en masse to save wasting blog space!



Documented in full in Carl's RevDevX blog.  Conventionally OpenInsight developers have adapted a naming convention of calling their commuter program by a standardised name (such as the Window name or the Window name with a suffix) so that they can easily identify the program for maintenance reasons. By having a COMMUTERMODULE property the developer can use whatever name they want. For example they could use the same commuter program for a logically related set of Windows. By having just one tried and tested code block used across multiple entities, this is yet another area where OpenInsight helps developers to have fewer lines of code to maintain and the minimum possible potential failure points

Historically attaching context menus to anything has been a… non-straightforward procedure. Now that context menus are the same as normal menus it is possible to design them using the Menu Designer and at design time they simply added to the CONTEXTMENU property.

Does what is has always done but it is now exposed in the Form Designer.

Does what is has always done but it is now exposed in the Form Designer.


A new property for all controls that just provides a slot for the developer to store stuff at design time and which can easily be accessed and modified at runtime.

A new property for all controls that support tooltips. The tooltip designer built into the Form Designer makes it very easy to add tooltips to controls.

Which are then displayed automatically when the user hovers over the control they’re associated with (in this case the Window).


Whilst IOOPTIONS still works, its component parts have been exposed as individual properties self-evidently named. Again, the flexibility to set these at design time removes the need for yet more code!

A couple of new properties have been exposed in here as well.

If this is set to “Yes” then PREV will be loaded on READ as well as WRITE. In other words, default OpenInsight behaviour is to only load the PREV property when a row is written – which only happens if a change has been made. If this is set then PREV will always be loaded (as it is loaded when the previous row is read).

Documented in full in Carl's RevDevX Blog. This property basically, instructs OpenInsight to write out ALL of ATRECORD not just the controls on the screen. If you didn’t know it did this then we’d recommend reading the article 😊.


When wishing to size a Window to a specific size it could be difficult using the mouse. Now the LEFT, TOP, WIDTH and HEIGHT properties make this a cinch.

This removes the need for simple centring code, providing you with the nominatively determinative values of “AsDesigned”, “CenterDesktop” or “CenterParent".

This is something which we routinely had to code for – to quote the MSDN documentation “The maximum tracking size is the largest window size that can be produced by using the borders to size the window. The minimum tracking size is the smallest window size that can be produced by using the borders to size the window.”. We used this normally to prevent the user from making any changes to the size of the Window – if we’d wanted a different size we’d have designed it that way 😉. By default, this isn’t set, so the user is free to resize the Window as they want. However, we no longer need to use TRACKINGSIZE to prevent this – see later!

Intended to be set at runtime by the system when the screen becomes smaller than its intended size.


Documented in full in Carl's RevDevX Blog. This simply sets the percentage translucency of the current Window to anything from 0% (completely opaque) to 100% (where’d my Window go?).

Upon opening a Window, you can now add a bit of theatre to your application. You can now select from the self-explanatory effects of Default, None, Fade, SlideDown, SlideUp, SlideRight, SlideLeft, SlideDownRight, SlideDownLeft, SlideUpRight, SlideUpLeft. As a PowerPoint user I sort of miss chequered et al but…

Note that this won't work on MDI Children or maximised Windows.

Upon closing a Window you do the same as with SHOWEFFECT. This is actually very handy for emulating popup menus.


Effectively defines the image used by the Window in great detail. But don’t worry most of the time you can just accept the defaults. It’s only if you really want your application to continue looking professional under all DPI conditions that you really have to pay attention to this. It is documented in great detail at   https://revdevx.com/2013/02/07/the-image-api  https://revdevx.com/2014/06/09/the-scaled-event  et al


A Boolean property indicating whether the Window can have files dropped onto it during a Drag and Drop operation. No more raw style bits to understand and contend with!

Permits the selection of a different cursor for use with this Window when over an editable control. The cursor will be in a file with extension .CUR.

Permits developers to set whether the system pages multi-page windows, or whether it pans them..

Determines whether the user is allowed to resize the Window. If set to “Never” they aren’t allowed. If set to "Always” then they're always allowed. If set to “Default” then the user is allowed if Windows deems it to be appropriate.

In multi-page forms, if set to “No”, tabbing off the last control on a page will move to the next page. If set to “Yes” then tabbing off the last control on a page will move to the first prompt on that page.


This exposes the frame types we were used to in previous versions of OpenInsight. We can have fixed, sizeable or dialog. This doesn’t actually affect the behaviour of the Window, rather it provides the user with a visual clue about the behaviour of the Window. In addition, three new frame styles have been added.

 “None”   No frame at all – good for a panel appearance
 “FixedTool”  Removes the ability to have help/minimise/maximise
 “SizeableTool”  Removes the ability to have help/minimise/maximise

Should a “Help button” be displayed next to the system “Close” button?

Note that this is mutually exclusive with the MAXIMIZEBUTTON and MINIMIZEBUTTON properties.

Whether the Caption should have a Maximize/Minimize button. Note that these are mutually exclusive with the HELPBUTTON property.

Exposes these properties both in the User Interface and programmatically.



If you know what these are you'll know when to use them. If you don't, it's highly unlikely you'll ever need them!

By Sprezz | Wednesday, 2 May 2018 12:14 | 0 Comments
Back in OI 8 the concept of Associated Multi Value (AMV) groups - present in the original Rev C-G - was reintroduced. Basically when designing systems, we, as the developer already know which columns make up an AMV group, so the dictionary was extended to include this information - specifically in columns 36 and 37

One column is defined as being the controlling Multi Value (the "group master") and it (and all other Multi Values in the group) are defined as being part of that group by name. So for example in my CODES table the controlling item CODES looks like this :-

and in the table builder the defined group looks like this

But here is the real beauty of this feature. In X the form designer knows about the group so when painting a new form and selecting the controlling MV I get this prompt

Clicking "Yes" provides me with this entry form

OK, so it's not perfect - the Exclude and Sortkey widths haven't been accounted for correctly BUT it's a vast improvement on the old way of doing things.

There are just so many cute little tweaks in X that are making my life so much easier. I haven't had so much fun in ages!

By Sprezz | Tuesday, 17 April 2018 16:35 | 9 Comments

So OpenInsight X has finally arrived resplendent in all its glory! After a gruelling beta cycle Revelation Software announced yesterday the formal release of OpenInsight 10.0.1.

We've been working with the software internally for quite some time and it has been a pleasure to see it flesh out and come to life. So many small but important details are taken care of. The main executable is now digitally signed - so no more scary warnings when launching the program. The long term goal of developing a tool that's good enough to develop a tool has finally been achieved - no more random executables! These are all of the exe files in the product - not a formdes.exe in sight. Finally form designer is written in OpenInsight itself. This is testimony both to the power and flexibility now delivered in the shipping product.

The first impression on logging in is that of an uncluttered clean interface

Gone is the busy VB3 style front end, replaced with a simple set of choices. Do you want to create something new or open something? If you're just beginning development you're going to want to create an application. As that's such an unusual thing to do it isn't included in the standard "New" dialog. Rather there's an item specially for it on the File/New menu.

The dialog is familiar but as we opted to use the new stronger security during installation our passwords have to conform to the default rules.

There's a lot to look at but in the first instance we're just going to take a flying visit to the form designer. First though let's add some existing tables into the mix. To do this we'll need to turn on the Database Panel.

and now we've done that we can choose to "Add files"

and add in our PROFILES table to give us something to play with

Apply the changes and then a  keystroke shortcut (Ctrl-Alt-D) to toggle the database panel off. All panels have keystroke shortcuts to toggle on and off.

So now let's launch the form designer

for a data bound form.

Just a couple of things to note here. By default the form designer DOESN'T add a menu to the form. This is consistent with good practice in an MDI application. Instead it offers to place OK and Cancel buttons on the form. As with 9.4 the form designer chooses the most suitable control type to place on the form but allows overriding if required.

All the usual suspects and a date/time picker too! Pressing OK generates a default form and opens the form designer.

The first thing that is apparent is that OI X makes intelligent choices for control width! The screen straight out of the box is visually appealing! The screen is now split up into four main areas (The menu and TCL are omnipresent). These areas are the Toolbar at the left, the main design screen in the middle, the properties and events at the right and the status line at the bottom. By default the screen features a grid and snap to grid is set. These options can easily be overridden from the Settings/IDE Settings menu option :-

Note also that right clicking on the screen image provides a context sensitive options menu from which you can override some of these preferences.

As you move from control to control the property panel changes to reflect the properties specific to that control type - so an edit line has a whole different set of properties to a check box.

Similarly an edit line has a whole different set of events to a check box.

But what is really impressive is what happens when you select more than one control of different types :-

The property panel now only shows COMMON properties between the two controls.

As with 9.4 it is possible to add quick events and/or scripts to a control but there has been some significant changes in ease of use for quick events. Let's illustrate this by adding a popup to the options for the user id prompt.

So firstly we add a quickevent to the OPTIONS event on the USERID edit line.

Note a couple of new additions.

Does the quick event have priority? In existing OI, quick events occur at the end of the event chain. So for example, if we are putting on a READ quick event, the system will look for a script, execute it if present, if required execute the actual READ then execute the quick event. This means that the READ quick event is always POST READ. By setting priority, the quick event will be executed before the script and actual READ event. This means that for the first time we can use commuter modules for everything and never actually have to cut a script. In 9.4 sometimes you had to used scripts to get in before the system logic. No more!
Note also the "Finalize" section. When the quick event has completed what should be done (if anything) to wrap up. In the case here where we've returned a row id into the key prompt we obviously would like to read the row. Now we no longer have to cut code to make this possible.

Moving on to linking to this options event - we add a hyperlink control to replace the user Id static.

and we set the tooltip property

and we add a quick event to the CLICK event of the hyperlink control. 

Clicking the button opens the dialog from where we can check that we want a quick event or check that we want a script.

We want a CLICK quick event so we select that

and rather than "General" we want to do something else. Dropping down the combo box we see a number of events, the newest one being "Trigger Options" - i.e. cause the OPTIONS event to be triggered for the control we were just on.

Choosing this leads to what I can only describe as a touch of genius

The quick event sets the SYSTEM FOCUS property to the control we were just on (@PREV - the PREVIOUS property of the current control) then finalizes by sending an OPTIONS event to the control currently having focus.

Running the window we see that the User Id: static is now a hyperlink

and hovering over it with the mouse changes the appearance and displays a tooltip

actually clicking the hyperlink sets the system focus to the USERID edit line and sends an OPTIONS event. The popup displays

a value is chosen

 and the USERID populates and a READ event is issued

No code required at all for such a comprehensive set of actions.

Moving onto the Toolbox section of the screen.

All of our old favourites are there along with a number of new control types.
The attention to detail is just phenomenal. Take as a simple example what is described as the "Up-Down Control". Let's add one into our screen and put it alongside an edit line.

Go into the properties of the up-down control and set a range to operate on and a "BUDDY" control - the edit line to associate with. Set the AUTOUPDATEBUDDY property to True

and now when you're in the entry form, scrolling the arrows will update the edit line and changing the edit line will update the scroll position! Again - no coding.

This short overview hasn't even begun to scratch the surface of what's changed in OI X but hopefully it will have whetted your appetite to get in there and play!
By Sprezz | Wednesday, 28 March 2018 12:09 | 0 Comments
We recently had the pleasure of working with one of our favourite sorts of client - the type who are enthusiastic about their speciality field and who have trained themselves to program - to allow themselves to write MOST of the system they need to service their enthusiasm. Every now and again, they call us in to do some of the heavy lifting for them.

This particular time the client had an issue with a multi page form. Under most circumstances the data displayed correctly but under - as yet undetermined circumstances - the data display would become corrupt. Data would appear in edit fields that belonged in other edit fields and existing data would be overwritten by seemingly unrelated data.

Approaching the issue logically, we installed break points to ensure that what was read from disk was correct and sure enough @Record and the ATRECORD and RECORD properties all contained what they should. It was only when a certain field was filled in that the data became corrupt. Through much testing we were able to determine which field had to be filled in to cause the corruption but it still made no sense. To illustrate using the AVERY_LABELS table (the client's data is commercially sensitive so we can't use screenshots from their system). In the example below the Cross Reference column references another row in the AVERY_LABELS table and extracts the product description.

So the above is what we expected to see. The below is more like what we were seeing - data that SHOULD have been there ("Removable Laser..." in Cross Ref Product Desc) wasn't - being replaced with the contents of the field above. Data was missing ("Label" in Product Type) and data was incorrect ("6464" in Template Family).

Painstakingly we played with entering data into the client screen - all 6 pages of it - until the error manifested itself when we entered data into a prompt that provided the key for a symbolic to xlate off. We turned on engine logging to see if some event was being triggered that would explain the corruption, but there was nothing other than standard engine flow. On a hunch we went to the system monitor and typed the equivalent of

LIST 100 AVERY_LABELS PRODUCT_DESC XREF_DESC SEQUENCE and were rewarded with something like

which was NOT what we would have expected to see. So we decided that the XREF_DESC formula must have been to blame in some way. Looking at it, it SEEMED to be straightforward enough :-

Until we looked REALLY closely... the column is called PRODUCT_DESC not PRODUCT_DESCS$. When we changed the spelling to the correct one - AVERY_LABELS$PRODUCT_DESC$ everything was right with the world again - the screen displayed correctly and the LIST statement produced

So - what went wrong? To understand this we need to be familiar with how the Window processor actually works with the data from @Record.

A major change in OI over AREV is that when the system WRITEs the current screen contents to disk, it does not simply write the contents of @Record onto disk as in AREV, rather it takes the current row from disk and updates ONLY those columns that feature in the current Window. THEN it writes the row back. This allows the user to have multiple windows open updating separate sections of the same current row.

To do this the Window processor has to maintain its own pseudo @Record, just containing the contents of the current screen. To illustrate using the pseudo code for a READ and populate operation

pseudoRecord = ""
for loopPtr = 1 to controlCount
  control = controlList< loopPtr >
  dictColumn = get_Property( control , "COLUMN")
  pseudoRecord := xlate( dataTable, @Id, dictColumn, "X") : @Fm
pseudoRecord[-1, 1] = ""
for loopPtr = 1 to controlCount
  control = controlList< loopPtr >
  call set_Property( control, "DEPFROP", pseudoRecord< loopPtr >)

In the original dictionary item the XLATE destination column was incorrectly spelt, so at compile time in the Table Builder the equate would NOT have been replaced with a column number, but with a blank. The Table Builder compiler before OI 10 does not include the error checking that the System Editor has. So the XREF_DESC formula was resolving to

   @Ans = Xlate("AVERY_LABELS", {CROSSREF}, "", "X")

which returns the entire row, not just an individual column. So instead of pseudoRecord containing

1 : @FM : 8 : @FM : 3 : @FM : Xlated 8  : @FM : 2 : @FM : 17 : @FM : 10 : @FM : 16

it contained

1 : @FM : 8 : @FM : 3 : @FM : Xlated 1 - 43  : @FM : 2 : @FM : 17 : @FM : 10 : @FM : 16

thereby pushing the subsequent SET_PROPERTY DEFPROP out of kilter.

Obvious with hindsight but not the easiest bug in the world to track down on a system written by someone else!
Pixel Footer R1 C1 Pixel