LibreOffice Developer's Guide: Appendix A - LibreOffice API-Design-Guidelines

From The Document Foundation Wiki
Jump to navigation Jump to search

The following rules apply to all external programming interface specifications for OpenOffice. The API consists of the following stereotypes or design elements:

Structures

Structures are used to specify simple composed data elements.(Structures only consist of data, not methods.)

Exceptions

Exceptions are used for error handling.(Exceptions can be thrown or transported using an any.)

Interfaces

Interfaces are used to specify a single aspect in behavior.(Interfaces only consist of methods, not data.)

Services

Services are used to specify abstract objects.(Services specify properties and the interaction of the supported interfaces.)

Typedefs

Typedefs are used to define basic types for specific purposes.(This stereotype should be used carefully.)

General Design Rules

These rules describe basic concepts used in LibreOffice API design. They are mandatory for all LibreOffice contributions. They are recommended good practice for development of third-party software.

Universality

It is preferable to design and use universal interfaces instead of specialized ones. Interface reuse should prevail. Whenever a new interface is about to be created, consider the possibility of similar requirements in other application areas and design the interface in a general manner.

Orthogonality

The functionality of interfaces should extend each other. Avoid redundancy, but if it leads to a major simplification for application programmers, proceed. In general, functionality that can be acquired from basic interfaces should not be added directly. If necessary, create an extra service which provides the functionality and works on external data.

Inheritance

All interfaces are derived from <idl>com.sun.star.uno.XInterface</idl>. Other superclasses are only allowed if the following terms are true:

  • the derived interface is a direct extension of the superclass
  • the superclass is necessary in every case for the interface and inheritance if it is logical for the application programmer
  • the superclass is the only possible superclass due to this definition

Uniformity

All identifiers have to follow uniform rules for semantics, lexical names, and order of arguments. Programmers and developers who are familiar with any portion of the API can work with any other part intuitively.

Correct English

Whoever designs API elements is responsible for the correct spelling and meaning of the applied English terms, especially for lexical names of interfaces, methods, structures and exceptions, as well as members of structures and exceptions. If not absolutely certain, use Merriam-Webster's Dictionary (https://www.m-w.com). We use U.S. spelling.

Mixed capitalization or underscores (the latter only for lexical constants and enumeration values) are used to separate words within single identifiers. Apply the word separation appropriately. English generally does not have compound words, unlike, for example, German.

Identifier Naming Convention

For common naming of identifiers, and to prevent potential restrictions for identifiers in UNO language bindings, a general naming convention has been defined. This naming convention allows a restricted set of identifiers, where no problems in any language bindings are expected. However, this cannot be guaranteed.

See the following pseudo-grammar, which shows, in a short but precise form, the permitted set of identifiers.

 r*      : zero or more r's, where r is a regular expression
 r+      : one or more r's
 r?      : zero or one r (that is, "an optional r")
 r|s     : either an r or a s
 [abc]   : a "character class"; in this case the pattern matches either an 'a', a 'b' or a 'c'
 [a-z]   : a "character class" with a range; matches any letter from 'a' through 'z'
 "xy"    : the literal string xy
 (r)     : match an r; parenthesis are used to override precedence
 DIGIT       [0-9]
 CAPITAL     [A-Z]
 SMALL       [a-z]
 ALPHA       CAPITAL|SMALL
 IDENTIFIER  (ALPHA(ALPHA|DIGIT)*)|(CAPITAL("_"?(ALPHA|DIGIT)+)*)

The following examples of valid and invalid identifiers should make the preceding grammar clear.

Valid identifiers:

  • getByName
  • XText
  • XText_2
  • CLOSEABLE
  • FATAL_ERROR
  • Message

Invalid identifiers:

  • _getByName
  • _Name
  • _name
  • get_Name
  • myName_2

When you define your own IDL specification, you should take this naming convention into account.

Warning.svg

Warning:
You will find incorrect identifiers in the current API, but this cannot be changed for compatibility reasons. Nevertheless, you should adhere to this naming convention for your own IDL specifications.


Definition of API Elements

In this chapter, several API elements are defined, and how they are used and the rules that apply.

Attributes

Attributes are used to access data members of objects through an interface.

Naming

Attributes are defined in interfaces as get and optional set methods. Although UNOIDL knows attributes for compatibility reasons, this feature is not used. The attribute identifier begins with a capital letter. The mixed upper and lower case method is used to separate single words. Only letters and numbers are allowed with no underscores, for example, getParent() and setParent().

Usage

Attributes are used to express structural relationships, with and without lifetime coupling. For scripting languages, the attributes are accessed as properties.

Methods

Methods are functions defined within an interface. Technically, an interface only consists of methods. There is a syntax for attributes, but these map to methods.

Naming

Method identifiers begin with a verb in lowercase, for example, close, and continue with initial caps, that is, the first letter of each word is capitalized with no underscores. For example, getFormat().

Method names consisting of a verb without any additional terms can only be used if they refer to the object as a whole, and do not operate on parts of the object specified with arguments of this method. This makes names semantically more precise, and we avoid the risk of two method names of two different interfaces at the same object folding into each other causing problems with scripting languages.

Special attention should be given to uniformity within semantically related interfaces. This means, if a method is named destroyRecord(), an insert method should be called insertRecord().

If a method refers to a part of the object and an argument specifies this part, the type or role of the part is appended to the verbal part of the method,for example, removeFrame( [in] XFrame xFrame ). If the name of the part or its position is specified as an argument, ByName or ByIndex is additionally appended, for example, removeFrameByName( [in] string aName ) or removeFrameByIndex( [in] long nIndex ).

The following method prefixes have special meanings:

get

To return non-boolean values or interfaces of other objects that have a lasting relationship with the object the associated interface belongs to, similar to being an attribute. This prefix is generated automatically for readable attributes. Multiple calls to the same method at the same object with the same arguments, without modifying the object in between, returns the same value or interface.

set

To set values or interfaces of other objects that get into a lasting relationship with the object the associated interface belongs to, similar to becoming attribute values. This prefix is generated automatically for writable attributes.

query

This prefix is used to return values, including interfaces that have to be calculated at runtime or do not have the character of being a structural part of the object which belongs to the associated interface. Multiple calls, even without modifying the object in between, do not necessarily return the same value and interface; but this can be specified in the specific methods.

is/has

Usage is similar to get, and is used for boolean values.

create

This prefix is used for factory methods. Factory methods create and return new instances of objects. In many cases, the same or a related interface has an insert or add method.

insert

This prefix inserts new sub objects into an object when the insertion position is specified.

add

This prefix inserts new sub objects into an object when the insertion position is not specified by any argument of the method.

append

This prefix inserts new sub objects into an object when the new sub object gets appended at the end of the collection of sub objects.

remove

This prefix removes sub objects from a container. Use destroy if the removal implies the explicit destruction of the sub object. If the sub object is given as an argument, use it's type or role additionally, for example, removeFrame() if the argument is a Frame. If the position index or name of the sub object to remove is given, use a name similar to removeFrameByName(). For generic interfaces, use removeByName() without the type name or role, which are unknown in that case.

destroy

This prefix removes sub objects from a container and explicitly destroys them in this process. Use destroy as a verbal prefix. For more details, see the description of remove.

clear

This prefix clears contents of an object as a whole, the verb itself, or certain parts of the object, such as add a specifying name giving something like clearDelegates().

dispose

This prefix initiates a broadcast message to related objects to clear references to the object. Normally, this verb is only used in XComponent.

approve

This prefix is used for the approval notification in listener interfaces of prohibited events.

Usage

Non-structural attributes are represented by the property concept, and not by get and set methods, or attributes of interfaces.

Consider possible implementations if there are several possible interfaces where you could put a method. For example, a file cannot destroy itself, but the container directory could.

Do not use const as an attribute for methods, because future versions of UNOIDL will not support this feature.

Interfaces

Interfaces are collections of methods belonging to a single aspect of behavior. Methods do not have data or implementation.

Once an interface gets into an official release of the API, it may no longer be changed. This means that no methods or attributes can be added, removed or modified, not even arguments of methods. This rule covers syntax, as well as semantics.

Interfaces are identified by their name.

Naming

Identifiers of interfaces begin with the prefix 'X' followed by the name itself in initial caps, capitalizing the first letter after the 'X', for example, XFrameListener. Avoid abbreviations.

We apply the prefix 'X', because interfaces have to be treated differently than pointers in C/C++ and also in normal interfaces in Java. It is also likely that the main interface of a service should get the same name as the service that can cause confusion or ambiguity in documentation.

It is a bad design if the name or abbreviation of a specific component appears within the name of an interface, for example, XSfxFrame or XVclComponent.

Usage

Interfaces represent stable aspects of design objects. A single interface only contains methods that belong to one aspect of object behavior, never collections of arbitrary methods. Both aspects of usage, client and server, should be considered in design. Keep the role of the object in mind. If some methods of your new interface are only used in one role and others in another role, your design is probably flawed.

Properties

Properties are descriptive attributes of an objects that can be queried and changed at runtime using the XPropertySet interface.

Naming

In non-scripting languages, such as Java or C/C++, property identifiers are simply strings. These identifiers always begin with an uppercase letter and use initial caps, for example, BackgroundColor. Avoid abbreviations.

Usage

Properties are used for non-structural attributes of an object. For structural attributes (composition) use get and set methods in an interface instead.

Events

Events are notifications that you can register as listeners. This concept is actually expressed by registration or unregistration methods for the broadcaster, listener interfaces for the listener and event structures for the event.

Naming

If an object broadcasts a certain event, it offers a pair of methods like addEventNameListener() and removeEventNameListener(). This scheme conforms to the naming scheme of JavaBeans and does not mean that the implementation keeps track of a separate list for each event.

The event methods of the listener interface use the past tense form of the verb that specifies the event, usually in combination with the subject to which it applies, for example, mouseDragged(). For events which are notified before the event actually happens, the method begins with notify, for example, notifyTermination(). Event methods for prohibited events start with the prefix approve, for example, approveTermination().

Usage

Use events if other, previously unknown objects have to be notified about status changes in your object.

Normally, the methods add...Listener() and remove...Listener() have a single argument. The type of argument is an interface derived from <idl>com.sun.star.lang.XEventListener</idl>.

The event is a struct derived from <idl>com.sun.star.lang.EventObject</idl>, therefore this struct contains the source of the event.

Services

Services are collections of related interfaces and properties. They specify the behavior of implementation objects at an abstract level by specifying the relationship and interaction between these interfaces and properties. Like interfaces, services are strictly abstract.

Naming

Service identifiers begin with an uppercase letter and are put in initial caps , for example, <idl>com.sun.star.text.TextDocument</idl>. Avoid abbreviations.

Usage

Services are used by a factory to create objects which fulfill certain requirements. Not all services are able to be instantiated by a factory, but they are used for documentation of properties or interface compositions. In a service, you can specify in detail what methods expect as arguments or what they return.

Exceptions

Exceptions are special classes which describe exceptional states.

Naming

Exception identifiers begin with a capital uppercase letter, and are put in initial caps and always end with Exception, for example, <idl>com.sun.star.lang.IllegalArgumentException</idl>. Avoid abbreviations.

Usage

The LibreOffice API uses exceptions as the general error handling concept. However, the API should be designed that it is possible to avoid exceptions in typical error situations, such as opening non-existent files.

Enums

Enums are non-arbitrary sets of identifying values. If an interface uses an enum type, all implementations have to implement all specified enum values. It is possible to specify exceptions at the interface. Extending enums is not allowed, because this would cause incompatibilities.

Naming

Enum types begin with an uppercase letter and are put in initial caps. Avoid abbreviations. If there is a possible name-conflict with structs using the same name, add Type or Style to the enum identifier.

Enum values are completely capitalized in uppercase and words are separated by underscores. Do not use a variant of the enum type name as a prefix for the values, because some language bindings will do that automatically.

enum FooBarType
{
  NONE,
  READ,
  WRITE,
  USER_DEFINED = 255
};

struct FooBar
{
  FooBarType Type;
  string FileName
};

Three typical endings of special enum values are _NONE, _ALL and _USER_DEFINED.

Usage

If by general fact an enum represents the most common values within an open set, add a value for USER_DEFINED and specify the actual meaning by a string in the same object or argument list where the enum is used. In this case, offer a method that returns a sequence of all possible values of this string.

Typedefs

Typedefs specify new names for existing types.

Naming

Typedefs begin with an uppercase letter and are put in initial caps. Avoid abbreviations.

Usage

Do not use typedefs in the LibreOffice API.

Structs

Structs are static collections of multiple values that belong to a single aspect and could be considered as a single, complex value.

Naming

Structs begin with an uppercase letter and are put in initial caps. Avoid abbreviations.

If the actual name for the struct does not sound correct, do not add Attributes, Properties or the suffixes suggested for enums. These two words refer to different concepts within the LibreOffice API. Instead, use words like Format or Descriptor.

Usage

Use structs as data containers. Data other than interfaces are always copied by value. This is an efficiency gain, especially in distributed systems.

Structs with just a single member are wrong by definition.

Parameter

Parameters are names for arguments of methods.

Naming

Argument identifiers begin with a special lowercase letter as a prefix and put in initial caps later, for example, nItemCount.

Use the following prefixes:

  • 'x' for interfaces
  • 'b' for boolean values
  • 'n' for integer numbers
  • 'f' for floating point numbers
  • 'a' for all other types. These are represented as classes in programming languages.

Usage

The order of parameters is defined by the following rule: Where, What, How. Within these groups, order by importance. For example, insertContent(USHORT nPos, XContent xContent,and boolean bAllowMultiInsert.

Special Cases

Error Handling (Exceptions/Error-Codes)

Runtime errors caused by the wrong usage of interfaces or do not happen regularly, raise exceptions. Runtime errors that happen regularly without a programming mistake, such as the non-existence of a file for a file opening method, should be handled by using error codes as return values.

Collection Interfaces

Collection-Services usually support one or multiple X...Access-Interfaces and sometimes add access methods specialized to the content type. For example,

 XInterface XIndexAccess::getElementByIndex(unsigned short)

becomes

 XField XFields::getFieldByIndex(unsigned short).

Postfix Document for Document-like Components

Components, whose instances are called a document, get the postfix Document to their name, for example, service <idl>com.sun.star.text.TextDocument</idl>.

Postfixes Start/End vs. Begin/End

The postfixes ...Start/...End are to be preferred over ...Begin/...End.

Abbreviations

Avoid abbreviations in identifiers of interfaces, services, enums, structs, exceptions and constant groups, as well as identifiers of constants and enum values. Use the following open list of abbreviations if your identifier is longer than 20 characters. Remain consistent in parallel constructions, such as addSomething() or removeSomething().

  • Abs: Absolute
  • Back: Background
  • Char: Character
  • Doc: Document
  • Ext: Extended, Extension
  • Desc: Description, Descriptor
  • Ref: Reference
  • Hori: Horizontal
  • Orient: Orientation
  • Para: Paragraph
  • Var: Variable
  • Rel: Relative
  • Vert: Vertical

Source Files and Types

For each type, create a separate IDL file with the same base name and the extension .idl.

Heckert GNU white.svg

Content on this page is licensed under the Public Documentation License (PDL).