Working with external sources

Introduction

When implementing applications, you often need to refer to external sources, such as large external libraries, without explicitly representing them at model level or by type libraries. For example, you may want to re-use external code or plug your applications to an external environment by implementing/overriding external interfaces.

Modelio C++ Designer provides features that let you conveniently use external sources in application UML models.

Using external headers

You can specify the external headers to use in a model class in the “Externals” tab of the C++ edition dialog box for a class.


Specifying external headers in the “Externals” tab of the C++ edition dialog box on a class

Modelio C++ Designer injects the text entered in the “Header includes and using namespaces” field into the header file of the selected class, right after automatically generated include directives. Similarly, the text entered in the “Body includes & using namespaces” field is injected into the body (C++ source) file of the selected class, also after automatically generated include directives. Arbitrary C++ constructions are possible in those fields.

For example, let’s imagine that we want to use our custom logging service in the “TaskWindow” class. We do not want to represent the “MyLogger” class, which implements the service, at model level, because it is not relevant to our application, so instead we write the code in the “Body includes & using namespaces” field of the “TaskWindow” class edition box. We want our code to be injected into the body file to isolate usage of the logging service from other application parts. For this, we are going to enter our code in the “Body includes and using namespaces” field.


Entering our code in the “Body includes and using namespaces” field

The code entered in this text field is injected into the body file of the “TaskWindow” class.

 1#include "MyPlanner/GUI/Windows/TaskWindow.h"
 2
 3//modifiable zone @13927@30671900:980@T
 4#include "MyLog/MyLogger.hpp"
 5
 6#ifdef DEBUG
 7#define MY_LOGGING_LEVEL 9
 8#endif
 9
10using namespace MyLogger;
11//modifiable zone @13927@30671900:980@E
12
13namespace MyPlanner
14{
15    namespace GUI
16    {
17        namespace Windows
18        {
19            TaskWindow::TaskWindow()
20            {
21                //modifiable zone @13351@30671900:701@T
22
23                //modifiable zone @13351@30671900:701@E
24            }
25
26            TaskWindow::TaskWindow(const TaskWindow& value)
27            {
28                //modifiable zone @13363@30671900:713@T
29                //TODO: write copy constructor code
30
31
32                //modifiable zone @13363@30671900:713@E
33            }
34
35            TaskWindow& TaskWindow::operator =(const TaskWindow& value)
36            {
37                //modifiable zone @13381@30671900:731@T
38                //TODO: write assignment operator code
39
40                //modifiable zone @13381@30671900:731@E
41
42                //modifiable zone @13382@30671900:732@T
43                return *this;
44                //modifiable zone @13382@30671900:732@E
45            }
46
47            TaskWindow::~TaskWindow()
48            {
49                //modifiable zone @13388@30671900:738@T
50                //TODO: write destructor code
51
52                //modifiable zone @13388@30671900:738@E
53            }
54
55            void TaskWindow::formatDisplayTitle(std::string FormatStr)
56            {
57                //modifiable zone @13845@30671900:918@T
58
59                //modifiable zone @13845@30671900:918@E
60            }
61        }
62    }
63}

Note: The “Externals” tab page is available only in the class C++ edition dialog box. To use external sources required for model operations or structural features, these must be specified for the owner classes.

Inheriting external classes

You can specify a selected class to be inherited from an external non-modeled class in the “Externals” tab of the class C++ edition dialog box.

Modelio C++ Designer injects the text entered in the “External inheritance” field after the colon token in the selected class definition, thus producing the inheritance declaration. To include headers with the definition(s) of the specified external class(es), the “Header includes & using namespaces” field can be used.

We want the “TaskWindow” class to be a child of the “CWnd” class from the MFC library, which represents a window and provides services for windows management. It is not wise to define this class in the “MFC” type library, because inheritance from a datatype (which would represent the “CWnd” class on the model) does not seem semantically correct.

Therefore, we enter public inheritance declaration and include the external headers with the “CWnd” definition in the respective fields of the “TaskWindow” class C++ edition dialog box.


Entering public inheritance declaration and including external headers

Modelio C++ Designer produces the following code for the “TaskWindow” class. External inheritance declaration and headers are injected. By clicking the “Preview” button in the class C++ edition dialog box, we can obtain this code immediately.

 1//includes for used library types
 2#include <string>
 3#include <cstringt.h>
 4#include <afxwin.h>
 5#include <afxcoll.h>
 6
 7//automatic includes (friends, associated classes, etc)
 8#include "MyPlanner/GUI/ITaskView.h"
 9#include "MyPlanner/TaskManagement/Task.h"
10
11//modifiable zone @13936@30671900:989@T
12#include "afxwin.h"
13//modifiable zone @13936@30671900:989@E
14
15namespace MyPlanner
16{
17    namespace GUI
18    {
19        namespace Windows
20        {
21            class TaskWindow : public CWnd, public GUI::ITaskView
22            {
23            //...
24            private:
25                CString displayTitle;
26
27            public:
28                CDC dc;
29
30            //associations
31
32            public:
33                TaskManagement::Task* task;
34                CMap<CString,CString&,CBrush,CBrush&> brushResource;
35
36            //operations
37
38            public:
39                TaskWindow();
40                TaskWindow(const TaskWindow& value);
41                TaskWindow& operator =(const TaskWindow& value);
42                ~TaskWindow();
43                void formatDisplayTitle(std::string FormatStr);
44
45            //non-modeled members
46
47            };
48        }
49    }
50}

Representing external classes

To explicitly represent relations with external classes, it can be useful to include them in the model. These classes may have quite a complex structure, which ?an make them difficult to reverse or irrelevant to the modeling context.

To represent an external class in the model without specifying its full structure, you can set the “External code” flag in the class C++ edition dialog box. You then specify the code required to use the external class (include directives, macro commands) in the “External headers for external code” field. Instead of translating the modeled class structure, Modelio C++ Designer simply injects the code specified in the field into the class header file.

As a result, you can specify only the relevant parts of external classes. These parts do not need to be specified to exactly correspond to the external class sources.

For example, we want to explicitly model the fact that the “TaskWindow” class is the child of the “CWnd” class from the MFC library. We create the “CWnd” class in the model and create UML operations to explicitly represent certain message handlers that we want to override. We do not define exact message handler signatures, but rather simply show their names in the model.


The newly created “CWnd” class with its operations

To specify the “CWnd” class as being external, we set the “External code” flag and provide the headers required to use the “CWnd” class from the MFC library in the class C++ edition dialog box.


Specifying that the “CWnd” class is external

Modelio C++ Designer produces only the following code for the “CWnd” class (despite the fact that the “OnCreate” and “OnPaint” UML operations are presented in the model).

 1#ifndef __CWnd_15265_H_INCLUDED
 2#define __CWnd_15265_H_INCLUDED
 3/*
 4 * File type:   Class header
 5 * Class: CWnd
 6 */
 7
 8#include "stdafx.h"
 9#include "afxwin.h"
10#endif __CWnd_15265_H_INCLUDED

This header is included when the “CWnd” class is used, so the “CWnd” class external definition (provided in the “afxwin.h” file) is available to all the class clients. For example, the “CWnd” class external definition is available in the code generated for the “TaskWindow” class.

 1//includes for used library types
 2#include <afxtempl.h>
 3#include <cstringt.h>
 4#include <afxwin.h>
 5#include <afxcoll.h>
 6
 7//automatic includes (friends, associated classes, etc)
 8#include "MyPlanner/GUI/Windows/CWnd.h"
 9#include "MyPlanner/GUI/ITaskView.h"
10#include "MyPlanner/TaskManagement/Task.h"
11
12namespace MyPlanner
13{
14    namespace GUI
15    {
16        namespace Windows
17        {
18            class TaskWindow : public CWnd, public GUI::ITaskView
19            {
20            //...
21            private:
22                CString displayTitle;
23
24            public:
25                CDC dc;
26                                   
27            //associations
28
29            public:
30                TaskManagement::Task* task;
31                CMap<CString,CString&,CBrush,CBrush&> brushResource;
32
33            //operations
34
35            public:
36                TaskWindow();
37                TaskWindow(const TaskWindow& value);
38                TaskWindow& operator =(const TaskWindow& value);
39                ~TaskWindow();
40                void formatDisplayTitle(std::string& FormatStr);
41                CDC getDc();
42
43            //non-modeled members
44            };
45        }
46    }
47}

Overriding external functions

To interface the application with an external environment, it can be necessary to override certain virtual functions defined in external sources. It is often necessary to override message handlers defined in the external GUI library, such as MFC.

To override an external virtual function, carry out the following steps:

To match the parameter type with an external one, you should simply switch off the automatic decoration flag in the C++ edition dialog box for the parameter, before specifying the intended type specifiers in the same dialog box.

Note: If you change the deduced values of the “Pointer type”, “Container type” and “Collection pointer type” properties in the parameter edition dialog boxes, the automatic decoration flag is switched off by Modelio C++ Designer.

For example, in the “TaskWindow” class we want to override the “OnCreate” message handler defined in the “CWnd” parent external class.

The “OnCreate” message handler has the following declaration:

1class CWnd : public CCmdTarget
2{
3//...
4public:
5    afx_msg int OnCreate(CREATESTRUCT* lpCreateStruct);
6//...
7};

We create the “OnCreate” operation in the “TaskWindow” class, and then set its “lpCreateStruct” parameter to the “CREATESTRUCT” dummy datatype (this structure is defined in the “afxwin.h” header, so it is available as a result of inheritance from the external “CWnd” class).

Then, we manually specify the C++ properties of the “lpCreateStruct” parameter, to set its type as the pointer, and remove the const specifier.


Manually specifying the C++ properties of the “lpCreateStruct” parameter

As a result, Modelio C++ Designer switches off the automatic decoration flag for the “lpCreateStruct” parameter and instructs that automatic deduction for this model element should be skipped and that only C++ decorations specified by us should be used.

The last remaining action is to define the “afx_msg” specifier for the “OnCreate” operation. This specifier is set in the operation C++ edition dialog box.


Defining the “afx_msg” specifier for the “OnCreate” operation

As a result, Modelio C++ Designer produces the correct code for the “TaskWindow” class, where the “OnCreate” function does override the “OnCreate” message handler defined in the external “CWnd” class.

 1//includes for used library types
 2#include <cstringt.h>
 3#include <afxwin.h>
 4#include <afxcoll.h>
 5
 6//automatic includes (friends, associated classes, etc)
 7#include "MyPlanner/GUI/Windows/CWnd.h"
 8#include "MyPlanner/GUI/ITaskView.h"
 9#include "MyPlanner/TaskManagement/Task.h"
10
11namespace MyPlanner
12{
13    namespace GUI
14    {
15        namespace Windows
16        {
17            class TaskWindow : public CWnd, public GUI::ITaskView
18            {
19            //...
20            private:
21                CString displayTitle;
22
23            public:
24                CDC dc;
25
26            //associations
27
28            public:
29                TaskManagement::Task* task;
30                CMap<CString,CString&,CBrush,CBrush&> brushResource;
31
32            //operations
33
34            public:
35                TaskWindow();
36                TaskWindow(const TaskWindow& value);
37                TaskWindow& operator =(const TaskWindow& value);
38                ~TaskWindow();
39                void formatDisplayTitle(std::string& FormatStr);
40                CDC getDc();
41                afx_msg int OnCreate(CREATESTRUCT* lpCreateStruct);
42
43            //non-modeled members
44            
45            };
46        }
47    }
48}