2017 June Release

Assigning user interface elements to an object classPermanent link for this heading

Fabasoft app.ducx allows you to assign forms, symbols, context menus, menu bars, button bars and task panes to object classes. These assignments are referred to as user interface element bindings.

Additionally you can specify default column settings for each object pointer property assigned to these object classes.

It is recommended that you create a separate .ducx-ui file for defining your user interface element bindings such as bindings.ducx-ui although you can define all user interface model-related elements within a single .ducx-ui file.

For all user interface element bindings, the extend class keywords can be used, followed by the reference of the object class to extend and curly braces. This way, all user interface element extensions for an object class can be combined into a single extension block.

Menus, forms and column bindings can also be defined using the respective constructs

  • menus for class {}
  • forms for class{}
  • columns for class {}

These constructs provide the possibiltity to specifiy more than one target class and reduce the complexity of the code by removing some indentation levels.

Cloud profile note: The assignment of user interface elements to an object class that belongs to another non-friend software component is discouraged.

Assigning a symbol to an object classPermanent link for this heading

Syntax

symbol = symbol;


Object classes should have default symbols for objects of these classes. This can be achieved by using the symbol keyword either in the object model or in the user interface model.

Example

objmodel APPDUCXSAMPLE@200.200
{
  import COOSYSTEM@1.1;

  class Order {
    symbol = SymbolOrder;
  }
}

Example

userinterface APPDUCXSAMPLE@200.200
{
  import COOSYSTEM@1.1;

  extend class Order {
    symbol = SymbolOrder;
  }
}

Deprecated: In the user interface model this assignment can also be surrounded by a symbols block.

Assigning menus and task panes to an object classPermanent link for this heading

Each object class has a default menu binding, defining main menu, context menu, background menu, container independent menu, task bar and selection dependent task bar. These should be sufficient for most cases.

To add a few menus at predefined positions, there is no need to change these standard menus (see ).

Should the need arise to do so, this can be done with the menus block, for one or more object classes.

Syntax

menus for references {
  mainmenu = menuroot;
  contextmenu = menuroot;
  windowmenu = menuroot;
  independentmenu = menuroot;

  tasks = taskpane;

  selectedtasks = taskpane;

  scope DomainTypeFolioCloud {
    mainmenu = menuroot;
    contextmenu = menuroot;
    windowmenu = menuroot;
    independentmenu = menuroot;

    tasks = taskpane;

    selectedtasks = taskpane;

  }
}

There can be scope-specific menu bindings. Any valid component object can be used as scope.

When the menu bindings are evaluated by the Fabasoft Folio Kernel, the currently active scope is determined by the expression defined in the User Interface Scoping Rule (COODESK@1.1:UIScopingRule) referenced in the Current Domain (COOSYSTEM@1.1:CurrentDomain) object of your Fabasoft Folio Domain. The object returned by the expression is used as the current scope.

Cloud profile note: In the Fabasoft Cloud, the current Teamroom’s type (represented by the corresponding app object) is used as current scope. For example, within a Teamroom of type “CRM”, the FSCFOLIOCLOUDCRM@1.1001:AppCRM app object is used as current scope.

If the current scope determined by the User Interface Scoping Rule matches the scope object referenced in a menu binding, the corresponding menu is displayed. If there is no scope-specific menu available in an object class for the current scope, the default menu is displayed instead.

It is also possible to specify a menus block in the extend class block, using a slightly different syntax.

Syntax

extend class reference {
  menus {
    default = {
      mainmenu = menuroot;
      contextmenu = menuroot;
      windowmenu = menuroot;
      independentmenu = menuroot;
      expansions {
        expansion point {
          target = property;
          condition = expression {...}
          priority = priority;
          entries = {
            menu

          }
        }
      }
    }
    scope = {
      mainmenu = menuroot;
      contextmenu = menuroot;
      windowmenu = menuroot;
      independentmenu = menuroot;
      }
    }
  }
}


The keywords listed in the next table can be used within a menu binding block for assigning the different types of menus.

Note: Taskpanes are just menus with a different appearance.

Keyword

Description

mainmenu

With the mainmenu keyword, a menu root can be assigned to an object class that is used as its main menu.

contextmenu

With the contextmenu keyword, a menu root can be assigned to an object class that is used as its context menu.

windowmenu

With the windowmenu keyword, a menu root can be assigned to an object class that is used as its background menu.

independentmenu

With the independentmenu keyword, a menu root can be assigned to an object class that is used as its container-independent menu.

tasks

With the tasks keyword a taskpane can be assigned to an object class.

selectedtasks

With the selectedtasks keyword a taskpane can be assigned to an object class that contains menu entries of the selected objects.

Table 17: Menu binding keywords

Example

userinterface APPDUCXSAMPLE@200.200
{
  import COOSYSTEM@1.1;
  import COODESK@1.1;

  extend class Order {
    menus {
      default = {
        mainmenu = MenuRootOrder;
        contextmenu = MenuRootOrderContext;
        windowmenu = MenuRootWinContext;
        independentmenu = MenuRootOLEContext;

      }
    }
  }
}

Assigning menu items to a object classes (Expansion Points)Permanent link for this heading

To ensure a consistent look and feel of the user interface, new menu items should appear at predefined positions in the default menus, including taskpanes and context menus.

Default menus are prepared for extension by using so called expansion points. Expansions points are named after the positions where they are used as placeholder.

The listed menu items or menu usecases are inserted at the predefined position.

Menu items can be restricted to UI scopes, this is achieved by surrounding the menu definitions with a scope block.

Example

userinterface APPDUCXSAMPLE@200.200
{
  import COOSYSTEM@1.1;
  import COODESK@1.1;
  import FSCTEAMROOM@1.1001;

  menus for Package {

    TaskpaneSelectedExpansion, MenuContextExpansion.objchildren {

      priority = 100;
      MenuEncryptObject {

        condition = expression { !cooobj.isencrypted }

      }
      MenuDecryptObject {

        condition = expression { cooobj.isencrypted }

      }

    }
    scope DomainTypeFolioCloud {

      MenuContextExpansion.trchildren {

        priority = 100;
        MenuEncryptObject {

         condition = expression { !cooobj.isencrypted }

        }
        MenuDecryptObject {

         condition = expression { cooobj.isencrypted }

        }

      }
    }
  }
}

Additional restrictions for using the menu items can be specified:

  • Specific views can be addressed by adding them to the expansion point or by using the keyword target.
  • For optional menu items use the keyword condition. Conditions must evaluate to true in order to make the menu item visible. The condition clause can be specified for the whole expansion block or inside a menu item block.
  • Generic assignments can be used to specifiy other values, for example priority.

When collecting menu items from the affected objects, the algorithm takes the object class hierarchy into account. The first object class referencing a menu item defines its appearance in the menu.

The priority property of expansions is used to define the order of the menu items. Expansions with a higher priority value are displayed before those with a lower priority.

Some well known expansion points are listed in the next table.

Expansions point

Description

COODESK@1.1:MenuBackgroundExpansion

This expansion point inserts a menu entry in the background area. A symbol is required for empty object lists.

COODESK@1.1:MenuRootSimpleExpansion

This is used to add a menu entry to the simple menu view. This menu contains only symbols. The menu entry requires a selection in the tree.

COODESK@1.1:MenuObjectDirectExpansion

This expansion point adds a menu entry in the Object menu. The menu items are retrieved from the object class of the container object.

COODESK@1.1:MenuObjectExpansion

This expansion point is used to insert a menu entry in the Object menu. The menu items are retrieved from the object classes of the currently selected objects.

COODESK@1.1:MenuToolsDirectExpansion

This expansion point adds a menu entry in the Tools menu. The menu items are retrieved from the object class of the container object.

COODESK@1.1:MenuToolsExpansion

This expansion point is needed to add a menu entry in the Tools menu. The menu items are retrieved from the object classes of the currently selected objects.

COODESK@1.1:MenuContextDirectExpansion

This expansion point is used to extend the context menu. The menu items are retrieved from the object class of the container object, which is also the current object if the context menu is displayed in the tree.

COODESK@1.1:MenuContextExpansion

This expansion point is used to extend the context menu. The menu items are retrieved from the object classes of the currently selected objects.

COODESK@1.1:TaskPaneSelectedExpansion

This expansion point is used to insert a task pane entry. The entry is only activated if an object is selected.

COODESK@1.1:TaskPaneExpansion

This expansion point is used to insert a task pane entry. The menu items are retrieved from the object class of the container object.

<any>Expansion

Other expansion points defined by various software components.

Table 18: Expansion points

When using the expansions which are targeting the container object (TaskPaneExpansion, *DirectExpansion) the current selection can be retrieved by using the current selection context.

Example

userinterface APPDUCXSAMPLE@200.200
{
  import COOSYSTEM@1.1;
  import COODESK@1.1;

  menus for Order {
   ToolsMenuDirectExpansion.myattachments {
      MenuSendAllObjects {

        condition = expression { #TV.TV_SELECTIONCONTEXT.selobjects!= null }
      }
    }
  }

}

Expansion points can be specified in extend object class also, but with a slightly different syntax. It is recommended to format these old style menu assignments to the new form.

Example

userinterface APPDUCXSAMPLE@200.200
{
  import COOSYSTEM@1.1;
  import COODESK@1.1;
  import FSCTEAMROOM@1.1001;

  extend class Package {
    menus {
      default = {
        expansions {
          TaskPaneSelectedExpansion, MenuContextExpansion {
            target = {

              objchildren,

              trchildren

            }

            condition = expression { !cooobj.isencrypted }
            priority = 100;
            entries = {
              MenuEncryptObject

            }
          }

          TaskPaneSelectedExpansion, MenuContextExpansion {
            target = {

              objchildren,

              trchildren

            }

            condition = expression { cooobj.isencrypted }
            priority = 50;
            entries = {
              MenuDecryptObject

            }
          }

        }
      }
    }
  }
}


Expert note: Expansion points are just dynamic menus which collect their menu items from the object class of the current container resp. the object classes of the currently selected objects, thus removing the need of directly extending the menus. They are defined as group so that the calculated menu items are surrounded with separator lines.

Assigning task panes to an object classPermanent link for this heading

Task panes are displayed in the overview.Task panes behave like menu bars, so they can be specified like menus (see ).
Deprecated: Task panes are assigned to object classes using a taskpanes block that must be nested within an extend class block.

Syntax

extend class reference {
  taskpanes {
    default = taskpane;
    scope = taskpane;
    ...
  }
}

Each object class has a default task pane which can be redefined using the default keyword.

You can also assign one or more scope-specific task panes to an object class. If there is no scope-specific task pane available in an object class for the current scope, the default task pane is displayed instead.

Example

userinterface APPDUCXSAMPLE@200.200
{
  import COOSYSTEM@1.1;

  extend class Order {
    taskpanes {
      default = TskPnOrder;
  }
}

Assigning forms to object classesPermanent link for this heading

Fabasoft Folio allows you to associate use cases and forms in the context of object classes. When a use case involving a user interface is invoked, Fabasoft Folio tries to locate a matching form for this use case in the list of form bindings in the object class of the current object.

The most common use cases involving a user interface are listed in the next table. When creating a new object class, it is recommended to define form bindings for at least the first four use cases listed in the table.

Use case

Description

COOSYSTEM@1.1:ObjectConstructor

If there is a form assigned to the use case COOSYSTEM@1.1:ObjectConstructor, the property editor is started after creation of objects of this class.

COODESK@1.1:ObjectInfo

The form assigned to this use case is used for showing the tool tip of an object. All form pages of the form are displayed one below the other. The colspan of each property has to be the same to ensure a proper layout.

COODESK@1.1:CreateObject

This use case is invoked in the “Create” dialog when an object class is selected. The form assigned to this use case is embedded in the “Create” dialog. By default, a form with the properties Name and Subject is displayed. If no property should be displayed, you can use the COODESK@1.1:FormCreateObjectEmpty form.

COOATTREDIT@1.1:ReadObjectAttributes

This use case is invoked when the properties of an object are read.

COOATTREDIT@1.1:EditObjectAttributes

This use case is invoked when the properties of an object are edited.

COOSEARCH@1.1:SearchObjects

This use case is invoked when the search dialog box is opened.

COODESK@1.1:DisplayOptions

The form assigned to this use case is used for allowing users to select columns when changing the column settings of an object list.

COODESK@1.1:ExploreObject

This use case is invoked when an object is opened in the explore view by selecting the Explore menu.

COODESK@1.1:ExploreTree

The form assigned to this use case is used when a compound object is displayed in the tree view.

Table 19: Use cases for form bindings

Note: COOSYSTEM@1.1:ObjectConstructor replaces the mapping of COOTC@1.1001:InitGUI.

The following example illustrates different scenarios for object creation. The default implementations used in the example show the form that is mapped to COOSYSTEM@1.1:ObjectConstructor.

Example

// Application executed when an object is created via menu or
// button in an object list

override FSCVENV@1.1001:InitializeCreatedObject {
  variant objectclass {
    impl = FSCVENV@1.1001:InitializeCreatedObjectApp;
  }
}

// Application executed when an object is created inside of
// an object pointer property
override FSCVENV@1.1001:InitializeCreatedObjectDoDefault {
  variant objectclass {
    impl = FSCVENV@1.1001:InitializeCreatedObjectApp;
  }
}

// Application executed when an object is created from
// a template
override FSCVENV@1.1001:InitializeTemplateCreatedObject {
  variant objectclass {
    impl = FSCVENV@1.1001:InitializeCreatedObjectApp;
  }
}

Form bindings for an object class are defined in a forms block for one or more object classes.

Syntax

forms for references {
  usecase {
    form;
    ...
  }
}

Deprecated: Form bindings can also be specified in a forms block inside the extend class block.

Syntax

extend class reference {
  forms {
    usecase {
      form;
      ...
    }
    ...
  }
}


The form block can contain one or more form bindings. Each binding consists of the reference of one or more use cases, and a block denoting the forms that should be bound to these. In each binding, you can reference one or more forms. The reason for referencing more than one form in a binding is that you might want to provide different forms for administrators and end-users. As a rule of thumb, remember that the administrator form must be listed before the end-user form in a form binding.

Instead of specifying the reference of a use case in the binding, the keyword default can be used to bind forms to the use cases COOATTREDIT@1.1:EditObjectAttributes, COOATTREDIT@1.1:ReadObjectAttributes and COOSEARCH@1.1:SearchObjects at once.

Example

userinterface APPDUCXSAMPLE@200.200
{
  import COOSYSTEM@1.1;
  import COODESK@1.1;
  import COOATTREDIT@1.1;
  import COOSEARCH@1.1;
  import COOTC@1.1001;

  forms for Order {
    OpenObject, ReadObjectAttributes, EditObjectAttributes {
      OrderAdminForm;
      OrderUserForm;
    }
    SearchObjects {
      OrderSearchForm;
    }
    ObjectConstructor {
      OrderCreateForm;
    }
  }

forms for Folder {
    default {
      FolderUserForm;
    }
  }
}

Moreover, the use case COODESK@1.1:OpenObject is used for both the form binding for objects that are opened by double clicking and the explore view binding. In this case, the order of the forms in the COODESK@1.1:OpenObject block is not relevant.

Example

userinterface APPDUCXSAMPLE@200.200
{
  import COOSYSTEM@1.1;
  import FSCFOLIO@1.1001;
  import COODESK@1.1;
  import COOATTREDIT@1.1;
  import COOTC@1.1001;
  import FSCTEAMROOM@1.1001;

  extend class ContactPerson {
    forms {
      OpenObject {
        // The following form is used when a contact person is double-
        // clicked by the user (i.e. the "Open" menu is invoked)

        FormCustomer;

        // The desk form is used when a contact person is opened in
        // "Explore" mode (e.g. it is selected in the tree view)

        DeskFormCustomer;
      }
      ReadObjectAttributes {
        FormCustomer;
      }
      EditObjectAttributes {
        FormCustomer {
          priority = 100;
          // The condition to determine whether the form should be displayed
          condition = expression { objteamroom != null }
        }
      }
      SearchObjects {
        SearchFormCustomer;
      }
      InitGUI {
        CtorFormCustomer;
      }
    }
  }
}


The property priority is a priority value from 0 to n, used to rank the lines of the aggregate COOSYSTEM@1.1:classviews. The highest value determines the used view.

The expression condition is evaluated to check if the form should be used.

The viewscope defines a scoping context in which that mapping should be used.

Assigning default column settings to an object classPermanent link for this heading

When displaying object lists in the Fabasoft Folio client, the default columns should be specified in the object class. This can be accomplished by using the keyword columns. columns can either be used standalone as columns for objectclasses or inside extend class.

Syntax

columns for reference {
  attrdef1 {
   column1;
    column2;

}

  attrdef2 {
    freeze {

      column1;
      column2;

    }

    column3;
    column4;

     …
    groupby {

      column1 asc;

    }

    sortby {

      column2 desc;

      …

    }

    displaymodes {

      LISTVIEW_DETAILS;

    }

}

  …
}

Syntax

extend class reference {
  columns attrdef1 {
    freeze {

      column1;
      column2;

    }

    Column3;
    column4;

    …
    groupby {

      column1;

    }

    sortby {

      column2 desc;

      …

    }

  }
  columns attrdef2 {
    freeze {

      column1;
      column2;

    }

    column3;
    column4;

  }

  …
}

This element can be repeated multiple times to specify distinct column settings for different object pointer properties.

Each column is represented by a property path, consisting of one or more properties. The width enclosed in parenthesis and the keyword readonly are optional.

The first columns can be marked as fixed by surrounding them with a block named freeze.

These columns can contain generic assignments. One of these assignments can be the property COOSYSTEM@1.1:dispmlname.  The values for this property are taken from the mlnames.lang file as usual, but the key to the distinct entries is the property path.

The next part could be a set of these columns to be displayed as group. This is specified with the keyword groupby.

Then a set of sorted columns can be listed, using the keyword sortby.

The next part can be the list of valid display modes. If this list is not specified, all display modes are valid.

After that, generic assignments to properties of the aggregate COODESK@1.1:DisplayViewList can be speciefied, just like with any other aggregate.

Here is an example of some more complex column settings:

Example

userinterface APPDUCXSAMPLE@200.200
{
  import COOSYSTEM@1.1;
  import FSCFOLIO@1.1001;
  import COODESK@1.1;
  import COOATTREDIT@1.1;
  import COOTC@1.1001;
  import FSCTEAMROOM@1.1001;

  columns for ContactPerson {
    objsecread {
      freeze {

        usertitle(20) {

          displmlname = {}

        }

      }

      userfirstname readonly;

      userlastname readonly;

      usermemberof.grshortname;

      active;

      groupby {

        usermemberof.grshortname;

      }

      sortby {

        userlastname asc;

        userfirstname;

      }

      displaymodes {

        LISTVIEW_DETAILS {

           dispviewthumbsize = 20;

        }

        LISTVIEW_PREVIEW;

      }

    }

    dispviewfilter = #MyUserFilter;

  }

}

The corresponding language files have entries for the column title with the property names as keys. Please note, that the property name will be fully qualified.

Example

ContactPerson.dispviews[objsecread].dispcolumns[usertitle].dispmlname = "The Title"

Assigning drag and drop actions to an object classPermanent link for this heading

To provide drag and drop functionality in the object pointer properties of an object, the system needs to know how to perform the drag and drop operation. By default nothing has to be done by the developer, as the app.ducxy compiler automatically sets the default actions for the desired behavior.

To change this default behavior, the actions COODESK@1.1:classcopyaction, COODESK@1.1:classlinkaction and COODESK@1.1:classmoveaction can be set to null or changed in the extend class section.

To learn more about drag&drop in Fabasoft Folio, please read the reference documentation.

Example

userinterface APPDUCXSAMPLE@200.200
{
  import COOSYSTEM@1.1;
  import COODESK@1.1;
  import COOTC@1.1001;

  extend class ContactPerson {
    classcopyaction = null;

    classlinkaction = COOTC@1.1001:DragIntoCopy;

    classmoveaction = COOTC@1.1001:DragIntoCopy;

    }
  }
}

Expert note: It is also possible to change the drag and drop behavior for single object properties by specifying the actions for COODESK@1.1:attrcopyaction, COODESK@1.1:attrlinkaction and COODESK@1.1:attrmoveaction when defining the object pointer property.