Tips   >   Misc   >   Misc

Misc

This section covers miscellaneous topics relating to Omnis Studio.

Boolean Logic in expressions

There is no need to compare the expression value to kTrue or kFalse for any expression in Omnis Studio which returns true or false.

Here are some code examples to clarify this.

; Calculate the number of selected lines.
Do ListVar.$sendall(LineCount.$assign(LineCount+1),$ref.$selected=kTrue)

; Using $ref.$selected is shorter and is the same as using $ref.$selected=kTrue
Do ListVar.$sendall(LineCount.$assign(LineCount+1),$ref.$selected)

; Using not($ref.$selected) to count the unselected lines.
Do ListVar.$sendall($ref.value.$assign(10),not($ref.$selected))

; Check the return flag.
If FlagOK=kTrue
   ; Do something
End If

; Using FlagOK is the same as FlagOK=kTrue
If FlagOK=kTrue
   ; Do something
End If

; Use not(FlagOK) to test for FlagOK=kFalse
If not(FlagOK)
   ; We have a problem.
End If

; Check if the file exists.
Do FileOps.$doesfileexist(Path) Returns bFileExists
If bFileExists
   ; Do something
End If

; You can put the expression in an If calculation since it evaluates to true or false.
If FileOps.$doesfileexist(Path)
   ; Do something
End If

; Check if a certain name is in the list.
Do ListVar.$search($ref.FirstName='Dawid',1,0,0,0) Returns LineNum
If LineNum>0
   ; Do something
End If

; You can put the expression in an If calculation since it evaluates to a numeric value.
If ListVar.$search($ref.FirstName='Dawid',1,0,0,0)
   ; Do something
End If

Calling any class method

You might run into a situation where you want to call a class method without first creating an instance of the class.

The trick for doing this is to use the Do code method command. The Do code method is not limited to Code Classes; it can be pointed to the class method of any type of class.

Do code method [$clib().$name].wWinClassName.MethodName (pParam1,pParam2)

Warning

I'm not sure why you would need to do this... this style of code is something the object-oriented programming police might pull you over for. You should be using a public method of a class instance.

Change IDE Font Sizes

Omnis Studio allows you to change the font sizes in most of the IDE (Interactive Developer Environment) windows. This can be especially helpful if you are doing a presentation.

To change the font size of the code list, methods treelist, Property Manager, Catalog, etc.

  1. Click on the list so it has the focus.
  2. Ctrl/Cmd+] to increase the size. (STRG+* to increase size - German keyboard layout)
  3. Ctrl/Cmd+[ to decrease the size. (STRG+† to increase size - German keyboard layout)

The changed font size will only be temporary. If you close and reopen the IDE window, the font size will revert to the original size.

To save the font size for the IDE window, right-click on the window and select Save Window Setup.

Code Classes

Here's a word of advice about code class... don't use them. (Okay, that was 3 words.)

When I started learning Omnis Studio I tried object classes and said to myself, "This is too hard, Code Classes are much easier to work with and call, I'm sticking with code classes". Six months later at my first Omnis Conference, Geir Fjaerli convinced me to use object classes. The statement he made proved true, "Anything you can do with a code class, you can do better with an object class."

Code classes are a slippery slope that draws you away from object-oriented programming, and back into Omnis Classic style coding. (There is a difference.) Omnis Studio will admit to you they only included code classes to make it easier for converting from Classis to Studio. I was told the original design of Omnis Studio did not include code classes.

There are several problems you will run into with code classes:

  1. Code classes don't extend instances. I discovered this when in a code class method I defined a list variable from a table class using $definefromsqlclass and then called a method in the table class. Everything worked fine until the table class needed the value of a task variable. Oops, it was out of scope!!
  2. Code class can't have private methods. All methods in your code class are public. As you get deeper into object-oriented programming (OOP) you will discover the importance and beauty of having public vs. private methods. (In Omnis Studio public methods start with the $ character, private methods do not start with $ character.)
My advices is that you avoid code classes. Use object classes instead. Anything you can do with a code class, you can do with an object class ... better. If you are coming from Omnis Classic, object classes might seem like a pain at first, but stick with them, it is worth the effort. Object classes will provide more powerful and elegant solutions.

Convert Numbers to Text

If you ever need to print checks, you'll need to convert the dollar value of the check to text.

For example, you may need to convert 550.25 to five hundred and fifty -------- 25/100

You can download a free library called convertNumberToText from the downloads section of the studiotips.net website.

www.studiotips.net/downloads

The library contains an object class which you can copy to your application and then instantiate and send messages to.

Calculate Number as 11578.97
Do oConvertNumberToText.$convertNumberToText(Number) Returns Text

Click the Run Demo button in the StudioTips Browser window to try out the oConvertNumberToText object class.

Delete stubborn ivar

To delete an instance variable from a class, you right-click on the variable in the variables pane and select Delete variable... in the context menu. As long as the variable is not used in any code, Omnis Studio will prompt you with a Delete variable No/Yes dialog. In some rare situations, Omnis Studio won't let you delete an instance variable, even though you have deleted every piece of code that contains the instance variable.

Find and Replace comes up empty and you've closed and reopened the class, but the stubborn ivar can't be deleted. One trick for getting rid of a stubborn instance variable is to drag it from the Instance variables pane to the Class variables pane. For some reason, once you've done that Omnis Studio allows you to delete the class variable.

Description Property - $desc

The $desc property is found is several different location in Omnis Studio:

  1. Class Description
  2. Method Decription
  3. Variable Description

The class desciption can be modified by selecting the class in the F2 Browser > pressing F6 Property Manager > selecting the General tab and clicking on the $desc property.

The method description for public methods (prefixed with $ character) can be viewed/modified through the Interface Manager. In the F2 Browser right-click on a class > select Interface Manager. At the bottom of the Interface Manager click the Description tab to view and modify the description property of the method.

Private and public method descriptions up to 255 characters can be edited in the method editor. Select the method in the method editor, then click on the grey field just below the code list.

The variable descriptions are accessed through the variables pane of the method editor.

Click the Run Demo button to find out the maximum length of each $desc property.

Developer vs. Runtime Versions

There is a difference between the developer, runtime, and web server versions of Omnis Studio. The runtimes contain less resources in order to have a smaller footprint. You can serialize a developer version as a runtime but you would not be able to do the opposite since the runtime version does not contain the debug resources.

Do redirect

This obsure little command redirects a command to a method of another instance with the same method name.

You could have a shell window which has an $editRecord method that redirects the message to the current subwindow.

The message could be forwarded as follows:

Do rSubWin.$editRecord(pPrimaryKey) Returns FlagOK

or using redirect

Do redirect rSubWin Returns FlagOK

An interesting feature of Do redirect is that you do not have to declare any parameters. Do redirect passes the incoming parameters without declaring them. Cool!

Note

You can only redirect to a method of the exact same name.

Install Size of Omnis Studio

The install size of Omnis Studio v4.2 is quite a bit bigger on the Mac OS X version than the Windows version.

A lot of it is the Mac xcomps, which for some reason all seem to link in a large library of common code. The simplest xcomp ends up being over 400K. You can look through them and discard those that your app doesn't use, notably the oXML at 6.4MB, DAMs you aren't using, docView, etc. - for every 2 xcomps you can remove you save a meg - and if you don't use graphs you can lose the Frameworks folder to save another 5MB. The webclient.plugin in the localclient folder can save almost 9MB if you don't use remote forms.

By trimming out things like that, you can get a 4.2 runtime plus library and data files down to a 50MB downloadable dmg file containing an Apple installer. The previous version, non-universal and not nearly as well cleaned-out, was 32MB.

The above info was provided by Kelly Burgess.

Localized Versions of Omnis

Omnis Studio is localized for different languages. The localized versions replaces the Yes/No/OK prompt button text wtih the appropriate local language text. It may also default to different separator characters in $prefs.$separators.

$separators is a 5 character string.The characters in this string are:

Character 1: the decimal point character
Character 2: the decimal number thousands separator
Character 3: the function parameter separator
Character 4: the import/export decimal point character
Character 5: the import/export comma delimiter character

I ran into trouble with the function parameter separator and the German localized version.

In the English version character 3 is a , comma.
In the German version character 3 is a ; semi-colon.

In the English version concatentate looks like this:
Calculate FullName as con(FirstName,' ',LastName)

If you opened the same library in the German version, you code would look like this:
Calculate FullName as con(FirstName;' ';LastName)

Your normal Omnis code will run without a problem in the English or German version. The problem will be write some code that assumes what the separator will be. The problem I hit in StudioTips was with a replaceall() function.

I wanted to determine then text of the tab strip which the user clicked on. The $event code for the tab strip object was something like this.

CODE THAT BROKE WHEN USING THE GERMAN VERSION OF OMNIS STUDIO.

On evClick
  Find out the text string represented by the tab strip.
  Calculate TabStripTabs as irTabStrip.$tabs
  e.g. About StudioTips, Basics Tutorial, Miscellaneous

  Convert the string for use in a pick statement. Replace each comman with quote-comma-quote ','
  Calculate ReplaceValue as "','" ;; quote-comma-quote
  Calculate PickString as replaceall(TabStripTabs,",",ReplaceValue)
  e.g. About STP',' Basics Tutorial',' Miscellaneous
  Add opening and closing quotes.

  Calculate PickString as con("'",PickString,"'")
  Prepare the pick() statement string to and evaluate it.
  Calculate EvalString as con('pick(',pTabStripNum-1,',',PickString,')')
  Calculate TabStripName as eval(EvalString)

The above code failed with the German localized version because I had assumed the comma separator in the replaceall() function, and in the eval(pick()) function.

FIXED CODE THAT WORKS WITH THE ENGLISH AND GERMAN VERSIONS OF OMNIS STUDIO.

To fix above code I modified it as follows:

On evClick
  Find out the text string represented by the tab strip.
  Calculate TabStripTabs as irTabStrip.$tabs
  e.g. About StudioTips, Basics Tutorial, Miscellaneous

  Find out the Omnis Studio localized function separator.
  Calculate FnSep as mid($prefs.$separators,3,1) ;; English comma, German semi-colon

  Convert the string for use in a pick statement. Replace each comman with quote-comma-quote ','
  Calculate ReplaceValue as con("'",FnSep,"'") ;; quote-FnSep-quote
  Calculate PickString as replaceall(TabStripTabs,",",ReplaceValue)
  e.g. About STP',' Basics Tutorial',' Miscellaneous ;; English
  e.g. About STP';' Basics Tutorial';' Miscellaneous ;; German

  Add opening and closing quotes.
  Calculate PickString as con("'",PickString,"'")
  Prepare the pick() statement string to and evaluate it.
  Calculate EvalString as con('pick(',pTabStripNum-1,FnSep,PickString,')')
  Calculate TabStripName as eval(EvalString)

TESTING YOUR OWN APPLICATION

Testing your own application for different localized version of Omnis Studio is quite simple to do.

In the Omnis Studio > local folder, there is a file named omnisloc.df1.

  1. Quit Omnis Studio if you have it open.
  2. Rename omnisloc.df1. eg. English_omnisloc.df1.
  3. Drag another language omnisloc.df1 file into the local folder.
  4. Open Omnis Studio again, and you are running with the new localized version.

You can download a free zip file containing the English, French, German, and Swedish versions of the omnisloc.df1 file from the downloads section of the studiotips.net website.

www.studiotips.net/downloads

Open PDF File

I wanted to be able to open PDF files from Omnis Studio.

MAC PLATFORM

On the Mac platform that's pretty easy to do:

Send Finder event {Open Files (FilePath)}

Note: This Omnis command does not affect the flag. So you can't test flag true or false.

WINDOWS PLATFORM

Life gets a little more complicated on the Windows platform. Tech Support was kind enough to provide me with sample code.
You have to use the Omnis commands Register DLL and Call DLL. These Omnis commands are not available to you in Omnis Studio when you are using a Mac.

Here's what we ended up with for the Windows platform:

Register DLL ("SHELL32.DLL","ShellExecuteA","JJCCCCJ")
Call DLL ("SHELL32.DLL","ShellExecuteA",0,"open",FilePath,"","",0) Returns HINST_EXPLORER

NOTES:

  1. You can only edit this code on a Windows machine.

    If you look at this code on a Mac, it will looks more like this:

    X250825050 ("SHELL32.DLL","ShellExecuteA","JJCCCCJ")
    X250825051 ("SHELL32.DLL","ShellExecuteA",0,"open",FilePath,"","",0) Returns HINST_EXPLORER

  2. HINST_EXPLORER is long integer, representing a handle on the instance of the launched program.
  3. JJCCCCJ is the calling convention for the parameters passed, so that Call DLL knows how to typecast the parameters passed.
  4. The code should work for any registered file type.

CROSS-PLATFORM CODE

Putting it together in a Switch/Case for cross-platform use, we end up with the following:

; Prompt the user to select a PDF file.
Do FileOps.$getfilename(FilePath,'Select a PDF file','*.pdf') Returns FlagOK
If not(FlagOK)
   Quit method kFalse
End If

; Open the file, using code for the specific platform.
Switch sys(6)
   Case 'M','X' ;; Mac or Mac OS X
      Send Finder event {Open Files (FilePath)}
   Case 'W','N' ;; Windows or NT
      Register DLL ("SHELL32.DLL","ShellExecuteA","JJCCCCJ")
      Call DLL ("SHELL32.DLL","ShellExecuteA",0,"open",FilePath,"","",0) Returns Hinst_Explorer
      If not(Hinst_Explorer)
         OK message (Icon) {Opening the file failed.}
         Quit method kFalse
      End If
   Default
      OK message [sys(85)] (Icon) {Open file code not written for sys(6) = [sys(6)]////Please notify the programmer.}
      Quit method kFalse
End Switch
Quit method kTrue

Optimize Method

A word of caution about the Optimize method command... Omnis programmers have been burned by this command.

The documentation says you can add this command to the first line of a method which you call frequently. The optimized version of the method will be stored in memory and used each time the method is called.

However, Optimize method has not proven to be reliable.

It caused my payroll program to completely crash Omnis Studio when I added it to a method which included twelve Switch/Cases. Others have reported various problems.

Personally, I didn't find any speed improvement. I think Optimize method had its purpose when we were running slow clunky computers. But in this age of faster and faster computers, Optimize method, has much less impact.

You decide whether or not you want to use Optimize method. For my peace of mind, I won't be using it in any application I write.

Show System Focus Mac OS X

The Mac OS X Aqua Interface draws a thick bluish border around the entry field which has the focus. This can be a problem if you have entry fields that are tightly spaced, or if you are using a different method for showing which field has the current focus.

The Omnis Studio preferences allow you to turn on the Mac OS X system focus.

You can set this preference in your application's Startup_Task using notation as follows:

Do $prefs.$showsystemfocus.$assign(kFalse)

Testing Item References

How can you tell for sure that a reference is valid? Testing for a valid reference is easy.

If Ref
   ; Valid reference.
Else
   ; Not a valid reference.
End If

The problem is if you are trying to just trap an invalid reference.

If not(Ref) will give you a problem if the reference is null or is an Unset Reference.

An interesting solution is to test the $ident property of the reference.

If not(Ref.$ident)
   ; NULL or Unset Reference.
End If

Warning

The only exception to the $ident test is testing a library refererence. All other references seem to work okay.

A sure fire way to set for invalid references is to always test first for the valid reference and put the invalid test in the else.

; This test will correctly trap a null or unset reference.
If Ref
Else
   ; NULL or Unset Reference.
   OK message {The item reference is unset or null.}
End If

Click the Run Demo button to step through the test code which runs the various item reference tests.

Trapping Null, Blank, or Zero

Trapping null, blank, or zero is a tricky thing to do cleanly in Omnis Studio.

One might expect the following If calculation to catch the 3 possibilities:

If isnull(Var)|Var=''|Var=0

but it won't work if Var=NULL

If Var=NULL, then the 2nd test, Var='', is testing NULL=''. Omnis Studio can't evaluate NULL='', and therefore it can't properly evaluate the If calculation.

Switch/Case doesn't help much either.

The difficulty with many solutions is that they may work if Var=kCharacter but fail if Var=kNumeric
(or visa versa)

Here's a bullet proof, one liner test for null, blank, or zero!

If pick(isnull(Var),Var,'')=''|pick(isnull(Var),Var,'0')='0'
   OK message {IS Null, Empty, or Zero////Var = [Var]}
Else
   OK message {IS NOT Null, Empty, or Zero////Var = [Var]}
End If

To avoid repeating the above If calculation statement all over your code, I recommend you add it as a method in your oFunctions object class. The following $isNullBlankZero method is included with the oFunctions object class in StudioTips. Feel free to copy it to your own library.

$isNullBlankZero method (included in oFunctions)

; Test for null, blank, or zero.
If pick(isnull(pfVariable),pfVariable,'')=''|pick(isnull(pfVariable),pfVariable,'0')='0'
   Quit method kTrue
End If
Quit method kFalse

If oFunctions is instantiated using the Startup_Task variable fn, you could do the following in your code.

If fn.$isNullBlankZero(Var)
   ; Action to take if null.
Else
   ; Action to take if a value.
End If

; Use not() if you just want to do something if there is a value.
If not(fn.$isNullBlankZero(Var))
   ; Action to take if a value.
End If

Click the Run Demo button in the StudioTips Browser window to step through an extensive series of null, blank, or zero tests which demonstrate the problems you can run into with testing for nulls, and the solution provided in this tip.

Updating to New Version Omnis Studio - Keeping Preference

When you upgrade your developer version of Omnis Studio to a newer version you lose all of your IDE preferences. (IDE window size and locations, toolbar settings, treelist preferences, etc.)

Your Omnis Studio preferences are stored in the omnis.cfg file which is located in the studio folder inside the Omnis Studio folder.
Your Omnis Studio SQL Browser session and VCS sessions are stored in the sql.df1 file which is located in the studio folder inside the Omnis Studio folder.

You simply need to copy the omnis.cfg file from your old version of Omnis Studio to the same location in your newer version of Omnis Studio.

If you have any SQL Browser sessions or VCS sessions also copy the sql.df1 file located in the studio folder to the same location in your newer version of Omnis Studio.

Be sure to copy any extra external components (i.e. Third party DAMs) from your old xcomp folder to the newer version xcomp folder. You might need to download newer versions of some of the external components rather than copy them across.

Note

As of Omnis Studio v4.2 on Mac OS X to get to the studio folder you will need to:


  1. Right-click on the Omnis Studio app icon/folder located in the Applications folder and select Show Package Contents.

  2. Right-click on the Contents folder and select Show Package Contents.

  3. The studio folder is located inside the MacOS folder.

The serial number is also imbedded in the omnis.cfg file. If you are moving to a version of Omnis Studio that requires a new serial number you will not be able to open Omnis Studio after you copy the omnis.cfg file. To solve this, you will need to enter the new serial number in the serial.txt file located in the Omnis Studio folder.

The format for the serial.txt file is:

UN=user name (not required)
CN=company name (not required)
SN=serial number

[Plugins]

The serial number in this file will over-ride the one that is held in the omnis.cfg file. Then when you are up and running, you can re-serialise and force the new serial number into the omnis.cfg file.

Use Field Ref or Return Value?

There are two ways a method can return a value to the sender.

  1. Return a value to the sender in the Quit method command.
  2. Pass a value to the sender using a field reference parameter.

This method uses Quit method to return the value to the sender.

$retRemoveSpaces(pVariable)
Quit method replaceall(pVariable,' ','')

This method uses a field reference parameter to pass the value back to the sender.

$removeSpaces(pfVariable)
Calculate pfVariable as replaceall(pfVariable,' ','')
Quit method kTrue

I normally use the return value to return a boolean value to indicate to the sender either: success (kTrue), or failure (kFalse) in the called method.

If you use the return value to return a real value it becomes more complicated to indicate failure to the sender. In most cases you could return null instead of a real value. The user can then use isnull(ReturnValue) to test for failure by the called method. However, if the method could return null as a valid value you have no way of testing for failure. That makes it very difficult for error handling in non-visual class methods.

The advantages of using the return value to return a real value is that you can use the method for inline calculations.

  1. They are simple to read and use in your code.

    Calculate NewValue as fn.$retRemoveSpaces(TextString)
  2. They can be used for inline calculations.

    Calculate MethodName as con('$',fn.$retRemoveSpaces('Button Name With Spaces'))

The advantages of using field reference parameters to pass values back to the sender are:

  1. The return value can always be used for returning a boolean to indicate success or failure.
  2. You can return more than one value to the sender by using multiple field reference parameters.

The disadvantages of using field reference parameters to pass values back to the sender are:

  1. You must first calculate the value to a variable, before sending it to the method. (Rarely a problem.)
  2. You can not use methods which return values through field reference returning for inline calculations.
I use both techniques for returning values to the sender, it all depends on what the method does. See Naming Conventions > Coding Conventions > Quit method Return Something for more information.

eval() Find Error

If you use an eval() function in your code and there is an error in your eval() how do you find the error?

You can use Test for valid calculation with #ERRTEXT. The beginning of the #ERRORTEXT will tell you the first and last character of your string which is causing the error in the eval().

#ERRTEXT might be something like

0:4:Unrecognized variable name, item name or attribute

. The 0:4 specifies that the error is with characters zero (0) to four (4) in the string.

The following sample code gives you a working example:

; Calculate a text string to be evaluated. ('midx' is not a valid function.)
Calculate EvalString as 'midx(#S1,1,3)'

; Test the evalf() with 'Test for valid calculation'.
Test for valid calculation {evalf(EvalString)}
If flag false
   
   ; The #ERRTEXT will look like '0:4: ...'. The 0:4 is the first and last characters in the string causing the error.
   
   ; Parse out the first and last character positions.
   Calculate ErrorTextString as #ERRTEXT
   Calculate FirstChar as strtok('ErrorTextString',':')
   Calculate LastChar as strtok('ErrorTextString',':')
   
   ; If the first character is zero, it will cause problems with the "mid()" function. Use pick() to set zero to one.
   Calculate FirstChar as pick(FirstChar=0,FirstChar,1)
   
   ; Calculate the portion of the eval string causing the error.
   Calculate EvalStringError as mid(EvalString,FirstChar,LastChar-FirstChar+1)
   
   OK message [sys(85)] (Icon) {There is a problem with the eval string: ////'[EvalString]' ////The error is: '[EvalStringError]'}
   
End If

Quit method kTrue

Click the Run Demo button in the StudioTips Browser to run through the sample code.