Você está na página 1de 96

WHITE PAPER

Rogue Wave Stingray Studio


Objective Toolkit
Filling the Holes in MFC to Provide Todays Modern GUI Features

www.roguewave.com

WHITE PAPER

Objective Toolkit Filling the Holes in MFC to Provide Todays Modern GUI Features
Executive Summary ...................................................................................................................................... 6 The Development Challenge .................................................................................................................. 6 The Stingray Studio Solution.................................................................................................................. 6 Overview of Objective Toolkit Features ................................................................................................. 6 Introduction ................................................................................................................................................... 9 Quick Tour of Objective Toolkit ................................................................................................................. 10 Features ................................................................................................................................................. 10 Compatibility .........................................................................................................................................11 Complete Online Help System ..............................................................................................................11 Comparing MFC Extensions to Other Component Architectures ...............................................................11 MFC Extensions ....................................................................................................................................11 OLE/ActiveX Controls (OCXs) ............................................................................................................11 DLL Components.................................................................................................................................. 13 Selecting a Component Architecture .................................................................................................... 13 Technical Overview of Objective Toolkit Components .............................................................................. 13 Objective Toolkit Window/Control Components ................................................................................. 13 Button Control ............................................................................................................................... 14 Color Well Control ......................................................................................................................... 15 Masked Edit Control ...................................................................................................................... 16 Browse Edit Control ...................................................................................................................... 16 Marquee Control ............................................................................................................................ 17 Progress Control ............................................................................................................................ 17 Editable List Box Control .............................................................................................................. 17 Tab Control/Tabbed window Components .................................................................................... 18 Calculator Edit Control .................................................................................................................. 20 Calendar Control ............................................................................................................................ 21 Currency Edit Control .................................................................................................................... 21 Customizable Status Bar ................................................................................................................ 22 Customizable Toolbar .................................................................................................................... 23 Shortcut Bar Control ...................................................................................................................... 24 List Bar Control ............................................................................................................................. 25 Date/time Edit Control ................................................................................................................... 25 Extended Win32 Tree Control ....................................................................................................... 26 Objective Toolkit User Interface Extensions ........................................................................................ 28 The Workspace Manager ............................................................................................................... 28 Keyboard Shortcut Components .................................................................................................... 30

www.roguewave.com

WHITE PAPER

User Tools Menu Components....................................................................................................... 30 Thumbnail Components ................................................................................................................. 31 Extended Control Bar Architecture ...................................................................................................... 33 Objective Toolkit MDI Alternatives and Enhancements ...................................................................... 35 Multiple Top-level Interface (MTI) ............................................................................................... 35 Floating Document Interface (FDI) ............................................................................................... 36 Workbook Document Interface (WDI) .......................................................................................... 37 Using MTI, FDI, and WDI ............................................................................................................ 38 The Gradient Caption Extension.................................................................................................... 39 View Components ................................................................................................................................. 39 Image Components ............................................................................................................................... 40 Image Example .............................................................................................................................. 42 Objective Toolkit Utility Components .................................................................................................. 42 Non-User-Interface Utility Extensions .......................................................................................... 42 Miscellaneous User Interface Utility Extensions........................................................................... 43 Challenges of Docking a CView........................................................................................................... 45 Docking Views: Architectural Overview .............................................................................................. 46 Using the Docking Views Architecture ................................................................................................ 47 Layout Manager Framework....................................................................................................................... 47 The Problem.......................................................................................................................................... 48 The Solution.......................................................................................................................................... 48 Why use the Layout Manager? ...................................................................................................... 48 Layout ManagerArchitecture ......................................................................................................... 49 Layout managers provided by Objective Toolkit........................................................................... 53 Implementing custom layout managers ......................................................................................... 53 Adding layout management to your applications .......................................................................... 54 Advanced Docking Windows ..................................................................................................................... 54 Introduction to a new architecture ........................................................................................................ 54 Why this architecture? ................................................................................................................... 55 ActiveScript hosting engine ........................................................................................................................ 59 JavaScript .............................................................................................................................................. 60 VBScript ............................................................................................................................................... 60 Hosting an ActiveScript ........................................................................................................................ 60 ActiveScript classes ....................................................................................................................... 60 The ActiveForm scripting and editing framework................................................................................ 62 ActiveForm classes ........................................................................................................................ 62 The Model-View-Controller (MVC) Framework ....................................................................................... 64 Introduction to MVC ............................................................................................................................ 64 Considering an alternative to DVA ....................................................................................................... 64

www.roguewave.com

WHITE PAPER

Problems with DVA .............................................................................................................................. 65 DVAs architecture is vague ........................................................................................................... 65 DVAs approach is monolithic ....................................................................................................... 66 CViews inhibit reuse ...................................................................................................................... 66 CView/CDialog are incompatible .................................................................................................. 67 OnUpdate creates problems ........................................................................................................... 68 DVAs presentation tied to control ................................................................................................. 68 Overview of the MVC architecture ...................................................................................................... 68 MvcModel ...................................................................................................................................... 69 MvcViewport ................................................................................................................................. 70 MvcController ................................................................................................................................ 70 Connecting the model, viewport, and controller............................................................................ 71 Additional reading on MVC .......................................................................................................... 71 The MVC class hierarchy ..................................................................................................................... 72 MvcVisualComponent ................................................................................................................... 72 MvcVisualPart ............................................................................................................................... 73 MvcLogicalPart ............................................................................................................................. 73 MvcViewport ................................................................................................................................. 73 MVCWrapper_T ............................................................................................................................ 74 IComposite_T ................................................................................................................................ 75 IMvcMsgHandler ........................................................................................................................... 75 The IMvcSubject, IMvcObserver and IMvcMessage Interfaces ................................................... 75 MvcModel ...................................................................................................................................... 76 The MvcPresentationModel_T class.............................................................................................. 76 IMvcVirtualPart ............................................................................................................................. 77 MvcTransactionModel ................................................................................................................... 78 MvcController ................................................................................................................................ 78 The collection classes .................................................................................................................... 79 MVCs Undo/Redo architecture ........................................................................................................... 80 MvcCommand ............................................................................................................................... 80 The transaction model .................................................................................................................... 80 The IMvcUndoRedo interface ....................................................................................................... 81 Tying Undo/Redo into the MVC framework ................................................................................. 81 Solving real problems with MVC ......................................................................................................... 81 Clarifying the role of the model and the viewport ......................................................................... 81 Leveraging the power and flexibility of the subject/observer interfaces ....................................... 85 Using MVC and MFC together ..................................................................................................... 86 Undoing a delete command ........................................................................................................... 86 Chaining controllers together......................................................................................................... 87 Using the MVC architecture ................................................................................................................. 87

www.roguewave.com

WHITE PAPER

Integrating your model class .......................................................................................................... 87 Integrating your viewport class...................................................................................................... 88 Integrating your controller class .................................................................................................... 91 Using MVCs Undo/Redo architecture ................................................................................................. 92 Conclusion .................................................................................................................................................. 96

www.roguewave.com

WHITE PAPER

Executive Summary
This section is for busy readers who need a quick overview of Objective Toolkit. It briefly describes major product features. For a more in-depth technical analysis of the product, begin reading at the Introduction on page 4. To help you determine which programming approach best suits your needs, we also encourage you to read the section entitled Comparing MFC Extensions to Other Component Architectures, beginning on page 7.

The Development Challenge


The simple answer is that many need to deploy their application across all windows versions, and cant impose a particular version of a 20+ MB framework (.NET) on their users. It seems Microsoft has recognized this, based on a recent major release called MFC Feature Pack 9. MFC offers tremendous capabilities, but as at a price. It isnt as full featured or easy to use as some other methods, but that is where Stingray comes in. Stingray wraps and extends MFC so seamlessly, that you may forget that you arent using MFC directly. It is portable across many windows versions, and extends the basic capabilities with hundreds of new controls. Stingray Edition 11 supports the new MFC Feature Pack 9 features, building on a long legacy of stable releases.

The Stingray Studio Solution


The Objective Toolkit component found in Rogue Wave Stingray Studio provides Windows software engineers with more than 60 drop-in components that address areas not covered by the MFC library. Engineers using Objective Toolkits components can leverage their knowledge of the MFC library and save time, bypassing the tedious task of writing extensions for common user-interface tasks.

Overview of Objective Toolkit Features


The components provided in Objective Toolkit can be divided into the following categories: Control components Advanced GUI components such as owner-draw buttons, bitmap buttons, menu buttons, well buttons, color well, pop-up color well, masked edit, browse edit, editable list box controls, 2D and 3D tab controls/tabbed windows, calculator control, calendar control, currency control, date/time edit control, marquee control, progress control, customizable toolbar, status bar, and an enhanced functionality tree control. User interface extensions A variety of user interface extensions, including splash window, tip of the day, bitmapped dialog, workspace manager, keyboard shortcut, run-time editing, user tools menu, and thumbnail components. Extended control bar architecture A set of MFC extensions that augment its docking window features. The extended control bar architecture and its supporting components give applications the same sizable docking window capabilitywith cool lookthat is available in the Visual C++ IDE (Integrated Development Environment).

www.roguewave.com

WHITE PAPER

MDI (Multiple Document Interface) alternatives and enhancements Objective Toolkit offers the following MDI alternatives and enhancements: Multiple Top-level Interface (MTI), Floating Document Interface (FDI), and Workbook Document Interface (WDI). View components CView extensions that provide features such as advanced zooming and panning. Zooming lets the user zoom in and out of a view and automatically handles all mapping mode changes. Image components A group of components that let users read, write, convert among, and manipulate popular image formats. Supported formats include DIB, GIF, JPEG, PCX, TGA, and TIFF. Utility components Utilities for data encryption and decryption in two different modes, file compression and decompression, accessing file system functions, random number generation, formula evaluation engine, and encapsulation of the Win32 Registry APIs. Data Extraction Classes Used to extract data from text streams. Docking Views is an enhancement to MDI that allows you to convert any document window (for example, MDI child) into a docking window. It allows you to dock complete MFC CViews and frame windows, providing the user with visual focus cues that automatically update the view menus and implement complete dockability. The docking views architecture allows views to float as MDI children, dock to the main frame, and also float outside the main frame. When a view is docked, you can resize the dockable views using the splitter bars positioned along the windows edge. When a view is floating as an MDI child or outside the main frame, you can resize the frames embedding the view in both directions. The Layout Manager framework manages resizing tasks through the use of a framework that implements plug-in layout algorithms and gives you the flexibility to design custom layout managers based on unique business needs. The framework includes several sample layout algorithms such as grid bag layout, relative, scaled and others. It also affords you the flexibility to design custom layout managers based on your needs (for example, for low-resolution displays). The layout manager plugs seamlessly into your existing dialog, formview, controlbar, property page, or any other window to allow for nested layouts. You can integrate the layout manager into applications in a matter of minutes. An Advanced Docking Windows (ADW) architecture, built on top of the Layout Manager framework, provides container independence, complex layout logic, and a drag-and-drop framework. It provides a powerful and flexible mechanism for docking any layout node such as any CWnd or Device Context rendered image (for example, a bitmap) to any other layout node that supports the proper docking interfaces. An ActiveScript hosting engine gives MFC applications complete access to Microsofts ActiveScript technology so they can host scripts. It also provides a mechanism for two-way interaction between MFC applications and ActiveScript so that you can quickly incorporate

www.roguewave.com

WHITE PAPER

VBScript and JavaScript scripting into your own MFC-based applications. A forms-editing engine works in concert with the ActiveScript hosting engine to give you the ability to edit and script MFC graphical user interfaces interactively, using a Visual Basiclike forms-editing interface. The Model-View-Controller (MVC) framework extends DVA so that you can easily separate command handling, view, and document/model information. MVC also makes it easier to create portable views that are application-independent. Build Only Components Required with Build Wizard. Reduce the size of deployed libraires by building only the required subset to reduce the overall footprint. Use the Build Wizard to generate a custom library and DLL. MFC extensions to the basic Microsoft Agent ActiveX components provide Agent-enabled Dynamic Data Validation, Tooltips, Message Boxes, and Tip of the Day support. They also provide a framework with a simple API to initialize the AgentServer, load/unload a default agent character with a default notification sink, and create Acts (critical and non-critical) associated with ActIDs. Namespace Extension Wizard-helps you quickly create a working namespace extension project. After the wizard generates the project, you can easily extend the generated skeleton namespace extension to a fully functional namespace using the classes in OT. Hyperlink Classes provide a convenient way to add point-and-click navigation to conventional non-browser-enabled applications. Web Browser Extensions provide utility functions and a COM Server handy for working with DHTML interfaces in C++. The APP (Asynchronous Pluggable Protocol) ATL Object Wizard provides a very convenient way to insert the OT APP ATL Object into any ATL project. The inserted object provides default features like parsing and validating the supplied URL, spawning a worker thread to perform asynchronous data fetch, and the ability to abort the operation gracefully. The COM object contains an implementation object to which it delegates all of the function calls. Subclassing the implementation object will provide you with virtual notifications and allow you to customize the default behavior. All Rogue Wave Stingray Studio MFC extension components include Visual C++-compatible source code. Objective Toolkit has been tested and optimized to run with Visual C++ 7.1/MFC 7.1, Visual Studio 2005/MFC 8.0, and Visual Studio 2008/MFC 9.0. Objective Toolkit provides developers with components that simulate the Visual Studio .NET/Office XP look and feel or the Microsoft Office 2003 look and feel. Objective Toolkit components provide the XP look and feel on the Windows XP platform, and when used with Visual Studio .NET, some components provide additional Visual Studio .NET look and feel features. Objective Toolkit includes full integration of the Class Reference and User Guide with

www.roguewave.com

WHITE PAPER

the Visual C++ MSDN help viewer, an Objective Toolkit AppWizard with automatic code generation for selected features, and full integration with the IntelliSense auto-completion utility. Its advanced docking windows architecture supports advanced features such as nested docking windows, containerindependent docking, real-time dragging, alternate docking layout logic, real-time splitter movement, fixed-size dockable windows, and more. A BuildWizard is included to minimize build time. Objective Toolkit is fully integrated with all other Stingray Studio components, including Objective Grid, Objective Chart, Objective Views, and Objective Edit.

Introduction
Many of the latest Windows applications incorporate innovative user interface features and graphical components. These featuressuch as the enhanced docking window capabilities in Microsoft Visual Studio, or the drag-and-drop customizable toolbar in Microsoft Wordhave universal appeal and benefit a myriad of Windows applications. Despite the popularity of these powerful enhancements, the Microsoft Foundation Classes (MFC) provide only the most basic user interface features and components. In addition, some of the frameworks provided by MFC are not suitable for all applications. In fact, many of these frameworks have become obsolete since they were first introduced. For example, MFCs Document/View Architecture (DVA) is designed to help separate the user interface from the data in an application. Time has shown that this architecture actually reduces code reuse. Another example is the choice of basic window management offered by MFC. MFC offers only Multiple Document Interface (MDI) and Single Document Interface (SDI) window development, despite the fact that most Windows applications no longer use this paradigm. Objective Toolkit is an MFC extension collection that extends and complements the MFC library. It provides more than sixty drop-in components that cover areas not addressed by the MFC library. Unlike other C++ components, Objective Toolkit components work seamlessly with MFC and, in most cases, inherit from existing MFC classes such as CView or CWnd. Objective Toolkit enables you to bypass the tedious task of writing extensions for common user-interface tasks. This white paper is a technical introduction to the MFC extension architecture and the major features of Objective Toolkit.

www.roguewave.com

WHITE PAPER

Quick Tour of Objective Toolkit


This section describes the key features of Objective Toolkit and discusses integration, compatibility, and support.

Features
The components provided in Objective Toolkit can be divided into the following categories: Control components: Advanced GUI components such as owner-draw buttons, bitmap buttons, menu buttons, well buttons, color well, pop-up color well, masked edit, browse edit, editable list box controls, 2D and 3D tab controls/tabbed windows, calculator control, calendar control, currency control, date/time edit control, marquee control, progress control, customizable toolbar, status bar, and an enhanced functionality tree control. User interface extensions: A variety of user interface extensions, including splash window, tip of the day, bitmapped dialog, workspace manager, keyboard shortcut, run-time editing, user tools menu, and thumbnail components. Extended control bar architecture: A set of MFC extensions that augment its docking window features. The extended control bar architecture and its supporting components give applications the same sizable docking window capabilitywith cool lookthat is available in the Visual C++ IDE (Integrated Development Environment). These docking windows also provide an autohiding feature similar to window pinning feature found in the Visual C++ .NET (2003, 2005, and 2008) IDE. MDI (Multiple Document Interface) alternatives and enhancements Objective Toolkit offers the following MDI alternatives and enhancements: Multiple Top-level Interface (MTI), Floating Document Interface (FDI), and Workbook Document Interface (WDI). View components: CView extensions that provide features such as advanced zooming and panning. Zooming lets the user zoom in and out of a view and automatically handles all mapping mode changes. Panning is a popular scrolling extension used in various Windows applications. Image components: A group of components that lets users read, write, convert among, and manipulate popular image formats. Supported formats include DIB, GIF, JPEG, PCX, TGA and TIFF. Utility components: Utilities for data encryption and decryption in two different modes, file compression and decompression, accessing file system functions, random number generation, and encapsulation of the Win32 Registry APIs. Data Extraction Classes: Data extraction classes are an object-oriented solution for scanning and extracting data from text streams.

10

www.roguewave.com

WHITE PAPER

Compatibility
Objective Toolkit is fully compatible with the latest 32-bit releases of Visual C++. Companies like Bristol and Mainsoft have ported some versions of Objective Toolkit to UNIX.

Complete Online Help System


Objective Toolkit is supported by a complete class reference online help system to help you learn and develop with the product. In addition, you can receive context-sensitive help for methods and components while editing or browsing with the Microsoft Visual Studio code editor. The Objective Toolkit Class Reference and User Guide are now integrated into the MSDN viewer as HTML Help. The documentation is also available in CHM, HxS and PDF formats.

Comparing MFC Extensions to Other Component Architectures


Before we examine the Objective Toolkit components in detail, lets compare the MFC extension approach with other available component architectures.

MFC Extensions
MFC extensions, like MFC, are a group of C++ components that are built on and extend MFC classes. All Stingray Studio MFC extension components include complete Visual C++-compatible C++ source code and can be built as either static libraries or as AFX DLLs, which are DLLs that share a DLL copy of MFC with your application and can be shared between several applications. Since C++ includes support for object-oriented components, MFC extensions are a natural way to extend MFC. Our MFC extensions fit so seamlessly with MFC that you might not notice that you are using a different product.

OLE/ActiveX Controls (OCXs)


OLE/ActiveX controls (OCXs) are the 32-bit successors to 16-bit Visual Basic eXtensions (VBX). OCXs are based on Microsofts ActiveX technologypreviously known as Object Linking and Embedding (OLE)that allows binary objects to interface with each other. Architecturally, OCXs and MFC extensions are quite different. MFC extensions are a source-level, or compile-time, interface, while OCXs are a binary-level, or run time, interface. There are benefits and drawbacks to each approach. The benefits of an OCX (run time) interface include: You can use the same OCXs in a variety of environmentssuch as Visual Basic, Visual C++, and Borland Delphiwithout having to recompile.

11

www.roguewave.com

WHITE PAPER

You can also load OCXs at run time, so you dont have to know about them at compile time.

Figure 1 - Diagram of the OCX Interface

The drawbacks of the OCX (run time) interface include: It is difficult to modify or subclass the defined behavior of the component. You can change various exported properties, but OCXs do not support C++ idioms like inheritance. Implementation inheritance is supported with MFC extensions, but not with ActiveX controls. Since a binary interface needs to be well defined, you must learn a completely new set of terminology and technology. Figure 1 diagrams the OCX interface. Attempting to simultaneously learn about both the OCX interface and a complex environment like MFC is time-consuming and difficult. Performance is an issue. Because OCXs are loaded at run-time, there is often a noticeable delay when the ActiveX COM layer loads the object and prepares it for use. There are ways to shift this delay to application startup, but this does not really solve the problem. The benefits of MFC extensions (compile-time) interface include: MFC extensions are easier to use and modify than OCXs. You can use MFC extensions the same way you use MFC classes. You can modify them with proven C++ techniques without having to learn any complex interfaces. Implementation inheritance is supported with MFC extensions.

DLL Components
Another popular component architecture used primarily by C and C++ developers is a library of C

12

www.roguewave.com

WHITE PAPER

functions that are built into a Dynamic Link Library (DLL). Some of these components even include MFC class libraries that wrap the C function calls to give them a C++ interface. The benefit of DLL components is that they are easy to learn and use. Most of the DLLs written in C originated from DOS and are fairly robust libraries. The drawback of these DLL componentseven ones that provide an MFC wrapperis that they are not object-oriented and thus not easily modified or subclassed. Because the MFC wrapper classes directly call functions in the DLL, you need to determine how to override behavior through the DLL interface instead of the typical MFC methods.

Selecting a Component Architecture


To select a component architecture that suits your needs, consider the following questions: Q: Do I need the component to work with a variety of development environments? A: If yes, use an OCX. Q: Do I need the component to work with MFC where modifying the component is not an issue? A: If yes, consider a regular DLL-based component. Q: Do I need a component that is based on MFC and that allows me to leverage my existing knowledge of MFC architectures and classes? A: If yes, use an MFC extension. MFC extensions can be used in other development environments. They also can be modified using object-oriented techniques.

Q: Do I need the functionality and look and feel of the MFC 9 Feature Pack? A: If yes, link in Stingray Studios Feature Pack MFC extension. A migration guide is provided.

Technical Overview of Objective Toolkit Components


Now that you are familiar with various component architectures, lets take a closer look at the components provided by Objective Toolkit and examine how they fit in with existing MFC classes. Note: To ensure that Objective Toolkit components do not conflict with current or future MFC classes, most Objective Toolkit components are prefixed with SEC, which stands for Stingray Extension Classes.

Objective Toolkit Window/Control Components


The Objective Toolkit window/control components provide sophisticated and attractive CWnd-based components similar to those in popular Windows applications. Objective Toolkit allows you to easily and quickly add these components to your applications.

13

www.roguewave.com

WHITE PAPER

Button Control

The Objective Toolkit button components provide versatile buttons that have more features and are easier to use than those provided by MFC. Figure 2 illustrates the bitmap, menu, and well button types associated with the Objective Toolkit button components.

Figure 2 Bitmap buttons, menu buttons, well buttons, and embedded color wells

SECOwnerDrawButton SECOwnerDrawButton simplifies the task of creating an owner-draw button. SECBitmapButton SECBitmapButton simplifies creation of buttons that include a bitmap and optional text caption on the face of the button. The top right quadrant of Figure 2 displays examples of bitmapped buttons.

Figure 3 SECBitmapButton control with text

SECMenuButton SECMenuButton provides a simple button that displays a pop-up menu to the right or below the button when a user clicks it.

14

www.roguewave.com

WHITE PAPER

Figure 4 SECMenuButton with pop-up menu

SECWellButton SECWellButton provides a color selection button. The face of the button displays the currently selected color. When the user clicks the button, a color appears below the button that allows the user to select a color.

Figure 5 SECWellButton with SECPopupColorWell control

Color Well Control

The Objective Toolkit color well components provide a sophisticated color selection control. This control displays the 20 system colors in a 4 x 5 grid. The user selects a color by clicking the cell containing that color. Each color well can have an additional button that displays a common color selection dialog when the user clicks it. This dialog allows the user to select a color other than those displayed on the face of the grid. SECColorWell SECColorWell implements an intuitive color picker window that you can embed in a dialog window or a CFormView. The color well automatically sizes to fit its content and you can apply a 3D raised border to it. SECColorWell optionally supports palette realization of its color.

Figure 6 SECColorWell control

15

www.roguewave.com

WHITE PAPER

SECPopupColorWell SECPopupColorWell has been designed for use with the SECWellButton component. It builds on the functionality of the SECColorWell component to provide a pop-up color selection window. This window self-destructs when it loses focus or when a color is selected.
Masked Edit Control

SECMaskEdit provides a subclassed CEdit that lets you specify the format and restrictions on the data entered. For example, if you want a user to enter a phone number, you set the mask to (###) ###-####. Then, SECMaskEdit can handle moving the cursor and restricting user input to digits where the # mask characters are located.

Figure 7 SECMaskEdit control

Browse Edit Control

A browse edit is a Windows edit control with a browse button positioned immediately to its right. The user can either type a value in the field or press the browse button and select a value from a dialog. A browse button is a push button with the label ... When you press a browse button, a dialog appears. This modal dialog contains possible values for the user to select. After the user chooses a value from the dialog, the value appears in the text field.

Figure 8 Example browse edit control

SECBrowseEditBase SECBrowseEditBase is an abstract base class that provides the interface and some of the functionality of a browse edit control. SECBrowseFileEdit SECBrowseFileEdit provides the functionality of a filename edit control. A filename edit is a browse edit that is customized for entering a filename. In a filename edit, the user can either type a filename or pick one from a dialog. SECBrowseDirEdit SECBrowseDirEdit provides the functionality of a directory edit control. A directory edit is a browse edit that allows the user to enter a directory name. The user can either type a directory name in the field or select one from a dialog.

16

www.roguewave.com

WHITE PAPER

Marquee Control

SECMarquee is derived from CWnd. Like any other control, it can be embedded in a view or dialog. The marquee can be used anywhere a CStatic can be used with scrolling enhancements.

Figure 9 SECMarquee example

Progress Control

The SECProgressCtrl includes several enhancements to the existing progress control, such as smooth fill with percentages, multidirectional progressions (left to right, right to left, bottom to top, or top to bottom), fully configurable foreground/background coloring, and custom status text with configurable fonts. The progress control also offers powerful virtual hooks for you to provide your own customizations easily.
Editable List Box Control

An editable list box is a Windows list box that contains items that the user can modify interactively. The user can modify the order of list box items, create and delete items, and edit the content of items. The editable list box is similar to the Visual Studios Include and Library path editors that are accessible from Tools|Options. You can edit text in place by selecting the item and typing or you can browse for a value by clicking the browse button to the right of the item. A browse button is a push button labeled ... that is only visible after the user double-clicks on an item. When you press the browse button, a dialog directs the user to choose from a list or tree of possible values. After the user picks a value and closes the dialog, the selected item appears in the list box. The following figure illustrates the SECListBoxEditor and the SECListBoxFileEditor components in action. The four buttons above each list box permit the creation, deletion, and reordering of items.

17

www.roguewave.com

WHITE PAPER

Figure 10 SECListBoxEditor and SECListBoxFileEditor controls in a dialog

SECListBoxEditor SECListBoxEditor implements an editable list box that supports item creation, deletion, reordering, and in-place text editing. However, it does not support browsing. If browsing is required, you must derive a class from SECListBoxEditor and override its OnBrowse() method. SECListBoxFileEditor SECListBoxFileEditor is an editable list box that is customized for entering a list of filenames. An SECListBoxFileEditor object enables users to enter filenames by typing or by picking from a file selection dialog. SECListBoxDirEditor SECListBoxDirEditor is an editable list box that is customized for entering a list of directories. An SECListBoxDirEditor object enables users to enter directory names by typing or by picking from a directory selection dialog.
Tab Control/Tabbed window Components

The tab control/tabbed window components work with the document/view interface to give the user a choice of either two- or three-dimensional tabs for switching between views. The following figures show tabbed windows and tab controls with two and three dimensions.

18

www.roguewave.com

WHITE PAPER

Figure 11 2D tabbed window in a view

Figure 12 3D tabbed window in a view

SECTabControlBase SECTabControlBase is an abstract base class that defines the interface API of a tab control. A tab control is a small, rectangular window that draws tabs and processes mouse events. SECTabControl SECTabControl implements a tab control with a two-dimensional look and feel. The SECTabControl inherits its interface from SECTabControlBase and adds the implementation details that define its appearance. SEC3DTabControl SEC3DTabControl implements a tab control with a three-dimensional look and feel like Visual Studios Project Workspace window. Tabs can now be positioned top, bottom, left, or right. The SEC3DTabControl inherits its interface from SECTabControlBase and adds the implementation details that define its appearance.

19

www.roguewave.com

WHITE PAPER

SECTabWndBase SECTabWndBase is an abstract base class that defines the interface of a tabbed window that contains a tab control and one or more child windows (one per tab in the tab control). A tabbed window contains and manages the layout of a tab control and one or more child windows (or pages). When a tab is selected with the mouse, the associated page is activated. SECTabWndBase supports a rich set of operations that allow new views to be added, deleted, renamed, activated, scrolled into view, and so forth. In addition, the appearance of the tabs can be customized to use different colors, fonts, tab shapes, and more. SECTabWnd SECTabWnd implements a tabbed window with a two-dimensional look and feel. The SECTabWnd inherits its interface from SECTabWndBase and adds the implementation details that define its appearance. The SECTabWnd interface is modeled after the popular MFC class, CSplitterWnd. SEC3DTabWnd SEC3DTabWnd implements a tabbed window with a three-dimensional look and feel similar to Visual Studios Project Workspace window. Tabs can be positioned top, bottom, left, or right. The SEC3DTabWnd inherits its interface from SECTabWndBase and adds the implementation details that define its appearance.
Calculator Edit Control

Figure 13 demonstrates usage of the Objective Toolkit calculator and pop-up calculator edit controls.

Figure 13 SECCalculator and SECPopupCalculator in a dialog

20

www.roguewave.com

WHITE PAPER

SECCalculator SECCalculator implements a calculator edit control capable of decimal arithmetic and other standard operations. SECPopupCalculator SECPopupCalculator creates a popup window for the calculator that is destroyed whenever the = key is pressed. SECCalcBtn The base class of the buttons on the calculator is SECCalcBtn. A helper class called SECCalcBtn::Attrib defines the attributes used for drawing the calculator button.
Calendar Control

SECCalendar is a CWnd-derived control class that implements a calendar control for date entry and display. Through the use of member functions, days on the calendar can be highlighted and selected. If you use the derived SECPopupCalendar component, you can view the calendar control as a drop-down window to save screen space. Figure 14 demonstrates the use of SECCalendar.

Figure 14 The calendar control

Currency Edit Control

Two components implement the currency edit control: SECCurrencyEdit and SECDropEdit.

21

www.roguewave.com

WHITE PAPER

SECCurrencyEdit is an extensible component for entering and displaying custom formatted currency data. Input data parsing and output display formatting can be customized by deriving new components from SECCurrencyEdit and SECCurrencyEdit::Format. The following figure illustrates use of the Objective Toolkit currency edit control.

Figure 15 The currency edit control in a dialog

SECDropEdit SECDropEdit adds a combo drop-down button to an edit control. This component is used with SECCurrencyEdit and SECCurrencyEdit::Format to implement the currency edit control. SECCurrencyEdit::Format is a nested helper class that provides the core currency formatting and parsing functions.
Customizable Status Bar

Objective Toolkits custom Windows status bar has more features and is easier to configure than MFCs CStatusBar.

22

www.roguewave.com

WHITE PAPER

SECCustomStatusBar allows you to configure the fonts, text alignment, and foreground and background colors in status bar panes. In addition, the custom status bar incorporates a progress indicator that can be programmatically shown in place of the status bar panes. When there is no progress to illustrate, the progress indicator is hidden. You can also embed icons in status bar panes. SECCustomStatusBar also provides support for handling mouse events in status bar panes.

Figure 16 The SECCustomStatusBar

Customizable Toolbar

Objective Toolkits customizable toolbar components extend traditional toolbars by allowing the user to easily drag and drop toolbar buttons into custom toolbar configurations.

Figure 17 Customizable toolbar dialog

The preceding figure is an example of the highly dynamic dialogs you can implement with the customizable toolbar components. In variety and configurability, these toolbars are comparable to those found in Visual Studio. SECCustomToolBar SECCustomToolBar lets your users create customizable toolbars from scratch. Each toolbar can be assigned a set of buttons in a style geared toward a specialized task. From a Customize dialog, a user

23

www.roguewave.com

WHITE PAPER

can add or delete buttons and set a style from default or custom categories. For example, one set of buttons can represent common File operations and another set can represent a user-defined task. In the toolbar dialog, the user can choose between large or small buttons, enabled or disabled ToolTips, and conventional appearance or the cool look. After a user selects a button, it can be dragged to any toolbar. SECCustomToolBar objects are derived from SECControlBar, not from CToolBar/SECToolBar. The following components work in conjunction with SECCustomToolBar: SECToolBarManager manages customizable toolbars and the state of an applications main frame during customize mode, which is invoked by SECToolBarsDlg, SECToolBarsPage and SECToolBarCmdPage. SECToolBarsBase provides a common code base for SECToolBarsDlg and SECToolBarsPage, which provide a user interface for listing and manipulating toolbars. SECToolBarsDlg displays a list of toolbars to the user. This component implements the Customize dialog, which allows a user to select toolbar buttons, manipulate default toolbars, and create a toolbar from scratch. In the toolbar dialog, the user can choose between large or small buttons, disabled or enabled ToolTips, and conventional appearance or the new cool look. SECToolBarCmdPage presents all the available toolbar buttons to the user. These buttons can be dragged onto an existing toolbar or used to create a new toolbar. This component should be used in conjunction with a toolbar manager and SECToolBarSheet. It cannot be used directly in a CPropertySheet. SECToolBarSheet constructs a property sheet used in conjunction with toolbar button templates created by SECToolBarCmdPage and SECToolBarsPage. SECToolBarsPage constructs a toolbar property page for the Customize dialog implemented by SECToolBarsDlg. SECNewToolBar constructs the New Toolbar dialog, which is invoked from the Customize dialog.
Shortcut Bar Control

SECShortcutBar is a new metaphor for a container class. This container class can hold any embedded CWnd-derived objects. Because the shortcut bar is a CWnd-derived class, it can also be embedded anywhere. Accordingly, you can embed shortcut bars in docking windows or the pane of a splitter window, or allow them to overtake the entire client area of the frame window.

24

www.roguewave.com

WHITE PAPER

Figure 18 The SECShortcutBar with icons you can select

List Bar Control

SECListBar is a specialized SECBar that knows how to insert and remove items from its associated CWnd. The CWnd needs to be an SECShortcutListCtrl or an SECShortcutListCtr-derived class.

Figure 19 The SECListBar with an embedded tab control

Date/time Edit Control

Figure 20 The date/time control with various default formats

SECDateTimeCtrl SECDateTimeCtrl is a date/time edit control. This component works in conjunction with SECDTGadget, which is an abstract base class for the gadget components used by SECDateTimeCtrl.

25

www.roguewave.com

WHITE PAPER

SECDTGadget SECDTGadget is an abstract base class for the gadget components used by SECDateTimeCtrl, which is a date/time editing control. There are several subclasses that are based on SECDTGadget: SECDTStaticGadget implements a non-editable text gadget. SECDTNumericGadget implements an editable numeric gadget. SECDTListGadget implements a text gadget with a defined list of possible strings. SECDTButtonGadget implements a simple push button gadget. SECDTSpinGadget implements a spin button gadget.
Extended Win32 Tree Control

A tree control is a window that displays a hierarchical list of items, such as the headings in a document, the entries in an index, or the files and directories on a disk. The Win32 tree control in the Windows common controls has some limitations, the most significant being its lack of support for multiple selection. Objective Toolkit includes an extended Win32 tree control that adds support for multiple selection, plus an integrated grid with resizable header row, wordwrap, extended ToolTip functionality, alternative viewing modes (for example, current branch + parents), and various color options. Each option is controlled by a style that permits the feature to be enabled or disabled. The following diagram compares MFCs tree control with Objective Toolkits extended version.

26

www.roguewave.com

WHITE PAPER

Figure 21 An MFC control compared to Objective Toolkits extended tree control

SECTreeCtrl By deriving from SECListCtrl, the SECTreeCtrl component is capable of multiple selection, allowing a range of tree items to be selected. Each node of the SECTreeCtrl has an associated SECTreeCtrl::Node item. Each tree node consists of a text label and icons indicating selection states. Each node can have a list of items (or children) associated with it. By clicking a node, the user can expand or collapse the associated list of items. In addition, SECTreeCtrl implements a grid on a dialog template. This enables: Wordwrapping of text labels ToolTips on nodes Highlight and caret to occur simultaneously

27

www.roguewave.com

WHITE PAPER

Alternative tree view modes (normal or grey parents) SECTreeCtrl has several auxiliary components, including SECTreeCtrl::Node, SECTreeNode, SECTreeNodeX, and SECTreeCtrlToolTips. SECListCtrl SECListCtrl currently contains a subset of functionality required to implement the SECTreeCtrl derivative. For this reason, SECListCtrl is not intended for general use. By deriving from SECListCtrl, SECTreeCtrl allows a user to select multiple items from a range of items. SECTreeCtrl also allows a user to click an item to expand or collapse its associated subitems. SECListCtrl implements a list view control that holds data associated with SECTreeCtrls nodes. A list view control displays a collection of items; each item consists of an icon and a label. Additional information about each item can be displayed in columns to the right of the icon and label. SECListCtrl manages columns and their headers as well as rows of data. Individual cells in a row can contain text strings or bitmap images, or both. The control can be set with or without grid lines. The default mode is on. SECTreeCtrl::Node This component provides state and draw information for each node. Each node of an SECTreeCtrl-based hierarchical tree control nests an SECTreeCtrl::Node item. Moreover, the value of a particular nodes HTREEITEM equates to the SECTreeCtrl::Node* for that node or SECTreeCtrl::Nodes base classes, which are SECTreeNodeX and SECTreeNode. Each nodes item consists of a label and an optional bitmapped image, and each item can have a list of sub-items associated with it. By clicking an item, the user can expand and collapse the associated list of subitems. A node can appear in two view modes: normal tree view or grey parents mode. SECTreeCtrlToolTips SECTreeCtrlToolTips adds ToolTips to an SECTreeCtrl-based tree control. A ToolTip is a small pop-up window that presents a short description of an item or a prompt to the user. ToolTips are displayed when the user positions the mouse over an item in the tree for a period of time.

Objective Toolkit User Interface Extensions


Objective Toolkit supports a variety of user interface extensions including a workspace manager (save/ restore), keyboard shortcut, user tools menu, and thumbnail.
The Workspace Manager

The Objective Toolkit workspace manager provides a powerful, yet easy to implement mechanism for saving and restoring multiple window and control bar configurations. Designed with extensibility in mind, the workspace manager provides many useful virtual functions to hook in your own custom storage

28

www.roguewave.com

WHITE PAPER

protocol or media (registry, file, network, and so forth), or to customize existing functions. In addition, the workspace manager exports an effective, easy-to-use dialog for administration of these workspaces. The workspace save/restore feature is an enhancement that does not require you to change or redesign your user interface to use it. Moreover, the workspace save/restore user interface enhancement can be used with the Stingray Studio MDI, FDI, MTI, or Extended Control Bar Architecture enhancements. The workspace manager tracks the creation and destruction of all windows in the application. It can save and then later restore the position, dimensions, and content of all windows. To gather the information required to restore the content of a window, the workspace manager calls upon the document/view architecture. As long as your application is document/view-based, the workspace manager works automatically. The workspace manager consists of two components: SECWorkspaceManager and the new, more powerful SECWorkspaceManagerEx. SECWorkspaceManagerEx features the following enhancements over SECWorkspaceManager: Persistence of workspaces directly to either a file or the registry Persistence of multiple views per document Persistence of an applications current activation state Workspace versioning Full support for Objective Toolkit docking windows, toolbars, and menubars Support for Docking Views SECWorkspaceManagerEx is easier to integrate into your application than the old SECWorkspaceManager. It is easy to extend with your own custom configuration information and your own custom persistence protocol. SECWorkspaceManager is now offered solely for backward compatibility, so if you have never used Objective Toolkit, you will want to use SECWorkspaceManagerEx exclusively. All data persisted by SECWorkspaceManagerEx is stored in a tree of SECPersistentTreeNode (PTN) objects. Each object can have an arbitrary number of key-value pairs to represent one piece of data. This model is similar to the Windows system registry. By default, SECWorkspaceManagerEx stores the application state in a preset tree where settings are grouped logically according to their role (for example, controlbar settings are in one subtree and child

29

www.roguewave.com

WHITE PAPER

frame windows in another). By overriding the appropriate Open() and Save() workspace manager methods, you can easily add your own child PTN objects to be included in the workspace state.
Keyboard Shortcut Components

The Objective Toolkit keyboard shortcut components provide an easy way to allow users to redefine the keyboard for your application. These components are able to update the accelerator table at run time with key bindings that the user chooses. In addition to the implementation details required to edit the key bindings at run time, Objective Toolkit also includes a shortcuts dialog that you can reuse in your application. The following figure demonstrates how to use the shortcut dialog to make a keyboard assignment for the File|Open command.

Figure 22 Shortcut dialog awaiting a new keyboard assignment for the File|Open command

SECShortcutTable SECShortcutTable contains key bindings in the form of an array of ACCELs. SECCommandList SECCommandList contains the list of all command IDs that can be assigned together with a short and a long description. Any and all parts of SECCommandList can be defaulted.
User Tools Menu Components

Objective Toolkits user tools menu components implement a user-configurable tools menu like the one in

30

www.roguewave.com

WHITE PAPER

Microsoft Visual Studio. The user can add custom menu items and specify what action occurs when the menu item is selected.

Figure 23 The SECUserToolsDlg

SECUserTool SECUserTool provides an abstraction of a user tool. A user tool is an executable that can be spawned programmatically by the application. An SECUserTool object encapsulates the filename, commandline arguments, and initial directory that describes how and where to run the executable. In addition, the SECUserTool interface contains an Execute() member function that uses these attributes to launch the user-defined tool. SECUserToolsDlg SECUserToolsDlg implements a user tools dialog. A user tools dialog allows a user to edit a list of user tools, where each tool is represented by one SECUserTool object. In this dialog, the user can create new user tools, edit and delete existing user tools, and reorder the list of user tools.
Thumbnail Components

Many Windows applications like Microsoft PowerPoint support thumbnailing. Thumbnailing lets the user preview files without having to open them. Objective Toolkit provides thumbnail support through the document/view architecture. The following sections describe the Objective Toolkit components that implement thumbnail support.

31

www.roguewave.com

WHITE PAPER

Figure 24 Example using the thumbnail component

SECTNBitmap SECTNBitmap is a CBitmap derivative that creates, saves and displays thumbnail images. SECTNDC SECTNDC is a CDC derivative that is passed to your SECTNViews OnDraw() method. The view draws the thumbnail image onto the SECTNDC, and Objective Toolkit then handles conversion to an SECTNBitmap and saves the image. SECTNDocument SECTNDocument is an optional CDocument derivative that stores an SECTNView thumbnail image during serialization and bypasses the thumbnail image when reading. SECTNFileDialog SECTNFileDialog uses a CFileDialog derivative to display a thumbnail. It also automatically reads and displays the thumbnail image when the user clicks a file name in the dialog. SECTNView SECTNView is a CView derivative that can automatically generate a thumbnail by drawing onto an SECTNDC. You can override this behavior so that applications can implement their own thumbnail drawing routines using an interface similar to CView printing.

32

www.roguewave.com

WHITE PAPER

SECTNWinApp SECTNWinApp automatically creates an SECTNFileDialog when the user selects Open from the File menu.

Extended Control Bar Architecture


The docking window support provided by MFC version 4.x is limited. Dockable windows can only be docked to the MDI parent frame or floated on the desktop. When docked, the dockable window can be repositioned but not resized. When floating, a dockable window can be resized in the horizontal or vertical directions, but not diagonally. The extended control bar architecture removes the above limitations and adds a host of new features, including those found in Microsofts Visual Studio. When docked, dockable windows can be resized via splitter bars positioned along the windows edge. When floating, a dockable window can be resized horizontally, vertically, and diagonally. Each dockable control bar can be stretched automatically when resized, or you can implement your own form of resize handling. In addition, each control bar has a default context menu accessed with a right mouse button that contains Show/Hide and Allow Docking menu items by default. Menu items can be added and subtracted from the context menu. Objective Toolkit docking windows also support control bars similar to Visual Studio 97. Extended styles allow you to customize attributes, including optional gripper, Hide button, and Expand button support. In addition, you can easily extend the gripper code with your own custom drawing code. Another feature is AutoHide, which allows the display of more information using less screen space by hiding or showing windows. This is done with a right click context menu, or by clicking the pin control. This moves the window to a border and displays a small icon. When you mouse-over a hidden window, it will again display. To keep the window visible, press the pin control again. The Stingray extended control bar architecture has been designed to extend MFCs docking control bar architecture, not alter it. Very few interface changes have been made, so your knowledge of MFCs CControlBar, CDialogBar and other classes still applies. A new feature as of Stingray Studio 2006 are auto-hide docking windows. Auto-hide docking windows are similar to the pinnable windows in Visual Studio. They are an extension to the Docking Windows architecture that deals specifically with the SECControlBar class. With this new feature, you can unpin a control bar, essentially hiding it while still keeping it docked to the corresponding dockbar. To unpin a control bar, simply click the pin button. Adding the Stingray dockable window enhancements to your application requires little more than a few base class changes.

33

www.roguewave.com

WHITE PAPER

Figure 25 Example using the extended control bar architecture

SECControlBar This component adds the internal state and implementation details required to support sizing when docked. It is a simple step to re-derive existing CControlBar-based classes from SECControlBar. SECDialogBar This component derives from SECControlBar and duplicates the CDialogBar implementation details. Re-derive your CDialogBar-based classes from SECDialogBar. SECToolBar This component adds support for sizing the toolbar when it is docked. SECToolBar derives from SECControlBar and duplicates the CToolBar implementation details. It is easy to re-derive your CToolBar-based classes from SECToolBar. SecToolBar also supports multiple toolbar bitmap resources. SECStatusBar This component serves as the base class for your applications status bar. SECStatusBar does nothing more than re-derive from SECControlBar so that all member variables and implementation details exist as the extended control bar architecture expects. Embed CWnd-derived control inside its pane.

34

www.roguewave.com

WHITE PAPER

SECMenuBar SECMenuBar replaces your menu with a dockable bar that has the look and feel of the Visual Studio and Office 2003 menus. SECMenuBar uses SECCustomToolBar as a base class. Consequently, not only does your menu bar have the cool flat look, but it is also completely customizable when used in conjunction with SECToolBarManager. SECDockState This component makes it possible to save control bar position and size, and then restore it in a later session. To add this feature, change all occurrences of CDockState in your application to SECDockState. SECFrameWnd This component adds the implementation details required to support enhanced docking window capabilities. Re-derive your CFrameWnd-based classes from SECFrameWnd. SECMDIChildWnd This component adds the implementation details necessary to support the enhanced docking window capabilities. SECMDIChildWnd derives from CMDIChildWnd. Re-derive your CMDIChildWnd-based class from SECMDIChildWnd. SECMDIFrameWnd This component derives from CMDIFrameWnd and adds the implementation details necessary to support the enhanced docking window capabilities. Most of the code introduced by the component consists of internal details. To make use of this code, you need to re-derive your CMDIFrameWnd-based class from SECMDIFrameWnd.

Objective Toolkit MDI Alternatives and Enhancements


Objective Toolkit offers the following MDI alternatives and enhancements: Multiple Top-level Interface (MTI), Floating Document Interface (FDI), and Workbook Document Interface (WDI). Before we explore how to use the components supporting these MDI alternatives and enhancements, lets consider the purpose of MTI, FDI, and WDI.
Multiple Top-level Interface (MTI)

MTI can best be described as a combination of SDI and MDI. As in SDI, each top-level window manipulates one document, but as with MDI there can be multiple open documents. MTI creates a new top-level window for each new document. Each new top-level window can include its own menu bar and tool bars. With the Windows taskbar, each MTI window can be easily activated.

35

www.roguewave.com

WHITE PAPER

This approach is common in other GUI operating systems such as the OSF/Motif windowing system for UNIX. Now it is becoming commonplace in Windows as well. Figure 26 illustrates the Multiple Top-level Interface alternative.

Figure 26 The Multiple Top-level Interface (MTI) MDI alternative

SECToplevelFrame SECToplevelFrame is the basis for the MTI MDI-alternative. MTI applications derive from SECToplevelFrame. An MDI application derives from CMDIChildWnd.
Floating Document Interface (FDI)

FDI is like MDI except the MDI children float freely on the desktop instead of being confined to the MDI parent window. As with MDI, you can have multiple documents open. FDI creates a new floating child window for each new document. Each FDI child window appears as a top-level window and manipulates one document. Each FDI child window can optionally include a menu bar containing menu items specific to that window. FDI-based applications have a look and feel similar to the Microsoft Visual Basic environment.

36

www.roguewave.com

WHITE PAPER

Figure 27 Example application using the Floating Document Interface (FDI)

Figure 28 Demo of the SECTabWnd Embedded in an SECControlBar

SECFDIChildWnd SECFDIChildWnd is a document window similar to an MDI child window, except that it floats freely on the desktop instead of being confined to a parent frame. FDI applications derive from SECFDIChildWnd while MDI applications derive from CMDIChildWnd. SECFDIFrameWnd SECFDIFrameWnd is a main frame window which adds support for the Window menu and the Windows dialog. FDI applications derive from SECFDIFrameWnd, while MDI applications derive from CMDIFrameWnd.
Workbook Document Interface (WDI)

The Objective Toolkit WDI components enhance MDI by allowing the user to place all documents in tabbed windows. This has the benefit of reducing MDI modality. In other words, all of the documents

37

www.roguewave.com

WHITE PAPER

are visible to the user as worksheets, so the user does not have to search the Window menu to locate the document. Figure 29 illustrates the Objective Toolkit WDI interface.

Figure 29 Sample application using the Workbook Document Interface (WDI)

SECWorkbook SECWorkbook is derived from SECMDIFrameWnd and adds the workbook (WDI) interface enhancements. Derive your main frame window class from SECWorkbook if you want to add the workbook interface enhancements. SECWorksheet SECWorksheet is derived from SECMDIChildWnd and adds the WDI enhancements. Derive your MDI child windows from SECWorksheet if you want to add workbook interface enhancements.
Using MTI, FDI, and WDI

These MDI alternatives may seem complex at first, but fortunately Objective Toolkit hides this complexity from the engineer. To change your MFC MDI-based application to an Objective Toolkit MTI- or FDIbased application, derive your frame window classes from one of Objective Toolkits frame window components instead of CFrameWnd or CChildFrame. For example, to convert your application from MDI to FDI, derive your CChildFrame class from SECFDIChildWnd and your CMainFrame class from SECFrameWnd.

38

www.roguewave.com

WHITE PAPER

The Gradient Caption Extension

The gradient caption extension is a frame window enhancement that provides simple emulation of the smooth gradient caption effects found in Microsoft Office. The extension also provides control over the caption text alignment. Note: The Gradient Caption Extension is not available on the Windows XP platform. The gradient caption feature is incorporated into the existing SECFrameWnd and SECMDIFrameWnd.

Figure 30 Sample application using the gradient caption frame component

SECFrameWnd This component derives from CFrameWnd and adds support for the gradient caption. SECFrameWnd also adds support for extended docking window features covered in the section entitled Extended Control Bar Architecture, beginning on page 30. SECMDIFrameWnd This component derives CMDIFrameWnd and adds support for the gradient caption and extended docking window features.

View Components
The Objective Toolkit view components enhance the MFC document/view architecture by providing new features, including printing, print preview, and automatic updating. SECZoomView SECZoomView supports automatic zooming of a view. It supports two modes: zoom-to-fit and zoom normal. In zoom-to-fit mode, the view automatically zooms the view to fit the current size of the window. In zoom normal mode, the developer instructs SECZoomView when to zoom by specifying either a zoom rectangle or a zoom percentage.

39

www.roguewave.com

WHITE PAPER

SECPanView SECPanView builds on SECZoomView and adds panning support. Panning allows the user to grab the view and scroll it in any direction by moving the mouse. SECPanWnd In addition to basic panning support, SECPanView also provides an overview window named SECPanWnd that lets the user see and manipulate the entire view. Figure 31 demonstrates these panning enhancements.

Figure 31 The SECPanView and SECPanWnd (overview window) components

Image Components
The Objective Toolkit image components let the developer manipulate the most popular graphic image types. SECImage SECImage is an abstract base class that defines the interface for each of the format components. This interface includes reading, writing, format conversion, and image manipulation. SECImage supports a variety of image manipulation routines, which include the following:

40

www.roguewave.com

WHITE PAPER

ContrastImage() sharpens or dulls the image. Crop() crops the image to the specified dimensions. FlipHorz() flips the image horizontally. FlipVert() flips the image vertically. Rotate90() rotates the image 90 degrees. The internal SECImage format is documented so you can easily implement your own image manipulation routines using the provided examples for reference. Since SECImage is derived from CObject, it fully supports CObject features such as run time class information, dynamic creation, and serialization. SECImage serialization is useful if you have images stored in your document that you would like to serialize along with other portions of your document. SECDib SECDib supports reading and writing of the popular Windows Device Independent Bitmap (DIB) format. Typically, a file in this format has a .bmp or .dib suffix. SECDib supports all color and compression formats for DIBs. SECGif SECGif provides reading and writing for Graphic Information File (GIF) images. The GIF format is defined by CompuServe and is one of the standard image types used by Internet browsers. Support is also included for interlaced GIF images. SECJpeg SECJpeg supports the JPEG compression scheme found in JFIF (JPEG File Interchange Format) files. This compression scheme is used in many Internet browsers and professional image applications. SECJpeg is based on the version 1.02 JFIF standard. SECPcx SECPcx supports the PC eXchange (PCX) format that many Windows graphics applications use for exchanging images. This format only supports 256 colors. SECTarga SECTarga handles the TGA (TarGA image file) format as defined by Truevision. Video Capturing Applications use TGA. In addition, it was one of the first image formats to support 24-bit color. SECTiff SECTiff can read and write Tagged Image File Format (TIFF) files. TIFF files are popular in scanning

41

www.roguewave.com

WHITE PAPER

applications. SECTiff supports version 6.0 of the TIFF standard and includes support for all image depths and compression schemes.
Image Example

Now that you have seen how the Objective Toolkit image components fit together and have become familiar with the supported formats, lets look at an example. The code below shows you how to load a GIF file, display it, rotate it 90 degrees, and then convert and save the image as a PCX file.
SECGif * pGif = new SECGif; pGif->LoadImage(mygif.gif); //should check for errors. //TODO display image using BitBlt/StretchBlt here. pGif->Rotate90(); //Rotate it! SECPcx * pPcx = new SECPcx; pPcx->ConvertImage(pGif); pPcx->SaveImage(mypcx.pcx);

Objective Toolkit Utility Components


Objective Toolkits utility components can be separated into two categories: non-user-interface components and miscellaneous user interface components.
Non-User-Interface Utility Extensions

The components in this section solve non-user-interface problems and perform the following functions: Support data encryption/decryption in two different modes Compress and decompress files Access file system functions Generate random numbers Encapsulate the Win32 Registry APIs SECCryptoFile SECCryptoFile is a CFile derivative that provides encryption and decryption for data written to and read from a file. SECCryptoFile uses a triple-ranked Vigenere cipher that operates in either Electronic Codebook (ECB) or Output Feedback (OFB), which is also known as Cipher Feedback (CFB) mode. You need to supply a password, which can be entered by the user if desired, and choose an encryption method. SECCompressFile SECCompressFile is a CFile derivative that provides compression and decompression for data written to and read from a file. SECCompressFile provides a SetCompressedMode() member function to treat the file as a compressed

42

www.roguewave.com

WHITE PAPER

file type, or a normal CFile type. The user can either treat the entire file as a single compressed block of data or jump to known spots of the file to decompress a smaller portion of the file. SECFileSystem SECFileSystem is a component that allows you to access common file system functions such as retrieving general information about files and directories, reading directories, copying files, and more. You can also access parsing, GUI, and CStringList functions. SECRandom SECRandom provides a method for generating a random number based on a seed value. To skew the results of the random number generation, SECRandom also supports weighted vectors. SECRegistry Objective Toolkit provides an encapsulation of the Win32 Registry APIs. Using our registry abstraction, a developer can modify the registry through a common interface that is consistent under all versions of windows, even back as far as Windows 95. SECRegistry encapsulates the APIs used to access and modify the Windows Registry in a single component. The SECRegistry member functions pertain to the Win32 API.
Miscellaneous User Interface Utility Extensions

The following components implement some other popular features for Windows applications. SECBitmapDialog SECBitmapDialog lets you create dialogs with either tiled or centered bitmaps in the background. This component supports 256 color bitmaps.

Figure 32 Example SECBitmapDialog

43

www.roguewave.com

WHITE PAPER

SECSplashWnd A splash window is a transient window that appears temporarily at application startup. Generally, the popup window displays a copyright notice while the application initializes. SECSplashWnd provides you with a ready-to-use splash window for your applications. All you need to do is insert your own splash bitmap and text. The splash window even deletes itself after a specified time or when the user clicks it, so you do not have to keep track of the splash window in your application. SECTipOfDay If you have used any Microsoft Office application, you are probably already familiar with the tip-of-theday concept. A tip of the day dialog is displayed at start up. It displays random but useful information about the application. SECTipOfDay stores tips in a plain ASCII file so you can easily create tip files (.tip) with any editor. SECTipOfDay is fully customizable. You can specify different fonts and icons, and change other attributes by deriving your own tip class from SECTipOfDay.

Figure 33 Example tip of the day using the SECTipOfDay component

SECTrayIcon SECTrayIcon helps MFC developers create applications that are invoked via the Windows tray interface. Animated icons are supported. If you look at the right edge of the Windows taskbar, there is a small tray of application icons and a system clock. This component provides your application with an easy-to-use mechanism to add your own custom icons to the system tray. It also provides UI feedback such as ToolTip text, context menu support, and animated icons.

44

www.roguewave.com

WHITE PAPER

Figure 34 Example of SECTrayIcon

Docking Views Objective Toolkit provides docking windows that enable you to designate any direct CWnd-derived window as dockable. The Docking Views in Objective Toolkit significantly extend dockability by allowing you to dock complete MFC CViews and frame windows. This metaphor provides the user with visual focus cues, updates the view menus automatically, and implements complete view dockability. Figure 35 shows Objective Toolkit Docking Views in action:

Figure 35 Objective Toolkit Docking Views

Challenges of Docking a CView


You may be wondering why you cannot dock CViews or any arbitrary CWnd derivative with Objective Toolkits standard docking windows extended control bar architecture. There are several reasons: MFC assumes that a CView has a CFrameWnd as a parent. This assumption permits no other parents. The control bar architecture has no knowledge of DVA, of which a CView is an integral part.

45

www.roguewave.com

WHITE PAPER

You can attach a CView to a document, but the document template cannot perform the creation or initialization of the document, view, or parent window. Because the document wasnt created through standard processes, the document manager does not know of its existence, which causes problems during shutdown. A control bar cannot receive focus or become the active window. Control bars are intentionally designed to remain inactive and without focus at all times, whereas CViews are designed to be active and receive focus. This conflict of interest manifests itself in many strange ways, such as focus anomalies. A CView embedded in an SECControlBar cannot receive menu picks because the command routing is not implemented properly. Command handlers in your CView never get called because control bars are not visited when searching for a command handler. You can alter the command routing so that the control bar is visited, but you will never know which control bar to target, because the control bar never becomes active. A CView embedded in an SECControlBar cannot receive keyboard input reliably. Again, this is because the control bar can never become active. Keyboard events are routed to the windowusually the MDI child that is active. The user interface is poorly designed. The problems mentioned above are technical in nature. Even if you overcome the technical obstacles, the resulting UI will not adhere to the standard Windows UI. Lets assume you successfully embed a CView that can receive menu picks and keyboard events inside an SECControlBar. Despite your hard work, this CView still will not adhere to Windows UI standards because the control bars have no way to represent activation or, in other words, there is no caption bar to show activation. This confuses the user because a CView that is receiving menu picks and key presses doesnt have an active caption bar. Worse yet, the window that has the active caption is the most recently active MDI child, which isnt even active. However, because the MDI child has the active caption bar, most users expect menu picks and key presses to occur in that MDI child. Instead, they occur on a control bar that appears inactive. Many engineers assume that Visual Studio is embedding CViews inside its control bars. This is not the case. The Project Workspace window, for instance, is not a CTreeView, its a CTreeCtrl embedded inside the control bar. The Output Window is not a CEditView; its a CEditCtrl. If Visual Studio could dock CViews, then your header and source files would be dockable as well. They are not dockable because Microsoft hasnt solved the problems described above.

Docking Views: Architectural Overview


Objective Toolkit overcomes docking obstacles by providing an architecture that supports docking a CView. The main feature of the Docking Views architecture is the SECDockableFrame class. This class is a hybrid of a control bar and a frame window that possesses the attributes and functionality of

46

www.roguewave.com

WHITE PAPER

both. Like a frame window, an instance of SECDockableFrame can parent a CView, CSplitterWnd, SECTabWnd or any CWnd-derivative. An SECDockableFrame also has an optional title bar for showing activation and contains the logic required to change the menu bar when it is activated like a frame window. Lastly, like an SECControlBar, a dockable frame can be docked and resized when docked. The SECMultiDocTemplate class plays a key role in the Objective Toolkit Docking Views architecture. SECMultiDocTemplate is derived from CMultiDocTemplate. The role of CMultiDocTemplate is to create the document, view, and frame window, and then connect them together. It has the following features: Supplies knowledge of the SECDockable frame. Contains the logic to open a new document as a standard MDI child or docking document. Adds a ToggleDocking() member that allows you to open documents between docked and undocked states. Objective Toolkit contains changes and additions to previous Objective Toolkit classes, such as SECMDIFrameWnd and SECMDIChildWnd. These changes ensure that SECDockableFrame objects are included in the command routing class chain so that menu picks are properly routed to a docked document when it is active.

Using the Docking Views Architecture


Adding Docking Views to your application is an easy process that entails changing several of the base classes used by your application to Objective Toolkit equivalents and using SECMultiDocTemplate instead of CDocTemplate. After you convert to Docking Views, you can customize Docking Views by turning different flags on and off.

Layout Manager Framework


One of the biggest problems you face as a Windows application engineer is how to manage window layout and device-independent positioning. Without Objective Toolkit you will spend a great deal of time writing thousands of lines of custom code to handle the resizing of dialogs and forms. Objective Toolkits Layout Manager addresses this challenge by providing a framework for implementing plug-in layout algorithms. The framework includes several sample layout algorithms, such as grid bag layout, relative, scaled, and more. It also provides the flexibility to design custom layout managers based on unique business needs. For example, a layout manager can be designed that supports low-resolution handling. The Layout Manager plugs seamlessly into an existing dialog, form view, control bar, property page, or any other window. It also allows you to nest layouts. Developers can integrate Layout Manager into applications in a matter of minutes.

47

www.roguewave.com

WHITE PAPER

The Problem
Whenever you create a dialog, form view, property page, or any other window with child window controls, you need to decide whether to let the user resize the window. You could forbid the resize event, but this leads to an awkward, unfriendly user interface. You could ignore the event, but this results in an ugly, under-utilized window with a disproportionate amount of extra space. Finally, you could trap the size event and code your own custom layout logic. Unfortunately, this requires a large amount of implementation-specific code that is time-consuming to create and difficult to change if you ever want to modify the windows layout. Adding support for resolution-independent positioning requires several more hours of work.

The Solution
Objective Toolkit provides a powerful layout management framework that encapsulates all the details of laying out your child window controls so you can concentrate on content rather than the mechanics of your user interface presentation. With the Layout Manager, you can work with layout constraints, which are easy to understand and change, instead of hard-coded pixel positions that are difficult to understand and even harder to change. As an added benefit, use of a relative constraint-based layout algorithm guarantees that your window or dialog looks the same at any resolution.
Why use the Layout Manager?

The concept of a layout manager is not new. Java, Motif, OWL, and Visual Basic OCXs have been offering layout managers for some time now. However, three features distinguish the Objective Toolkit Layout Manager from the rest: tight integration with MFC, a strong and highly extensible architecture, and ease of integration. 1. MFC integration. The lack of default layout management in MFC has been a noticeable shortcoming for some time now. The Visual C++ IDE offers an excellent mechanism for creating and initializing dialog templates, but it is a static view of your application. Once you run your application and try to resize the window, you must implement your own size logic. The Objective Toolkit Layout Manager is written in MFC for MFC. It plugs seamlessly into your existing MFC application without any modifications to your existing window class hierarchy, so no base class changes are necessary. In addition, the Objective Toolkit Layout Manager offers several calculation and redraw optimizations that minimize the CPU processing and screen flickering that occur with every window resize. This is useful with the increasing popularity of full drag mode for resizing windows. 2. Extensible architecture. The Objective Toolkit Layout Manager is strong and extensible.

48

www.roguewave.com

WHITE PAPER

Most existing layout managers offer just one canned layout algorithm that is tightly tied to a specific dialog or form view implementation. However, the Objective Toolkit Layout Manager is scalable. It has a tree-like division of labor that makes it easy to nest layouts inside of layouts or add your own layout type. In addition, the Layout Manager is not tied directly to CWnd, so you can also position non-CWnd entities, such as a rendered image on a CView. This architecture separates the layout logic from the actual visual implementation to provide a robust and extensible component for reuse in an endless variety of contexts. 3. Ease of integration. Some layout managers force you to abandon your existing window base class and use a canned base class that is layout-aware. Although you may find this acceptable, you should know that it can cause difficulties if you are using a custom base class, like a special CDialog derivative. Because MFC does not adequately support multiple inheritance, it puts you in an awkward position. If you decide to use one of these layout managers, you might need to decide which base class is more valuable to you and discard the other. The Objective Toolkit Layout Manager uses aggregation instead of inheritance to apply its layout logic. Merging it into your application is as easy as instantiating a member layout factory, and producing a listener object that hooks laterally to your existing class with no base class changes. The layout factory tracks memory management for you, so you can merge a layout into your existing window with as little as three lines of source code and one declared member variable.
Layout ManagerArchitecture

The Layout Manager has an architecture that is ideal for reuse and extensibility. Based, in part, on the composite design pattern, the Layout Manager is a collection of nodes arranged in a tree-like hierarchy of responsibility. Layout Nodes The basis for the layout tree is the base class SECLayoutNode, which defines the interface for membership in the tree. A layout node is any object that derives its interface from the SECLayoutNode base class. Conceptually, layout nodes are either proactive or reactive in nature. Proactive nodesalso known as compositesare home to the layout algorithms. Each proactive node encapsulates one layout algorithm. Examples are SECLNRelative, SECLNScale, and SECLNGridBag. Proactive nodes are designed to have and administrate child nodes. Reactive nodesalso known as primitivesare home to the leaf objects intended to be administrated by the proactive nodes. By overriding the appropriate functions in the SECLayoutNode base class, a reactive node can respond to events driven by its parent node, positioning, resizing, and rendering itself as appropriate. SECLayoutNodeWnd is an example of a reactive node. It is designed to link to a CWnd, although you could also design your own reactive node to link to a non-CWnd, such as a rendered graphic in a view.

49

www.roguewave.com

WHITE PAPER

The difference between proactive and reactive nodes is conceptual. Syntactically, both are derived from SECLayoutNode and possess the same type of interface. The intended usage of the object defines its designation. Some objects can be both proactive and reactive. For example, SECLayoutNodeSplitter is both an end-node reactive type and a simple proactive layout algorithm. In general, proactive nodes are not visible entities. For example, an algorithmic layout node is a black box rectangle that is responsible for administrating all of its children within that rectangle. However, one of its children can be another proactive node, which in turn administrates its child nodes as it sees fit, and so forth. This is the strength of a polymorphic layout node in a composite, tree-like hierarchy. Consider the following example. Suppose you have a dialog with three pushbuttons and you want to lay out those pushbuttons in a two-row grid, with one button spanning the entire top row, and the other two spanning the bottom row.

Using nested layouts solves this problem in a snap. At the top of your layout tree, you can use an SECLNGrid grid layout node so you have one black-box grid layout node.

If you configured this grid layout node to have one row and two columns, it would have two layout node children.

The SECLNGrid parent does not care what type of children it creates. Its only concern is that it has two child objects derived from SECLayoutNode. Because you want Child Node 1 to hook to a button, you

50

www.roguewave.com

WHITE PAPER

can use SECLayoutNodeWnd for this task. SECLayoutNodeWnd attaches to a CWnd via aggregation to guarantee type compatibility with the layout-node hierarchy. However, for Child Node 2, you want to administrate both Button 2 and Button 3. The easiest way to do this is to nest another proactive node. Embed another grid node to administrate the two buttons. Now, configure this nested grid node to be a 1 x 2 grid with two SECLayoutNodeWnd children.

Associate one child with Button 2 and the other child with Button 3. Heres the result:

The tree layout appears as follows:

51

www.roguewave.com

WHITE PAPER

As you can see, the only information the top-level grid node possesses is knowledge of its two children: an SECLayoutNodeWnd object and an SECLNGrid object. Because all children must be derived from SECLayoutNode, it can polymorphically manipulate the two children with the same interface. After the top-level grid node positions the nested grid, the nested grid positions its two children and the two SECLayoutNodeWnd objects attached to Button 2 and Button 3. Each parent treats its child nodes as black boxes: there is no parent-grandchild manipulation. This divide-and-conquer division of labor provides a powerful mechanism that is tremendously extensible so you can easily add your own custom algorithms or window types into this framework with little or no change to an existing layout. Window listeners The SECWndListener class is used as a bridge between the Win32 windowing world and the abstracted layout node tree. The window listener attaches laterally through aggregation to an existing dialog, view, control bar, or any other CWnd-derived window and listens for the appropriate windows message to start the layout management recalculations. The listen mechanism utilizes a streamlined window subclass that has a negligible performance hit and does not disrupt the normal message flow in any way. This provides your application with a seamless hook into the layout framework with no need for a base class change. The only purpose of the window listener is to simplify the layout insertion process; you do not need it in order to use the layout framework. An alternate migration path is available on demand. Layout factory The SECLayoutFactory class simplifies the process of creating and merging layout nodes into the Layout Manager framework. Because every componentsuch as a window control, graphical entity, or layout algorithmneeds to be dynamically allocated, you need to allocate a large number of layout node objects. The layout factory simplifies this process by dynamically creating the node type of interest, automatically setting some default parent-child relationships and other various settings, and monitoring all of the allocated storage for self-contained memory management. Typically, you need to instantiate only one layout factory object as a member of your parent window class. Using this one factory object, you can use the layout factory methods to allocate all additional storage required directly in the source. The layout factory can also allocate a window listener object, which is a feature that simplifies layout integration even further. Like the window listener, use of the layout factory is not requiredbut it is highly recommendedfor complete utilization of the Layout Manager. Splitter node The SECLayoutNodeSplitter class easily merges splitter functionality into your layout manager. This powerful splitter class is optimized so you can plug it into the layout framework like any other layout node. This overcomes many of the difficulties that engineers encounter when trying to use CSplitterWnd with any window other than a CView. The SECLayoutNodeSplitter complements any layout node. It

52

www.roguewave.com

WHITE PAPER

can even embed layouts inside a splitter pane, and it works inside a dialog or control bar. Additionally, it supports full drag mode for instant dragging without a tracker, two-dimensional dragging for both threeand four-pane splitters, and useful virtual callbacks for further customization.
Layout managers provided by Objective Toolkit

This section describes each of the default layout algorithms supplied with the Objective Toolkit Layout Manager component. Creating your own custom layouts is addressed in the next section. Alignment Layout. The Alignment Layout aligns a child node relative to the parent alignment node. You can align the child node to the left, right, top, bottom, horizontal center, vertical center, or both. You can also specify top, left, right, and bottom margins. This layout algorithm is useful when used as a nested layout. Scale Layout. The Scale Layout maintains all children with a constant aspect ratio to the parent scale node. In other words, the child nodes top, left, right, and bottom coordinates are stored as percentages of the parent nodes size, and are resolved to actual pixel values with each recalculation. This guarantees a constant aspect ratio no matter what the size of the parent node. Grid Layout. Inspired by the Java Grid Layout, this algorithm allows you to position child nodes in a two-dimensional grid of specific or arbitrary size. The grid can be initialized to a specific two-dimensional matrix, or set to grow arbitrarily in one direction as rows or columns. GridBag Layout. Inspired by the Java GridBag Layout, GridBag is a powerful grid that supports node spanning of multiple rows or columns, or both, variable width columns, variable height rows, variable row/column resize weights to control the rate of change, grid cell insets, grid fill modes, and grid cell anchoring. Relative Layout. The Relative Layout allows a logical organization of layout nodes. Constraints can be set using English-like semantics. For example: set the left side of node 1 equal to the right side of node 2 plus 10 pixels set the bottom of node 1 to 25 percent of the height of node 2 move node 1 such that its bottom is equal to the top of node 2 10 pixels This algorithm is also useful in guaranteeing device-independent positioning.
Implementing custom layout managers

Adding your own layout manager is easy. All you need to do is derive a class from SECLayoutNode and override the OnRecalcLayout() method. A nodes parent calls this method whenever a size/position recalculation is required. In your override, you can reposition your custom nodes children as you see

53

www.roguewave.com

WHITE PAPER

fit by issuing a RecalcLayout() on each child in turn to guarantee the proper message flow. You can examine any of the provided layout algorithms as a model for this customization.
Adding layout management to your applications

The process of merging the layout framework into your application is easy. All you need to do is follow the four basic steps described in the Objective Toolkit Users Guide: 1. Add an instance of the layout factory to the header of the window class to which you want to apply the layout manager. 2. During the windows initialization stage, initialize the layout. 3. Add the relevant layout constraints. 4. Create the window listener and bridge between the parent window and the layout framework.

Advanced Docking Windows


Built on top of the Objective Toolkit Layout Manager, the Advanced Docking Window (ADW) architecture provides a powerful and flexible mechanism for docking any layout node, such as any CWnd or device-context-rendered image (like a bitmap) to any other layout node that supports the proper docking interfaces. Although the architecture is intentionally independent of MFCs docking control bar architecture, ADW is compatible with pre-existing control bar-based docking applications and works with control bars.

Introduction to a new architecture


Below are some of the most-requested features of the ADW architecture: Docking inside an MDI child frame, dialog, or any other non-main frame container. Docking between two different parent windows, such as an MDI child and main frame. Fixed-sized docking windows. Real-time Microsoft Office-style docking, featuring instant docking instead of prediction rectangles, and so forth. Indefinite nesting of docking windowsin other words, a docking window that contains docking windows. Alternate docking layout logic that negotiates left/right first, top/bottom second, and more. Simplified docking API and implementation procedure. Lightweight implementation that does not depend upon existing, fat, frame window classes.

54

www.roguewave.com

WHITE PAPER

The ADW architecture is essentially a marriage between the highly extensible Layout Manager, which provides container independence and complex layout logic, and the OT drag-and-drop framework. The Layout Manager can be used transparently inside any existing container, such as CWnd, CView, CDialog, and more. It can also be linked to any arbitrary layout element, such as a CWnd control or a non-windowed entity like a bitmap or device context (DC) image. For these reasons, the Layout Manager is an ideal infrastructure for providing a generic docking mechanism.
Why this architecture?

Because the Docking Window extensions are built on top of MFCs existing docking control bar architecture, the number of possible architectural changes to add new features is limited. Instead of implementing elaborate workarounds and extensive code bridges, the cleanest solution is to extend our existing layout management architecture. This strategy circumvents the design constraints imposed by the wide feature set referred to previously in this white paper. The gains in flexibility and extensibility make this migration worthwhile and do not cost Objective Toolkit users any pre-existing functionality. One of the benefits of the ADW architecture is that you can use it seamlessly with existing control bar-based docking windows. A fundamental design requirement of this architecture is complete cooperation with existing control bar-based applications. The ADW architecture shrinks the client area to accommodate its docking infrastructure the same way an OLE object shrinks a frame windows client to accommodate its own tool bars. This allows any existing dockable control bars, including MFCs tool bars and status bar, and the Stingray customizable tool bars/menu bars and Docking Views, to operate with no adverse interaction with the ADW docking infrastructure. In fact, this arrangement leads to a powerful banding-style user interface that you can use to group one set of bars, such as your tool bars, logically outside another, such as ADW dockable nodes in an arrangement similar to that of Microsoft Visual J++ 6.0. In addition, because any CWnd can be wrapped in a dockable ADW node, you can migrate an existing CControlBar to the advanced architecture. The ADW architecture provides some of the advanced docking features that are difficult or impossible to create with the existing MFC dockable control bar architecture. We recognize the significance of the existing Objective Toolkit Docking Window code base and have no intention of abandoning users of this code. Development resources are devoted to improving this component of Objective Toolkit, including customizable tool bars/menu bars and Docking Views, with a strong emphasis on smooth interoperability. Docking inside an MDI child frame One of the strengths of the ADW architecture is that the core docking logic is not tied to a specific parent window. This allows the docking mechanism to be plugged transparently into any container window, including frames, dialogs, and generic CWnds with no modification of the existing architecture.

55

www.roguewave.com

WHITE PAPER

However, Objective Toolkit includes only an external interface for hooking into frame window docking. In subsequent releases, we will add further external interfaces to support seamless dialog and CWnd docking. Fortunately, the frame window interface is still powerful and flexible. For example, you can apply this docking logic to any CFrameWnd-derived object, including CMDIFrameWnd, CMDIChildWnd, SECFrameWnd, SECMDIFrameWnd, SECWorkbook, and more. Note that the ADW architecture does not require the usage of the Stingray SEC docking frame classes (SECFrameWnd, SECMDIFrameWnd) from Objective Toolkit, which is an important distinction if you want a lighter footprint. In addition, note that you can apply the docking logic to an MDI child frame window. Floating MultiDock mode Another addition to the architecture is the floating frame MultiDock capability. This feature allows you to dock more than one dockable node inside the same floating window and then re-dock that entire floating window as one entity. Real-time drag mode Real-time Microsoft Office-style drag-and-drop mode is also available. This feature allows the contents of a docking operation to update instantly in response to mouse movement before the mouse button is released. This is similar to how the Microsoft Office-style tool bars update instantly in response to a drag and drop. Alternate border layout logic By default, the frame docking feature is configured so that the top and bottom borders receive precedence over the left and right borders. For example, the top and bottom borders always occupy the entire available client width, whereas the left and right borders shrink to accommodate the height between the top and bottom borders. This mode is configurable so that the left and right borders can receive priority over the top and bottom.

56

www.roguewave.com

WHITE PAPER

Figure 36 Advanced Docking Windows top/bottom, left/right layout logic

Figure 37 Advanced Docking Windows left/right, top/bottom layout logic

Advanced docking configurations You can use the insertion constraint object SECDockInsertionConstraints in conjunction with SECFram
eDockingFeature::DockNode() to achieve more advanced docking configurations with relative ease.

57

www.roguewave.com

WHITE PAPER

One of the primary advantages of this mechanism is that it allows easy reuse of similar constraints across multiple insertions. In addition, the relative insertion constraints are automatically updated to reflect the last insertion at each docking call. ADW splitter styles The ADW architecture allows you to reconfigure the look and feel of each splitter in your application, at run time, via the SECSplitterBase::SetDrawingStyleAll() static member function. Below are two examples of the available splitter styles.

Figure 38 Advanced Docking Windows Flat style splitters

58

www.roguewave.com

WHITE PAPER

Figure 39 Advanced Docking Windows border-style splitters

ActiveScript hosting engine


Objective Toolkit includes an MFC-compatible ActiveScript engine that gives MFC applications complete access to Microsofts ActiveScript technology and the ability to host scripts. With Microsofts ActiveX scripting technology, which is part of what is called the Internet Client SDK, you can host VBScript or any other compliant scripting language in your application. Internet Explorer, since version 4.0 has shipped with DLLs that implement a VBScript and JScript scripting engine. Through the implementation of several required COM interfaces, your C++ code can expose automation objects that can be controlled by a VBScript script like Internet Explorer. Objective Toolkit includes MFC extension classes that provide a default implementation of these COM interfaces and wrap these interfaces as an MFC extension to make it easier to incorporate scripting into your own MFC-based applications. The result is that engineers can now add VBScript and JScript scripting to their applications in minutes instead of days. Objective Toolkits ActiveScript framework currently supports two independent scripting languages: JavaScript and VBScript. Below is a brief overview of each these languages.

59

www.roguewave.com

WHITE PAPER

JavaScript
Java Script is a compact, cross-platform, object-oriented scripting language, originally developed by Netscape. A JavaScript-enabled browser, such as Internet Explorer or FireFox, interprets JavaScript statements embedded in an HTML page. This enables you to create server-based applications similar to Common Gateway Interface (CGI) programs. The JavaScript language resembles Java and supports most of its expression and basic control-flow constructs. However, there are fundamental differences. JavaScript lacks Java static typing and strong type checking and supports a smaller number of data types.

VBScript
VBScript is a scripting language that is upwardly compatible with Visual Basic for Applications (VBA), which currently ships with Microsoft Office and Visual Basic. Internet Explorer 4.0 ships with a COM server that implements a VBScript engine. Unlike VBA, it can be leveraged into your existing applications free of licensing or royalty charges. Aside from language syntax and semantics, one of the key differences between VBScript and JScript is that VBScript has a complete server-side role, whereas JScript does not. For example, VBScript can be integrated with the ISAPI component of Microsofts Internet Information Server (IIS) to run a variety of back-end applications.

Hosting an ActiveScript
Before making your application scriptable, you need to determine the applications object model. The object model is the specification of the objects in your application that are available to the scripting engine through OLE automation. Internet Explorer, for example, exposes objects that are appropriate for HTML authoring, such as the document, form, window, and browser. The objects you choose to expose for your application should be specific to your problem domain. After you have determined the object model for your application, you are in the implementation phase. To host a script, you need to implement the necessary ActiveX scripting COM interfaces, such as IActiveScriptSite and IActiveScriptSiteWindow. By implementing these interfaces, you expose the properties and methods for each object in your object model and enable manipulation of these objects from VBScript or JavaScript, or both. Objective Toolkits SECAScriptHost class provides a default encapsulation and implementation of these two interfaces so you only need to instantiate an SECAScriptHost to accomplish the aforementioned steps.
ActiveScript classes

There are many classes in the ActiveScript framework that work together to simplify the addition of scripting capabilities to your applications. These classes are described in detail below.

60

www.roguewave.com

WHITE PAPER

SECAAppObj SECAAppObj defines an application object that can be loaded from an ActiveScript script. An application object and a form object (SECAFormObj) work together to create new forms or load existing forms. An application object has the member functions that implement form creation and loading. The form object can return the application object that created it. Via the application object, you can create another form if required. The SECAAppObj supports OLE automation and exposes the commands OpenForm, NewForm, and
FormByName. You can call these commands from your scripts by calling the OpenForm(), NewForm(),

and FormByName() member functions of the SECAAppObj class. SECAAppObj derives from CCmdTarget and implements a dispatch map. SECAFormObj SECAFormObj is an ActiveX control that implements a scriptable form object to link your script to your application. SECAFormObj supports OLE automation and exposes commands for manipulating forms such as Show, Hide, Minimize, GetApp and more. The GetApp command returns an application object (SECAAppObj) that you can use to create additional forms. In addition, the form defines events that it sends to its container such as OnLoad() and OnUnload(). SECAScriptHost The script host implemented by SECAScriptHost is a COM object that implements the IActiveScriptSite, and IActiveScriptSiteWindow interfaces. Microsoft defines the IActiveScriptSite, and IActiveScriptSiteWindow interfaces as part of their ActiveScript technology. A script host can create and destroy either the VBScript or JScript script engine, create a new top-level OLE automation object as part of the script, set a reference to the window hosting the script, and parse and execute a script. An application that requires scripting must instantiate a script host and use this pointer to create the scripting engine and execute a script. SECAScriptOccManager SECAScriptOccManager implements an OLE control container for use with ActiveScript. It creates a script control site and a script control container. You must instantiate this class in your applications
InitInstance() member to enable support for containment of ActiveScript controls and hosting

COM objects. IActiveScriptErrorHandler IActiveScriptErrorHandler is the basic interface for receiving and handling Active Scripting runtime error notifications. Your class that hosts scripts needs to derive from IActiveScriptErrorHandler and override its
HandleError member.

61

www.roguewave.com

WHITE PAPER

The Objective Toolkit Users Guide has detailed instructions on using and leveraging the ActiveScript Framework. The ScriptMDI sample includes a dialog that demonstrates the canonical form of an ActiveScript host. Refer to the CDlgScript class in the sample for an example of the minimalist ActiveScript host. An MDI sample, scriptMDI, is also provided if you want to add scripting to an MDI application.

The ActiveForm scripting and editing framework


The Objective Toolkit forms engine works in concert with the ActiveScript Hosting Engine to provide a completely scriptable user interface. The ActiveForm Editing Engine provides a Visual Basic-like editing and run-time environment which you can embed in your own applications. The forms engine gives the user the ability to dynamically edit and interactively script MFC graphical user interfaces using a familiar RAD user interface. To add editable forms to an application, modify the parameters to the document template instantiated in the applications InitInstance member. The ActiveForm framework works with the ActiveScript framework. In fact, the ActiveForm framework needs the ActiveScript Framework in place to operate correctly.
ActiveForm classes

The classes that implement the ActiveForm framework are: SECScriptHostDoc, SECScriptHostView, SECAFloatDocTemplate, and SECADlgFrame. SECScriptHostDoc SECScriptHostDoc is an ActiveForm document that derives from COleDocument and IActiveScriptErrorHandler (through multiple inheritance) and manages the process and state of scripting and editing the form. For example, the SECScriptHostDoc implements the ability to toggle between edit and run mode, create and delete script items, handle ActiveScript error notifications and creation, and destroy and serialize forms and their contents. You can pass the SECScriptHostDoc directly into your doctemplate instantiation or you can derive your own document class from it and then customize its behavior.

SECScriptHostView The SECScriptHostView, a CFormView-derived class, is a specialized form view that implements drag and drop of OLE controls onto its surface. It also implements a user interface for sizing, positioning, and setting the properties of contained ActiveX controls and manages the tool bars that accompany it. You can pass the SECScriptHostView directly into your doc-template instantiation or you can derive your own view class from it and customize its behavior. SECAFloatDocTemplate SECAFloatDocTemplate facilitates the creation of new forms for scripts that want to provide support for dynamic form creation. Use this class in conjunction with SECScriptHostDoc, SCScriptHostView, and SECADlgFrame to provide suitable support for scriptable frame creation. When the script executes a NewForm

62

www.roguewave.com

WHITE PAPER

or OpenForm function, SECAAppObj responds by instructing the SECAFloatDocTemplate to create a new form. The forms created by the SECAFloatDocTemplate object typically are SECADlgFrame-derived classes. SECADlgFrame SECADlgFrame implements a simple SDI top-level frame utilized by ActiveScript scripts during dynamic form creation. The SECAFloatDocTemplate object instantiates a frame of this type whenever the script creates a new form via the commands OpenForm, NewForm, and FormByName. The Objective Toolkit Users Guide describes how to incorporate the ActiveForm functionality into your applications. The ScriptMDI and ScriptSDI samples illustrate how to use the ActiveForm framework in MDI- and SDI-based applications. The following figure shows the key features of the Objective Toolkit ActiveScript/ActiveForm support:

Figure 40 The key features of ActiveScript/ActiveForms

63

www.roguewave.com

WHITE PAPER

The Model-View-Controller (MVC) Framework


Some of the most complex challenges facing MFC application engineers are due to the shortcomings of MFCs DVA (Document View Architecture), its limitations can overwhelm developers of large, complex applications. To overcome the limitations of DVA, Objective Toolkit supports an object-oriented framework called the Model-View-Controller (MVC) architecture. MVC lets you create highly reusable and easily extensible objects by dividing the functionality of an application into three logical categories: document or model classes, view classes, and command handling or controller classes. Although this architecture requires you to reconsider the use of two traditional class types, documents and views, its implementation is simple and elegant. We think youll discover that the MVC framework makes it easier to create large-scale applications. Moreover, because our implementation of MVC coexists peacefully with MFC and DVA, youll still be able to draw from the rich user interface features provided by MFC and the Objective Toolkit classes.

Introduction to MVC
MVC is an object-oriented framework that provides a clear and concise definition for how to construct reusable and extensible graphical user interface parts. Despite its lack of widespread use, the model-viewcontroller architecture is not a new concept. It was inventedalong with the graphical user interface and the concept of object-oriented programmingabout thirty years ago by researchers at the Xerox Palo Alto Research Center (PARC). The culmination of that research was the Smalltalk language and its multi-windowed, highly interactive Smalltalk-80 interface. Even by todays standards, the invention of Smalltalk and MVC are revolutionary. To some degree, nearly every user interface developed in the last three decades has been an adaptation of the work done at Xerox PARC. In fact, MVC has been partially reproduced in many other development environments. DVA itself is an adaptation of the concepts introduced by the MVC paradigm. However, it can be argued that the key purpose of MVCreusewas lost in the adaptation. Although DVA is based on the sound design principle that data and presentation should be kept separate, its implementation of this ideal compromises reuse, modularity and scalability. This section shows how you can resolve many of the problems caused by the drawbacks and limitations of DVA by applying some of the concepts of MVC to MFC. This adaptation requires you to use DVA in a new wayone that adheres to the principles of MVC.

Considering an alternative to DVA


In the past fifteen years, MFC and the DVA have been used in the development of thousands of Windows applications. The advantage of DVA is that you can adapt it to solve most of the problems that arise in medium-sized Windows applications without much difficulty. Its relative simplicity and generality have made it an ideal foundation for many Windows applications.

64

www.roguewave.com

WHITE PAPER

However, do not assume that DVA is the right architecture for you, especially if you are developing large, complex applications. Despite a proven track record, DVA lags behind in some areas, which we will describe in the next section. The net effect is a reduced capacity for reuse and an inherent lack of scalability. Specifically, although DVA can support an application containing two or three CDocument- or CView-derived classes of lesser complexity, it strains under the weight of numerous documents and views. When DVA was first introduced, C was the programming language of choice for Windows application engineers. In fact, many of us had never even used C++. Consequently, one of Microsofts primary goals when developing the MFC implementation of DVA was ease of comprehension, even at the expense of object-orientation and scalability. At that time, introducing a more complex (albeit more object-oriented and reuse-friendly) architecture would have made the paradigm shift in Windows development from C to C++ a bit too difficult for most engineers. Accordingly, DVA is a relatively thin layer of C++ code on top of the procedural-based Windows event model. Although DVA is ideal for developing applications like the Visual C++ Scribble sample, it is inadequate for developing large, highly object-oriented applications. This is why many experienced engineers find DVAs scope to be limited. Because the development framework you use affects the organization and structure of your application, your framework dictates ease of application development and maintenance. No segment of code should be trusted with such influence without careful scrutiny. The larger your project, the greater the likelihood that DVA is not the solution for you.

Problems with DVA


If youve done any development with MFC, you already know that the Visual C++ Scribble tutorial is widely accepted as the canonical form of a Windows graphical user interface application using MFC and DVA. What you might not know, however, is that the architecture of the Scribble tutorial is far from exemplary. In fact, at least one Microsoft technical publication has described Scribble as the perfect example of how not to structure your graphical user interface code. Although DVA suits the Scribble sample, it does not suit an application a hundred times bigger and more complex than Scribble. Unfortunately, DVA has been applied to applications of this size because Scribble is seen as Microsofts model for correct MFC usage. An engineer who creates an application adhering to the Scribble model will inevitably reach a point where DVA can no longer support the project. The following sections describe the problems an engineer encounters when attempting to create a large application supported by DVA.
DVAs architecture is vague

It could be argued that DVA is not responsible for the problems with the Scribble sample. It could be argued that the problems are due to a violation of the principle of encapsulation. However, there are problems inherent in DVA that tend to encourage this violation. First of all, it is not clearly defined where in DVA the application data and visual representation should be separated. As a result, it is unclear

65

www.roguewave.com

WHITE PAPER

how DVA maps onto an applications problem domain. For some applications, such as a simple word processor, the answer seems obvious: an MFC document represents a user document. However, this is not true for applications like interface builders or graphical tools. The data for such applications might include colors, fonts, pens, and window bounds, all of which need to be saved. However, it seems inappropriate to include this information in a CDocument-derived class because it describes a visual representation of the underlying data. It is unclear how you would separate the document and view classes in this scenario. Because DVA is vague and contains few usage restrictions, its easy to make a bad decision, as was done in the Scribble sample.
DVAs approach is monolithic

DVA takes a monolithic approach to application decomposition. Because documents and views cannot easily be nested, a DVA application typically contains large, highly functional document classes paired with equally large, highly functional view classes. Of course, it is possible to place one CView-derived class inside another, but that construct is not specifically supported by DVA. Instead, you must perform all message forwarding yourself. Moreover, although its certainly not a requirement that CDocumentderived classes be large and bulky, they often become that way because engineers add representation information to the document class so that it can be serialized along with the data. Consequently, DVA is not suitable for decomposing an application into small building-block classes that can be composed into larger ones. With DVA, the result is large, cumbersome classes that complicate the model and make it difficult to divide an application along functional boundaries. Due to the lack of modularity and numerous interdependencies inherent in DVA, development teams usually find it difficult to subdivide a problem and work in parallel. In fact, the lack of modularity usually requires every team member to know the entire application model. These types of dependencies translate into reduced team productivity and reduced application stability.
CViews inhibit reuse

CView is one of the most significant and fundamental building blocks of any MFC-based application. In fact, MFC programmers often place a majority of their code in CView-derived classes, particularly in graphics-intensive applications. The role of CView leads many engineers working with MFC to assume that Microsoft has constructed this class with due diligence, taking care to ensure that the class that houses 30-70% of your code is reusable. This is not the case; CViews are not reusable. Unfortunately, many engineers arrive at this realization late in the development cycle and pay dearly. A CView isnt reusable for a number of reasons. Most importantly, a CView depends on an applicationspecific document type. This dependency renders it unusable in applications that have a different document type. To illustrate the point, assume you are developing a set of CView-derived classes that are to be reused throughout your company. Further, assume youve decided that reusable views must adhere

66

www.roguewave.com

WHITE PAPER

to DVA. This means that for each view you declare, you must also create an associated document type that the view understands and expects whenever and wherever it is used. The implication is that wherever you use the reusable view, you must use the document. This causes problems when you want to use the view in an existing application that has an incompatible document class. There are a number of imperfect solutions available. First, you can change the base class of the reusing applications document from CDocument to the document type the reusable view expects. This approach eventually forces you to use multiple inheritance from your document class, making your code difficult to read and maintain. MFC discourages using multiple inheritance from two CCmdTarget-derived classes due to the complications that can arise. For that reason, this solution is fragile and ill advised. Another solution is for every engineer across a company to use the same common document class. You then can exchange all CViews among projects. Unfortunately, it is difficult to choose which document class to use. Even if you do establish a common document class, maintenance of the selected document often becomes difficult or impossible as the documents become more complex. In addition, a document with an interface wide enough to serve all possible view types is usually an undesirable solution anyway. You may also be tempted to make all data accesses go through virtual functions rather than directly accessing the members of a document. When you access data through virtual functions, you remove the reusable views dependency on any document. However, you cannot access data through virtual functions and adhere to DVA, so its not a viable solution. In addition, accessing data through virtual functions, rather than directly from the document, is not prescribed in the Scribble sample set. Typically, an engineer retrofits the virtual data access methods after realizing that CViews are not reusable. The best solution, short of creating an alternative to DVA, is to limit the functionality in CView. Ideally, CView should only contain an OnUpdate() handler. All of the drawing logic should be contained within a completely reusable CWnd. In this context, the purpose of the CView is to adapt the reusable CWnd for use within a particular application that defines a document and updates hints. This solution concedes that CViews are not reusable, so no potentially reusable code is placed in a CView. In this solution, the CView acts as an adapter, or a wrapper, that translates the weakly-typed messaging protocol, defined by the documents update hint, into calls to a strongly-typed C++ interface, defined by the CWnd child of the CView. One problem with this approach is that you miss some of the chief CView features, such as print and print preview support.
CView/CDialog are incompatible

One of the limitations of MFC is the incompatibilities between CView and CDialog. For example, MFC bans the placement of a CView-derived class inside a dialog. If you want to create a reusable GUI

67

www.roguewave.com

WHITE PAPER

component that can be used inside a frame window or a dialog, you must confine your design to CWndderivation, which requires you to avoid DVA altogether. However, you can use templates as a workaround for this problem.
OnUpdate creates problems

Ironically, one of the most popular functions of DVA, the UpdateAllViews() and OnUpdate() notification mechanism, is also one of the most problematic. It is important to design your notification system carefully. Otherwise, your OnUpdate() handlers can easily grow into pages of switch statements and weakly-typed hints that are difficult to read and maintain. In addition, because this notification mechanism is a weakly-typed interface, coding errors are not caught at compile time. When engineers use Scribble as a model, they tend to use notifications at too low a level. In other words, update hints tend to be numerous and detail-oriented, which leads to pages of weakly-typed checks in the OnUpdate() handler. DVA does not describe the best use of the notification mechanism. It only passes you an opaque pointer to a hint. This lack of specificity often leads engineers to embed the API to their component inside the notification hints to the OnUpdate() handler. For example, suppose you were developing a Windows Explorer-like application for the display of hierarchy data. In this type of tool, youd include a splitter window that contains a tree view on the left and a list view on the right. The typical approach to this type of user interface is to maintain the hierarchy data in a document that is observed by both tree and list views. The synchronization of the two panes is accomplished by passing update hints via
CView::OnUpdate(). When DVA and its OnUpdate() mechanism is used at too fine a granularity, the

end result is an interface to a logical control or widget that is embedded in the hints. For example, you should avoid code that looks like this:
UpdateAllViews(this, HINT_NODE_EXPANDED, pNode);

If a client wants to expand a node, it must understand this message-passing protocol.


DVAs presentation tied to control

Generally speaking, a CView has two responsibilities. First, it must present the data contained in the document to the user. Second, it must interpret and react to user input. Its role imposes several limitations. Both presentation and control are packaged in one class, which means that if you reuse a views presentation data, you also need to reuse the views reaction to user input.

Overview of the MVC architecture


The MVC paradigm allows you to subdivide an application, or even just a piece of an applications interface, into three parts: the model, the view, and the controller. MVC was originally developed to map

68

www.roguewave.com

WHITE PAPER

the traditional input, processing, and output roles into the GUI realm: Input Controller --> Processing --> Model --> Output --> View

The user input, the modeling of the external world, and the visual feedback to the user are separated and handled by model, viewport, and controller objects. The controller interprets mouse and keyboard inputs from the user and maps these user actions into commands that are sent to the model or viewport, or both, to effect the appropriate change. The model manages one or more data elements, responds to queries about its state, and responds to instructions to change state. The viewport manages a rectangular area of the display and is responsible for presenting data to the user through a combination of graphics and text. As previously mentioned, DVA is derived from MVC. Consequently, many of the concepts set forth in MVC are similar to concepts in DVA. MVC adheres to many of the same design principles. For example, you separate data from presentation in MVC. However, MVC gives a concise definition of how to accomplish this separation. In addition, MVC provides a more thorough and full-featured architecture than DVA. Because it is well defined, it is obvious how to add common pieces to the architecture, such as undo/redo support, scripting mechanisms, record and playback, and more.
MvcModel

MvcModel has some of the same responsibilities as CDocument. For example, both classes manage information and notify observers when that information changes. However, there is an important distinction. In MFC, a CDocument often becomes a storehouse for unrelated information. The edict is: if it must be saved, put it inside a CDocument. When this edict is followed, the documents design becomes a function of what needs to be serialized rather than what needs to be modeled. An MVC model is a more concise abstraction than a DVA document because it contains only data and functionality that are related by a common purpose. If you need to model two groups of unrelated data and functionality, you need to create two separate models. Another key difference between a model and a CDocument is that a model encapsulates more than just data and functions that operate on it. A model is meant to serve as a computational approximation or abstraction of some real-world process or system. It not only captures the state of a process or system, but how the system works. This makes it easy to use real-world modeling techniques to define your models. For example, you could define a model that bridges your computational back-end with your GUI frontend. In this scenario, the model wraps and abstracts the functionality of a computation engine or hardware system while acting as a liaison that requests the real services of the system it models.

69

www.roguewave.com

WHITE PAPER

MvcViewport

MvcViewport is similar to the MFC CView class. We chose to call the class a viewport instead of an MvcView to avoid an overlap in terminology and to make the distinctions between a view and a viewport obvious. The MvcViewport class is responsible for mapping graphics onto a device. A viewport typically has a one-to-one correspondence with a display surface and knows how to render to it. A viewport attaches to a model and renders its contents to the display surface. In addition, when the model changes, the viewport automatically redraws the affected part of the image to reflect those changes. As with DVA, there can be multiple viewports onto the same model and each of these viewports can render the contents of the model to a different display surface. The biggest difference between CView and MvcViewport is that a viewport is not derived from CWnd. The designers of MFC chose to implement the concept of a view through derivation, whereas MVC implements the same concept through aggregation. This is a common theme throughout MFC and a common distinction relative to MVC. In many cases, where MFC and DVA use derivation, MVC uses aggregation. In this case, a window aggregates one or more viewport objects and then delegates to them when a paint event occurs. Because a viewport avoids the CWnd derivation and does not create a physical window, a viewport is significantly lighter than a CView. A viewport simply takes a pointer to a device context and draws to whatever device context it is passed. In addition, because a viewport can be aggregated into any window, such as CFrameWnd, CWnd, or CView, you can display a viewport inside a CWnd, a CView, or a dialog box without modification. In addition, support for printing and print preview is preserved. Another difference between MvcViewport and CView is that MvcViewport should not contain menu handlers or command handlers. Instead, delegate this responsibility to the views controller object. Additionally, an MvcViewport class can easily be nested but a CView cannot. For example, an MvcViewport can be a composite viewport that contains several subviews that can also contain a dditional subviews.
MvcController

A controller is the means by which the user interacts with the application. A controller accepts input from the user and instructs the model and viewport to perform actions based on that input. In effect, the controller is responsible for mapping user action to application response. For example, if the user clicks the mouse button or chooses a menu item, the controller determines how the application should respond. The MvcController class has no equivalent in MFC. In MFC, the CView is both the view and controller. It is responsible for presentation and control. In small applications, it can be simpler to handle user input in the view instead of the controller. However, in

70

www.roguewave.com

WHITE PAPER

large applications, putting user input in the controller affords you greater modularity, reuse and control exchangeability. Unlike DVA, MVC gives you a choice. You can preserve the separation or collapse presentation and control into one class. If you want a separate controller, derive your viewport from MvcViewport and your controller from MvcController. If you want presentation and control in one class, derive your viewport from both MvcViewport and MvcController.
Connecting the model, viewport, and controller

The model, viewport, and controller are entwined and in constant contact. Consequently, they must reference each other. The figure below illustrates the basic Model-View-Controller relationship:

Figure 41 Model-View-Controller relationship

The figure above shows the basic lines of communication among the model, viewport, and controller. In this figure, the model points to the viewport, which allows it to send the viewport weakly-typed notifications of change. Remember that the models viewport pointer is only a base class pointer; the model should know nothing about the kind of viewports that observe it. By contrast, the viewport knows exactly what kind of model it observes. The viewport also has a strongly-typed pointer to the model so that it can call any of the models functions. In addition, the viewport also has a pointer to the controller, but it should not call functions in the controller aside from those defined in the base class. You should keep dependencies between the viewport and controller minimal if you want to swap out one controller for another. The controller has pointers to both the model and the viewport and knows the type of both. Because the controller defines the behavior of the triad, it must know the type of both the model and the viewport to translate user input into application response.
Additional reading on MVC

Before we introduce more information on MVC, wed like to recommend some additional references on the subject. MVC is regarded as a classic example of a design pattern. It has recently experienced

71

www.roguewave.com

WHITE PAPER

a resurgence in popularity. The classic text, Design Patterns: Elements of Reusable Object-Oriented Software by Erich Gamma et al (ISBN 0-201-63361-2), describes MVC and the Command design pattern. However, its coverage of MVC is minimal. The more recent text, A System of Patterns: Pattern-Oriented Software Architecture by Frank Buschmann et al (ISBN 0 471 95869 7), provides an in-depth description of MVC and the Command Processor design pattern within the context of C++.

The MVC class hierarchy


MVC embodies a rich framework of base classes, the most derived of which are the model, viewport, and controller classes. It is important to gain a complete understanding of the entire MVC class hierarchy if you expect to benefit fully from MVC. The complete class hierarchy is shown below:

The following sections delve more deeply into the MVC framework and the individual classes that comprise it.
MvcVisualComponent

A visual component is an object that can draw itself to any given device context. In essence, a visual component is a rectangle with a draw function. The MvcVisualComponent base class defines an interface from which all other displayable objects in MVC ultimately derive, which allows you to treat a collection of visual components consistently. The MvcVisualComponent class is intentionally light to accommodate applications that may need to instantiate more than one object. A visual component maintains its size and position relative to its containers origin. Because its origin is an offset from its containers origin, if the container moves, all sub-components move with it. A visual component doesnt address units of measure of the size and position values. That is the containers

72

www.roguewave.com

WHITE PAPER

responsibility. If the container measures its client area in inches, the bounding rectangle of the visual component is in inches. Another MvcVisualComponent or derived class contains an MvcVisualComponent. Any visual component derivative can be nested to any depth. However, ultimately, there must be a viewport type of container at the root of this hierarchy of visual components to map the visual components onto a real device. In other words, visual components cannot render themselves by themselves. They must be told which device context to render to. Only a viewport can know this.
MvcVisualPart

A visual part is a type of visual component that keeps a back pointer to its container. The only other thing it adds is a few member functions to support invalidation. We didnt collapse this class into MvcVisualComponent because we wanted to keep MvcVisualComponent as small as possible so you could instantiate thousands of them in an application. It this case, it isnt necessary or desirable for each visual component to know its container.
MvcLogicalPart

An MvcLogicalPart is a visual part that supports a logical coordinate system. If you have used MFCs CScrollView and the SetWindowExt()/SetViewportExt() members of the CDC, you are already familiar with a logical coordinate system. MvcLogicalPart is similar. The logical part establishes a unit of measure that it uses to measure and draw to its client area. That unit of measure can be pixels, inches, millimeters, or something application-specific. When the logical part is instructed to draw itself, it first prepares the given DC so that its units of measure are in effect for its subsequent drawing. MvcLogicalPart is the largest body of code in MVC. Accordingly, it provides you with substantial functionality. The MvcLogicalPart adds zooming and panning, mapping mode support, a virtual size, and more. There is another important characteristic of MvcLogicalPart: it can be nested. Like any visual component, a logical part can be a child of another logical part. This means a child can establish an entirely different mapping mode than its parent. For example, the parent could measure its client area in inches, although its child measures its client area in twips.
MvcViewport

An MvcViewport is a type of logical part that observes a model and delegates user input to an MvcController for handling. A viewport is responsible for displaying graphics on the screen and reflecting updates in model state. To perform its responsibilities, it generally requests information required

73

www.roguewave.com

WHITE PAPER

for rendering from the model and responds to notifications of change from the model. A viewport is also responsible for routing messages to a suitable handler. By default, it routes all messages to its controller for handling; however, it can be overridden. Consider a viewport that contains several child viewports. In this scenario, the parent viewport might route the messages to one or more children first. The parent viewport would send the message to its own controller only after giving its children a chance to obtain the message. Another important characteristic of the viewport is that it can retain a pointer to the CWnd that contains it. Knowing the containing CWnd is critical to the viewport; it gives the viewport a special significance. For example, a viewport is the only visual component derivative than can retrieve a real window pointer, instantiate a real CDC pointer for rendering, map logically to device coordinates, or perform a real invalidation of a windows client area. We delayed the introduction of a real window that binds to the viewport because you might want to put your visual component hierarchy in a model and render it through multiple viewports. If you were to organize your visual component hierarchy in this way, a visual component, visual part, or logical part might appear in multiple windows, which means that it cannot be bound to a particular window.
MVCWrapper_T

The MVCWrapper_T class implements the Decorator design pattern as described in the book, Design Patterns. A wrapper is a container with a single component. The wrapper provides certain services to its component, such as decorating the component with a border or adding scroll bars to the sides of the component. Wrappers are classes that can be plugged into any window in place of the component it wraps without affecting the window. The ability to add wrappers dynamically without affecting client code is accomplished by endowing the wrapper with the same interface as its component. The MVCWrapper_T class is a template, so it allows you to specify which component to inherit and emulate. Some wrappers are visual and others are not. For example, a wrapper can be used solely to offset the origin of its component. One of the most interesting properties of wrappers is that they can be nested to any depth. For example, you can create a border wrapper that wraps a scroll bar wrapper that wraps another border wrapper that finally wraps the actual component. The Stingray MVC implementation currently has three wrapper classes: MvcBorderWrapper_T, MvcScrollWrapper_T, and MvcBufferedWrapper_T. MvcBorderWrapper_T wraps a border and MvcScrollWrapper_T wraps a scroll bar wrapper. MvcBufferedWrapper_T provides off-screen rendering for the component it wraps. For small memory overhead, off-screen rendering reduces or eliminates flicker during redraw. This is convenient because it provides buffered rendering to a component without requiring any change to the component whatsoever, making buffered rendering an afterthought.

74

www.roguewave.com

WHITE PAPER

IComposite_T

The composite interface includes members for adding, deleting, retrieving, and locating children. Mix this interface into anything you need to make a composite. For example, if you need to create a composite visual component, you can do so by mixing this interface into your MvcVisualComponent-derived class.
IMvcMsgHandler

IMvcMsgHandler is a small interface that can be mixed into any class that requires the capacity to route and handle messages. By default, it is implemented in MvcViewport and MvcController.
The IMvcSubject, IMvcObserver and IMvcMessage Interfaces

The most fundamental of all MVC classes are the subject and observer interfaces. These two interfaces constitute the dependency mechanism that is central to MVC. The 1995 book, Design Patterns: Elements of Reusable Object-Oriented Software discusses what the author calls the Subject/Observer design pattern. The idiom the author describes is similar to the roles of document and view in MFC, where the document is a subject and the view is an observer. However, the subject/observer design pattern is more general. In the subject/observer relationship, a subject encapsulates related data and functionality that an observer monitors. If the state of the subject changes, the observer must know about it. To accomplish this, the subject defines a notification dictionary that is the set of all notifications of change a subject can broadcast. A notification is any class that mixes in and implements the IMvcMessage interface. It is the responsibility of the subject to define and export a notification dictionary and to broadcast individual notifications of change to its list of observers. It is the responsibility of the observer to attach itself to a subject and understand and react to the notifications it receives. As you see, the interfaces act like document and view in some regards. However, some differences do exist. First, the subject and observer interfaces can be mixed into any class via multiple inheritance. Conceptually, IMvcSubject and IMvcObserver are interfaces, not objects. This means that any existing class, including CWnd-derivatives, can become a subject or an observer, or both, by simply supporting the appropriate interface(s). To reiterate, an object can mix in both subject and observer interfaces to yield an object that observes one object and serves as subject to another. This is analogous to a CDocument that is dependent upon other, nested documents. This concept has important implications. It means, for example, that you could have nested models or even a directed cyclic graph of models that are interdependent. This yields the important

75

www.roguewave.com

WHITE PAPER

composition quality that DVA lacks. With respect to subjects or models, you can compose larger, more intelligent models out of smaller, reusable ones. This yields a composite model that can be made into an even larger model in future applications.
MvcModel

Although rich in concept, the MvcModel class is sparse on code. The MvcModel class mixes in the IMvcSubject interface and implements it. MvcModels main purpose is to serve as a base class for your domain-specific models.
The MvcPresentationModel_T class

Generally speaking, there are two types of models: System models Presentation models A system model is an MvcModel-derived class that models some non-graphical, real-world system or process. A presentation model models a graphical presentation. System and presentation models can be used exclusively or in combination. Used in combination, a presentation model provides the presentation for a system model by mapping the system into the graphical realm. This scenario is illustrated below:

Figure 42 A System model and Presentation model used in combination

The presentation model is a piece that is absent from both DVA and MVC. The presentation model describes where to store GUI data.

76

www.roguewave.com

WHITE PAPER

A presentation model is a templatized class, which inherits from both MvcModel and MvcVisualPart. The use of multiple inheritance here allows the presentation model to function as both a model and a visual-in effect, a visual model. Visual models are particularly useful in diagramming applications. It is intuitive to implement a diagram class as a presentation model. A diagram is a type of presentation model, which manages the graphical symbol data, font choices, pen widths, and more. Like a model, it manages data, albeit graphical data, and exports functionality. However, like a visual part, a diagram can draw itself and even be nested as a symbol inside a parent diagram. A diagram acts as both a model and a visual part. Just because a presentation model can draw itself, do not think that the viewport is devoid of functionality. Actually, the viewport is offloaded to some degree, but it still has a well-defined role. When you use a presentation model, a viewport becomes a gateway through which a presentation model can render itself. In other words, the viewport becomes a perspective on the presentation that defines what subregion of the overall presentation or diagram to display. The presentation model, in effect, is a graphics server that presents whatever rectangular portion of the graphics the viewport instructs it to paint. This rectangle is measured in logical units and corresponds to the zoom factor and scroll positions of the viewport. For a more detailed explanation of the why system and presentation models should be separated, see the section titled Solving Real Problems with MVC, beginning on page 41.
IMvcVirtualPart

This interface is complex. Earlier, in the section entitled OnUpdate creates problems on page 41, we described how difficult it is to read and maintain the large switch statements that usually reside in CView::OnUpdate(). IMvcVirtualPart solves this problem. This interface, used in combination with the presentation model, nearly eliminates the need for the switch statement because OnUpdate() typically is trying to determine which rectangle to invalidate. With IMvcVirtualPart, invalidation no longer goes through the OnUpdate() channel, which eliminates 90 to 100 percent of the cases in the
OnUpdate() switch statement.

IMvcVirtualParts functionality is a variation of the subject/observer design pattern, called the virtual part/renderer pattern. In this instance, you have one virtual part, which is rendered by one or more renderers. Like subject/observer, if the virtual part changes, the renderers need to be informed. However, instead of passing a message from a subject to observer, the virtual part passes an invalid rectangle to all its renderers. The virtual part notifies each render which rectangle in logical coordinates has been invalidated. The virtual part sends this rectangle by calling InvalidateRect(), which then broadcasts the invalidate call to all renders in the following manner:
void MyVirtualPart::InvalidateRect(const CRect& rcLog, BOOL bErase, BOOL bRepairNow)

77

www.roguewave.com

WHITE PAPER

Iterator_T<MvcVisualPart*> i(&m_setRenderers); MvcVisualPart* pRenderer; for (pRenderer = i.GetFirst(); pRenderer != NULL; pRenderer = i.GetNext()) { pRenderer->InvalidateRect(rcLog, bErase, bRepairNow); }

It is the responsibility of the renderer to determine where that logical rectangle is on its display surface and, if it is currently showing the invalid region, to perform a true windows invalidation. The presentation model implements the IMvcVirtualPart interface and the viewports serve as renderers. So, if a presentation model creates a new visual component and positions it within its virtual display surface, it invalidates the visual components bounds. All attached viewports hear the invalidation and trigger a repaint. This technique is convenient. It allows the presentation model to draw and erase within its own virtual space, using its own logical units, without needing to know how the graphics it produces get mapped onto a device.
MvcTransactionModel

A transaction model is a central component of the Undo/Redo architecture. Its primary purpose is to maintain the undo and redo stack. See the section entitled MVCs Undo/Redo architecture beginning on page 41 for more details.
MvcController

The controller makes a viewport seem to respond directly to mouse movements and keyboard activity. A controller receives input from the user and translates that into application response. The application response is in the form of function calls to the model and viewport. The MvcController class is an MVC base class that defines the basic structure and behavior of a controller. This includes the ability to acquire, maintain, and relinquish control. It is also a mechanism for mapping messages to handlers. You can reuse MFCs message map solution, but it is problematic for a number of reasons. Even though a separate controller class for message handlers sounds like a good idea, MFC is designed in such a way that this seems impossible to implement. MFC allows commands such as menu picks to be rerouted to non-windows. However, you cannot reroute windows messages such as mouse clicks. In MFC, only a CWnd can receive windows messages and only one instance of a CWnd can receive the messages for a real Windows window. Because a controller is a non-window that can handle windows messages and exist in multiple instances per window, this seems to be an unworkable solution. An

78

www.roguewave.com

WHITE PAPER

interesting aside: this problem was cited by an original MFC team member as the main reason Microsoft emulated MVC for the CDocument and CView, but stopped short of implementing a controller (MFC Professional Developers Conference, 1995). As previously mentioned, this problem appears to be unsolvable. We arrived at a number of relatively undesirable workarounds, but we never found a solution. Eventually, we discovered a unique trick that allows us to do something MFC was never meant to do: route windows messages, such as mouse clicks, to any number of potential handler classes. We call this solution the window plug-in (SECWndPlugIn). A window plug-in is a class that you can plug into a window to listen to, and potentially handle all messages that the window receives. In essence, its equivalent to a modular MFC message map. Imagine being able to take a large message map, break it up into blocks, and put each block and its associated handlers in its own classes. Then, you could dynamically and conditionally aggregate only the message map blocks you need. In addition, if you had two window types that needed to handle the same messages in the same way, such as mouse wheel support, you could put that code in one place and aggregate this block of handlers in all window types that require the feature. This is exactly what window plug-ins do. The controller class, MvcController, overcomes the aforementioned problems through its derivation from SECWndPlugIn. An MvcController serves as a listener that allows all derivatives to plug into a window and control it. A window can host any number of controllers and the controllers can be delegated to in any order you see fit. Once again, where MFC uses derivation, MVC uses aggregation. The result is greater flexibility and reusability. Another convenient characteristic of controllers is that they are seen by MFC and Visual Studio as a even though they arent. In fact, they dont incur the overhead of a Windows window handle. This allows you to create a standard MFC message map in your derived controller classes and even edit them using Class Wizard. In addition, controllers dont disturb the normal MFC message and command routing channelsthey simply extend them. Furthermore, because controllers route messages using MFCs own highly-optimized message map mechanism, there is virtually no performance degradation.
The collection classes

The collection classes, such as CCArray_T, MvcSet_T, CCStack_T, and more, are simple wrappers around MFCs collection classes. The only reason weve wrapped them is to make it convenient for you to use STL or your own internal collection classes without modifying the MVC framework. Our goal is to remain collection-class-independent without inventing a new set of collection classes and without becoming notationally inconvenient. We accomplished this goal by doing the following:

79

www.roguewave.com

WHITE PAPER

Weve wrapped the MFC collection classes using inheritance. In other words, CCArray_T derives from CArray, so you can still use the collection as if it were a CArray if you like. Weve created a very convenient iterator class called Iterator_T. Using this class, you can iterate over any collection that happens to implement the ICollection_T interface, regardless of whether the actual collection implementation is MFC, STL or otherwise. The following code shows how Iterator_T is used:
Iterator_T<MvcVisualPart*> i(&m_setParts); MvcVisualPart* pParts; for (pPart = i.GetFirst(); pPart != NULL; pPart = i.GetNext()) { // Do something }

MVCs Undo/Redo architecture


Although the Undo/Redo architecture is not part of the original MVC architecture, weve added support for undo/redo on top of the MVC framework. The Undo/Redo architecture is based on well-known design patterns and, accordingly, is a natural extension of the MVC concepts. At the core of the Undo/Redo architecture are the MvcCommand and MvcTransactionModel classes. MvcCommand is equivalent to the Command design pattern as described in the classic text Design Patterns: Elements of Reusable Object-Oriented Software by Erich Gamma et al. In addition, the MvcTransactionModel is based upon the Command Processor design pattern as described in A System of Patterns: Pattern-Oriented Software Architecture by Frank Buschmann et al. Please see these books for more information.
MvcCommand

The command class is simple. It has two primary virtual functions: Execute() and Unexecute(). As you might expect, these members must be overridden in concrete command classes that you define. Effectively, this moves the implementation of undoable operations out of member functions and into persistent records. This is necessary because there is no way to undo a function call. No record of the parameter values, or even the call itself, is maintained. This is what MvcCommand isa persistent function call, which stores all parameter values so that it can be undone later.
The transaction model

The transaction model is where the command records are stored upon their execution. The transaction model is responsible for storing the commands and undoing or redoing the most recent ones. In terms of implementation, the transaction model maintains two separate stacks: an undo stack and a redo stack. As commands are executed, they are automatically pushed onto the undo stack. If the transaction model is instructed to undo the most recent command, it pops the command off the top of the undo stack and instructs it to unexecute itself. Then, it pushes the command onto the redo stack. If a redo is requested, the opposite occurs.

80

www.roguewave.com

WHITE PAPER

The IMvcUndoRedo interface

The Undo/Redo interface can be mixed into any class for which you want to provide undo/redo support. By default, it is already supported by the MvcPresentationModel_T. The Undo/Redo interface is straightforward. It includes the Undo() and Redo() member functions in addition to a few other utility and query members.
Tying Undo/Redo into the MVC framework

So far, nothing we have said about the Undo/Redo architecture is MVC-specific. The Undo/Redo architecture ties into MVC by using an MvcCommand to mix in the IMvcMessage interface. This approach allows a command to act as both a persistent function call record and a notification of change, so a model can define a notification dictionary and a command dictionary as one and the same. After a model executes a command that it defines, it forwards the command itself as notification to its observers.

Solving real problems with MVC


Until now, we have only described how MVC differs from DVA. Now, were going to tell you how you can solve real problems with MVC. MVC is a powerful tool, but like any tool, it can be misused. In this section, we cover many of the typical questions and issues that arise when an engineer is trying to determine how to map MVC onto a particular domain.
Clarifying the role of the model and the viewport

Perhaps the most frequent and most baffling design issue is where to draw the line between model and viewport data and functionality. Consider the following example. Lets assume you are developing a schematic capture application that displays a computers circuitry. The domain data in an application like this would be the components used on the motherboard, the interconnections between pins, the timing characteristics, and more. This information and the functions for accessing it seem to be an obvious candidate for a model class. Next, we need to think about how to present this information to the user. Most likely, we want to show this information in several different ways. For example, we might want to view the information as a schematic or topology-type diagram that shows the layout of the components and their interconnections. We might also choose to view the information as a hierarchical, tree-structure display of the components. Lastly, we might want to supply a table of parts required to assemble the motherboard. So, because we want to present the same data in three ways, this application is an ideal candidate for the viewport class. We could define three separate viewport classes that present the model data in three separate ways. At this point in the design phase, the architecture becomes more ambiguous. Lets say we want to have two different viewports on the same schematic (topology diagram), but at different zoom levels. In this scenario, the circuit data is identical and even the diagramming data is identical. The only difference is

81

www.roguewave.com

WHITE PAPER

that one viewport is zoomed in and one is zoomed out. The problem we need to address is how to present the data. We need to decide: If two different viewports can present the same diagram If we should move the diagram data into the model How to address serialization If we should save the diagram data to a file All indicators seem to support putting presentation data in the model, which seems counter to good design. It overloads the model with two different classes of data and leaves the viewport with little else to do. The prior example typifies the issues engineers consider when deciding how to map MVC or DVA onto the application. In summary, the dilemma is what qualifies data as model data versus viewport data. In some applications, it is obvious how you should define model data. In a text editor, the model data is the text. However, in other instances it is not so obvious. Consider, for example, a GUI builder/forms engine. The model data in this case is the buttons, fonts, sizes, properties, and more. Another good example is Objective Views. Objective Views is a Visio-like MFC- and MVC-based framework for building diagramming applications or complex, structured graphics systems. DiagramModel, DiagramViewport, and DiagramController are at the top-level of Objective Views class hierarchy. Because you want more than one view of the diagram, you might put the squares, ellipses, pen widths, and more into DiagramModel, which seems counter to the design principle of MVC. Lets start by distinguishing among the different types of data and functionality. Typically, GUI applications have four categories of data: Problem domain data Presentation domain data Perspective domain data Selection state The problem domain data is non-GUI. The objects and data in the problem domain exist independently of the rest of the application, even if you are developing a console application. The problem domain usually consists of an MvcModel-derived class that emulates or models some real world process or system in the vocabulary of the problem domain. In our previous example, a schematic of the computers motherboard, the components, interconnections and timing characters is the problem domain.

82

www.roguewave.com

WHITE PAPER

The presentation domain data contains graphical data necessary for rendering. The data in this domain is metadata that references and renders the data in the problem domain into the graphical realm. In the previous example, the visual components, symbols, and links in a schematic diagram that represent the motherboard are part of the presentation domain. The perspective domain is simple. Usually, it is the scroll and zoom positions that specify how the data of the previous two domains should be presented to the user. In conclusion, the selection state is the selected visual components from the presentation domain. Each of these data domains can: Have a one-to-many relationship with the layer directly above them (domain) Vary independently Be serialized independently The first bullet applies to the problem domain. You can have multiple renderings into the graphical domain. For example, the circuit board can be shown as a schematic diagram or a hierarchy by using multiple graphical domains to render the problem domain data in two ways. In addition, each graphical domain can have multiple perspectives. For example, the schematic diagram can be shown twice at different zoom factors. The graphical and perspective domains can also have one-to-many relationships. Each domain can vary independently. Perspective data illustrates this. Lets assume you want to display two different data sets in two different views and lockstep the zoom factor of these views. For example, you could lockstep the zoom factors of a gate-level schematic and a block functional diagram so you could see the same hardware component at different levels of abstraction. The zoom factor could be an IMvcSubject that both views observe. Then, when zooming into the functional diagram, the user would zoom into the gate-level diagram as well. In this example, the perspective domain changes independently of the other domains. However, this isnt a requirement. Changes in one layer can still propagate to other layers via the subject/observer pattern. For example, if you add a new node to the problem domain, the graphical domain must create a new visual component that references and renders it. This implies the need for a subject/observer relationship between the problem and the graphical domains. Alternatively, a base class/derived class relationship could tell the graphical domain that a change has occurred in the problem domain. Lastly, you can serialize each layer independently, which means that you can serialize each layer to a different section of the same file. In addition, you can also save each data domain to a separate file with references among the files. For example, you can save a netlist in one file, a schematic rendering of the

83

www.roguewave.com

WHITE PAPER

netlist in another file that references the file that contains the netlist, and a snapshot file that saves

the zoom and scroll positions that the user defined. Each netlist file can have multiple schematics and snapshot files, or both, referencing it. Now that weve specified how we are going to categorize the data, we need to decide where each category should reside. In DVA and MVC, engineers typically use only two classes, model and view, for storing four domains of data. The result is that these classes are overloaded and overlap (one object mixes two domains together). How you choose to distribute the data domains across the MVC triad depends on your application requirements. Sometimes it is unnecessary to keep the four domains separated. Generally, if you dont need to have the one-to-many relationship between two layers, you can combine the layers. The graphical and perspective domains usually are combined. Sometimes engineers are unsure where to put the graphical domain. As a result, oftentimes the graphical data is put in the model because only the code in a CDocument can be serialized. The decision of where to put data is determined by whether it should be persistent. With MVC, putting graphical information in the viewport doesnt preclude the information from persisting because the viewport receives the serialize command first instead of the model. This is a side effect of the MVC widget definition. In MVC, the widget is the viewport. The model and controller are treated as member variables and implementation details. For example, you can instantiate an MVC-based widget inside a parent without informing the parent of all three objects in the triad. The viewport is a facade for the rest. When the parent wants to serialize the state of its widget, it tells the component to serialize itself. The component is responsible for deciding what data needs to be written to the file, including its model. Consequently, the Serialize() member is a member of the viewport. Now, you no longer need to decide where data should reside based on whether the data should be persistent. Now that we have a choice, we need to decide where to put this data. If you dont need to separate presentation from system information, you can put the data in the viewport. However, if you want to show multiple perspectives on the same presentation, use MvcPresentationModel_T. The classes responsible for each of the four domains of data are: MvcModel-based system model: problem domain data MvcPresentationModel_T: presentation domain data MvcViewport: perspective domain data MvcController: selection state

84

www.roguewave.com

WHITE PAPER

The presentation model creates and maintains MvcVisualComponents that reference a node or object in the system model for which they provide presentation. The presentation model also receives notifications of change from the system model, so it must have an OnUpdate() member. The presentation model acts upon the notifications it receives from the problem domain by creating, destroying or invalidating visual components. Accordingly, the viewport receives a change notification or invalidation request from the presentation model. Lets assume the system model models a nuclear reactor. If a dangerous condition arises, the monitoring system provides input to the system model. The system model then sets a flag internally and forwards a notification of the change to all its observers. Once the presentation model receives the notification, it creates an MvcVisualComponent object to display a red, flashing message. The presentation model subsequently broadcasts an invalidation request to all renders that cause the viewports to paint the alert.
Leveraging the power and flexibility of the subject/observer interfaces

Using nested models, you can create a Model Adapter. A model adapter is an intermediate or translating model that maps the interface and notification dictionary of one model onto the interfaces and notification dictionary of another. Lets assume your model and viewport speak different languages. Lets also assume that your viewport was originally written to observe a different type of model. Accordingly, it only understands the interface and notifications of the model for which it was designed. However, you want to reuse the viewport with a new model. This model has a different interface and notification dictionary, however, many of the same operations are available under different names. A model adapter can act as an intermediary or translator in this scenario. The adapter model is the model to which the viewport attaches. The adapter model observes the foreign model. All calls to operations and notifications go to the adapter model. The adapter model then translates and forwards these calls to the foreign model in its terms. Another difference between the DVA relationship and subject/observer relationship is that in the subject/ observer relationship you can have a many-to-many cardinality between subjects and observers. In MFC, a view expects only one document, however, an observer can depend upon as many subjects as you require. When an observer is notified of a state change it also receives an indication of which subject changed. If you prefer to have one subject per observer, but require the state of multiple subjects, you can create either a composite or umbrella model. An umbrella model is a model that allows multiple models to be presented as one. It observes the component models it contains and passes on the change notifications it receives to its observer. In general, when the subject is a model in an MVC triad, the umbrella model is the preferred approach because the controller doesnt need to depend upon the same list of models that its viewport does. However, if youre only working with subject and observer derivatives, either method will suffice.

85

www.roguewave.com

WHITE PAPER

Using MVC and MFC together

None of the MVC classes are derived from MFCs CObject class or CWnd class, or both. This means you can safely use multiple inheritance and C++ templates with all MVC classes. This allows you to use MFC window and view classes in MVC-based code by packaging them as MVC classes. For example, if you want to nest a CListView inside your MVC-based viewport, you can inherit a ListViewport from both CListView and MvcViewport. In addition, you can achieve persistence in MVC by inheriting from CObject and any MVC class. For example, if you want to save a collection of MvcVisualComponents during your documents serialization process, all you need to do is inherit your visual components from both CObject and MvcVisualComponent.
Undoing a delete command

One of the most difficult actions to plan in an Undo/Redo architecture is how to undo a delete operation. For example, if we delete the object, a subsequent undo must reconstruct the object, which usually requires a full snapshot of the objects state. There are two ways you can avoid taking a full snapshot using the MVC-based Undo/Redo architecture. The first is to make a copy of the objects state. However, the copy is usually almost as large as the object itself. Additionally, it can be time-consuming, complex, and memory-inefficient to reinstantiate a hierarchy of objects when undoing a delete. However, this is a suitable solution if these issues arent significant in the context of your application. The second solution is to never really delete objects. Instead of deleting an object, remove all the models references to the object, but keep the object. Then, you can move the pseudo-deleted objects to a to be deleted list. If the user then undoes the delete, the application takes the object off the list and repairs the models references. Reference counting allows you to delete the object when appropriate. It also ensures that a pseudo-deleted object can be referenced multiple times by the command sequence undo, redo, undo, redo, undo, redo of a delete operation, even though you now have several commands referencing the object but the model doesnt. To implement reference counting, weve borrowed the AddRef() and Release() members from COMs IUnknown interface. Each time a new command or model references an object, it does an AddRef(). Each time a command expires from the undo buffer and is deleted, the commands destructor does a
Release() as does the model when it removes the object. When the number of references on an object

becomes zero, the object auto-deletes itself. The implications of this solution are multiple. First, you should never call Delete() on objects on which you want to support undoable deletion. Instead, you should call Release() and then nullify the

86

www.roguewave.com

WHITE PAPER

reference. Second, you must inherit all objects for which you want to support undoable deletion from the IRefCount base class to get the AddRef() and Release() members. See the following section entitled Using the MVC architecture for more details.
Chaining controllers together

MVC allows you to chain controllers together. You can have any number of controllers that have been daisy-chained together associated with one view. In this scenario, you have one primary controller, and n secondary controllers. This allows you to achieve an even greater modularity with respect to control. For example, if you wanted to provide a separate OLE drag-and-drop controller, you would write it once and chain it to the end of your existing set of controllers by overriding the primary controllers Create() member and creating the secondary controllers. Then, override OnWndMsg() and OnCmdMsg() and extend the message routing so that secondary controllers are visited as well.

Using the MVC architecture


The MVC base classes are generic, so you can incorporate them into your application in a number of ways. For example, you could use MVC in place of DVA. However, if you have an investment in DVA-based code but wish to use parts of MVC, you can. You can use as much or as little of the MVC architecture as you want. If you want to integrate MVC into your application, you need to work with the three primary parts of an MVC triad. The model is usually integrated via containment into the document class. The viewport is usually integrated via containment into the window or CView-derived class. Lastly, the controller is usually instantiated by the viewport it controls. To incorporate an MVC triad into your application, use the following steps.
Integrating your model class

1. Create your MvcModel-derived class. You have a choice of deriving your model from MvcModel or MvcPresentationModel_T. See the section entitled Solving real problems with MVC beginning on page 41 for a description of both choices. For the purposes of this tutorial, well use the presentation model as a base. If you require serialization support in your model, inherit your model from CObject and MvcPresentationModel_T.
class CloudDiagram : public CObject, public MvcPresentationModel_T<MvcVisualComponent> { public: ~CloudDiagram();

To avoid confusion, remember that the CloudDiagram class is a model, even though Model is not part of its name. We could have called it CloudModel or CloudPresentationModel

87

www.roguewave.com

WHITE PAPER

or CloudDiagramModel. However, because a diagram is a kind of presentation model, CloudDiagram is the most concise name. 2. Add your model class as a member variable inside your document.
Class CmyDoc : public CDocument { // Attributes protected: CloudDiagram m_CloudDiagram;

3. Create an accessor member inside your document that returns the model.
CloudDiagram* GetCloudDiagram() { return &m_CloudDiagram; };

4. Override CDocument::IsModified() so that it tests the modified flag of the contained model as well.
BOOL CMyDoc::IsModified() { return CDocument::IsModified() || GetCloudDiagram()->IsModified(); }

5. Override your documents serialize member so that the contained model is serialized as well.
void CMyDoc::Serialize(CArchive& ar) { GetCloudDiagram()->Serialize(ar); }

7. If your model creates and destroys objects for which you want to support undoable deletion, you must derive those objects from IRefCount. See the section entitled Undoing a delete command on page 41 for a complete explanation.
class CloudComponent : public CObject, public MvcVisualComponent, public IRefCount { 8. Override the cloud diagrams Draw() member and implement the presentation of its data. void CloudDiagram::Draw(CDC* pDC) { Iterator_T<CloudComponentPtr> i(GetClouds()); for (CloudComponent* pCloud = i.GetFirst(); pCloud; pCloud = i.GetNext()) { pCloud->Draw(pDC); } } Integrating your viewport class

9. Create your MvcViewport-derived class. At a minimum, your viewport class should specify

88

www.roguewave.com

WHITE PAPER

a GetModel() function that returns a typecast version of your model and override the Draw(), CreateController(), OnInitalUpdate(), SetVirtualSize(), and GetVirtualSize() members. Well describe how to implement these members later in this procedure.
class CloudViewport : public MvcViewport { public: CloudDiagram* GetCloudDiagram() { return (CloudDiagram*)m_pModel; }; virtual void Draw(CDC* pDC); virtual BOOL CreateController(); virtual void OnInitialUpdate(); void SetVirtualSize(int cx, int cy); CSize GetVirtualSize() const;

10.Add your viewport as a component to your CWnd- or CView-derived class:


class CMyView : public CView { protected: // create from serialization only CMyView (); DECLARE_DYNCREATE(CMvcCloudView) // Attributes protected: MyViewport m_component;

11. Create your viewport and attach it to the model contained in the document. Call the viewports Create() member and then call its SetModel() member. This initialization is typically done from the OnCreate() member.
int CMyView::OnCreate(LPCREATESTRUCT lpCreateStruct) { if (CView::OnCreate(lpCreateStruct) == -1) return -1; CMvcCloudDoc* pDoc = GetDocument(); CloudDiagram* pModel = pDoc->GetCloudDiagram(); m_component.Create(this, NULL); m_component.SetModel(pModel); } return 0;

12.Delegate all calls to OnInitialUpdate() and OnDraw() to your viewport from the Cviewor CWnd-derived class that contains it. This gives your viewport the opportunity to initialize and render itself on the drawing surface of its container:
void CMyView::OnInitialUpdate()

89

www.roguewave.com

WHITE PAPER

m_component.OnInitialUpdate(); } void CMyView::OnDraw(CDC* pDC) { CMyDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); m_component.Draw(pDC); }

13.Next, you need to size and position your viewport to occupy the entire client area of its container.
void MyView::OnSize(UINT nType, int cx, int cy) { m_component.SetOrigin(0, 0); // Position the viewport m_component.SetSize(cx, cy); // Size the viewport CView::OnSize(nType, cx, cy); }

14.Now, you need to define the override members for initializing the viewport to create its controller and define what it renders.
BOOL CloudViewport::CreateController() { // EMPTY FOR NOW. WELL COME BACK TO THIS FUNCTION // IN THE NEXT SECTION. } void CloudViewport::Draw(CDC* pDC) { OnPrepareDC(pDC); GetCloudDiagram()->Draw(pDC); } void CloudViewport::OnInitialUpdate() { SetAxisExtents(X, 4000, 1000); SetAxisExtents(Y, 4000, 1000); }

Note: The OnInitialUpdate() member function is ideal for initializing the logical and container extents of the viewports client area. This statement asserts that for every 1000 units along the X axis in the containers client area, there are 4000 logical units in this viewport. We dont use values like one and four because small values like these allow for zooming in and out. The extents can never be less than one because CDC::SetWindowExt() expects an integer. 15.Next, we need to define the GetVirtualSize() and SetVirtualSize() functions for the virtual size of the viewport.
void CloudViewport::SetVirtualSize(int cx, int cy) {

90

www.roguewave.com

WHITE PAPER

GetDiagram()->SetSize(cx, cy);

CSize CloudViewport::GetVirtualSize() const { return GetDiagram()->GetSize(); }

The virtual size of the viewport is equated to the size of the diagram because the diagram is rendered through the viewport and can be larger than the viewport. Accordingly, the size of the diagram is the virtual size of the viewport.
Integrating your controller class

16.Create a controller class that knows how to mediate among the user, your model, and your viewport classes. At a minimum, you need to create GetDiagram() and GetViewport() member functions that return a typecasted pointer to your model and viewport classes.
class CloudController : public MvcController { // Constructors public: CloudController(); virtual ~CloudController(); // Overrides public: CloudDiagram* GetDiagram () { return (CloudDiagram*)m_pModel; }; MyViewport* GetViewport() { return (MyViewport*)m_pVisualPart; };

17.Add a message map to your controller class so you can use Class Wizard to manage your message handlers.
// Generated message map functions protected: //{{AFX_MSG(CloudController) afx_msg void OnLButtonDown(UINT nFlags, CPoint point); //}}AFX_MSG DECLARE_MESSAGE_MAP()

18.Generate a new Class Wizard file that incorporates your new controller class. You can do this by deleting the *.clw files and then running Class Wizard. It prompts you to rebuild the .clw file. 19.Go back to your viewport class (CloudViewport). Override its CreateController() member function to create a new instance of your controller:
BOOL CloudViewport::CreateController() {

91

www.roguewave.com

WHITE PAPER

m_pCtlr = new CloudController; m_bAutoDelCtlr = true; return TRUE;

Remember to set the flag m_bAutoDelCtlr to true so that the instance of MyController is deleted when the viewport destructs. If you dont want the viewport to own the controller, leave the flag set to FALSE, but be sure to delete the controller yourself. It may seem incorrect to have the viewport own the controller and know the type of its controller. However, allowing the viewport to own the controller simplifies the reuse of the viewport without loss of generality, because the controller instantiation and type knowledge can be deferred to a subclass. In other words, define your drawing code in your viewport class and then specify a default controller in the CreateController() member to allow the user to override the CreateController() with their own controller class. 20.To incorporate your controller into your application, include it in the standard message routing so your controller can listen and handle the messages being sent to the containing window. To enable this functionality, you must override two functions: OnWndMsg() and OnCmdMsg().
BOOL CMvcCloudView::OnCmdMsg(UINT nID, int nCode, void* pExtra, AFX_CMDHANDLERINFO* pHandlerInfo) { // First pump through normal channels. This allows you to // override the components default handling inside the view class. if (m_component.OnCmdMsg(nID, nCode, pExtra, pHandlerInfo)) return TRUE; else return CView::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo); } BOOL CMvcCloudView::OnWndMsg(UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pResult ) { // First pump through normal channels. This allows you to override // the components default handling inside the view class. if (m_component1.OnWndMsg(message, wParam, lParam, pResult)) return TRUE; else return CView::OnWndMsg(message, wParam, lParam, pResult); }

At this point, you have a completely reusable component integrated into your DVA application that defines its control, its data and its rendering.

Using MVCs Undo/Redo architecture


Undo/Redo architecture is used on top of the MVC base classes. If you want to incorporate our Undo/ Redo architecture into your application as well, use the following steps:

92

www.roguewave.com

WHITE PAPER

21.Instantiate the MvcTransactionModel in your CDocument class.


class CMvcCloudDoc : public CDocument { ... // Attributes protected: MvcTransactionModel m_transModel;

22.Create commands that correspond to every action your controller class can perform on its associated model and viewport. The number, granularity, and scope of these commands are your choice. Below is an example of a derived command class:
class AddCloudCommand : public CloudCommand { MVC_DECLARE_COMMAND() public: AddCloudCommand(CloudDiagram* pDiagram, const CPoint& pt, CloudComponent* pCloud = NULL); virtual ~AddCloudCommand(); void Sprint(CString& strCmd); virtual BOOL Execute(); virtual BOOL Unexecute(); CPoint m_pt; SmartPtr<CloudComponent> m_pCloud;

};

Notice the MVC_DECLARE_COMMAND macro in the class declaration. This macro adds a static member variable to store the type ID of the command. You can avoid the use of macros and declare the static yourself if you prefer. The macro is provided as a convenience. Notice that SmartPtr is used to wrap the reference to the cloud added by the execution of this command. This allows us to reference count the cloud instance so we know when we can free it. 23.Now, we need to define a type ID for the command. Observers that receive the command via their OnUpdate functions require a type ID. Without the type ID, the OnUpdate function cannot determine what type of command it has received. To initialize the type ID for the command, add the following line to the implementation file that contains the command code.
MVC_IMPLEMENT_COMMAND(AddCloudCommand, CMD_ADDCLOUD)

The MVC_IMPLEMENT_COMMAND macro takes two arguments. The first is the commands class name and the second is the type ID to assign it. The type ID is a unique integer, which is #defined to CMD_ADDCLOUD in the above example.

93

www.roguewave.com

WHITE PAPER

24.Next, we need to implement the command. Lets start with the constructor:
AddCloudCommand::AddCloudCommand(CloudDiagram* pDiagram, const CPoint& pt, CloudComponent* pCloud) : CloudCommand(pDiagram) { m_pt = pt; m_pCloud = pCloud; }

When a new cloud is created, we need to know where to position the cloud. This is enough information to instantiate a new cloud. You need to pass in a pointer to a cloud object because the AddCloud command may be undoing a previous RemoveCloud() command. In this case, we dont need to create a new cloud, we just need to insert the original one. The Execute() function makes the insertion later. The AddRef() call is there to ensure the cloud isnt deleted while we are still referencing it. 25.Now, lets add the primary function: the Execute() override. This function completes the task the command is designed to perform:
BOOL AddCloudCommand::Execute() { if (m_pCloud == (CloudComponent*)NULL) m_pCloud = new CloudComponent(m_pt, m_pDiagram->m_clouds.GetSize()); m_pDiagram->m_clouds.Add(m_pCloud); m_pDiagram->InvalidateVisual(m_pCloud); } return TRUE;

26.Next, we need to override the Unexecute() function. This function reverses the effect of the command, which is assumed to have previously executed.
BOOL AddCloudCommand::Unexecute() { MvcCommand* pInvCmd = new RemoveCloudCommand(m_pDiagram, m_pt, m_pCloud); pInvCmd->Execute(); delete pInvCmd; } return TRUE;

Notice that the Unexecute() command determines the inverse of this command and executes it. This is a convenient way to avoid duplicating the code required to remove a cloud. 27.Lastly, you can override the Sprint() member so you can dump textual descriptions of the Command objects that exist in the undo history.
void AddCloudCommand::Sprint(CString& strCmd)

94

www.roguewave.com

WHITE PAPER

{ }

strCmd.Format(_T(Adding Cloud at point (%d, %d)), m_pt.x, m_pt.y);

28.Now that weve implemented the AddCloud() command, we need to create, execute, and log it. For this we turn our attention to the model object. The model class defines member functions, which are implemented by creating, executing and logging the corresponding command object. This allows the controller to call functions defined by the model without having to know the implementation details of how the model implements the function. In other words, the controller doesnt have to know that the model uses commands to implement its functionality.
class CloudDiagram : public CObject, public MvcPresentationModel_T<MvcVisualPart> { // Operations public: virtual void AddCloud(CPoint ptLog) { Do(new AddCloudCommand(this, ptLog)); }

Notice that were using the Do() member function defined by the presentation model. This is the convenience function that executes and logs a given command. You can override Do() if you dont want to log the command. 29.Add the menu handlers required to initiate the undo and redo operations. These functions should delegate to the controller and transaction model.
void CloudController::OnEditUndo() { GetDiagram()->Undo(); } void CloudController::OnUpdateEditUndo(CCmdUI* pCmdUI) { pCmdUI->Enable(GetDiagram()->PeekUndo() != NULL); } void CloudController::OnEditRedo() { GetDiagram()->Redo(); } void CloudController::OnUpdateEditRedo(CCmdUI* pCmdUI) { pCmdUI->Enable(GetDiagram()->PeekRedo() != NULL)); }

95

www.roguewave.com

WHITE PAPER

Conclusion
Although the Microsoft Foundation Classes provide developers with a more efficient method for designing applications, the libraries do not include help for many of the powerful, innovative features you want for todays applications. Objective Toolkit fills the holes in MFC to provide Windows software engineers with more than 60 drop-in components that address areas not covered by MFC. Objective Toolkit solves some of the most complex problems that Windows application engineers face. Although many of the solutions seem complex, they are easy to use in your MFC applications. Whether you are an architectural-level engineer or a beginner, we believe that Objective Toolkit will save you days, weeks and even months of valuable development time that you can now allocate to applicationspecific logic. This report has focused on the main features and benefits of Objective Toolkit. You may also have questions about how this product would function in your own development environment. If you would like to learn more about how Objective Toolkit can help your business reduce its software development costs, e-mail sales@roguewave.com, visit http://www.roguewave.com/products/stingray.php or call any of the Rogue Wave offices listed on the back cover of this report.

Rogue Wave Software maintains local offices worldwide. For additional contact information, visit: http://www.roguewave.com/contact/

CORPORATE HEADQUARTERS Toll-free: (800) 487-3217 E-mail: sales@roguewave.com www.roguewave.com UNITED KINGDOM Rogue Wave Software UK Limited Dukesbridge House 23 Duke Street Reading RG1 4SA Phone: +44 (0)8450 549950 Fax: +44 (0)8450 549951 E-mail: sales@roguewave.co.uk

GERMANy Rogue Wave Software GmbH Robert-Bosch-Str. 5, Haus C D-63303 Dreieich, Germany Phone: +49 6103 59 34 0 Fax: + 49 6103 3 69 55 E-mail: sales@roguewave.de FRANCE Rogue Wave Software S.A.R.L. Immeuble Le Wilson 1 - 70, Avenue du Gnral de Gaulle F-92058 PARIS LA DEFENSE Cedex Tl. : +33 (0)1 46 93 94 20 Fax : +33 (0)1 46 93 94 39 E-mail: sales@roguewave.fr

JAPAN ASIA PACIFIC Telephone: (303) 545-3331 e-mail: sales@roguewave.com

Copyright 2009, Rogue Wave Software, Inc. All Rights Reserved. Rogue Wave is a registered trademark of Rogue Wave Software, Inc. Stingray is a trademark of Rogue Wave Software, Inc. All other trademarks are the property of their respective owners

Você também pode gostar