All posts by Dennis Vorst

Uniface Developer since 1996. Working at the Uniface lab in Amsterdam as a QA engineer on U10 since October 2014.

Drop it like it’s hot

What very few people know is that in the Import Repository Objects component there is a small section where you can drag and drop your export files from Windows Explorer.  After you drop them, the File name box is updated with the list of files that you dropped.

Uniface

The red section is where the drag-and-drop field is located.

Download for this drag n drop sample

Creating this element in your own component is pretty easy. Just follow these steps:

  1. Create a component. In this example I have created a component named DragNDrop
  2. Paint an entity. I used a non-database entity named DE in the DM application model.
  3. Paint a field. DROPTARGET
  4. Now set the properties according to the image below.

Uniface

We set the widget type to DropTarget indicating that this element will be able to receive elements using a drop event. Make sure you painted the widget large enough so that you can find it very easy on the component. In this setting the widget will have the same gray color as the rest of the component, making it impossible to find if you paint it too small. I painted it across the entire component so it is impossible to miss.

I have set the datatype to string since the result will of a type string. Made the interface a shorthand C* just because I do not know how long the string of filenames will be and the default of 40 characters will probably not cut it.

Now compile the component and test it by dragging something from Windows Explorer to the droptarget.

As you may have noticed that did not work at all. No worries you need to make one small change and it will work.

DoubleClick the droptarget widget to open the properties and then navigate to the widget properties. In the valrep list enter a value named “file” and leave the representation empty.

Uniface

When you compile it and test it again you will notice that the mouse pointer changes from the no-entry sign to a arrow with a plus sign when you hover over the drop target. You can drop it, but it will not do very much.

How to get to the goodies

Dropping something on the drop target will fire the value changed trigger. Here you can put the code to verify if the dropped elements are actually the files that you want and process them further.

In my component I have created an entity FILES in the DM application model and added a field named NM of type string and set its interface to C*. The component looks like this:

Uniface

Next I opened the value changed trigger of the DROPTARGET field and added the following:

variables
   string v_nm
endvariables
 
forlist v_nm in <$fieldname>.<$entname>
   if ($lfileexists(v_nm))
      creocc "FILES"
      NM.FILES = v_nm
   endif
endfor
 
sort "FILES", "NM"
 
; reset the background image
<$fieldname>.<$entname> = "image"

In the first line I declared a variables block holding a string variable named v_nm. In the fifth line the forlist command extracts a value from my droptarget field and inserts it in the variable. After I checked if it the file exists, I add a record to my FILES entity and adds the variable value to the NM field in the entity.

The reference to <$fieldname>.<$entname> will be replaced during compilation with the actual fieldname. In my case DROPTARGET.DE.

If you are using Uniface prior to 9.5.01 you cannot use the forlist command. You should use a combination of getitem, delitem. I am assuming you know how to do this, if not here is an example:

variables
   string v_nm
endvariables
 
while <$fieldname>.<$entname> != ""
   getitem v_nm, <$fieldname>.<$entname>, 1
   delitem <$fieldname>.<$entname>, 1
 
   if ($lfileexists(v_nm))
      creocc "FILES"
      NM.FILES = v_nm
   endif
endwhile
 
sort "FILES", "NM"
 
; reset the background image
<$fieldname>.<$entname> = "image"

Picture this

The last line in the previous code might have given it away, but I am using an image to highlight the droparea. On the drop event this value is being reset to the list of files, so after processing I need to reset it. Otherwise I will be left with a grey target or even worse, a target screaming “!format” at me.

In the same location where we created the file valrep just minutes ago, I have added a value “image” and a representation “@droptarget.png”. The @ symbol implies that we are loading an image file named droptarget.png from the project folder and displaying it in the widget. The properties now look like this:

Uniface

Just get your own cool looking image file and play around with the properties to get it right.

To make sure the image is loaded on startup of the component we need to add two more lines to our component. In the EXECUTE trigger we add:

DROPTARGET.DE = "image"
edit

My component finally looks like this:

Uniface

Download for this drag n drop sample

Where to put your code

As a Uniface developer, I’ve seen a lot of Uniface applications first hand. On more than one occasion I encountered a situation where developers put all their code in the component. This happened for a number of reasons—access to the model or the library was constricted, there wasn’t enough time in the project to do it correctly, or just unfamiliarity with Uniface. I cannot speak on behalf of project managers or architects, but I can tell you how I code my projects.

The first rule of Uniface is that you do not copy and paste! (Very obvious movie reference!) If you find yourself in a situation that you think you need to copy code: stop! You are probably better off removing the code from its original source, putting it in either the application model or the library, and then reusing it in both the original component and the component where you wanted to paste it.

Single field implementation

Consider the following:

if (HEIGHT.PERSON < 0)

HEIGHT.PERSON = 0

endif

 

A person can never have a height that is smaller than 0 meters. Maybe there are people with a negative size, but I have never seen one. So if someone enters a negative value we reset the value to 0. If you were to put this in a component, than you need to copy and paste it the next time you need it. Remember the first rule? So where would you put it? The most logical place would be in the trigger of the modeled field HEIGHT in the PERSON entity. Creating an entry on entity level and then calling it from the leave field trigger would score equally well. This way the inheritance in Uniface will provide this piece of code in every component you use the field on.

Multiple field implementation

On record level

But what about two fields in the same entity? The formula for the Body Mass Index of a person would be:

BMI.PERSON = WEIGHT.PERSON/$sqrt(HEIGHT.PERSON)

The content of BMI is calculated by dividing the WEIGHT by the square root of a person’s HEIGHT. In order to calculate the BMI we need the value of two different fields in the entity PERSON.

If you thought about putting it in the modelled entity you’d be correct. I would create an entry that can be reused in (for instance) the value changed triggers of the WEIGHT and HEIGHT field or call it from a collection operation if you wanted to update all the BMI’s in some type of batch.

Between entities

Here is a classic. The total amount of an order is calculated by multiplying the price by the number of items in an order line, and then adding that to the total of the order. :

forentity "ORDERLINE"

   TOTAL.ORDER += PRIZE.ORDERLINE * NUMBERITEMS.ORDERLINE

endfor

 

The second rule of Uniface (you can actually here the voice of Brad Pitt, can’t you?) is that you never make a reference to another entity from a modelled entity. If you do, you need to include the referenced entity on every component you use the modeled entity on or the compiler will keep wagging its finger at you.

So we can’t reference the TOTAL.ORDER field in the trigger of the ORDERLINES entity. The only logical place is to put it in in a component. In this case, I would put it in a service that can be called from other locations as well. I can even activate that service in the modelled trigger of the ORDER entity.

What if it is a non-database entity?

Non-database entities come in two distinct flavors. The modelled ones and the non-modelled ones. An example of a modelled non-database entity is the entity containing a list of buttons containing default behavior that you can reuse when creating components. With these particular non-database entities the same rules apply as for the modelled database entities.

Non-modelled entities are created on the fly on a component. In this case there is only one place to put your code. The component level.

And non-database fields?

Non-database fields, have the same distinct flavors. They are either modelled (for instance a button that shows detailed information about a certain record of a modelled entity) or the non-modelled ones. If the non-database field is in the application model, code it there, otherwise code it in the component.

When I mention the component, there are actually three levels where to place your code. In the triggers of the component, in the triggers of the non-database entity, or in the triggers of the non-database field. Based on the previous rules you should be able to determine the correct position.

There is no entity or field reference

Once more for good measure:

 

if ($status < 0)

   return $status 

endif 

This code contains no field references and is of a more technical nature. This is an example of the smallest form of error handling in Uniface. If you intend to use it only once, the component is the best place to put it. If you need it in other places, you should move the code to the library and include it where required.

Can I use A Global Proc, instead of an Include Proc?

I have not used a Global Proc since the introduction of Include Procs. In my mind it is a deprecated feature of Uniface. From a component based development perspective Include Procs are better (but that is for another story). Besides using Global Procs for error handling purposes has one drawback. What happens when your Global Proc fails? Where are you going to catch that?

Let’s Summarize

Description Logical place
Code references exactly one field in one modeled entity Trigger level of the modelled field
Code references more than one field in one modeled entity Trigger level of the modelled entity
Code references more than one modeled entity In the component, preferably a service.
Code references a non-modeled entity If a non-modeled entity is used more than once, it should be defined as a modeled non-database entity. If it is a very specific non-modeled entity, it can be only in the component.
Code does not reference a field or an entity. Include proc. Never in a global proc. Component only, when it is really specific.

 

 

10 things you need to know about Uniface 10

Working on a product like Uniface 10 feels a bit like the movie Oceans Eleven. A team of highly skilled professionals get together to pull off a feat that is considered undoable, or at least quite difficult to achieve. In fact there are quite a few similarities between the teams working in Amsterdam and the guys in the movie (Although me being Brad Pitt isn’t one of them, apparently). For instance the team working on Uniface 10 consists of people, each with his or her own unique skill set, working towards a common goal. There are lead-characters and supporting cast and everything.

But enough about us, what about Uniface 10? The first thing you will probably notice, besides the fresh white paint instead of the dull gray, is the UBAR, an explorer-type address bar that lets you open your editors. The other thing that jumps from the screen is the tabstrip. A horizontal ribbon bar showing all the open editors, allowing you to switch easily between entity, component, and other UDO’s.

A UDO, short for Uniface Development Object, is something we use in the lab to indicate a Uniface element (entity, field, component, library, and so on). These UDO’s come in two distinct flavors – UDO’s and main UDO’s. The difference? Main UDO’s have their own editor.

Before you can start creating these UDO objects you need to create a project (also a UDO). In my mind one of the better features of Uniface 10 is the ability to organize your work in… well projects. Something I really hated doing was having to verify that all my changes were compiled. Sometimes I would just compile all from the command line (not an option if the application contains over a 1000 components). Just put everything in a project and hit compile. It is even possible to export the entire project and share it.

The Integrated Development Environment or IDE for friends (we dropped the term IDF) also allows you to use snippets in your code. Put your favorite piece of code (HTML, CSS, JavaScript or Uniface code) in a snippet and copy and paste into the wee hours of the night. We will provide you with some of our snippets but feel free to create your own.

Just as in any other film there are some characters that will not make it to the end of the movie. For instance the (pirate voice) URR file is no longer part of Uniface. I have always had great difficulty understanding the Uniface Runtime Repository and am glad to see it go. Seeing it off with a bonfire made from my URR notes and the documentation. The UAR deployment option is the way to go from now on.

The removal of the application model entity from the meta dictionary hit me a little harder. In Uniface 10 the application model is just a namespace. Need to move an entity from one model to another? Just rename the model part of the entity name. So be careful, especially with typos.

We pulled all the triggers. And replaced them with script containers. From now we will supply you have with a Declaration container and a Script container to write your ProcScript in. Just for good measure we will give you three containers in the entity editor (Declarations, Collection and Occurrence). But that’s it. Want to create a trigger? Just use the keyword trigger in the same fashion you define an operation or an entry. Just to raise the stakes a little we have renamed the trigger names to make them more uniform.

What else do you need to know? Well the first version is an early adopter version. We are still working on a lot of stuff, that will be made available in future release. For instance there are no library elements yet. So you have to do without include procs, messages and such. But we just couldn’t wait to show you what we have done so far.