objective views user’s guide - perforce

214
Objective Views User’s Guide Stingray ® Studio Version 11.2.0

Upload: others

Post on 20-May-2022

6 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Objective Views User’s Guide - Perforce

Objective Views User’s GuideStingray® Studio

Version 11.2.0

Page 2: Objective Views User’s Guide - Perforce

OBJECTIVE VIEWS USER’S GUIDE

THIS MANUAL

© Copyright 1997-2014 Rogue Wave Software, Inc. All Rights Reserved.

Rogue Wave and Stingray are registered trademarks of Rogue Wave Software, Inc. in the United States and other countries. All other trademarks are the property of their respective owners.

ROGUE WAVE SOFTWARE, INC.

Address: 5500 Flatiron Parkway, Boulder, CO 80301 USA

Product Information: (303) 473-9118 (800) 487-3217Fax: (303) 473-9137Web: http://www.roguewave.com

This documentation, and the information contained herein (the "Documentation"), contains proprietary information of Rogue Wave Software, Inc. Any reproduction, disclosure, modification, creation of derivative works from, license, sale, or other transfer of the Documentation without the express written consent of Rogue Wave Software, Inc., is strictly prohibited. The Documentation may contain technical inaccuracies or typo-graphical errors. Use of the Documentation and implementation of any of its processes or techniques are the sole responsibility of the client, and Rogue Wave Software, Inc., assumes no responsibility and will not be liable for any errors, omissions, damage, or loss that might result from any use or misuse of the Documentation

ROGUE WAVE SOFTWARE, INC., MAKES NO REPRESENTATION ABOUT THE SUITABILITY OF THE DOCUMENTATION. THE DOCUMENTATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. ROGUE WAVE SOFTWARE, INC., HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS WITH REGARD TO THE DOCUMENTATION, WHETHER EXPRESS, IMPLIED, STATUTORY, OR OTHER-WISE, INCLUDING WITHOUT LIMITATION ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NONINFRINGEMENT. IN NO EVENT SHALL ROGUE WAVE SOFTWARE, INC., BE LIABLE, WHETHER IN CONTRACT, TORT, OR OTHERWISE, FOR ANY SPE-CIAL, CONSEQUENTIAL, INDIRECT, PUNITIVE, OR EXEMPLARY DAMAGES IN CONNECTION WITH THE USE OF THE DOCUMENTATION.

The Documentation is subject to change at any time without notice.

ACKNOWLEDGMENTS

Page 3: Objective Views User’s Guide - Perforce

CONTENTS

1Chapter 1 Introduction to Objective Views

1.1 Welcome to Objective Views 1

1.2 Product Features 2

1.3 Location of Samples 2

1.4 Supported Platforms 3

1.5 Dependencies and Relationships 3

1.6 Getting Help 31.6.1 Documentation 31.6.2 Knowledge Base 41.6.3 Professional Services 41.6.4 Technical Support 4

1.7 License Restrictions 4

2Chapter 2 Getting Started with Objective Views

2.1 Building the Objective Views Libraries 72.1.1 Naming Conventions 82.1.2 Build Configurations 92.1.3 Building with Visual Studio 92.1.4 Make Files and Building Directly with nmake 112.1.5 Stingray Foundation Library 112.1.6 Cleaning Build Targets 112.1.7 Build Wizard 12

2.2 Using the Objective Views AppWizard 13

2.2.1 Starting the Objective Views AppWizard 132.2.2 Selecting Options in the Objective Views AppWizard 142.2.3 Generating the Application 19

Contents iii

Page 4: Objective Views User’s Guide - Perforce

3Chapter 3 Quick Tour

3.1 Summary of the Quick Tour 21

3.2 Create Symbols Using Symbol Designer 22

3.3 Add Symbols to Your Application 26

3.4 Creating Code for the Toolbar 31

3.5 Add the Finishing Details 34

3.5.1 Adding Drop-Down Menus 343.5.2 Organizing Toolbars in the Application 353.5.3 Add an Arrow to the Link 36

3.6 Integrate Objective Views into an Existing Project 38

3.6.1 Including Objective Views Files 383.6.2 Adding MVC Architecture and OLE Support 383.6.3 Adding Menu Items and Accelerators 413.6.4 Adding Objective Views Toolbars 42

4Chapter 4 Product Overview

4.1 Introduction to Product Overview 45

4.2 Key Concepts in Objective Views 46

4.2.1 Canvas 464.2.2 Viewport 464.2.3 Model 464.2.4 Controller 464.2.5 Component 474.2.6 Composite 474.2.7 Connection 474.2.8 Control Handles 474.2.9 Label 484.2.10 Link 484.2.11 Port 484.2.12 Property 494.2.13 Symbol 494.2.14 Translation 49

4.3 Drawing Capabilities 50

4.4 Drawing Components 51

4.5 Manipulating Components 53

4.5.1 Selection 534.5.2 Movement 534.5.3 Rotation 55

iv

Page 5: Objective Views User’s Guide - Perforce

4.5.4 Scaling 554.5.5 Grouping and Ungrouping Components 564.5.6 Ordering Components 564.5.7 Editing Vertices 57

4.6 Symbols 58

4.7 Labels 59

4.8 Property Pages 61

4.8.1 General Properties 614.8.2 Edit Properties 614.8.3 Line Properties 624.8.4 Fill Properties 624.8.5 Font Properties 634.8.6 Text Properties 644.8.7 Position and Size 64

4.9 Canvas Background 66

4.10 Canvas Grid 67

4.11 Rulers 68

4.12 Zoom 69

4.13 Pan 70

4.14 Measurements and Size 71

4.14.1 Size and Units 714.14.2 Drawing Scale 714.14.3 Coordinate Mapping 71

v

Page 6: Objective Views User’s Guide - Perforce

4.15 Page Layout 73

4.16 File Export 74

5Chapter 5 The Symbol Designer

5.1 Purpose of the Symbol Designer 75

5.2 Creating a Symbol 76

5.3 Setting the Symbol Type 77

5.4 Saving a Symbol 78

5.5 Alternatives to Using Symbol Designer 79

6Chapter 6 Key Architectural Concepts

6.1 Overview of Interface-Based Programming 81

6.2 IQueryGuid and IRefCount 82

6.3 Interfaces in Objective Views 82

6.4 Model View Controller 83

7Chapter 7 The Canvas

7.1 MVC in Objective Views 85

7.2 The CODModel Class 86

7.2.1 Components and the Model 867.2.2 Generation of Component IDs 877.2.3 Transaction Model 877.2.4 Background 877.2.5 Drag and Drop 877.2.6 Page Settings 877.2.7 Modification 87

7.3 The CODViewport Class 88

7.3.1 Grid 887.3.2 Angle Snap 887.3.3 Page Boundaries 887.3.4 Zoom Limits 887.3.5 Selection Handle Size 887.3.6 Component Tracking 897.3.7 Updating 897.3.8 Scrolling 897.3.9 Off-Screen Buffering 89

vi

Page 7: Objective Views User’s Guide - Perforce

7.3.10 Logical Units 897.3.11 Coordinate Mapping 907.3.12 Inverting the Y Axis 907.3.13 Drawing Scale 927.3.14 Print and Print View 92

7.4 The CODController Class 94

7.4.1 State 947.4.2 Interacting with Components 947.4.3 Other Capabilities 98

7.5 Graph Navigation 100

7.5.1 Graph Navigation Interfaces 1007.5.2 Node and Edge Collections 1017.5.3 IODGraph Interface 1017.5.4 IODNode Interface 1017.5.5 IODEdge Interface 102

7.6 Binary Space Partitioning Trees 103

7.6.1 CODBspTree 1037.6.2 CODBspNode 1037.6.3 CODBspRect 103

7.7 OLE Drag-and-Drop 104

7.7.1 CODDropSource 1047.7.2 CODDropTarget 1047.7.3 OLE Drag-and-Drop and Metafiles 104

8Chapter 8 Components

8.1 Components 1078.1.1 Component Class Hierarchy 108

8.2 Component Essentials 109

8.2.1 CODComponent 1098.2.2 Component Properties 1098.2.3 Parents and Children 1108.2.4 Component Transforms 1108.2.5 Control Points 1118.2.6 Handles 1118.2.7 Region 1118.2.8 User Data 111

8.3 Shape Components 112

8.3.1 CODPointComponent 1128.3.2 CODCurveComponent 1128.3.3 CODClosedCurveComponent 1128.3.4 CODEllipseComponent 112

vii

Page 8: Objective Views User’s Guide - Perforce

8.3.5 CODEllipseComponent2 1128.3.6 CODLineComponent 1128.3.7 CODRectComponent 1138.3.8 CODPolygonComponent 113

8.4 Text Components 114

8.4.1 CODTextComponent 1148.4.2 CODTextCompEdit 1148.4.3 CODLabelComponent 114

8.5 Windowed Components 115

8.6 Image Components 116

8.6.1 CODDib 1168.6.2 CODImageCache 1178.6.3 CODImageComponent 1178.6.4 CODImageEntry 1178.6.5 CODMetafileComponent 1178.6.6 CODSprite 1178.6.7 Using Metafile Components 117

8.7 Line Endpoints 119

8.7.1 CODEndpoint 1198.7.2 CODArrowEndpoint 1198.7.3 CODCircleEndpoint 1208.7.4 CODDiamondEndpoint 1208.7.5 Creating Your Own Endpoints 120

8.8 Port Components 121

8.8.1 CODPortComponent 1218.8.2 CODCirclePort 121

8.9 Other Types of Components 122

8.9.1 CODAnchorSymbol 1228.9.2 CODDocViewAnchor 122

8.10 Component Tracking 123

8.10.1 CODComponentTracker 1238.10.2 CODComponentSetTracker 123

8.11 Transforms 124

8.11.1 Transform Classes 1248.11.2 Transformation Matrices 1248.11.3 Using CODTransform 1258.11.4 Components and Transformation Matrices 1268.11.5 Child Components 1268.11.6 Nested Transformation Matrices 1278.11.7 How the Transform Stack Works 128

viii

Page 9: Objective Views User’s Guide - Perforce

8.12 Regions 130

8.12.1 CODRgn 1308.12.2 CODPolygonRgn 130

9Chapter 9 Properties

9.1 Introduction to Properties 131

9.2 Property Objects 133

9.2.1 CODProperty 1339.2.2 CODBoolProperty 1339.2.3 CODEditProperties 1339.2.4 CODFillProperties 1349.2.5 CODFontProperties 1349.2.6 CODIntProperty 1359.2.7 CODLineOrientation 1359.2.8 CODLineProperties 1359.2.9 CODOrientationProperties 1369.2.10 CODStringProperty 136

ix

Page 10: Objective Views User’s Guide - Perforce

9.3 Property IDs 137

9.4 Property Containers 138

9.5 Registering Properties 140

9.6 Getting and Setting Property Values 140

9.7 The Property Cache 142

10Chapter 10 Symbols

10.1 Introduction to Symbols 143

10.2 Accessing Symbol Files from Disk 144

10.3 Using Symbols as Resources 145

10.4 Creating Symbols on the Fly 146

10.5 Creating a Symbol Class 147

10.6 Placing Symbols on a Toolbar 150

10.7 Ports 151

10.8 Symbol Conversion 152

10.9 Labels 152

10.10Connections 153

10.11A Connection Scenario 154

10.12CODConnection 155

10.13CODConnectionMap 155

10.14Additional Symbols 155

11Chapter 11 Links

11.1 Introduction to Links 157

11.2 Linking Symbols 159

11.3 CODLinkComponent 160

11.4 Changing Endpoints 160

11.5 Orthogonal Links 161

x

Page 11: Objective Views User’s Guide - Perforce

12Chapter 12 Commands

12.1 Introduction to Commands 163

12.2 Type IDs 165

12.3 Executing and Unexecuting 165

12.4 Target Model 165

12.5 Components in a Command 165

12.6 Using or Not Using Command Objects 166

12.7 Command Classes 16612.7.1 CODCommand 16612.7.2 CODMoveCommand 16612.7.3 CODRotateCommand 16612.7.4 CODScaleCommand 16712.7.5 CODInsertVertexCommand 16712.7.6 CODDeleteVertexCommand 16712.7.7 CODMoveVertexCommand 16712.7.8 CODMovePortCommand 16712.7.9 CODSpacingCommand Class 16712.7.10 CODSizeCommand Class 16812.7.11 CODNameCommand 16812.7.12 CODTextCommand 16812.7.13 CODTransparencyCommand 16812.7.14 CODLinkCommand 16812.7.15 CODUpdateCommand 16812.7.16 CODIndexedCommand 16912.7.17 CODInsertCommand 16912.7.18 CODDeleteCommand 16912.7.19 CODGroupCommand 16912.7.20 CODUngroupCommand 16912.7.21 CODOrderCommand 16912.7.22 CODMacroCommand 17012.7.23 CODAlignCommand 17012.7.24 CODPropertyCommand 17012.7.25 CODFontCommand 170

13Chapter 13 Dialogs

13.1 Introduction to Dialogs 171

13.2 Component Property Sheet 173

13.2.1 CODCompPropSheet 17313.2.2 CODDefPropSheet 17413.2.3 CODGeneralCompPP 174

xi

Page 12: Objective Views User’s Guide - Perforce

13.2.4 CODEditCompPP 17513.2.5 CODLineCompPP 17513.2.6 CODLineStyleLB 17613.2.7 CODLineSizeLB 17613.2.8 CODFillCompPP 17613.2.9 CODHatchLB 17613.2.10 CODFontCompPP 17713.2.11 CODFontListBox 17713.2.12 CODSizeListBox 17713.2.13 CODLabelCompPP 17813.2.14 CODPosSizeCompPP 17813.2.15 CODTextCompPP 179

13.3 Measurement Property Sheet 180

13.3.1 CODMeasurePropSheet 18013.3.2 CODMeasurePropPage 18013.3.3 CODCoordinateMappingPage 18013.3.4 CODCanvasSizePage 18113.3.5 CODDrawingScalePage 181

13.4 Other Dialogs 182

13.4.1 CODComponentDlg 18213.4.2 CODComponentLB 18213.4.3 CODGridDlg 18313.4.4 CODZoomDlg 183

xii

Page 13: Objective Views User’s Guide - Perforce

14Chapter 14 Utility Classes

14.1 CODGlobal 185

14.2 CODPageSettings 185

14.3 IODIdGenerator 185

14.4 Smart Pointers 186

14.5 Sets and Iterators 186

15Chapter 15 OLE Document Servers

15.1 Introduction to OLE Document Servers 187

15.2 Server Document and Items 188

15.3 Declaring the COleServerDoc Class 189

15.4 Declaring the COleServerItem Class 190

15.5 Server Item Creation 191

15.6 Server Item Serialization 192

15.7 Server Item Viewport 193

15.8 Server Item OnGetExtent() 194

15.9 Rendering the Server Item 195

Index 197

xiii

Page 14: Objective Views User’s Guide - Perforce

xiv

Page 15: Objective Views User’s Guide - Perforce

Chapter 1 Introduct

Chapter 1

Introduction to Objective Views

1.1 Welcome to Objective ViewsObjective Views is a comprehensive set of Microsoft Foundation Classes (MFC) C++ classes for cre-ating symbols that you can manipulate on a diagram. Objective Views provides a drawing surface abstraction, also known as the canvas, onto which you can draw and manipulate symbols and graphics. Objects on the canvas encapsulate graphical elements that the user or application can move, scale, rotate, connect, or animate.

In addition to extending the functionality of Microsoft Foundation Classes, Objective Views also acts as a layer of abstraction for the Windows GDI. This layer shields you from low-level GDI details so you can concentrate on creating an application design. Because the Objective Views classes extend MFC classes, you can seamlessly integrate an existing application into Objective Views. However, this does not prevent you from customizing the behavior of any of the Objective Views classes.

Objective Views classes enhance the MFC classes that thinly encapsulate the Windows GDI API by supporting interactive graphics that support high-level drawing actions such as rotation, copying, or grouping objects.

Using Objective Views, you can quickly and effectively develop any application that includes a drawing surface and interaction with graphical objects. Here are some of the possibilities:

CASE software, applications that show the relationship among concepts using symbols as notation, such as a modeling tool.

Hierarchy Diagrams that show hierarchical relationships, such as a corporate organization chart that connects the symbols for executives, managers, developers, and other staff.

Control Flow Applications that describe a process graphically using symbols to represent decision points that link to different sections of the diagram. An example would be a diagram showing the control flow of a voice mail system.

A variety of other applications, such as classic flowcharts, computer network diagrams, family trees, and office layouts.

ion to Objective Views 1

Page 16: Objective Views User’s Guide - Perforce

1.2 Product FeaturesObjective Views is a robust, feature-rich library that includes full source code and no run-time licensing fees. It supports

a comprehensive component, property, and event model for graphical objects on a canvas

translation, rotation, and scaling of graphical components using transformation matrix

flexible Model-Viewport-Controller (MVC) architecture

extensible command architecture with unlimited levels of undo and redo

scrolling, panning, zooming, and drag-scrolling on the canvas

snap to grid, ruler guides, and page settings

support for text components, single and multiple line, and word wrap

text labels for symbols, with a variety of orientation options

the import and export of Windows enhanced metafiles (.wmf)

connecting symbols via ports

navigating symbols on a canvas as a directed or undirected graph

accurate real-world measurement of objects on the canvas

OLE drag-and-drop

OLE document server

usage of BSP trees and caching of GDI objects

Symbol Designer, a utility for drawing symbols for use in your applications

1.3 Location of SamplesStingray Studio ships the most basic and commonly used samples with the product itself. The less commonly used and more specialized samples have been removed from the product distribution, but are available from the Rogue Wave web site.

If you are looking for a sample and it does not appear under <stingray-installdir>\Samples\Views\<sample-name>, you can download the sample bundle from the Knowledge Base on the Rogue Wave Web site, as described in Section 3.6.1, “Location of Sample Code,” in the Stingray Studio Getting Started Guide.

2

Page 17: Objective Views User’s Guide - Perforce

1.4 Supported PlatformsFor a list of supported operating systems and compilers, see http://www.roguewave.com/products/stingray.aspx, then click on the link “Supported Plat-forms” to download a PDF.

1.5 Dependencies and RelationshipsObjective Views depends on the Stingray Studio Standard Foundation Library (SFL), which is installed with the product. The SFL contains general purpose classes that are used by several Sting-ray Visual Studio component libraries and our Model-View-Controller framework.

For more information about the SFL, refer to the Stingray Foundation Library User’s Guide.

Do not launch Visual Studio to build SFL (Stingray Foundation) libraries. They will be automatically built while you build the OV libraries.

1.6 Getting HelpSeveral avenues of help are available to you when working with Objective Views.

1.6.1 DocumentationWe provide a comprehensive set of documents in a variety of formats in the Docs subdirectory of your installation directory. You can access by selecting Documentation from the Objective Views submenu in your Windows Start |Programs menu. The following documents are available:

User's Guide - This manual. The User's Guide is a how-to manual that provides an introduction to Objective Views and a foundation for using Objective Views “out-of-the-box.” There are several tutorials included to help new users learn how to create Objective Views applications quickly. This document is available in two formats: HTML Help (ovug.chm) and Portable Document Format (ovug.pdf).

Reference Guide- The reference document (ovref.chm) is a detailed description of the properties, methods, and events in Objective Views.

ReadMe file - The latest information about the product, ViewsReadme.htm located in the Readme folder in your Stingray installation directory.

For more information on the documentation, including all Stingray documentation, an index to the Help files, and document type conventions, see Section 1.4, “Product Documentation,” in the Stingray Studio Getting Started Guide.

Chapter 1 Introduction to Objective Views 3

Page 18: Objective Views User’s Guide - Perforce

1.6.2 Knowledge BaseThe Rogue Wave Knowledge Base contains a large body of useful information created by the Sup-port Services team. This information is available to any user of the Rogue Wave Web site, and no login or registration is required.http://www.roguewave.com/support/knowledge-base.aspx.

1.6.3 Professional ServicesThe Rogue Wave Professional Services offers training and mentoring for all levels of project devel-opment, from analysis and design to implementation. For more information, see Section 1.5, “Professional Services,” in the Stingray Studio Getting Started Guide.

1.6.4 Technical SupportTechnical support for Objective Views products is provided through the Rogue Wave Web site. For more information on registering with the support system, and the type of support you may receive, see Section 1.6, “Technical Support,” in the Stingray Studio Getting Started Guide.

1.7 License RestrictionsPlease read the license agreement that shipped with this package. You are bound by the licensing restrictions contained in that document. Do not use this product unless you accept all the terms of the license agreement.

You can use every file that accompanies this product for development of an application. You can distribute the Objective Views Dynamic Link Libraries (DLLs) according to the terms of the license agreement.

If you dynamically link to the Objective Views library, you need to deliver the DLLs in Table 1 with your application.

If your application is statically linked to the Objective Views library, then you do not need to dis-tribute any Objective Views files with your application.

Table 1 – Files to Distribute

Configuration Files Remarks

OVDLL,AFXDLL,Ascii OV<ver>AS.DLL Objective Views Classes

SFL<ver>AS.DLL Stingray Foundation Library Classes

RWUXThemeS<ver>.D

LL

Themes Library

4

Page 19: Objective Views User’s Guide - Perforce

Our license agreements prohibit the distribution of Objective Views header files, source files, or samples. Exposure of the Objective Views programming interface in your program (for example, a DLL or OCX/ActiveX that provides similar functionality) is also prohibited.

OVDLL,AFXDLL,Unicode OV<ver>AUS.DLL Objective Views Classes

SFLM<ver>AUS.DLL Stingray Foundation Library Classes

RWUXThemeSU<ver>.

DLL

Themes Library

Table 1 – Files to Distribute (Continued)

Configuration Files Remarks

Chapter 1 Introduction to Objective Views 5

Page 20: Objective Views User’s Guide - Perforce

6

Page 21: Objective Views User’s Guide - Perforce

Chapter 2 Getting Started

Chapter 2

Getting Started with Objective Views

2.1 Building the Objective Views LibrariesAfter you have installed Objective Views, you need to build the Objective Views libraries before you can begin using the classes included with Objective Views.

You should take care to ensure that the libraries you build are exactly compatible with your version of the compiler and operating system. If you have difficulties, contact Rogue Wave Technical Sup-port according to the terms of your support agreement.

Objective Views ships with all of the makefiles and project files (VC++ solution files) required to build the various configurations of the library. The Build Wizard, a utility that generates Objective Views makefiles, is also shipped with the product so that you can easily reconfigure the makefiles and change the generated library names.

The Objective Views library can be built as a static library or as a DLL. It can also be built to sup-port either the Unicode or ASCII character sets, and each configuration can be built with debug information or in release mode. The various configuration options result in twelve combinations for the build.

Objective Views relies on the Stingray Foundation Libraries, which are installed with makefiles and run automatically when you build Objective Views. Objective Views also relies on RWUXTheme libraries. You can build the RWUXTheme libraries from <stingray-installdir>\Src\StingrayLibraries<ver>.sln or from solutions in the <stingray-installdir>\RWUXTheme\Src directory.

Do not launch Visual Studio to build SFL (Stingray Foundation) libraries. They will be automatically built while you build the OV libraries.

1. Run the OV BuildWizard if necessary, refer to Section 2.1.7 for details. (There is nothing to check or uncheck).

2. Launch Visual Studio.

3. Build the Objective Views libraries.

with Objective Views 7

Page 22: Objective Views User’s Guide - Perforce

During the install process, the Stingray Foundation Libraries are installed in addition to the Objective Views library. The SFL library contains classes that provide general functionality to each of our MFC C++ class libraries.

To build the Objective Views libraries, the Visual Studio environment must be configured with directory paths to the include files and libraries. Please refer to Section 2.6.3, “Stingray Studio Paths in Property Sheets,” in the Stingray Studio Getting Started Guide for more detailed information about these paths.

After the libraries are built, they are placed in the <stingray-installdir>\Lib\<compiler>\<arch> directory, where <compiler> is one of the supported com-pilers listed in the support matrix and <arch> is either x86 or x64. Each configuration is saved to a separate file. Each build configuration has a subdirectory under <stingray-installdir>\Src\objs\<compiler>\<arch>\<configuration> in which object files are placed.

Refer to Section 2.1, “Build Wizard,” of the Stingray Studio Getting Started Guide for more informa-tion about running the Build Wizard and changing library names.

2.1.1 Naming ConventionsObjective Views uses the following naming scheme to distinguish between the various build con-figurations of Objective Views libraries. The library names can be changed using the Build Wizard, which is explained later in this section.

Note that the product version number refers to the version number for Objective Views, not Visual Studio. If you use Objective Views with more than one version of Visual Studio, consider altering the library names to distinguish among compiler versions.

Figure 1 – Objective Views naming conventions

O V x x a s u d

Library Name

ProductVersionNumber

MFC DLL(AFXDLL)

StingrayDLL

UnicodeBuild

DebugBuild

8

Page 23: Objective Views User’s Guide - Perforce

2.1.2 Build ConfigurationsThe following table lists all of the library configurations supported and the default library name for each configuration, where <ver> stands for the current product version number.

If you are dynamically linking to an Objective Views DLL, you must add the directory containing the DLL to your path or manually copy the Objective Views DLL to your Windows directory.

2.1.3 Building with Visual StudioA Visual Studio solution file is supplied that can be used to build each configuration of the library. These files are located in the <stingray-installdir>\Src directory.

The solution contains a single project with all of the configurations listed above. The following list of steps can be used to build one or more configurations of the library.

1. Start Microsoft Visual Studio.

2. Open the solution file appropriate to your compiler.

Table 2 – Possible library configurations and their default names

Configuration Name Default Library Name

Win32 Lib MFC Lib Debug ov<ver>d

Win32 Lib MFC Lib Release ov<ver>

Win32 Lib MFC Dll Debug ov<ver>ad

Win32 Lib MFC Dll Release ov<ver>a

Win32 Dll MFC Dll Debug ov<ver>asd

Win32 Dll MFC Dll Release ov<ver>as

Win32 Lib MFC Lib Unicode Debug ov<ver>ud

Win32 Lib MFC Lib Unicode Release ov<ver>u

Win32 Lib MFC Dll Unicode Debug ov<ver>aud

Win32 Lib MFC Dll Unicode Release ov<ver>au

Win32 Dll MFC Dll Unicode Debug ov<ver>asud

Win32 Dll MFC Dll Unicode Release ov<ver>asu

Win32 All ANSI N/A

Win32 All Unicode N/A

Win32 All N/A

Chapter 2 Getting Started with Objective Views 9

Page 24: Objective Views User’s Guide - Perforce

3. From the Build menu in Visual Studio, select Set Active Configuration and then choose the build configuration that suits your needs. By default, Win32 All is selected, which builds all combinations of the Objective Views library. The Unicode configuration builds all the librar-ies that support Unicode. All of the other configurations build one specific library. afxlib indicates that MFC will be linked statically and afxdll indicates the MFC will be used as a DLL.

Figure 2 – Setting the Active Configuration

4. From the Build menu in Visual Studio, select Build Views## to build the selected library. (The symbols ## refer to the compiler version, for example 11 for VC++ 11.0.) Visual Studio will then build the selected libraries and copy them into the <stingray-installdir>\Lib directory.

10

Page 25: Objective Views User’s Guide - Perforce

Figure 3 – Building the library

2.1.4 Make Files and Building Directly with nmakeWhen you build the Stingray libraries in Visual Studio, Visual Studio invokes make files that ship with the product. For information on these underlying make files, and how to build the libraries by invoking nmake on these files directly, see Section 2.2, “Building from the Command Line with nmake,” in the Stingray Studio Getting Started Guide.

This section also discusses the issue of building the libraries with 1-byte structure alignment rather than the default 8-byte structure alignment.

2.1.5 Stingray Foundation LibraryObjective Views relies on the Stingray Foundation Library (SFL), which is installed with the prod-uct. SFL is installed with a makefile that is run automatically when you build Objective Views. The Build Wizard can also be used to reconfigure the SFL makefile and change the library names. Refer to the Stingray Foundation Library User’s Guide for more information about building the SFL libraries.

2.1.6 Cleaning Build TargetsThe intermediate object files produced when building the Objective Views libraries can require a significant amount of disk space on your computer. After building the libraries, it is recommended that you delete these files to free up space on your hard drive. A batch file is installed which allows you to delete all of the object files, precompiled headers, and other intermediate files produced by the build process. To clean these files, execute the file <stingray-installdir>\Src\BldClean.bat. Note that BldClean.bat will remove intermediate files for all Stingray Studio products that you have installed – not just the Objective Views libraries.

Chapter 2 Getting Started with Objective Views 11

Page 26: Objective Views User’s Guide - Perforce

2.1.7 Build WizardThe Views<ver>.vcxproj file contained by the Views<ver>.sln solution invokes NMAKE with a different target name for each configuration. The makefile passed to NMAKE is called Views.mak, and it is generated by the Stingray Build Wizard utility. The Build Wizard is a makefile generator that allows you to select various library build options and creates a makefile. Running the Build Wizard is optional because a default makefile is installed with Objective Views. You only need to run the Build Wizard if you need to do one of the following.

Customize library names

On a machine running Windows earlier than 6.0 (Vista), uncheck the "Embed UAC Manifest" option

The Build Wizard can be run by selecting Programs>Stingray Studio>Product Name>Build Tools>Objective Views Build Wizard from the Windows Start menu, where Product Name is the Stingray Studio product that you have installed. It can also be run by double-clicking on the ViewsBuildWiz.exe program in your <InstallDir>\Utils directory.

Refer to Section 2.1, “Build Wizard,” in the Stingray Studio Getting Started Guide for more informa-tion about using the Build Wizard.

12

Page 27: Objective Views User’s Guide - Perforce

2.2 Using the Objective Views AppWizardWhen you install Objective Views, the Objective Views AppWizard is added to the Visual Studio environment. The AppWizard asks the user a series of questions and generates a working applica-tion that uses the Objective Views library. Except for the addition of two steps specific to Objective Views, it is identical to the MFC AppWizard. Using the Objective Views AppWizard, you can quickly create applications that serve as a starting point for your projects.

2.2.1 Starting the Objective Views AppWizard1. Open Visual Studio IDE. Select the File|New|Project menu command.

2. Select Visual C++ | MFC projects from the Installed Templates.

3. Select Stingray Objective Views Application Wizard from the list of available project types.

Figure 4 – Visual Studio New Project Dialog

If Stingray Objective Views Application Wizard does not appear in the project type list, the AppWizard is not properly installed. Please contact Rogue Wave Technical Support for additional information.

Chapter 2 Getting Started with Objective Views 13

Page 28: Objective Views User’s Guide - Perforce

2.2.2 Selecting Options in the Objective Views AppWizardThe AppWizard consists of a series of pages. Each page consists of options that you can select for your application. Navigate between steps using the links in the left frame of the dialog. On the first page of the AppWizard, you can click the Finish button to select the defaults for the remaining steps and generate the application.

The Objective Views AppWizard is based on the Visual Studio MFC AppWizard, and the steps are identical. See the Microsoft Visual Studio documentation to learn more about the MFC AppWizard.

Instead of MFC Feature Pack framework classes, the Objective Views AppWizard uses classes from Stingray Studio library FoundationEx. For example, in an MDI application it uses SFLWinAppEx instead of CWinAppEx, SFLMDIFrameWndEx instead of CMDIFrameWndEx, and SFLMDIChildWndEx instead of CMDIChildWndEx. Also, the AppWizard adds classes derived from Objective Views-specific ones: CODModel, CODViewport, CODController.

2.2.2.1 Toolbar Commands in Visual Studio

The Objective Views AppWizard adds the following FoundationEx bars instead of the MFC Fea-ture Pack ones:

SFLMenuBarEx m_wndMenuBar; // Replaces CMFCMenuBar m_wndMenuBarSFLToolBarEx m_wndToolBar; // Replaces CMFCToolBar m_wndToolBarSFLToolBarEx m_wndSymbolBar; // Objective Views CMFCToolBarSFLStatusBarEx m_wndStatusBar; // Replaces CMFCStatusBar m_wndStatusBar

These bars are created with specific code inside the CMainFrame::OnCreate() method. For example:

if (!m_wndSymbolBar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | CBRS_TOP | CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC) || !m_wndSymbolBar.LoadToolBar(theApp.m_bHiColorIcons ? IDR_SYMBOLS : IDR_SYMBOLS)) { TRACE0("Failed to create symbols toolbar\n"); return -1; // failed to create }

To create other Objective Views toolbars, simply replace IDR_SYMBOLS with the corresponding resource name, and create another SFLToolBarEx member variable.

A full list of Objective Views toolbar creation methods can be found in the <stingray-installdir>\Samples\Views\Showcase sample, or the <stingray-installdir>\Samples\FoundationEx\ShowcaseEx sample. Look inside the CMainFrame::OnCreate() method.

14

Page 29: Objective Views User’s Guide - Perforce

2.2.2.2 Zoom/Pan

The Zoom/Pan toolbar contains commands for zooming and panning the canvas.

Figure 5 – Zoom/Pan toolbar

Zoom. Changes cursor to a magnifying glass and allows the user to click the left and right mouse buttons to zoom in and out.

Zoom to Fit. Sets the magnification level of the canvas so that all components on the canvas are visible in the viewport.

Zoom to Selection. Sets the magnification level of the canvas so that the selected components are visible in the viewport.

Pan. Changes the pointer to a hand and allows the user to grab the canvas with the left mouse button and pan in any direction.

2.2.2.3 Drawing

The Drawing toolbar contains commands for basic shapes on the canvas.

Figure 6 – Drawing toolbar

Select. Changes the cursor to an arrow and puts the canvas in select mode.

Edit Vertices. Puts the canvas in a mode that allows the user to move the vertices of the currently selected component. Depending on the type of component, the user may also be allowed to add and delete vertices.

Properties. Opens the property editor for the currently selected components.

Line. Sets the canvas to line drawing mode. Changes the cursor to a cross and allows the user to create a line by clicking the left mouse button, dragging the mouse, and then releasing the left mouse button.

Polyline. Sets the canvas to polyline drawing mode. Changes the cursor to a cross and allows the user to draw a component composed of multiple line segments.

Polygon. Sets the canvas to polygon drawing mode. Changes the cursor to a cross and allows the user to draw a polygon component on the canvas using the mouse.

Rectangle. Sets the canvas to rectangle drawing mode. Changes the cursor to a cross and allows the user to draw a rectangle component on the canvas.

Polycurve. Sets the canvas to polycurve drawing mode. Changes the cursor to a cross and allows the user to draw a shape composed of Bezier curves.

Chapter 2 Getting Started with Objective Views 15

Page 30: Objective Views User’s Guide - Perforce

Closed curve. Sets the canvas to closed curve drawing mode. Identical to the Polycurve command, except that the endpoints of the resulting component are connected.

Ellipse. Sets the canvas to ellipse drawing mode. Changes the cursor to a cross and allows the user to draw an ellipse on the canvas by outlining a bounding box using the mouse.

Text. Allows the user to add a text component to the canvas.

Image. Allows the user to add an image component to the canvas.

Port. Allows the user to add a circle port component to the canvas.

2.2.2.4 Alignment

Contains commands for aligning components with respect to a given anchor component. The anchor component is always the last component selected and is differentiated from the other selected components by gray selection handles.

Figure 7 – Alignment toolbar

Align Top. Horizontally aligns the selected components with the top of the anchor component.

Align Middle. Horizontally aligns the selected components with the center of the anchor component.

Align Bottom. Horizontally aligns the selected components with the bottom of the anchor component.

Align Left. Vertically aligns the selected components with the left edge of the anchor component.

Align Center. Vertically aligns the selected components with the center of the anchor component.

Align Right. Vertically aligns the selected components with the right edge of the anchor component.

2.2.2.5 Rotate

Contains commands for rotating the selected components.

Figure 8 – Rotate toolbar

16

Page 31: Objective Views User’s Guide - Perforce

Rotate. Sets the canvas to rotate mode. Changes the cursor to a circular arrow when it is over a component. Allows the user to grab a component and rotate it with the mouse.

Rotate Left. Rotates the selected components by 90 degrees to the left.

Rotate Right. Rotates the selected components by 90 degrees to the right.

Flip Vertical. Flips the selected components 180 degrees about the Y axis.

Flip Horizontal. Flips the selected components 180 degrees about the X axis.

2.2.2.6 Nudge

Contains commands for moving the selected components by one logical unit in any direction.

Figure 9 – Nudge toolbar

Nudge Up. Move the selected components one logical unit up.

Nudge Down. Move the selected components one logical unit down.

Nudge Left. Move the selected components one logical unit left.

Nudge Right. Move the selected components one logical unit right.

2.2.2.7 Structure

Contains commands for grouping components together and changing the Z-order (stacking order of layers) of components on the canvas.

Figure 10 – Structure toolbar

Group

Ungroup

Front

Back

Forward

Backward

Chapter 2 Getting Started with Objective Views 17

Page 32: Objective Views User’s Guide - Perforce

2.2.2.8 Layout

Contains commands for arranging components with respect to each other. The spacing commands take three or more components and evenly space them between the minimum and maximum points in the range selected. The size commands adjust the size of the selected components to match the anchor component.

Figure 11 – Layout toolbar

Space Across. Space the selected components evenly between the left-most and right-most components selected.

Space Down. Space the selected components evenly between the top-most and bottom-most components selected.

Same Width. Change the width of the selected components to match the anchor component.

Same Height. Change the height of the selected components to match the anchor component.

Same Size. Change the width and height of the selected components to match the size of the anchor component.

2.2.2.9 Canvas

Contains commands that change the appearance and behavior of the canvas.

Figure 12 – Canvas toolbar

Undo. Undo the last command executed on the canvas.

Redo. Redo the last undo that was performed.

Toggle Grid. Turn display of the grid on and off.

Snap to Grid. Toggle the snap-to-grid feature on and off.

Toggle Page Bounds. Turn display of page boundaries on and off.

This step also contains a checkbox group called Canvas Options. These options affect the appearance and behavior of the canvas. The two options in this group allow the user to add ruler guides to the canvas. The user can add a horizontal ruler, a vertical ruler, or both.

18

Page 33: Objective Views User’s Guide - Perforce

2.2.3 Generating the ApplicationThe last page in the Objective Views AppWizard looks like Figure 13.

Figure 13 – AppWizard - Generated classes and files

This page displays the names of classes and files generated by the Objective Views AppWizard. The Class Name, Header File, and Implementation File fields on this dialog display information regarding the currently selected class in the list box. The user can change the class name, header file, or implementation file by editing these fields.

When you click the Finish button, the Objective Views AppWizard creates the files for your new project and loads it into Visual Studio.

You can add _OVDLL in Preprocessor Definitions if you want to link dynamically to Objective Views library. The AppWizard creates the project for Win32 builds only. You can add x64 build con-figurations if you need to.

For Visual Studio 2010 or later, please refer to Section 2.6.3, “Stingray Studio Paths in Property Sheets,” in the Stingray Studio Getting Started Guide for information on how to add property sheet(s) with Stingray Studio paths to the project.

At this point, the application is ready to build and run. Make sure that the Objective Views libraries have been built prior to building and running your new project.

Chapter 2 Getting Started with Objective Views 19

Page 34: Objective Views User’s Guide - Perforce

20

Page 35: Objective Views User’s Guide - Perforce

C

Chapter 3

Quick Tour

3.1 Summary of the Quick TourThe following tutorials show you how to create a simple Objective Views application. First, use the Objective Views AppWizard to generate a basic application as described in Section 2.2. With the Objective Views AppWizard, you can create a new Visual C++ | MFC project that contains the code you need to integrate Objective Views into an MFC application.

These tutorials describe how to:

Create a running application using the Objective Views AppWizard.

Create symbols using Symbol Designer.

Add symbols to a toolbar in your application.

Add Objective Views commands to menus in your application.

Customize the appearance and behavior of symbols.

Integrate an existing application into Objective Views.

The tutorial assumes that you have already built the DLL configurations of the Objective Views libraries.

hapter 3 Quick Tour 21

Page 36: Objective Views User’s Guide - Perforce

3.2 Create Symbols Using Symbol DesignerNext, let’s create some custom symbols with the Symbol Designer and then save them as disk files. In this section, you learn how to:

Use the component drawing commands in the Symbol Designer.

Set properties for a component.

Import a bitmap image into an Objective Views canvas.

Save a symbol to a disk file.

The Symbol Designer is built with the Objective Views library. Most of the functionality in the Sym-bol Designer is part of the Objective Views library and is available to your applications.

1. Run the Symbol Designer from the Windows Start menu.

Figure 14 – Running the Symbol Designer

2. Symbol Designer appears on the screen.

22

Page 37: Objective Views User’s Guide - Perforce

Figure 15 – Symbol Designer window

Now let’s create a symbol that consists of a circle that contains a smaller square.

3. Select the Ellipse tool button from the drawing toolbar. The cursor changes to a cross to indicate that the canvas is ready to draw an ellipse.

4. Hold the left mouse button down and drag the mouse. An outline of an ellipse is drawn on the canvas. Release the left mouse button when you are finished drawing the ellipse.

5. Select the Rectangle tool button from the drawing toolbar. Draw a square inside of the ellipse using the same technique you used to draw the ellipse. Your symbol should appear as in Figure 16:

Figure 16 – Sample symbol

Chapter 3 Quick Tour 23

Page 38: Objective Views User’s Guide - Perforce

6. Click the right mouse button over the circle and select Properties from the context menu. The property sheet appears.

Figure 17 – Symbol property sheet

7. The Fill and Line property pages allow you to alter the appearance of your symbol. Pick any foreground color from the Fill page.

When you the change the properties of a component in a symbol, only the individual com-ponent is changed. The components are children of the symbol. For example, if you changed the edit properties of the circle, the symbol it is part of would not be impacted in any way.

8. Next, assign a type identifier to the symbol. The type identifier is a string that you can use to categorize your symbols. Select the Set Symbol Type entry from the Edit menu. Enter a type name, such as My Circle. Then, click OK.

9. Now, save the symbol to a file. Select Save As from the File menu and save it as circle.sym in the RES directory of your project directory.

Now let’s create another symbol that contains a bitmap.

10. Select New from the File menu to create a new symbol.

11. Click the Image toolbar button on the drawing toolbar. Using the File Open dialog box, select the file STINGRAY.BMP from the <stingray-installdir>\Samples\Views\Showcase\Res directory in the Objective Views installation directory. Then, close the dialog box by clicking the Open button.

12. The cursor changes to indicate that the canvas is ready for you to insert an image. Click the left mouse button on the canvas to insert the bitmap. The bitmap should appear as in Figure 18.

24

Page 39: Objective Views User’s Guide - Perforce

Figure 18 – Symbol containing a bitmap

Notice that the bitmap has a white background and that you cannot see the grid dots behind it. We can set the properties of the bitmap so that it is transparent.

13. Place the pointer over the bitmap and click the right mouse button. Choose Properties from the context menu. Symbol Designer displays a property sheet for the bitmap.

Figure 19 – Component property sheet

14. Click the Transparent check box and select the color white from the transparency color but-ton. Then click OK. The background for the bitmap becomes transparent.

15. Now let’s assign a type to this symbol. In this instance, name it Stingray. As before, save it to the RES subdirectory under Foobar.

16. The next step is to add the symbols to our new application. Close the Symbol Designer and return to Visual Studio.

Chapter 3 Quick Tour 25

Page 40: Objective Views User’s Guide - Perforce

3.3 Add Symbols to Your ApplicationNow we need to add the symbols created in the previous section to our application so your user can insert a symbol onto your application’s canvas. In this section, you learn how to:

Add symbols as resources.

Add custom and Objective Views symbols to a toolbar.

1. In Visual Studio, open the Resource View for your project. Expand project node, right click on *.rc node and select Add Resource, as shown in Figure 20.

Figure 20 – Importing a symbol into an application

2. In the Add Resource dialog box, click on Import, then select the circle symbol file you cre-ated. Because Visual Studio cannot automatically recognize the symbol resource type, it prompts you to specify the resource type.

26

Page 41: Objective Views User’s Guide - Perforce

Figure 21 – Specifying a resource type

3. Type SYMBOL in the Resource type: box and then click OK. Visual Studio adds a symbol folder to your project’s resources.

4. Now, let’s assign an ID to the newly imported symbol. Select the circle from the SYMBOL folder in the resource tree and choose Properties from the View menu. Assign an ID of IDR_CIRCLE to the circle.

Figure 22 – Assigning an ID to a symbol

5. Insert the stingray symbol the same way you inserted the circle and assign it an ID of IDR_STINGRAY.

Now that the symbols have been added to the application as resources, we need to provide a way to insert the symbols onto the canvas through the application’s user interface, such as a toolbar with buttons for each symbol.

Chapter 3 Quick Tour 27

Page 42: Objective Views User’s Guide - Perforce

6. Create a new toolbar resource. (If you have never created a toolbar with Visual Studio, we recommend you review this feature before continuing.) To make a new toolbar, click the right mouse button on the toolbar folder in the resource tree and select Insert Toolbar.

Figure 23 – Creating a new toolbar resource

7. Next, let’s name the toolbar. Highlight the toolbar in the Resource View tab. Then, on the View menu, click Properties. Name the toolbar IDR_SYMBOLBAR.

Figure 24 – Naming the toolbar

8. Now we’ll add four buttons to the Symbol toolbar. You can copy these buttons from resource files shipped with Objective Views. The first two buttons are in the Objective Views resource file, which is called OdRes.rc. It is stored in the Objective Views Include directory. Open the OdRes.rc file in Visual Studio and click the Resource View tab.

Our toolbar should look like Figure 25.

28

Page 43: Objective Views User’s Guide - Perforce

Figure 25 – Sample symbol toolbar

9. Find the IDR_OD_LINK toolbar in OdRes.rc, as in Figure 26.

Figure 26 – The IDR_OD_LINK in OdRes.rc

10. Open IDR_OD_LINK and copy the Link toolbar button . Paste the button directly onto the Symbol toolbar, as shown in Figure 27.

Chapter 3 Quick Tour 29

Page 44: Objective Views User’s Guide - Perforce

Figure 27 – Pasting a button onto the symbol toolbar

11. In OdRes.rc, find the IDR_OD_DRAWING toolbar.

Open it and copy the Select button . Then, paste it onto the Symbol toolbar.

12. The last two toolbar buttons you need to add to the Symbol toolbar enable the user to insert the symbols you created earlier. You can copy the buttons for the circle and stingray symbols from the resource file for the Showcase sample. The name of the resource file is Showcase.rc. It is stored in the <stingray-installdir>\Samples\Views\Showcase directory.

13. Open Showcase.rc and open the IDR_SYMBOLS toolbar.

Copy the Stingray button and paste it onto the Symbol toolbar. With the button selected, select Properties from the View menu and name the button ID_STINGRAY.

14. Copy the Circle button from the IDR_SYMBOLS toolbar. Then, paste it onto the Sym-bol toolbar. With the button selected, select Properties from the View menu and name the button ID_CIRCLE.

15. Rearrange the buttons on the Symbol toolbar so it resembles Figure 28.

Figure 28 – Symbol toolbar

30

Page 45: Objective Views User’s Guide - Perforce

3.4 Creating Code for the ToolbarNow we need to add some new toolbar commands and write handlers for those commands.

The following procedure is applicable if the MFC feature pack is not used. Otherwise, see the document <stingray-installdir>\Docs\Stingray Feature Pack Migration, and the sample <stingray-installdir>\Samples\FoundationEx\ShowcaseEx.

1. First, let’s add the toolbar to the frame window. Declare the new toolbar in the CMainFrame class:

class CMainFrame : public CFrameWnd{ . . . protected: // control bar embedded members . . . CToolBar m_wndSymbolBar; // Symbol toolbar . . .};

2. To create the toolbar, you need to add some code to the frame window class in the source file. Find the CMainFrame::OnCreate() method and update it as follows. Make sure you add this code before the EnableDocking(CBRS_ALIGN_ANY) call.

if (!m_wndSymbolBar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | CBRS_TOP | CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC)|| !m_wndSymbolBar.LoadToolBar(IDR_SYMBOLBAR)){ TRACE0 ("Failed to create symbol toolbar \n"); return -1; //fail to create}

3. The EnableDocking member function of the newly created toolbar must be called:

m_wndSymbolBar.EnableDocking(CBRS_ALIGN_ANY);

4. Add the following code after the EnableDocking(CBRS_ALIGN_ANY) call:

DockControlBar(&m_wndSymbolBar);

5. Now add command handlers for the commands on the toolbar. The ID_OD_DRAW_SELECT and ID_OD_LINK_SYMBOLS commands already have handlers in the Objective Views CODController class. The controller is the piece of the canvas that handles events and translates them into actions. The AppWizard generated a controller class called CSimpleController for our project, derived from the CODController class. You need to add command handlers to the CSimpleController class to insert your custom symbols.

Add the following function declarations to CSimpleController:

afx_msg void OnCircle();afx_msg void OnStingray();. . .

Add the following entries to the CSimpleController message map:

BEGIN_MESSAGE_MAP(CSimpleController, CODController)

Chapter 3 Quick Tour 31

Page 46: Objective Views User’s Guide - Perforce

//{{AFX_MSG_MAP(CSimpleController)… ON_COMMAND(ID_CIRCLE, OnCircle) ON_COMMAND(ID_STINGRAY, OnStingray)…//}}AFX_MSG_MAPEND_MESSAGE_MAP(). . .

Add the implementation of the command handlers to the CSimpleController .cpp file.

. . .void CSimpleController::OnCircle(){ CODSymbolComponent* pSymbol = new CODSymbolComponent(); if(NULL!=pSymbol) pSymbol->Create(IDR_CIRCLE); OnInsertSymbol(pSymbol);}

void CSimpleController::OnStingray(){ CODSymbolComponent* pSymbol = new CODSymbolComponent(); if(NULL!=pSymbol) pSymbol->Create(IDR_STINGRAY); OnInsertSymbol(pSymbol);}

6. Now you’re ready to compile the application and execute it. Your compiled application should appear as in Figure 29.

Figure 29 – Sample compiled application

32

Page 47: Objective Views User’s Guide - Perforce

Experiment with your new application. Create the canvas in Figure 30 using the tool buttons you just created.

Figure 30 – Sample canvas

Chapter 3 Quick Tour 33

Page 48: Objective Views User’s Guide - Perforce

3.5 Add the Finishing DetailsNow you are going to learn how to polish the application. In this section, you learn how to:

Add some drop-down menus.

Organize your toolbars.

Add an endpoint to the link symbol.

3.5.1 Adding Drop-Down MenusLet’s enhance the application by adding a few finishing details. First, let’s add some drop-down menus. Adding a drop-down menu is a three-fold process. To add a drop-down menu you need to:

Open the Objective Views resource script file.

Copy the resource elements to your application.

Delete any string resources generated by the copy/paste operation that are already present in the included OD resource file.

1. Select Open from the File menu. Then, select OdRes.rc from the INCLUDE subdirectory, which is immediately under the Objective Views install directory. Double-click the file to open it. It appears as in Figure 31.

Figure 31 – OdRes.rc

2. Let’s copy the Structure and Align drop-down menus to the application. Select the Struc-ture menu from the IDR_OD_MENU resource in OdRes.rc and copy it. Select the empty slot in the project’s IDR_MAINFRAME menu resource and paste it. Do the same for the structure menu. The finished menu should appear as in Figure 32.

34

Page 49: Objective Views User’s Guide - Perforce

Figure 32 – Creating a menu

3. When you copy a resource to your application, its string table entry is copied over as well. You need to delete each of the OD string table definitions from your string table before you can begin compiling your application. Otherwise, the application considers the string table entries to be duplicates of the existing string table entries in the included OdRes.rc resource file. After copying resource elements, your string table should look like Figure 33.

Figure 33 – Sample string table

4. Delete each of the ID_OD_xxx entries to prevent the compiler from producing errors.

3.5.2 Organizing Toolbars in the ApplicationYou almost have a fully functional application. Next, let’s rearrange the tool bars.

1. Find the CMainFrame::OnCreate() method in your application’s MainFrame.cpp source file. The following code is near the end of the file.

// TODO: Delete the DockControlBar lines if you don't want// docking toolbars.

Chapter 3 Quick Tour 35

Page 50: Objective Views User’s Guide - Perforce

// To make the toolbars line up better, utilize the // utility method CODGlobal::DockControlBarLeftOf() DockControlBar(&m_wndToolBar); DockControlBar(&m_wndAlignBar); DockControlBar(&m_wndNudgeBar); DockControlBar(&m_wndStructureBar); DockControlBar(&m_wndSymbolBar);

2. Now, incorporate CODGlobal::DockControlBarLeftOf() into your code. The code should look like the following after you make a change:

DockControlBar(&m_wndToolBar);DockControlBar(&m_wndSymbolBar);CODGlobal::DockControlBarLeftOf(this, &m_wndAlignBar, &m_wndToolBar);CODGlobal::DockControlBarLeftOf(this, &m_wndNudgeBar, &m_wndSymbolBar);CODGlobal::DockControlBarLeftOf(this, &m_wndStructureBar, &m_wndNudgeBar);

3. After you rebuild and execute the application, your application should look like Figure 34.

Figure 34 – Sample application with rearranged toolbars

3.5.3 Add an Arrow to the LinkOur application is almost complete. Let’s add an arrow to the link by adding a command handler for the ID_OD_LINK_SYMBOLS command.

1. First, add the following line to the class declaration for CSimpleController.

afx_msg void OnLinkSymbols ();…

2. Then, add the following code to CSimpleController’s message map.

BEGIN_MESSAGE_MAP(CSimpleController, CODController) //{{AFX_MSG_MAP(CSimpleController) …

36

Page 51: Objective Views User’s Guide - Perforce

ON_COMMAND(ID_OD_LINK_SYMBOLS, OnLinkSymbols) … //}}AFX_MSG_MAPEND_MESSAGE_MAP()…

3. Lastly, add the following code to SimpleCtlr.cpp. …void CSimpleController:: OnLinkSymbols (){ CODLinkComponent* pLinkComp = new CODLinkComponent(); pLinkComp->Create(); pLinkComp->SetTargetEndpoint(new CODArrowEndpoint()); OnInsertLink(pLinkComp); }…

This is the same technique you used to add other symbols to a canvas. We create the link component and add a CODArrowEndpoint object to it by calling SetTargetEndpoint(). Then, you pass the link component to the controller for insertion onto the canvas by calling OnInsertLink(). The OnInsertLink() method serves the same purpose as OnInsertSymbol(). Any command handler can add custom links to a canvas using OnInsertLink(). The CODController class provides a default handler for the ID_OD_LINK_SYMBOLS command, which creates a link with no adornments.

4. Our simple application is now complete. Rebuild the application and experiment with it.

Although this sample is not equivalent to a fully functional Objective Views application, it demonstrates many of its basic features.

Chapter 3 Quick Tour 37

Page 52: Objective Views User’s Guide - Perforce

3.6 Integrate Objective Views into an Existing ProjectTo add Objective Views functionality to an existing program, you need to complete the steps that Objective Views AppWizard automatically implements when it creates a skeleton application. In the following tutorial, you add code to a typical MDI application so you can use the Objective Views Library. If you have a different configuration, some of these steps may differ.

3.6.1 Including Objective Views Files1. Let’s include the Objective Views header files. Open the file stdafx.h and add the follow-

ing line near the end of the file:

#include “views\OdAll.h”

2. Now, add the Objective Views resources from the View menu and select Resource Includes.

3. In the Read-only symbol directives box, type the following code on the last line:

#include “views\OdRes.h”

4. In the Compile-time directives box, type the following line:

#include “views\OdRes.rc”

5. Click the OK button. A warning dialog appears. Click the OK button again.

6. Include header files that are common for all Stingray Studio products:

Add #include <SupportedPlatforms.h> toward the top of the application’s stdafx.h file.

Add #include <ManifestDefs.h> at the end of the include statements.

3.6.2 Adding MVC Architecture and OLE SupportIf you have configured your application to include MVC architecture and OLE support, use the fol-lowing steps to add them.

3.6.2.1 Add the Property Cache

1. Let’s add the global Property Cache. Open the source file that holds the implementation of your main application object. If you were working with a project named Foobar, this would be called Foobar.cpp.

2. After the declaration of the application object (theApp), add the declaration of the global property cache object:

CODPropertyCache thePropCache;

38

Page 53: Objective Views User’s Guide - Perforce

3.6.2.2 Add the Model and Support for OLE Drag-and-Drop

1. Now, add a Model to your document object. Open your document’s header file (for exam-ple, FoobarDoc.h).

2. Add your model or the default model CODModel as a member variable:

CODModel m_mdlCanvas;

3. Now, add an accessor method for your model:

CODModel* GetModel() { return &m_mdlCanvas; }

4. Open your document’s source file (for example, FoobarDoc.cpp).

5. Add the model to the Serialize() method.

void CFoobarDoc::Serialize(CArchive& ar){ m_mdlCanvas.Serialize(ar);

if (ar.IsStoring()) { // TODO: add storing code here } else { //TODO: add loading code here }}

6. Now, add support for OLE drag-and-drop. If you would like to use the OLE drag-and-drop features in addition to Objective Views drag-and-drop, you need to initialize the OLE libraries. Ensure that the following code is at the beginning of your application object’s InitInstance() method.

if (!AfxOleInit()){ AfxMessageBox(IDP_OLE_INIT_FAILED); return FALSE;}

7. Ensure that your string table contains a string resource for IDR_OLE_INIT_FAILED. If it does not, add one.

3.6.2.3 Add the Viewport

1. Let’s add a viewport to your view object. Open your view’s header file (for example, FoobarView.h).

2. Add your viewport or one of the standard viewports supplied with Objective Views as a member variable. The CODScrollViewport has scrollbars and the CODViewport does not.

CODScrollViewport m_vpCanvas;

Chapter 3 Quick Tour 39

Page 54: Objective Views User’s Guide - Perforce

3. Now, you need to add the viewport to the CView::OnDraw() method: In your view’s source file, add a call to the Refresh() method in the viewport’s OnDraw() method:

m_vpCanvas.Refresh(pDC);

4. Add the OnCreate() method to your view object. Use the Class Wizard to add a handler to your view for the WM_CREATE message.

5. In the resulting OnCreate() method, add code to attach the model to the viewport.

int CFoobarView::OnCreate(LPCREATESTRUCT lpCreateStruct) { if (CView::OnCreate(lpCreateStruct) == -1) return -1;

CFoobarDoc* pDoc = GetDocument(); CODModel* pModel = pDoc->GetModel(); m_vpCanvas.Create(this, NULL); m_vpCanvas.SetModel(pModel);

return 0;}

6. Now, add the OnInitialUpdate() method to your view object. Use the Class Wizard to add an override method for OnInitialUpdate().

7. In the OnInitialUpdate() method, call the OnInitialUpdate() method of the viewport.

void CFoobarView::OnInitialUpdate(){ CView::OnInitialUpdate(); m_vpCanvas.OnInitialUpdate();}

8. Let’s add the OnSize() method to your view object. Use the Class Wizard to add a handler for the WM_SIZE message.

9. On the OnSize() method, call the SetSize() method for the viewport.

void CFoobarView::OnSize(UINT nType, int cx, int cy) { m_vpCanvas.SetSize(cx, cy); CView::OnSize(nType, cx, cy);}

10. Override OnCmdMsg() in your view object. In the view’s header file, add a public declara-tion for OnCmdMsg():

virtual BOOL OnCmdMsg(UINT nID, int nCode, void* pExtra, AFX_CMDHANDLERINFO* pHandlerInfo);

11. In the view’s source file, add an implementation of OnCmdMsg() that gives the viewport access to the messages:

BOOL CFoobarView::OnCmdMsg(UINT nID, int nCode, void* pExtra, AFX_CMDHANDLERINFO* pHandlerInfo){

40

Page 55: Objective Views User’s Guide - Perforce

// first pump through normal channels. This allows you to // override the components default handling inside the view // class. if (CView::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo)) return TRUE;

// then pump through the viewport BOOL bHandled = FALSE; if (m_pDocument != NULL) bHandled = m_vpCanvas.OnCmdMsg(nID, nCode, pExtra, pHandlerInfo);

return bHandled;}

12. Let’s override OnWndMsg() in your view object. In the view’s header file, add a public decla-ration for OnWndMsg():

virtual BOOL OnWndMsg(UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pResult);

13. In the view’s source file, add an implementation of OnWndMsg() that gives the viewport access to the messages:

BOOL CFoobarView::OnWndMsg(UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pResult){ // give the viewport a chance to route the message to a //controller. BOOL bHandled = m_vpCanvas.OnWndMsg(message, wParam, lParam, pResult);

if( !bHandled ) { bHandled = CView::OnWndMsg(message, wParam, lParam, pResult); } return bHandled;}

At this point, you can build and run the application to verify that you did everything correctly so far. Make sure that you have built the OV libraries (they should be in the <stingray-installdir>\Lib directory). A view with a canvas should appear on the screen. There are no com-mands in place to do anything with it. If a grid of dots is visible, the application is working correctly.

3.6.3 Adding Menu Items and Accelerators1. Now, add Objective Views menu items. If you want menu items that interact with the view,

you can copy them from the Objective Views resources into your own. Make sure you do not move them from the Objective Views resources. Open your application’s resource file and then open Objective Views’s resource file, which is stored in the Objective Views Include directory.

2. Highlight the menu items you want to include in your application from Objective Views’s View menu and then copy them.

Chapter 3 Quick Tour 41

Page 56: Objective Views User’s Guide - Perforce

3. Select the empty space in your application’s View menu and paste in the items. Then, delete the string resources for these menu items from your string table. Each resource ID for the menu items will be prefixed by ID_OD_.

4. Now let’s add Objective Views accelerators. The OdRes.rc file contains a set of common accelerators used with Objective Views.

5. Select the accelerators you want to use in your application and then copy them.

6. Select the empty slot in your application’s accelerator table and then paste the accelerators.

3.6.4 Adding Objective Views ToolbarsNow, add Objective Views toolbars. The Objective Views resources include several defined toolbars that fire commands recognized by the CODController. They are divided by function:

You can include any combination of these toolbars. You can also choose individual buttons to cre-ate toolbars with specific functionality.

If you want to use the standard Objective Views toolbars, you do not need to copy them into your application’s resources because the toolbars are imported from OdRes.rc at compile time. If you want to make your own custom toolbars, you need to create new ones in your project and copy the buttons from OdRes.rc.

The following procedure is applicable if the MFC feature pack is not used. Otherwise, see the document Stingray Feature Pack Migration and the ShowcaseEx sample.

1. You add an OV toolbar to your frame window just like you would any other toolbar. In your main frame’s header file (for example, MainFrm.h), add a member variable for the toolbar:

CToolBar m_wndDrawingBar;

Drawing Toolbar IDR_OD_DRAWING

Rotation Toolbar IDR_OD_ROTATE

Structure Toolbar IDR_OD_STRUCTURE

Nudge Toolbar IDR_OD_NUDGE

Alignment Toolbar IDR_OD_ALIGN

Zoom/Pan Toolbar IDR_OD_ZOOM_PAN

Link Toolbar IDR_OD_LINK

Layout Toolbar IDR_OD_LAYOUT

Canvas Toolbar IDR_OD_CANVAS

42

Page 57: Objective Views User’s Guide - Perforce

2. In your main frame’s source file (for example, MainFrm.cpp), add code to create the toolbar in the OnCreate() method:

if (!m_wndDrawingBar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | CBRS_TOP | CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC) || !m_wndDrawingBar.LoadToolBar(IDR_OD_DRAWING)) { TRACE0("Failed to create drawingbar\n"); return -1; // fail to create }

3. To make the toolbar dockable, type the following line to enable docking.

m_wndDrawingBar.EnableDocking(CBRS_ALIGN_ANY);

4. Set the name of the toolbar, which appears in the caption when it is floating.

m_wndDrawingBar.SetWindowText("Drawing");

5. If you want to dock toolbars to the frame window, add the following line to the OnCreate() method.

EnableDocking(CBRS_ALIGN_ANY);

6. Now, you can dock all the toolbars you created with calls like the following.

DockControlBar(&m_wndDrawingBar);

7. Objective Views’s CODGlobal class has a static utility method for docking one toolbar to the left of another. To use it, make a call like the following.

CODGlobal::DockControlBarLeftOf(this, &m_wndDrawingBar, &m_wndToolBar);

Now you can use your MDI application with Objective Views. With Objective Views, you can define your own symbols, add them to the toolbar, and then let Objective Views integrate them into the application.

To add symbols, you need to handle more messages than the default CODController contains. To add functionality to the controller, derive your own controller from it and add whatever behavior you need. When you derive the controller, you also need to derive a new class from CODViewport to create the new controller.

Chapter 3 Quick Tour 43

Page 58: Objective Views User’s Guide - Perforce

44

Page 59: Objective Views User’s Guide - Perforce

Chapter

Chapter 4

Product Overview

4.1 Introduction to Product OverviewThis section describes Objective Views’s features from an end user’s perspective. Applications developed with Objective Views can include some or all of the features described in this chapter. You can add or remove many of the features of an Objective Views application by changing the application’s toolbars and menus. For example, adding a toolbar button with the command identi-fier ID_OD_DRAW_RECT enables a feature that allows the user to draw rectangles on the canvas.

To see the features described in this chapter:

1. Start Visual Studiio.

2. Open the <stingray-installdir>\Samples\Views\Showcase directory. Then, select the Showcase<ver>.sln solution file that corresponds to your version of Visual Studio.

3. Build the application and execute it.

4 Product Overview 45

Page 60: Objective Views User’s Guide - Perforce

4.2 Key Concepts in Objective ViewsSeveral important Objective Views concepts are defined in this section.

4.2.1 CanvasA canvas is a drawing surface for a set of components. It has a size, a coordinate system, a set of components, and several other attributes that you can configure. The canvas consists of three pieces – the model, the viewport, and the controller. The model is the container for the components; the viewport maps the components to a region of a window and renders; the controller handles messages and user interaction within the canvas. Conceptually, think of the canvas as a surface that comprises the model, viewport, and controller.

Figure 35 – Canvas

4.2.2 ViewportThe viewport presents information stored in a model. It is an observer of the model and knows how to render the model onto a device context. Whenever the model is notified of a change by the con-troller, the viewport or viewports update themselves accordingly.

4.2.3 ModelA model is a collection of components, symbols and links that show a complete system of graphical objects and their relationship to each other.

4.2.4 ControllerA controller is an object that handles messages and user interaction. It receives messages from the viewport and interprets them as user tasks or activities. The controller is responsible for translating the messages into commands or actions that affect the model, viewport, or both.

1.Canvas

Controller

Components

Viewport

Model

46

Page 61: Objective Views User’s Guide - Perforce

4.2.5 ComponentA component is an object that is drawn onto a canvas. Lines, text, ellipses, and rectangles are exam-ples of components. Components have a logical position, occupy a rectangular area on the canvas, and are responsible for drawing themselves onto the canvas. You can assign a component proper-ties such as fill color, line color, font, and boolean flags to determine its appearance and behavior.

Figure 36 – Component

4.2.6 CompositeA composite is a component that contains child components. It consists of a group of components that act as a unit. Moving, rotating, or scaling the composite affects the children it contains. The children of a composite can inherit the properties that belong to the composite or parent compo-nent. When a component is added as a child to a composite, its properties may be altered slightly by the parent component. For example, you cannot edit the vertices of a component when it is a child of a composite component.

Figure 37 – Composite

4.2.7 ConnectionA connection binds two ports and establishes a connection between two symbols. Connections attach two symbols to one another.

4.2.8 Control HandlesControl handles are small boxes that appear on a component when you select it. On primitive com-ponents such as lines or rectangles, the control handles are placed on each vertex of the shape. This allows the user to move these vertices to change the shape of the component.

A composite component always has eight control handles that define a box around the edges of the component. You can use the control handles to scale the component.

Chapter 4 Product Overview 47

Page 62: Objective Views User’s Guide - Perforce

Figure 38 – Control handles

4.2.9 LabelA label is a text component that you can use to annotate a symbol. You can also create a default alignment option for a label. For example, you can align the label directly below a symbol.

Figure 39 – Label

4.2.10 LinkA link is a line drawn between symbols to indicate a relationship. Links are special symbols that have a port on either endpoint. You can connect the ports on a link to ports on other symbols.

Figure 40 – Link

4.2.11 PortA port defines a location on a symbol at which you can connect another other symbol or symbols. A connection binds together two ports. Ports are components and can be either visible or invisible.

Figure 41 – Port

48

Page 63: Objective Views User’s Guide - Perforce

4.2.12 PropertyA property is a tagged value that you can assign to a component. Properties are objects that have a unique identifier and a value that you can associate with components either at compile-time or run-time. They provide a flexible and dynamic way of associating fonts, line style, colors, or other features with a component. Users can easily create their own properties for use in applications.

Figure 42 – Properties

4.2.13 SymbolA symbol is a component that can have ports and labels. Ports are locations on a symbol at which connections to other symbols or links can be established. Labels are text components that are attached to a symbol. Symbols are typically composite components, composed of one or more drawing primitives. You can create symbol objects for use in your application using Symbol Designer, a simple drawing application bundled with Objective Views. Symbols created with the Symbol Designer can be loaded into your application from a disk file or as a custom application resource. Symbol components can also be created and manipulated programmatically at run-time.

Figure 43 – Symbol components

4.2.14 TranslationTranslation is a matrix transformation that can be applied to a component that moves the compo-nent in the X direction, the Y direction, or both directions.

Chapter 4 Product Overview 49

Page 64: Objective Views User’s Guide - Perforce

4.3 Drawing CapabilitiesObjective Views provides a set of drawing capabilities similar to most end-user, drawing applica-tions. Users can draw the following types of components onto a canvas.

Lines

Polygons

Rectangles

Curves

Closed Curves

Ellipses

Text

Bitmap Images

Windows Icons

Windows Enhanced Metafiles

Objective Views provides the functionality you need to alter shapes and images drawn on the can-vas. Here are some of the actions that users can perform on components:

Selection

Movement

Rotation

Scaling

Vertex Editing

Alignment

Cut, Copy, and Paste

Grouping/Ungrouping

Stacking Order (Z-Order)

Grid Alignment

Connect symbols and links together

50

Page 65: Objective Views User’s Guide - Perforce

4.4 Drawing ComponentsComponents are objects that are placed on the canvas and manipulated by the user. A component can be a simple shape (for example, a drawing primitive) or a complex collection of shapes or images. Objective Views provides the user interface functionality needed to draw shapes and add them as components onto a canvas. To start drawing a component, the user selects the toolbar but-ton or menu command that corresponds to a particular shape. This puts the Objective Views application into a mode that enables it to accept further input to draw the component. The left mouse button is used to draw the shape, while the right mouse button cancels the draw command. The following table describes how to draw each type of shape or primitive component and perform other drawing related tasks.

Table 3 – Drawing Shapes

To Do this

Draw a component of equal propor-tions or at 90 degree angles

Hold the SHIFT key while drawing a component. For example, if the user selected a rectangle tool button and then clicked in the client area while holding the SHIFT key, the application would draw a square.

Draw a component that is centered on the point at which the drawing started.

Hold the CTRL key while drawing a component.

Draw a line

Click the Line button . Then, click and hold the mouse button in the client area and drag until the line is the appropriate length.

Draw a polyline

Click the Polyline button . Then, click in the client area. Click again to place a vertex. Double-click to finish drawing. Right-click to cancel the action.

Draw a rectangle

Click the Rectangle button . Then, click and hold the mouse button in the client area. Drag the pointer until the rectangle is the width and length you want.

Draw a polygon

Click the Polygon button . Then, click in the client area. Click again to place a vertex. Double-click to finish drawing. Click the right mouse button to cancel the action.

Chapter 4 Product Overview 51

Page 66: Objective Views User’s Guide - Perforce

Draw a polycurve

Click the Polycurve button . Then, click in the client area. Click to place an endpoint, two control points and another endpoint. Double-click to finish drawing or right-click to cancel.

Draw a closed curve

Click the Closed Curve button . Then, click in the client area. Click to place an endpoint, two control points and another endpoint. Double-click to finish drawing or right-click to cancel. Unlike the polycurve, the user can assign a fill color to a closed curve.

Draw an ellipse

Click the Ellipse button . Then, click and hold the mouse button while dragging in the client area until the ellipse is the size you want.

Add text

Click the Text button . Then, click in the client area. The text can be changed by double-clicking on the text component.

Add an image

Click the Image button to open a standard Open dialog from which the user can select an image in either .bmp, .wmf or .dib format.

Table 3 – Drawing Shapes

To Do this

52

Page 67: Objective Views User’s Guide - Perforce

4.5 Manipulating Components

4.5.1 SelectionBy default, an Objective Views application starts in selection mode. If you are not in selection mode, you can switch to it by clicking the Selection tool button .

You can select a single component by clicking it while selection mode is activated. If you want to select multiple components, hold the CTRL key and then click each of the components you want to include in the selection, or click and drag on empty space to draw a selection rectangle. The last component selected for a multiple selection is distinguished from the others by its gray selection handles. The gray handles are used to indicate that it is an anchor component. Objective Views uses anchor components as a reference for alignment operations. If you want another component to serve as the anchor, hold the CTRL key and then click on another component within the selection. Objective Views transfers the gray handles from the previous component to the selected component.

Figure 44 – Component selection

To deselect a single component from a group, press the SHIFT key and click the component you want to exclude from the selection.

4.5.2 MovementWhen the application is in selection mode, you can move selected components by clicking them and dragging the mouse. When you place the pointer over a component that you can move, the mouse pointer changes to a can move pointer. If the Snap to Grid option in the Viewport is enabled, the top left corner of the component’s bounding box aligns with the grid.

Chapter 4 Product Overview 53

Page 68: Objective Views User’s Guide - Perforce

You can move the selected Components slightly using the nudge operations. These commands move the Components one unit by default and five units if you are holding the SHIFT key. These commands are as follows:

You can easily line up multiple components using the alignment operations. You can align a com-ponent by any edge or by its center. The anchor component in a multiple selection, which is distinguished by its gray selection handles, is the point of reference to which all other components in the multiple selection align. These commands are as follows:

You can also evenly space a group of components vertically or horizontally based on the position of the upper-most and lower-most component on the canvas.

Nudge Up

Nudge Down

Nudge Left

Nudge Right

Align Top

Align Middle

Align Bottom

Align Left

Align Center

Align Right

Space Across

Space Down

54

Page 69: Objective Views User’s Guide - Perforce

Objective Views allows you to resize the height, the width or both the height and width of a group of selected components. When you select a resize button, the selected components automatically grow or shrink to match the dimensions of the anchor component, which is the last component you selected. Gray handles distinguish this component from the rest of the selected components.

4.5.3 Rotation

To rotate the selected component to any angle, click the Rotate tool button .

When you place the cursor over a component that you can rotate, the pointer's shape changes to reflect this. Click the component you want to rotate or one of the components in a multiple selec-tion and then drag the mouse to rotate the component or components in place. If you hold the SHIFT key while rotating, the rotation snaps to fifteen-degree increments. The same effect occurs automatically if you select the Angle Snap option in the Viewport.

There are two predefined rotation commands that you can use to rotate components ninety degrees clockwise or counter-clockwise:

4.5.4 ScalingIf a component is scalable, the pointer turns into a directional arrow when you place the pointer over one of the control handles on the component. Depending on which selection handle you select, you can either scale the object horizontally, vertically, or both.

If you hold the SHIFT key while you scale an object, the horizontal and vertical scale factors are always equal. If you hold the CTRL key while you scale an object, the scaling performed is relative to the center of the component.

Same Width

Same Height

Same Size

Rotate Left/Rotate Right

Chapter 4 Product Overview 55

Page 70: Objective Views User’s Guide - Perforce

Objective Views also includes two operations that enable you to flip the component the opposite way either horizontally or vertically.

4.5.5 Grouping and Ungrouping Components

You can group components together to form composites with the Group button .

Select the components you want to group together and then click the Group button. Grouped com-ponents act like a single graphical component. Any changes you make to a composite affects each of its components. Because a composite is also considered a component, you can create a composite that is composed of other composites.

To ungroup a composite object, select the composite you want to ungroup and then click the

Ungroup button .

Because a symbol component is treated as a single unit, you cannot ungroup it unless you open it in Symbol Designer.

4.5.6 Ordering ComponentsThe individual components in a model understand the concept of a stacking (or layer) order, also known as an Z-order. Stacking order determines where each component is drawn in the stack. In other words, the order determines which component is drawn last. The last drawn component overwrites the components already on the canvas. Z-order is determined by the order in which the components are added to the model. The last component to be added is on top.

The user can change the Z-order using a set of order commands. The Bring Forward command moves a component one place in the direction of the top of the stack. The Move Back command moves a component one place in the direction of the bottom of the stack. A component can be moved directly to either the top or bottom of the stack using the Bring to Front or Send to Back commands.

Flip Horizontal / Flip Vertical

Bring Forward

Move Back

Bring to Front

Send to Back

56

Page 71: Objective Views User’s Guide - Perforce

4.5.7 Editing VerticesWhen the user selects a primitive component such as a line or a rectangle, Objective Views places control handles on every vertex that defines its shape. You can manipulate these vertices to change the shape of a component. However, these commands do not apply to all components. For exam-ple, if you have a rectangle component or a line with only two vertices, you cannot delete its vertices.

To move a vertex, position the pointer over a control handle. The cursor changes to signal that you can move this vertex. Click the control handle and then drag it to a new position. Release the mouse button to place the vertex at its new coordinates.

To insert a vertex, move the pointer between two control points and hold down the CTRL key. The cursor changes to signal that you can insert a vertex. Click the mouse button to place the vertex on the line segment.

To remove a vertex, move the pointer over a vertex and press CTRL. The cursor changes to signal that you can delete the vertex. Click the mouse button to delete the vertex from the component.

Chapter 4 Product Overview 57

Page 72: Objective Views User’s Guide - Perforce

4.6 SymbolsSymbols, as mentioned previously, are typically comprised of primitive components. However, a line can also be a symbol. A symbol is any component that you can annotate with a label and link to another symbol via a connection port.

Figure 45 – Symbols

You can use symbols to create detailed and annotated diagrams of linked information.

58

Page 73: Objective Views User’s Guide - Perforce

4.7 LabelsText can be added to the canvas by pressing the Text toolbar button and then clicking the left mouse button on the canvas. The text is added to the canvas at the mouse pointer location when the mouse is clicked. The added text contains a default string that can be configured by your application.

Text components are similar to rectangle components. A rectangular box is drawn around the bor-der of the text component using the line properties. If the line property is set to transparent, no border is drawn. The text component can be moved, scaled, and rotated. The four vertices that comprise the bounding rectangle of the text component can be edited. Like the rectangle compo-nent, the text component maintains its shape when a vertex is moved.

The text component can be configured to support either a single line or multiple lines of text. If the multi-line text is enabled, the automatic word break (word wrap) feature can be enabled or dis-abled. Both of these features are implemented as properties that can be configured through the Text property page.

The text can also be aligned vertically or horizontally. Vertical alignment is only applicable to single line text. The alignment properties can be configured through the Text property page.

Figure 46 – Example of Centered Text

Figure 47 – Example of right horizontal and bottom vertical alignment

Figure 48 – Example of multi-line text

Chapter 4 Product Overview 59

Page 74: Objective Views User’s Guide - Perforce

Figure 49 – Example of rotated text

60

Page 75: Objective Views User’s Guide - Perforce

4.8 Property PagesYou can associate any component with a number of properties. To determine what properties are associated with a component, you need to open the component property sheet. To access this prop-erty sheet, select one or more components and then choose the Properties command from the View menu. You can also right-click over a component and choose Properties from the shortcut (context) menu to view a property sheet for the selected component.

The component property sheet is a tabbed dialog box that displays the properties you can edit. The pages available on the property sheet depend on the type of component selected. The remainder of this section explains how to use each property page.

4.8.1 General PropertiesThis property page shows information such as the name and type of the component. The properties displayed here depend on the type of the component.

Figure 50 – General properties page

4.8.2 Edit PropertiesOn this page, you can define what actions a user can perform on a component. For instance, you can forbid stretching a component out of proportion.

Chapter 4 Product Overview 61

Page 76: Objective Views User’s Guide - Perforce

Figure 51 – Edit properties page

4.8.3 Line PropertiesThese properties define how the lines appear in the component. You can set color, style and width.

Figure 52 – Line properties page

4.8.4 Fill PropertiesThese properties define how a component is filled. The most commonly used fill is a solid fill, which is a foreground color with no hatching. You can also choose a hatched fill pattern with a background color.

62

Page 77: Objective Views User’s Guide - Perforce

Figure 53 – Fill properties page

4.8.5 Font PropertiesThese properties define how the text appears in a component. You can choose any True Type font and then apply any typographical effects such as italic or underline. Only True Type fonts are avail-able because True Type fonts are the only fonts that support rotation.

Figure 54 – Font properties page

Chapter 4 Product Overview 63

Page 78: Objective Views User’s Guide - Perforce

4.8.6 Text PropertiesThe text property page allows you to determine how the text is displayed and edited. You can use a checkbox to toggle between single line and multiple line text. If multi-line text is enabled, the Word Break checkbox allows you to toggle automatic word break on and off. Horizontal alignment can be set to left, center, or right. Vertical alignment can be set to top, center, or bottom.

Figure 55 – Text property page

4.8.7 Position and SizeThis property page displays the position and size of the given component. It is only shown when a single component is selected. The position and size is shown using the current unit of measure set for the canvas.

64

Page 79: Objective Views User’s Guide - Perforce

Figure 56 – Position and Size property page

Chapter 4 Product Overview 65

Page 80: Objective Views User’s Guide - Perforce

4.9 Canvas BackgroundThe background color for the canvas is maintained by the model. The viewport uses the back-ground color to fill the canvas prior to rendering the components. If a solid color is not sufficient for the canvas background, you can assign a background component to the model. A background component appears behind all of the other components on the canvas and cannot be directly manipulated by the user.

66

Page 81: Objective Views User’s Guide - Perforce

4.10 Canvas GridThe grid is a set of evenly spaced points on the canvas that you can use to align components. The grid is defined by horizontal and vertical spacing values maintained by the viewport. When the snap-to-grid option is enabled, the top left corner of a component is aligned to a grid point when the component is moved. The snap to grid feature can be enabled and disabled using the View|Snap to Grid menu command. Grid visibility can be turned on and off using the View|Grid menu command.

The View menu also has an Angle Snap option that you can turn on and off. The angle snap feature limits rotation of components to fifteen-degree increments.

Figure 57 – View Menu

To change the distance between the points of the grid or to change the color of the grid, you need to change properties in the Grid Properties dialog box. To open this dialog, select Grid Properties from the View menu.

Figure 58 – Grid Properties Dialog Box

Chapter 4 Product Overview 67

Page 82: Objective Views User’s Guide - Perforce

4.11 RulersYou can use the ruler to move a symbol or component to a precise position on the canvas. When you move a symbol, a shadow appears on both the vertical and horizontal rulers to indicate the exact position of the symbol.

Figure 59 – Using the ruler to move components

Rulers are helpful when exact placement is important, such as in an application for creating blueprints.

68

Page 83: Objective Views User’s Guide - Perforce

4.12 Zoom

To zoom in or out of the canvas, select the Zoom tool button .

When you place your pointer in the client area, it changes to a magnifying glass. In zoom mode, you can click the left mouse button to zoom in or the right mouse button to zoom out. You can set the zooming percentage explicitly by selecting a value from the Zoom menu.

To zoom in on a selected area of the viewport, click and hold the left mouse button while in zoom mode. When you hold the mouse button and drag in zoom mode, Objective Views draws a rectan-gle to indicate the area into which you are zooming. Once you have the rectangle positioned in an area of the viewport, release the mouse button to select the area for zooming.

Objective Views also includes a zoom to fit feature, which sets the viewport magnification so that all components in the model are visible within the viewport. To use this feature, select the Zoom to Fit tool button.

Chapter 4 Product Overview 69

Page 84: Objective Views User’s Guide - Perforce

4.13 Pan

To pan the viewport to different areas of the model, select the Pan tool button .

The pointer changes to a hand. Then, click and drag the mouse to move around the model.

70

Page 85: Objective Views User’s Guide - Perforce

4.14 Measurements and SizeThe Measurements property sheet is a tabbed dialog that allows the user to change the size of the canvas, unit of measurement, drawing scale, and coordinate mapping information. It is accessible in the Symbol Designer and in samples from the Edit|Measurements and Size menu item. You can configure this property sheet to hide pages that are not relevant to your end users. The Draw-ing Scale and Coordinate Mapping pages are advanced features that are set programmatically in most applications.

4.14.1 Size and UnitsThe Size and Units page allows the user to choose a unit of measurement and set the canvas width and height. The unit of measurement is selected from a combo box and it determines how all mea-surements for the given canvas are presented to the user. The canvas width and height are presented as real-world measurements in the current unit of measure. Changing the unit of mea-sure automatically converts the canvas width and height values. The canvas width and height is the logical area that the user can scroll through in the viewport.

4.14.2 Drawing ScaleThe drawing scale allows the user to specify what a given real-world size on the canvas represents. It influences how measurements are presented to the user. If you use the drawing scale to indicate that 1 inch = 1 foot, then all measurements are scaled by a factor of 12. If your mapping mode is MM_LOENGLISH (1 logical unit = 0.01 inch), then 1 logical unit would be presented to the user as 0.01 * 12 = 0.12 inches. This does not literally scale the object or zoom in. The drawing scale only deter-mines how measurements are taken.

The default drawing scale is 1:1, so that real-world measurements in the user’s domain match real-world measurements on the output device.

4.14.3 Coordinate MappingThe coordinate mapping defines how logical units are mapped onto device units. A coordinate mapping consists of a mapping mode, physical extents, and logical extents. See documentation for CDC::SetMapMode() in the MFC Class Library Reference for more information on mapping modes and extents.

The following table shows the relationship between each field with the Windows GDI in addition to the default value for each field.

Field Corresponding GDI function

Default Value

Mapping Mode CDC::SetMapMode() MM_ANISOTROPIC

Physical Extents CDC::SetViewportExt() X=1000, Y=1000

Logical Extents CDC::SetWindowExt() X=1000, Y=1000

Chapter 4 Product Overview 71

Page 86: Objective Views User’s Guide - Perforce

The default coordinate mapping is equivalent to MM_TEXT, where 1 logical unit equals 1 device unit (pixel). If the screen resolution is 96 dpi, then 1 logical unit equals 0.0104167 inches on the screen.

72

Page 87: Objective Views User’s Guide - Perforce

4.15 Page LayoutThe user can configure the page settings for a canvas by selecting the File|Page Setup menu item. Page settings determine how the canvas is printed and where page breaks occur. The standard Windows Page Setup dialog is used, which allows the user to select paper size, page orientation, margins, and printer. The page settings are saved with your document, and the default printer is used to initialize the page settings for a new document. Page boundaries are drawn onto the canvas as dotted lines.

Figure 60 – Page Setup dialog

Chapter 4 Product Overview 73

Page 88: Objective Views User’s Guide - Perforce

4.16 File ExportThis feature allows the user to export the canvas to a file using one of several common graphics file formats. Objective Views currently supports file export to Windows Enhanced Metafile Format and several bitmap graphic formats. The enhanced metafile format is a vector graphics format sup-ported by most Windows drawing programs.

Export to bitmap graphic formats is implemented using the Objective Toolkit SECImage class. Objective Views can export to any class derived from SECImage. Support for the following formats is always shipped with Objective Views.

Windows device-independent bitmap (DIB or BMP).

JFIF (JPEG file interchange format).

The following formats are available in Objective Toolkit Pro:

PCX (PC Paintbrush)

GIF (Graphics Interchange format)

TGA (Targa image file)

TIFF (Tagged Image File Format)

To export to a file, select the File|Export command from the menu. This opens the standard Win-dows File Save dialog. The file type can be selected from the combo box below the filename field.

74

Page 89: Objective Views User’s Guide - Perforce

Chapter 5

Chapter 5

The Symbol Designer

5.1 Purpose of the Symbol DesignerThe Symbol Designer helps you create and save symbol objects for use in your Objective Views application. With the Symbol Designer, you can define the visual characteristics of a symbol and determine where other symbols can connect to it. Once you finish designing a symbol, you can save it to disk for later use. This method enables you to create a library of symbol objects for use in any number of Objective Views applications.

Once you save a symbol to disk, you can incorporate it into your application in one of two ways. You can either add the symbol file as a custom resource if you want to compile it with your execut-able, or you can leave the symbol file on disk and then open it from your application whenever you need it. If you decide to leave the symbol on disk, you need to distribute the symbol files with your application. Consider using this method if you expect some of the symbols to change after you dis-tribute the application. Saving the symbols separately enables you to change symbols without recompiling the executable.

The Symbol Designer 75

Page 90: Objective Views User’s Guide - Perforce

5.2 Creating a SymbolA symbol is a combination of primitive graphical components. You can define specific connection points, also known as ports, to which links or symbols can connect. If you do not define any ports in your symbol, the links point towards the center of the symbol.

You create symbols in Symbol Designer with the drawing toolbar. The toolbar contains all the primitive graphical components used in Objective Views. You can select any component for use. Some of the symbols are complex, while other symbols are fairly simple.

Figure 61 – The Drawing toolbar

76

Page 91: Objective Views User’s Guide - Perforce

5.3 Setting the Symbol TypeEvery component has a string that defines its type. For primitive components, the type typically matches the default name of the component. For example, a rectangle is of type Rectangle. You can see the type string in the component property sheet on the General tab.

Objective Views allows you to assign a custom type to a symbol. Consider the following scenario:

You create a symbol that looks like a Stingray.

You assign it a type of Stingray.

Now, whenever an end-user views properties for the symbol, the type is Stingray.

Figure 62 – Symbol Type toolbar

You can set the type for a symbol in Symbol Designer. To open the Symbol Type dialog, either

select Symbol Type from the Edit menu or click the Symbol Type button on the toolbar.

After you assign a name to the type, Symbol Designer saves the type to the symbol the next time you save it.

Chapter 5 The Symbol Designer 77

Page 92: Objective Views User’s Guide - Perforce

5.4 Saving a SymbolOnce you create a symbol with Symbol Designer, you need to save it to disk. When you save a sym-bol, Symbol Designer bundles up all of the components you defined, including their ports, and creates a CODSymbolComponent object based on them. Then, this object is serialized to disk. If you open a symbol file in Symbol Designer, Symbol Designer splits the symbol object into its indi-vidual components for editing purposes.

To save a symbol:

1. Create a symbol.

2. From the File menu, click the Save option.

3. Save the symbol with the .sym file format.

Figure 63 – Saving a symbol

78

Page 93: Objective Views User’s Guide - Perforce

5.5 Alternatives to Using Symbol DesignerYou can also create CODSymbolComponent objects for your application programmatically. For example, if you already have a number of bitmap resources that you want to use as symbols in your application, you can create a symbol object and then add the bitmap of your choice to the symbol’s definition.

Symbol Designer always creates CODSymbolComponent objects. If you want to derive from CODSymbolComponent to add functionality to the symbol, you need to create the derived symbol object from the symbol object you defined in Symbol Designer. You can also create a derived sym-bol object dynamically in your application.

Chapter 5 The Symbol Designer 79

Page 94: Objective Views User’s Guide - Perforce

80

Page 95: Objective Views User’s Guide - Perforce

Chapter 6 Key A

Chapter 6

Key Architectural Concepts

6.1 Overview of Interface-Based ProgrammingInterface-based programming is a popular and convenient technique frequently used in object-ori-ented software development. An interface is a collection of pure-virtual or abstract functions that provide related functionality. An interface has no implementation and no data members. An inter-face defines a contract or protocol between the user of the interface and objects that implement the interface. Interfaces make a design more flexible because they reduce coupling between client code and an object's implementation. The same client code can manipulate objects that are completely unrelated in the class hierarchy, as long as the objects provide the client with an interface it understands.

Interface-based programming is the cornerstone of Microsoft's Component Object Model (COM). Everything in COM is an interface. All COM interfaces are derived from the root interface IUnknown, which provides the basic services required by all interfaces. Lifetime management is the first service required by COM interfaces, and is provided through the IUnknown functions AddRef() and Release(). Run-time discovery of interfaces is the other service required by COM interfaces, and is provided through the IUnknown function QueryInterface(). The QueryInterface() function is used to interrogate an object for another interface. QueryInterface() takes a GUID (Globally Unique Identifier) and returns a pointer to an interface. It is similar to the dynamic_cast operator in C++, although it is more flexible and efficient.

The same techniques that are used by COM are also very useful in straight C++ programming. In order to do interface-based programming in C++, the same basic services— reference counting and run-time interface discovery— are required. It is possible to use IUnknown to provide these ser-vices for C++ interfaces, but that results in some confusion if the C++ interfaces and the classes that implement them don’t follow COM conventions. One such convention is that all functions in a COM interface must have a return type of HRESULT, which is an important convention to follow for remote DCOM objects, but is not a convenient notation for local C++ objects. It’s also not very convenient or efficient to create your C++ objects using CoCreateInstance(). Mixing C++ objects and COM objects in the same code can also be confusing and potentially dangerous. What’s needed is a mechanism similar to IUnknown for C++ objects that doesn’t interfere with COM.

rchitectural Concepts 81

Page 96: Objective Views User’s Guide - Perforce

6.2 IQueryGuid and IRefCountThe Stingray Foundation Library (SFL) provides a mechanism for interface-based programming that provides the same types of services as COM, without interfering with COM. The IQueryGuid interface defines the QueryGuid() function, which is similar to QueryInterface(). The QueryGuid() function takes a GUID and returns a pointer to a given data type. It provides a flexi-ble substitute for the dynamic_cast operator. The IRefCount interface defines AddRef() and Release() functions that have identical signatures to those defined by IUnknown. SFL also pro-vides a guid_cast operator that is syntactically equivalent to dynamic_cast, but is implemented using the IQueryGuid interface. Refer to the Stingray Foundation Library User’s Guide for more infor-mation about IQueryGuid, IRefCount, and guid_cast.

6.3 Interfaces in Objective ViewsObjective Views separates certain key pieces of functionality into interfaces in order to increase the flexibility and reduce coupling. All interfaces in Objective Views contain the prefix IOD and are derived from the base interface IODObject. The IODObject interface mixes the IQueryGuid and IRefCount interfaces. Interfaces derived from IODObject are associated with a GUID. The follow-ing table shows a list of interfaces and their associated GUIDs.

All GUIDs are defined in the header file <stingray-installdir>\Include\Views\OdGuids.h. This file must be included in your source code in order to retrieve one of these interfaces using QueryGuid(). If your application dynamically links to the Objective Views library, you must also make sure that the GUIDs are defined in one of your application modules by including initguid.h just before OdGuids.h. If you forget to include initguid.h and your application uses the DLL version of Objective Views, references to the GUID symbols will be unresolved at link-time.

Table 4 – Interfaces and their associated GUIDs

Interface Name GUID

IODGraph IID_IODGraph

IODNode IID_IODNode

IODEdge IID_IODEdge

IODPropertyContainer IID_IODPropertyContainer

82

Page 97: Objective Views User’s Guide - Perforce

6.4 Model View ControllerModel-View-Controller (MVC) is a design pattern that provides a clear separation of responsibili-ties for graphical objects. Data, control, and presentation are treated as separate and interchangeable parts. MVC provides a concise definition for constructing reusable and extensible graphical user interface objects. The MVC design pattern separates a graphical object into three parts: model, view, and controller.

Objective Views is based on the Stingray Foundation Library’s implementation of Model-View-Controller (MVC). In addition to providing a solid foundation on which to build graphical compo-nents and document management services, MVC adds support for scrolling, zooming, coordinate mapping, and command undo and redo. The MVC framework is part of the Stingray Foundation Library, which is installed with Objective Views. Use of Objective Views does not require in-depth knowledge of MVC, but users are encouraged to read the MVC section in the Stingray Foundation Library User’s Guide.

Chapter 6 Key Architectural Concepts 83

Page 98: Objective Views User’s Guide - Perforce

84

Page 99: Objective Views User’s Guide - Perforce

C

Chapter 7

The Canvas

7.1 MVC in Objective ViewsThis section describes the Objective Views classes that are derived from MVC classes. Figure 64 shows how the Objective Views classes fit in with the MVC architecture.

Figure 64 – MVC class hierarchy

MvcViewport

MvcLogicalPart

CObject

CCmdTarget

MvcVisualComponent

MvcModel

MvcPresentationModel_T

CODModel

CODComponent

MvcVisualPart

CODViewport

MvcBufferedWrapper_T

CODBufferedViewport

MvcScrollWrapper_T

CODScrollViewport

CPropertyContainer<IODPropertyContainer, sfl::CPropertyNoopAccessor>

IMvcVirtualPart

IMvcUndoRedo

IODGraph

IODIdGernerator

MvcController

CODController

hapter 7 The Canvas 85

Page 100: Objective Views User’s Guide - Perforce

7.2 The CODModel ClassThe model is a container for the components on a canvas. The model also stores other visual infor-mation about the canvas, such as the page settings and background color. The model acts as the target for commands and supports undo and redo capabilities. When a command is executed, it performs one or more actions on the model by calling methods in the model. After a command is executed, the model stores it in the transaction model.

Models share many of the same characteristics as components, so the CODModel class derives from CODComponent. The CODModel class is a visual component that contains other visual com-ponents. Components and models share the same composite interface for adding and removing child components. Like components, models can also have properties. Another consequence of models being components is that models can be nested.

MVC models that contain visual data are referred to as presentation models and have characteris-tics that are slightly different from system models. A system model contains strictly non-visual data that is rendered by one or more viewports. A presentation model contains visual data and is responsible for rendering that data onto a display surface. Frequently, presentation models have a subject-observer relationship with a system model in which the presentation model observes the system model. In other words, the presentation model is both a subject and an observer.

For example, you might have a model that displays information contained in a database. Each visual component in the model might represent a record in the database. The CODModel object can be setup to act as an observer of a separate system model, which encapsulates the non-visual infor-mation contained in the database. When records in the database are modified through the system model, the system model sends a notification to its observers. The CODModel object receives this notification and has the chance to update the canvas accordingly.

Setting up a subject-observer relationship between an Objective Views model and a system model is optional and is easy to do. Just mix-in the IObserver interface into your CODModel derived class and override the OnUpdate() method. Create a system model class derived from MvcModel. Then add instances of your CODModel derived class (your presentation model) as observers to your sys-tem model.

7.2.1 Components and the ModelA component is a visual object that can be placed on a canvas. Anything that can be placed on a canvas and manipulated is a component, including links.

Because it contains visual information, the CODModel class derives from CODComponent. The CODComponent class supports nesting of components, so a component may have any number of child components. The model stores the components on the canvas as child components using the mechanism provided by CODComponent.

The model supplies a comprehensive set of methods that you can use to manipulate the compo-nents on the canvas. You can edit any aspect of a component via the model. For example, you can change the appearance of the component’s lines, fill, font, position and more. If you want to manip-ulate the model programmatically, use these methods. The command objects use these same methods to respond to user interaction.

86

Page 101: Objective Views User’s Guide - Perforce

7.2.2 Generation of Component IDsThe model holds a map of unique IDs that map to component objects. When you add a new com-ponent to the model, a new ID is randomly generated. The model implements the IODComponentID interface, which defines some standard methods for generating these IDs.

If you would prefer some other scheme for generating IDs, override the CreateUniqueID() method.

7.2.3 Transaction ModelEach model contains a transaction model, which supports the undo/redo capabilities of Objective Views. The transaction model logs the CODCommand objects that are created when the user per-forms an action on the canvas. They can be undone in order. For more information regarding CODCommand, see Section 12.7, “Command Classes.”

7.2.4 BackgroundThe canvas background color and appearance is maintained by the model. You can define a back-ground component or use the background color. By default, the background color is white, but you can change it to any color you wish.

The background component is any CODComponent that you would like to appear behind the other components on your canvas. You can create the background in Symbol Designer or load a pre-existing background, such as a bitmap.

7.2.5 Drag and DropYou can drag a component from one canvas to another. To manage this activity, a model needs to know whether it is the source of a drag and drop operation or the target. CODModel contains a pair of Boolean values that manage this status.

7.2.6 Page SettingsThe selected page settings determine how the model is printed. Information such as the units of measure, the size of the paper, and the margins is stored in the model as well. A class named CODPageSettings manages this information.

7.2.7 ModificationA model knows when it has been changed. Its state is reset whenever the model is serialized.

Chapter 7 The Canvas 87

Page 102: Objective Views User’s Guide - Perforce

7.3 The CODViewport ClassThe viewport contains all the logic you need to render your graphical model to the screen. It han-dles the drawing and printing of the model, as well as the scrolling, zooming, and panning. The viewport’s main function is to update sections of the screen when the model changes. When the model changes, it informs all of its observers of the change ensuring that every viewport associated with that model receives the update message. The viewport needs only to override the creation of the controller.

7.3.1 GridBy default, each viewport is overlaid with a grid to which the components snap. You can show or hide the grid and turn on or turn off the snap feature. You can also change the color of the grid so that it is visible against the background color of the canvas.

By default, the grid rows and columns are 1/8 inch apart. You can also change the distance. The grids in each viewport are independent of each other. Consequently, if you change the spacing or color of the grid in one viewport, the grids in other viewports will not be affected.

7.3.2 Angle SnapAngle Snap is related to the “snap to grid” feature. When you turn on angle snap, the rotation of components is restricted to 15 degree increments.

7.3.3 Page BoundariesAnother visual aspect of the viewport is the page boundaries. The viewport checks the page set-tings in the model to determine how the canvas will span the paper. These boundaries are drawn over the canvas to show you how the canvas will look when you print it. You can turn off this dis-play if you like.

7.3.4 Zoom LimitsThe end-user of your application can zoom in and out on the canvas. There are limits set to this zoom factor that you can change. The default is a minimum of 5% and a maximum of 1500%.

7.3.5 Selection Handle SizeAnother visual detail that you should consider is how your components appear when they are selected. The selection handles are maintained by the viewport. You can set how large they are. You can also override the methods that draw the handles to change their appearance.

88

Page 103: Objective Views User’s Guide - Perforce

7.3.6 Component TrackingTracking the manipulation of components is another responsibility of the viewport. When an end-user moves, rotates or scales a component, tracking places an outline around the component. The purpose of this outline is to convey how the component would look if you dropped it in its current position. The controller accomplishes tracking by interpreting the end-user’s actions and then ask-ing the viewport to draw the “ghosting” of the component.

7.3.7 UpdatingThe viewport observes a model. When an aspect of the model changes, it notifies all of its observ-ers. The viewport has an OnUpdate() method that receives these notifications. Then, it determines which sections of the viewport were effected by the change and redraws them.

7.3.8 ScrollingThe CODScrollViewport class extends the CODViewport class by adding scrolling capabilities. This class uses the MvcScrollWrapper_T template class to subclass the viewport and add scrollbars.

7.3.9 Off-Screen BufferingThe CODBufferedViewport class extends the CODViewport class by adding off-screen buffering. Off-screen buffering eliminates screen flicker and improves performance by rendering the image in memory before drawing on the screen. The screen updates are reduced to a single BitBlt() or paint operation.

7.3.10 Logical UnitsLogical units are abstract units stored as integers. Logical units have no real-world equivalent until they are applied to a coordinate mapping. A coordinate mapping consists of a mapping mode, win-dow extents, and viewport extents. (See documentation for CDC::SetMapMode() in the MFC Class Library Reference for more information on mapping modes).

The coordinate mapping defines how logical units are mapped onto device units. The device reso-lution determines the real-world size of device units on the output device. Combining the coordinate mapping and device resolution determines the size of a logical unit on the output device. For mapping modes other than MM_ANISOTROPIC, MM_ISOTROPIC, and MM_TEXT the map-ping mode alone is enough to determine the size of a logical unit on the output device. For example, MM_HIMETRIC mode specifies 1 logical unit to be 0.01 mm on the output device. The num-ber of pixels that 1 logical unit maps to in MM_HIMETRIC mode varies based on the device resolution. For MM_ANISOTROPIC, MM_ISOTROPIC, and MM_TEXT mapping modes, the window extents and viewport extents define a ratio that maps logical units to device units. The default coor-dinate mapping for Objective Diagram is MM_ANISOTROPIC with the extents set at a 1:1 ratio, which is equivalent to MM_TEXT.

Chapter 7 The Canvas 89

Page 104: Objective Views User’s Guide - Perforce

Given the default coordinate mapping (MM_ANISOTROPIC with 1:1 extent ratios) and a device reso-lution of 96 dpi, 1 logical unit is 1/96 = 0.0104167 inches.

You can experiment with mapping modes and extents using the coordinate mapping page in the diagram measurement property sheet (CODMeasurePropSheet). The size of a logical unit is dis-played on the property page.

7.3.11 Coordinate MappingThe coordinate mapping defines how logical units are mapped onto device units. A coordinate mapping consists of a mapping mode, window extents, and viewport extents. (See documentation for CDC::SetMapMode() in the MFC Class Library Reference for more information on mapping modes). The coordinate mapping can be set interactively through the Coordinate Mapping page in the Measurement property sheet. It can also be set programmatically in your CODViewport derived class. The methods for setting the coordinate mapping in the viewport are SetMapMode(), SetExtents(), and SetLogExtents(). CODViewport inherits these methods from MvcLogicalPart.

Here are the GDI equivalents of these MvcLogicalPart methods.

MvcLogicalPart::SetMapMode() — CDC::SetMapMode()

MvcLogicalPart::SetExtents() — CDC::SetViewportExt()

MvcLogicalPart::SetLogExtents() — CDC::SetWindowExt()

The default coordinate mapping is set in CODViewport::OnInitialUpdate() to the following values.

SetMapMode(MM_ANISOTROPIC)

SetExtents(1000,1000)

SetLogExtents(1000,1000)

This is equivalent to MM_TEXT, where 1 logical unit equals 1 device unit (i.e. pixel). If the screen res-olution is 96 dpi, then 1 logical unit will equal 0.0104167 inches on the screen.

7.3.12 Inverting the Y AxisIn order to preserve backward compatibility, in Objective Views the default direction of the Y-axis is positive Y down. Several of the Windows mapping modes such as MM_LOMETRIC, MM_HIMETRIC, MM_LOENGLISH, and MM_HIENGLISH set the orientation of the Y-axis so that it matches a Cartesian coordinate system (positive Y is up and negative Y is down). Objective Views supports both possi-ble configurations of the Y-axis.

There are a few things that must be done in order to invert the Y-axis and use Cartesian coordinates in your Objective Views application. First, determine what your virtual bounds will be. The virtual bounds are determined by the bounds of your CODModel-derived class. One way to set the virtual bounds is to assign the origin and size of the model in the Initialize() method, as shown in Example 1.

90

Page 105: Objective Views User’s Guide - Perforce

Example 1 – The CODModel Initialize method - Assigning origin and size

void CCartesianModel::Initialize(){ ... SetOrigin(-2000,2000); SetSize(4000,-4000); NormalizeBounds(); ...}

Note that the size along the Y-axis is specified as -2000. The size is always added to the origin, so 2000 + (-4000) yields -2000. Therefore, the range on the Y-axis is 2000 to -2000. The logical bounds can also be set as shown in Example 2.

Example 2 – The CODModel Initialize() method - Setting logical bounds

void CCartesianModel::Initialize(){ ... SetOrigin(-2000,-2000); SetSize(4000,4000); NormalizeBounds(); ...}

Both methods of setting the virtual bounds are equally valid and produce the same result.

It is very important to note that the bounds of components are always assumed to be normalized rectangles. This means that the top of the rectangle is always less than the bottom. In other words, RECT.top < RECT.bottom regardless of the direction of the Y-axis. This is necessary because numerous Windows API functions assume normalized rectangles (such as hit testing functions). This assumption applies to any code that manipulates logical rectangles.

Next, set the direction of the Y axis to YAXIS_UP in the viewport. This can be done in the OnInitializeUpdate() method as in Example 3.

Example 3 – The CODModel OnInitializeUpdate() method

void CCartesianViewport::OnInitialUpdate(){ ... SetMapMode(MM_LOMETRIC); SetYAxisDirection(YAXIS_UP); ...}

In order to preserve backward compatibility, the default direction of the Y-axis is positive Y down. That is why you need to explicitly set the Y-axis direction up.

There is a method in the viewport to draw the X and Y axes called DrawAxes(). You can override DrawRect() or DrawGrid() in your CODViewport-derived class and add a call to DrawAxes() in order to see the coordinate axes.

Chapter 7 The Canvas 91

Page 106: Objective Views User’s Guide - Perforce

7.3.13 Drawing ScaleThe drawing scale feature allows you to specify what a given size on the output device represents. It influences how measurements are presented to the user. If you use the drawing scale to indicate that 1 inch = 1 foot, then all measurements are scaled by a factor of 12. If your mapping mode is MM_LOENGLISH (1 logical unit = 0.01 inch), then 1 logical unit would be presented to the user as 0.01 * 12 = 0.12 inches. This does not literally scale the object or zoom in. The drawing scale only deter-mines how measurements are taken.

The default drawing scale is 1:1, so that real-world measurements in the user’s domain match real-world measurements on the output device.

7.3.14 Print and Print ViewObjective Views provides the print methods PreparePrinting() and EndPrinting() that can be used to override the standard MFC methods OnPreparePrinting() and OnEndPrinting(). These extended methods provide a variety of ways to print the view displayed on a canvas. The options are:

Print the entire canvas at the currently defined zoom value.

virtual BOOL PreparePrinting(CPrintInfo* pInfo, long percentOfNorm);

For example, if a user has set the zoom to 400% such that only a part of the canvas can be viewed at a given time, the print operation will nevertheless print the entire canvas, both the seen and unseen parts. Note that the logical size of the canvas in such a case might be large, resulting in a printout spread across a number of pages.

Print the entire canvas as X pages wide by Y pages tall.

virtual BOOL PreparePrinting(CPrintInfo* pInfo, long x_pages_wide, long y_pages_tall);

For example, let’s say the logical size of the canvas is 32 inches wide by 20 inches tall. You could specify a printout that was 4 pages wide by 2 pages tall, giving you an effective area (assuming 8.5 by 11 pages in portrait orientation), of 34 inches wide by 22 inches tall. This method assumes a normal (100%) zoom setting. You can set a property, SetIsPrintMaintainAspect(TRUE|FALSE), that either maintains the aspect ratio (the default) or stretches the canvas to fit the available print area.

Print the portion of the canvas currently in view.

virtual BOOL PreparePrinting(CPrintInfo* pInfo, long percentOfNorm, CRect rcCurView);

This feature prints exactly what is in view in the user application. It maintains the current zoom setting, and takes into account the user-defined page setup information.

Print the current view as X pages wide by Y pages high.

virtual BOOL PreparePrinting(CPrintInfo* pInfo, long percentOfNorm, long x_pages_wide, long y_pages_tall, CRect rcCurView);

This feaure is essentially a combination of items two and three above. The current view at the current zoom setting is printed as X pages wide by Y pages high.

92

Page 107: Objective Views User’s Guide - Perforce

The above features are demonstrated in the Showcase sample, located at <installdir>\Samples\Views\Showcase.

The general requirements for using these features are illustrated below, using the first of new listed features as the example:

Override OnPreparePrinting() with PreparePrinting():

BOOL CShowcaseView::OnPreparePrinting(CPrintInfo* pInfo){ ... // do things: see Showcase sample for details

SetIsPrintMaintainAspect(TRUE);

... // do things: see Showcase sample for details

if(!GetViewport()->PreparePrinting(pInfo, fZoom)) return FALSE;

// Default Preparation return DoPreparePrinting(pInfo);}

Override OnEndPrinting() with EndPriniting():

void CShowcaseView::OnEndPrinting(CDC* pDC, CPrintInfo* pInfo){ // Call this to restore the viewport state. GetViewport()->EndPrinting(pDC, pInfo);}

Chapter 7 The Canvas 93

Page 108: Objective Views User’s Guide - Perforce

7.4 The CODController ClassThe controller handles the interaction between the user and the canvas. Its purpose is to receive command and mouse messages from the user, and translate them into actions or commands to be performed upon the model or viewport. The controller is a state machine that transitions when a message is received. When the user completes a task or activity, the controller typically sends a command to the model and updates the viewport.

The controller inherits message map processing from CWnd, but it does not actually have its own window handle. Instead, the controller is plugged into the window that contains the viewport so that it can process messages for the viewport.

The controller changes its state and updates the viewport as it receives events. When a user interac-tion task is complete, the controller typically generates a command object and passes it to the model. A set of virtual methods containing the prefix Execute() take care of command creation and execution.

7.4.1 StateThe controller acts as a state machine: it alters its state so it can monitor a series of user actions. For example, when an end-user moves a component, the controller needs to perform multiple actions. A different state is assigned for each action, such as selecting, dragging, and dropping.

Because the controller performs multiple functions, it also supports multiple states. Each possible state is enumerated at the beginning of the OdController.h file. The controller keeps the current state in its m_state member variable.

By default, the state is ready. However, the state changes each time the end-user performs an action with the mouse, keyboard, toolbar or menu.

If you want the controller to perform a new action, you need to create a new state. Ensure that the new state does not conflict with an existing state.

7.4.2 Interacting with ComponentsThe activity most frequently performed by the controller is manipulating the components on the canvas. There are many means to change components. A list of the most common means follows:

7.4.2.1 Hit Testing

If the controller is given a coordinate, it will detect whether the coordinate is within one of the com-ponents on the canvas. The system uses hit testing extensively to decide which components to act upon. Three methods support hit testing:

Rollover(). This method is called when the mouse is moved. If the user moves the mouse cursor over a component, the cursor changes shape to indicate that the user can perform some action on that component.

94

Page 109: Objective Views User’s Guide - Perforce

Hit(). This method is called when the user clicks the mouse. In addition to detecting whether the cursor is over a component when the user clicks the mouse, this method also performs an appropriate action when it detects the mouse is over a component. Typically, the end-user can select a component by clicking it. This method can distinguish between the control handle of a component and the component itself. Clicking a component or its control handle prompts a number of actions to occur such as moving, rotating, scaling, or moving the vertices of a component.

DblHit(). This method is called when the user double-clicks the mouse. If the user double-clicks a component, this method performs the appropriate action. The default action is editing of a label.

7.4.2.2 Selection

The user can select multiple components to act upon. As mentioned earlier in this section, you gen-erally select components by clicking on them. The user can also select multiple components by clicking the canvas and then dragging a selection box around the components. The set of selected components is maintained in the member variable m_setSelection.

The selection changes when certain actions are performed. For example, if the user selected three components and then grouped them together to form one composite component, the selection would change from the three individual ones to the one group component. There are two methods that handle this logic: DoSelection() and UndoSelection(). DoSelection() alters the selection when an action is performed, while UndoSelection() undoes the selection.

7.4.2.3 Cursor Changes

When the user manipulates the components on the canvas, the cursor changes to reflect the current state and the user’s options, which are described in the “Hit Testing” section. There are two ways to change the cursor’s appearance. Select SetStandardCursor() to set the cursor to one of the Windows cursors. Select SetCustomCursor() to load a cursor from the application’s resources.

7.4.2.4 Mouse Cursor Restrictions

A user can restrict the mouse cursor to make precise movements. Several methods support this functionality.

AlignWithGrid() and FindClosestDeviceGridPoint(). These methods address aligning moving components to the grid.

EqualOffset(). This method restricts the manipulation of components to equal consideration in the horizontal and vertical directions. For example, if a user wanted to create a circle, he could select the Ellipse tool button and restrict its proportions.

Manhattan(). This method allows manipulation in only one direction: horizontal or vertical. This method is used to restrict lines to 90° degree angles.

Chapter 7 The Canvas 95

Page 110: Objective Views User’s Guide - Perforce

7.4.2.5 Movement

One of the primary actions the controller performs is moving components. A move begins when the user clicks a component and drags it within the viewport. The controller handles moves in one of two ways.

OLE drag-and-drop is used when the OLE libraries are initialized, which is the default behavior. OLE drag-and-drop enables the end-user to move or copy components from the current window to another window. The controller copies the components to the clipboard. The OLE system refers to the components on the clipboard when it’s determining where to move them.

Each controller has its own drop target object (CODDropTarget) to handle all the logic for dragging and dropping components within its canvas.

If the OLE libraries have not been initialized, component movement can only occur within the component’s window. Objective Views provides three methods to support this type of movement: StartMoving(), Moving(), and EndMoving(). The state machine within the controller determines which of these methods is called in response to mouse messages.

No matter how the movement is performed within the controller, once the move is complete a CODMoveCommand is created and executed to change the model.

7.4.2.6 Rotation

An end-user can also rotate a component. The logic for rotating a component is similar to the logic for moving components. Since rotation always takes place in the same window, no OLE functional-ity is necessary. There are three methods that can be called depending on the state of the controller and the processing of mouse messages. These methods correspond to the methods used for move-ment: StartRotating(), Rotating(), and EndRotating(). A CODRotateCommand is created and executed when the user finishes rotating the component.

7.4.2.7 Scaling

Scaling components is similar to moving and rotating them, except there are a few more variables. The direction that the component is scaled depends on which of the eight control handles the user clicked to start the scaling. There are also three methods that handle the scaling action: StartScaling(), Scaling(), and EndScaling(). When the user finishes scaling a component, a CODScaleCommand is created and executed.

7.4.2.8 Vertex Editing

The user can edit the individual vertices of a primitive component, such as a polygon. An interface exists to add, delete, or move a vertex.

In the controller, moving a vertex is similar to moving a component. The methods that support this action are: StartMovingVertex(), MovingVertex(), and EndMovingVertex(). A CODMoveVertexCommand is created and executed upon completion.

96

Page 111: Objective Views User’s Guide - Perforce

7.4.2.9 Text Editing

An end-user can edit a label associated with a component on the screen. Call the methods StartTextEdit() and EndTextEdit() to enable this functionality.

7.4.2.10Drawing New Components

The controller allows the user to draw a new primitive component on the screen. There is a set of methods for drawing each of the following primitives.

Line

Polyline

Polygon

Curve

Closed Curve

Rectangle

Ellipse

Which component is drawn depends on two factors: the state of the controller and the type of mouse message. After the user finishes drawing the component, a CODInsertCommand is created and executed.

7.4.2.11Inserting New Components

Methods exist for inserting components directly onto the canvas. There is a set of methods for inserting image components, text components, port components, and complete symbol components.

7.4.2.12Tracking

Tracking is the type of feedback Objective Views supplies to the end-user while he is creating or manipulating components. When the user moves the component across the canvas, tracking places an outline around the component. The purpose of this outline is to convey how the component would look if you dropped it in its current position. The controller accomplishes tracking by inter-preting the end-user’s actions and then asking the viewport to draw the “ghosting” of the component.

There are several methods that address tracking objects. There is a tracking method that manages each primitive type when the end-user is drawing a new component. The application calls the BeginTracking() method when the end-user starts moving an existing component. It calls EndTracking() when the end-user stops moving an existing component.

Chapter 7 The Canvas 97

Page 112: Objective Views User’s Guide - Perforce

7.4.2.13Linking Symbols

The controller provides an interface for defining a relationship or a link between two components. Drawing a link is like drawing a line or polyline, except the endpoints of the link are connected to either the center of a symbol or a specific port on a symbol.

7.4.3 Other CapabilitiesThis section lists additional capabilities.

7.4.3.1 Zooming

The controller detects when the user wants to zoom in or out on the canvas, or focus in on a certain section of the canvas. There is a set of methods for handling this functionality.

7.4.3.2 Panning

The end-user can pan the viewport to look at different areas. The controller interprets the state and mouse movements and then instructs the viewport on a course of action.

7.4.3.3 Context Menus

You can right-click to display a shortcut (context) menu. The content of this menu varies depending on the selection. By default, different menus are assigned to the background and to symbols. In addition to customizing menus, you can also customize the rules for displaying menus. Just over-ride the PopupMenu() method to change the behavior.

7.4.3.4 Coordinate Transformations

The mouse coordinates that are supplied through mouse messages are always in device coordi-nates. To convert these coordinates into the logical coordinate system, the viewport requires methods similar to DPtoLP() and LPtoDP(). The controller supplies two utility methods for this purpose: VpDPtoLP() and VpLPtoDP().

7.4.3.5 Command Creation

The end result of many of user actions is a command object. Using command objects enables you to log user actions into the model’s transaction model for undo and redo purposes. When you enable this functionality, any change that affects the model is bundled into a command object. For exam-ple, a move would become a command object while a zoom would not.

98

Page 113: Objective Views User’s Guide - Perforce

You do not have to wait for the user to do something to create a command object. There are many utility methods in the controller for creating commands whenever you wish. These methods are all in the form of ExecuteXCommand(). If you call one of these, a command will be created and exe-cuted and the model will be changed. If the user decides to undo a command, the last one you created will be undone.

Instead of using commands, you can always call the corresponding methods in the model.

Chapter 7 The Canvas 99

Page 114: Objective Views User’s Guide - Perforce

7.5 Graph NavigationMany applications must navigate the symbols and links on the canvas as a directed or undirected graph. A graph is a set of connected edges and nodes, where an edge defines a path between two nodes. The edges that are connected to a node are incident to the node. The degree of a node is defined as the number of edges incident to the node. Each node in a directed graph has 0 to N edges entering it and 0 to N edges leaving it. In an undirected graph, no distinction is made between edges leaving a node and edges entering a node. Nodes that share an edge are connected by the edge and are said to be adjacent. Two nodes are connected if there is a path of edges and nodes between them.

Figure 65 – Graph navigation example.

In the figure shown above, the following node pairs are adjacent: (A,B), (A,C), and (B,D). We say that Node A is adjacent to Node B because the directed edge <A,B> leads from A to B. Conversely, Node B is adjacent from Node A because the directed edge <A,B> goes from A to B. Node D is con-nected from Node A because D is reachable from A.

7.5.1 Graph Navigation InterfacesObjective Views defines a set of interfaces that allow applications to navigate the components on a canvas as a collection of nodes and edges. These interfaces are mixed into existing concrete classes in the library to implement the graph navigation capabilities. The default implementation treats the model as a graph, symbols as nodes, and links as edges. However, these interfaces can be imple-mented by any component subclass, so it is possible to create entirely new types of components or symbols that behave as either nodes or edges.

Some of the graph navigation functions use component IDs to retrieve nodes or edges in the graph. The component IDs used for graph navigation are the same ones used to uniquely identify compo-nents on the canvas. Component IDs are generated by the CODModel object and are unique within a model.

100

Page 115: Objective Views User’s Guide - Perforce

The graph navigation functions return interface pointers for edges and nodes. These functions always increment the reference count on the associated object using AddRef() before returning the interface pointer to the caller. The caller must decrement the reference count using Release() when the interface pointer is no longer needed.

Each graph navigation interface is assigned a GUID, so classes that support the IODObject inter-face can be interrogated for a specific interface using QueryInterface().

7.5.2 Node and Edge CollectionsGraph navigation methods that return multiple edges or nodes use the IODEdgeCollection and IODNodeCollection interfaces. These minimal collection interfaces provide a type-safe way for the graph navigation routines to add objects to a collection and determine if an object belongs to a col-lection. Any type of collection that supports these interfaces can be used with the graph navigation interfaces. Array and map implementations for these interfaces are provided with the library, but developers can easily add their own collection types by mixing these interfaces into their own col-lection classes.

7.5.3 IODGraph InterfaceThe IODGraph interface is implemented by the CODModel class. It contains methods for retriev-ing nodes and edges in the graph using unique component identifiers. The GetNode() method takes an CODComponentId and returns a pointer to an IODNode interface. The GetEdge() method is identical to GetNode(), except that it returns a pointer to an IODEdge interface.

7.5.4 IODNode InterfaceThe IODNode interface is implemented by the CODSymbolComponent class. It contains methods for retrieving incident edges and adjacent nodes. There are functions to support both directed and undirected node and edge traversal. Directed edge functions have names that indicate whether they look for edges entering or leaving the node. Directed node functions have names that indicate whether to look for nodes that are adjacent to or adjacent from the given node. Undirected tra-versal functions have names that do not indicate a direction.

The following example takes the currently selected node and finds all of the nodes adjacent from the node. Example 4 is an example of directed node traversal. It finds nodes that are pointed to by the currently selected node.

Example 4 – Directed node traversal

void CMyController::OnOdNodesAdjacentFrom() { CODComponent* pComp = NULL;

if (GetSelection()->GetSize() == 1) pComp = GetSelection()->GetAt(0);

if (pComp != NULL) { IODNode* pINode;

Chapter 7 The Canvas 101

Page 116: Objective Views User’s Guide - Perforce

pINode = guid_cast<IODNode*>(pComp); if(pINode != NULL) { pINode->GetNodesAdjacentFrom(&m_animateNodes); m_nAnimateCounter = 10; SetTimer(ANIMATE_TIMER, 50, NULL); pINode->Release(); } }

7.5.5 IODEdge InterfaceThe IODEdge interface is implemented by the CODLinkComponent class. It contains methods that return the nodes that are adjacent to the link. Each directed edge has a head and a tail node. This interface has a GetHeadNode() to retrieve the head node and a GetTailNode() method to retrieve the tail node. The function GetNodesAdjacent() returns both adjacent nodes without regard to direction. This interface also has a GetWeight() virtual method that can be overridden by develop-ers for implementing weighted edges. Weighted edges typically represent a distance or some other application specific quantity, and can be used to implement algorithms such as shortest path.

102

Page 117: Objective Views User’s Guide - Perforce

7.6 Binary Space Partitioning TreesA binary space-partitioning (BSP) tree is used to divide the canvas into sections that can be quickly searched. Every top-level component in a model gets placed into the tree. Then, the tree can be quickly searched to determine what components contain a point, or are within or intersect a rectan-gle of space.

Figure 66 – Binary space positioning (BSP) class hierarchy

7.6.1 CODBspTreeThis class provides the interface for the binary space-partitioning tree. It has a pointer to the root level node of the tree and methods to add or remove components from the tree. This class can also be given a section or point of space and it returns all of the top-level components in that space.

7.6.2 CODBspNodeThis class represents one node in the BSP tree. A node contains pointers to its child nodes that fur-ther divide the space represented by the tree. Component information is usually stored on the leaves of the tree, providing an excellent level of granularity.

7.6.3 CODBspRectBSP rectangles are derived from CRect and add the capability to store a pointer to a component. These rectangles are what are actually stored in a BSP tree, and represent a piece of the bounding box of a component.

CODBspNode

CRect

CODBspRect

CODBspTree

Chapter 7 The Canvas 103

Page 118: Objective Views User’s Guide - Perforce

7.7 OLE Drag-and-DropObjective Views allows you to use OLE drag-and-drop for moving components. You can only use this functionality if you initialized the OLE libraries in your application. To initialize the libraries, add a call to AfxOleInit() in the InitInstance() method of your application object.

Using OLE drag-and-drop enables the end-user to drag components from one window to another. It also supports the dragging copy operation. The dragging copy operation copies components the end-user is dragging to the new location instead of moving them. If you do not want to support this functionality or load the OLE DLLs, do not initialize OLE. When OLE is not initialized, the standard drag-and-drop capabilities included in the CODController object are available.

Figure 67 – OLE Drag-and-Drop class hierarchy

7.7.1 CODDropSourceThe drop source is created in the controller when the user initiates a move operation. It is responsi-ble for determining when a drag operation begins, in addition to providing feedback during the drag operation, and determining when the drag operation ends.

7.7.2 CODDropTargetThe drop target handles the receiving end of the drag-and-drop operation. It determines where components are dropped in the window. Then, it performs the move or copy when the drag opera-tion ends.

7.7.3 OLE Drag-and-Drop and MetafilesMetafile components can also be added to the canvas from other Windows applications using OLE drag-and-drop and the clipboard. Any Windows application that supports the CF_ENHMETAFILE format for OLE drag-and-drop or clipboard operations can be used to copy metafiles onto the can-vas. When a metafile is dropped onto the canvas, a CODMetafileComponent is created to contain the new metafile. For example, you can drag-and-drop Visio symbols into your Objective Views applications.

CObject

CCmdTarget

COleDropSource

COleDropTarget

CODDropTarget

CODDropSource

104

Page 119: Objective Views User’s Guide - Perforce

Objective Views also supports the CF_ENHMETAFILE format when it copies components to the clip-board or starts an OLE drag operation. This allows Objective Views components to be copied to any Windows application that supports pasting or dropping of metafiles. For example, you can drag-and-drop one or more symbols from your Objective Views application into Microsoft Word. This allows a great deal of interoperability with other Windows applications.

By default, support for the enhanced metafile format is enabled for clipboard and drag- and-drop operations. It is possible to disable support for enhanced metafile format by calling the function EnableClipboardEnhMetafiles(). Example 5 is an sample of a controller class that disables sup-port for the enhanced metafile format.

Example 5 – Disabling enhanced metafile support

CMyController::CMyController(CODViewport* pViewport){ EnableClipboardEnhMetafiles(FALSE);}

Chapter 7 The Canvas 105

Page 120: Objective Views User’s Guide - Perforce

106

Page 121: Objective Views User’s Guide - Perforce

Chap

Chapter 8

Components

8.1 ComponentsAll objects that exist in an Objective Views canvas are visual components. A component is an object that has properties, two-dimensional bounds, and that can draw itself onto a device context. The Stingray Foundation Library (SFL) provides a class called MvcVisualComponent, which provides the basic definition of a visual component used by Objective Views. Objective Views extends the basic definition that SFL provides for a visual component, providing a hierarchy of component classes that can be used on a canvas.

ter 8 Components 107

Page 122: Objective Views User’s Guide - Perforce

8.1.1 Component Class HierarchyThe class hierarchy of Objective Views component classes is shown in Figure 68.

Figure 68 – Component class hierarchy

CODLineComponent

CODImageComponent

CObject

CCmdTarget

MvcVisualComponent

CODPointComponent

CODCurveComponent

CODClosedCurveComponent

CODComponent

CODEllipseComponent

CODRectComponent

CODMetafileComponent

CODPolygonComponent

CODPortComponent

CODCirclePort

CPropertyContainer<IODPropertyContainer, sfl::CPropertyNoopAccessor>

CODSymbolComponent

CODLinkComponent

CODWndComponent

CODControlComponent

CODEditComponent

CODButtonComponent

CODTextComponent

CODLabelComponent

IODVertices

CODRichEditComponent

CODListBoxComponent

CWnd

CEdit

CODTextCompEdit

CODSprite

CODComponentTracker

CODComponentSetTracker

CODSymbolConverter

CODConverterException

108

Page 123: Objective Views User’s Guide - Perforce

8.2 Component Essentials

8.2.1 CODComponentCODComponent is the base class for all visual components and models in Objective Views. A com-ponent has properties, two-dimensional bounds, and can draw itself onto a device context. Every component is associated with a unique ID and component type. Components maintain a transfor-mation matrix used to calculate points based on movement, rotation, and scaling.

The CODComponent class is derived from the SFL class MvcVisualComponent. The MvcVisualComponent class implements the IVisual and IBounds2D interfaces, so an MvcVisualComponent is essentially a rectangular object with two-dimensional bounds that can draw itself to a device context. CODComponent also inherits from the CODPropertyContainer class, which implements the IODPropertyContainer interface. The IODPropertyContainer inter-face provides components with a generic way to access properties. Properties help to define the appearance and behavior of a component. Font information, line attributes, fill attributes, and edit behaviors are stored as properties. Developers can easily add custom properties to classes derived from CODComponent.

A component can also be composite. A composite component is a complex object that comprises other simpler components. Every component keeps a list of child components that determine its appearance. The CODModel uses this scheme to maintain all the components on the canvas.

8.2.2 Component PropertiesEach component can have zero or more properties associated with it. Properties help to define the appearance and behavior of a component. The CODComponent class implements the IODPropertyContainer interface for accessing the properties it contains. Property values are stored as a list of pointers to property value objects, which are instances of classes derived from CODProperty. The property values are cached in order to avoid duplication of information and reduce memory overhead.

The description of a property (ID, name, description, etc.) is stored separately from the property value. The description of a property (meta property) is defined by the IProperty interface. Property descriptions are registered in a static property map associated with each component class. Keeping the property description separate from the property value is necessary in order to avoid duplicat-ing the name, description, and other property information for each value.

The CODComponent class defines methods for directly accessing its list of property value objects (instances of CODProperty derived classes). The GetProperty(), SetProperty(), and ChangeProperty() methods provide raw access to the list of property value objects maintained by a component. These methods are provided only for backward compatibility and should be avoided. Users should use the IODPropertyContainer interface for accessing a component’s prop-erties instead.

Chapter 8 Components 109

Page 124: Objective Views User’s Guide - Perforce

Developers can add their own custom properties to a class of components. The RegisterProperty() method can be used to add property descriptions to the static property map. Registering a property makes it available to all instances of a given component class. Chapter 9 covers properties in more detail.

8.2.2.1 Component IDs

Each component has an ID that distinguishes it from the other components on the canvas. This ID consists of a long integer. It is generated randomly by the model.

8.2.2.2 Type

This identifies the type of component. The type is set for primitive components. For example, a rectangle component is automatically assigned a type of “Rectangle.” You can change the type of a component by calling its SetType() method.

When you create symbols in Symbol Designer, you can open the Symbol Type dialog by selecting Symbol Type from the Edit menu.

8.2.2.3 Name

Every component has a name. By default, the name is the same as the type. Give meaningful names to components so you can distinguish among components in your model. You can set the name through the component’s SetName() method.

8.2.3 Parents and ChildrenA component can have children. They are stored in a component set in the parent. However, the set can be empty if the component has no children. There are many methods you can use to add a child to a component or to access a child from a component. When you add a child, ensure that there is a subcomponent in memory so you only need to pass a pointer to the component.

A component can also have a parent. When a component is added to a composite as a child, the composite becomes the parent. If a component is at the top-level of the model, its parent is the model.

8.2.4 Component TransformsIf a component has not been moved, rotated or scaled directly, it will not have a transformation matrix. Typically, a child component uses its parent’s transform.

When an end-user manipulates a component on the screen, a transformation matrix is created to record what occurred to the component. This matrix is used to transform the points that define the coordinate just before it is drawn.

110

Page 125: Objective Views User’s Guide - Perforce

8.2.5 Control PointsThere are nine control points on a component. They are situated around the component’s bounding box: one on each corner, one halfway along each side, and one in the center of the component. Con-trol points set the origin for spatial calculations such as rotation and scaling. The points along the edges of the bounding box are also used as the default grab handles.

8.2.6 HandlesThe grab handles appear on a component when it is selected by the end-user. These handles allow the end-user to see what is selected and then scale the component or move its vertices.

On most components, the grab handles are the eight control points around the edges of the bound-ing box. However, for lines and curves, the handles appear on the vertices of the component, which allows the end-user to move them around.

You can place any primitive component in “edit vertices mode” so that handles appear on the indi-vidual vertices of the component, which allows the end-user to change its shape.

8.2.7 RegionEach component knows the amount of logical space it fills as defined by the canvas. The regions of a component’s children are combined with its own to form one logical region. This region is used extensively for hit testing and screen invalidation. The bounding box for a component is calculated from this region object.

8.2.8 User DataA component also has a generic CObject pointer that you can set to hold anything you like. There is no specific use for this pointer other than to allow the programmer to associate application spe-cific data with a component. The object assigned to the user data pointer must be derived from CObject and support MFC serialization.

Chapter 8 Components 111

Page 126: Objective Views User’s Guide - Perforce

8.3 Shape Components

8.3.1 CODPointComponentMany of the primitive components in Objective Views are based on geometrical shapes that depend on a set of vertices. CODPointComponent contains all the logic for maintaining the points of components such as lines, polygons and curves.

If you needed to create a new component, such as a triangle, you would use CODPointComponent as your base. If you wanted to create a component that doesn’t use vertices, you would use CODComponent as a base. Note that the CODSymbolComponent class is derived directly from CODComponent.

8.3.2 CODCurveComponentThe curve component defines a series of control points for a bezier curve. Like a line, a curve can be assigned a color and style.

8.3.3 CODClosedCurveComponentThe closed curve component is derived from the curve component. Like a curve component, it defines a series of control points to form a bezier curve. Since the curve is always closed, it can be assigned a fill color and style as well as a line color and style.

8.3.4 CODEllipseComponentThe ellipse component defines a series of control points that form a bezier curve in the shape of an ellipse. The ellipse component remains an ellipse even when the user moves its points. Like a closed curve, the ellipse can be assigned a line color and style as well as a fill color and style.

8.3.5 CODEllipseComponent2This class provides an alternative to the CODEllipseComponent. It uses the Windows GDI Ellipse() function to draw the ellipse instead of approximating the ellipse using bezier curves. The Windows Ellipse() function does not support rotation, so it is not possible to rotate CODEllipseComponent2 objects. The advantage to using this class is that in certain situations it will scale more accurately than CODEllipseComponent, because the CODEllipseComponent approximates the ellipse using bezier curves.

8.3.6 CODLineComponentThe line component defines a series of line segments. A line can have a color and style.

112

Page 127: Objective Views User’s Guide - Perforce

8.3.7 CODRectComponentThe rectangle component defines a series of line segments that form a rectangle. A rectangle remains a rectangle even when you manipulate its vertices. Like a polygon, a rectangle can be assigned a line color and style or a fill color and style.

8.3.8 CODPolygonComponentThe polygon component defines a series of line segments to form a polygon. You can assign a poly-gon line color and style, and fill color and style.

Chapter 8 Components 113

Page 128: Objective Views User’s Guide - Perforce

8.4 Text Components

8.4.1 CODTextComponentThe text component defines a single line of text within a rectangle. You can assign a text component a line color and style as well as a fill color and style. The font used to draw the text is a property of a text component. It includes a color and point size.

8.4.2 CODTextCompEditThis is derived from CEdit and is the edit box that pops up when the user changes the text of a component in-place on the viewport. It performs some special processing of key messages so as not to confuse the controller.

8.4.3 CODLabelComponentA label component is a special case of a text component. A label is a text component that is associ-ated with a CODSymbolComponent. It is not only a child of the symbol. The end-user can position it at an arbitrary point relative to the symbol. You can also set it to a specific orientation with respect to the symbol. For example, you could set the label so it is centered below the symbol.

In addition to maintaining the same properties as a text component, a label also maintains an orien-tation with respect to a symbol.

114

Page 129: Objective Views User’s Guide - Perforce

8.5 Windowed ComponentsObjective Views supports windowed components such as edit controls, list boxes, and buttons. The CODWndComponent class is the base class for all window components. CODWndComponent is derived from CODComponent and maintains a window handle as a member variable. The CODWndComponent class defines a virtual CreateWnd() method which is overridden by derived classes. Derived classes override the CreateWnd() method and create the appropriate type of window.

The CODControlComponent class is the base class for control components such as edit controls, list boxes, and buttons. It extends the CODWndComponent class by adding a control ID member vari-able. The following classes are derived from CODControlComponent and support Windows controls.

CODEditComponent – Edit controls

CODButtonComponent – Button controls

CODRichEditComponent – Rich edit controls

CODListBoxComponent – List box controls

Chapter 8 Components 115

Page 130: Objective Views User’s Guide - Perforce

8.6 Image ComponentsThe CODImageComponent class encapsulates drawing of a bitmap image. It contains an SECDib object that can be loaded from a disk file, from an application resource, or from memory. The images are stored in a cache in order to prevent multiple copies of the same image from consuming memory. The file name or resource ID is used to identify images in the cache.

Image components cannot be assigned line or fill properties; however, they can be made transpar-ent by assigning a transparent color. The CODSprite class is used to provide transparency for DIBs contained by CODImageComponent objects.

The hierarchy for image classes is shown in Figure 69.

Figure 69 – Image class hierarchy

8.6.1 CODDibThe DIB class handles the loading of and storage of images as device independent bitmaps. It also implements the code to make one color in a bitmap transparent when it is drawn.

MvcVisualComponent

CCmdTarget

CObject

CList

CODImageCache

CODSprite

SECImage

SECDib

CODImageEntry

CODDib

CODComponent

CODPointComponent

CODImageComponent

CODMetafileComponent

IRefCount

116

Page 131: Objective Views User’s Guide - Perforce

8.6.2 CODImageCacheThe image cache stores bitmaps for the image components. Suppose you had one thousand sym-bols in your model that incorporated an image of a stingray. Obviously, it would require a large space in memory to store one thousand stingray bitmaps. Fortunately, you can use the image cache to store one copy of a bitmap and let multiple components reference it.

Use of the image cache is not restricted to image components. You can store images from any source in the cache.

8.6.3 CODImageComponentThe image component contains a bitmap. The points stored in the component define the edges of the bitmap. This component cannot be assigned a line or fill property; however, you can assign it a color so that the bitmap is transparent when the user draws it.

8.6.4 CODImageEntryAn image entry is the data stored in the image cache. Each image entry holds a device independent bitmap that is ready for use. Image entries are reference counted, so if a program ceases to use an image, it is freed from memory.

8.6.5 CODMetafileComponentThe metafile component encapsulates a Windows Enhanced Metafile. The metafile can be loaded from a file, as an application resource, or be copied from a handle. The Windows Enhanced Meta-file Format (EMF) is a vector graphics format that stores a list of GDI drawing commands. Each record in the file represents a GDI drawing function and its parameters. When the metafile is played onto a device context, the records in the metafile are executed. The metafile component draws itself by playing the metafile into the bounding rectangle of the component.

8.6.6 CODSpriteThe sprite class wraps a DIB class and implements the transparency feature. It sets up the DIB so that a certain color does not get drawn when the rest of the bitmap does.

8.6.7 Using Metafile ComponentsThe CODMetafileComponent class encapsulates a Windows enhanced metafile as an Objective Views component. The Windows metafile format is a vector graphics format that consists of a list of GDI commands. A metafile is rendered by playing the list of GDI commands onto a device context. For simple to moderately complex graphics, metafiles are more efficient in terms of space and per-formance. Unlike bitmaps, metafiles do not distort when scaled. Unless your graphics are complex in nature, it is recommended that you use metafiles instead of bitmaps.

Chapter 8 Components 117

Page 132: Objective Views User’s Guide - Perforce

Metafile components can be loaded from a file, an application resource, or from an existing metafile handle. The metafile component is derived from CODPointComponent and always contains four points that define a bounding rectangle in local coordinates. The local points can be set with the function CODMetafileComponent::SetLocalBounds(). The component’s transformations are applied to the local points to yield the world points, which determine the bounding rectangle in which the metafile is played. The logical bounding rectangle in which the metafile is drawn can be acquired by calling the GetBounds() function. Example 6 demonstrates loading a metafile from a disk file, setting the local bounds, and moving it.

Example 6 – Working with metafile components

void CMyController::OnFoobar(){ CODMetafileComponent* pMetafile = new CODMetafileComponent(); pMetafile->LoadFromFile(“foobar.emf”); pMetafile->SetLocalBounds(CRect(0,0,100,100)); pMetafile->Translate(50,25); ExecuteInsertCommand(pMetafile);}

In order to draw a metafile component at the original size of the metafile, you need to explicitly call SetLocalBounds() or SizeToFrame(). The metafile contains a header that indicates the original frame size of the graphic in MM_HIMETRIC units. This size must be converted into logical units for your canvas. To get the original frame size in logical units for your canvas, call CODMetafileComponent::GetLogFrame() passing it a pointer to the IODRuler interface for your viewport. Then call SetLocalBounds(), passing it the resulting rectangle. Alternatively, you can call SizeToFrame() and have it scale the metafile component to the original frame size. Example 7 demonstrates loading a metafile from an application resource and setting its size to the original metafile size.

Example 7 – Setting the size of a metafile

void CMyController::OnFoobar(){ CODMetafileComponent* pMetafile = new CODMetafileComponent(); pMetafile->LoadFromFile(IDR_FOOBAR); CRect rcFrame; pMetafile->GetLogFrame(GetCanvasVp()->GetRuler(), rcFrame); pMetafile->SetLocalBounds(rcFrame); ExecuteInsertCommand(pMetafile);}

118

Page 133: Objective Views User’s Guide - Perforce

8.7 Line EndpointsEndpoints are the small objects that mark the end of line components. Objective Views includes three styles of endpoints: arrow, circle, and diamond. Endpoints are lightweight objects that know how to draw a simple shape. You can use these endpoints with the lines or links by calling SetSourceEndpoint() or SetTargetEndpoint().

Unlike other visible objects on the screen, endpoints are not derived from CODComponent. They are small, simple objects that do not need to support the overhead of a robust component since they cannot be selected or manipulated by the user. Instead, CODEndpoint is derived directly from CObject.

Endpoints only maintain a few pieces of information: their size in logical units and the vertices of their line segments. The line vertices keep the endpoint on the line when it is moved or rotated. The line component establishes the location of these vertices before it asks the endpoint object to draw or calculate the region it requires on the screen.

Unless it is told otherwise, a CODEndpoint-derived object draws itself using the current settings in the device context. Before calling the OnDraw() method of the endpoint, ensure that you have either set up the device context or prepared the endpoint object to set up the device context. Figure 70 shows the hierarchy for endpoint classes.

Figure 70 – The endpoint class hierarchy

8.7.1 CODEndpointThis is the base class for all endpoints in Objective Views. Because endpoints are simple objects, they do not need to carry the overhead of an entire CODComponent. Instead, a CODEndpoint accompanies the line component to which it belongs. To create your own endpoint for a line, derive a new class from CODEndpoint and then implement the drawing code.

8.7.2 CODArrowEndpointThis is the standard arrow endpoint. It draws the shape of an arrow, a simple polygon, at the end of a line.

CObject

CODEndpoint

CODCircleEndpoint

SECDiamondEndpoint

CODArrowEndpoint

Chapter 8 Components 119

Page 134: Objective Views User’s Guide - Perforce

8.7.3 CODCircleEndpointThis is the standard circle endpoint. It draws a circle at the end of a line.

8.7.4 CODDiamondEndpointThis is the standard diamond endpoint. It draws a diamond, a simple polygon, at the end of a line.

8.7.5 Creating Your Own EndpointsIf you do not want to use one of the endpoints provided with Objective Views, you can create your own. Simply derive a new object from CODEndpoint and override OnDraw() and CalculateRgn(). Refer to the existing endpoints, CODArrowEndpoint and CODDiamondEndpoint, for examples.

To create a customized endpoint, you need to calculate how your geometry appears in relation to the line for both the OnDraw() and CaclulateRgn() methods. In CODArrowEndpoint, this is cal-culated in the CalculateArrow() method. CalculateArrow() acquires the angle and position of the line segment that ends in an endpoint and then creates a transformation matrix. It uses the matrix and arrow size values to determine how to display the polygon. The values for the vertices of the polygon are used in both the region calculations and in the drawing of the endpoint.

120

Page 135: Objective Views User’s Guide - Perforce

8.8 Port Components

8.8.1 CODPortComponentA port component defines a point on a CODSymbolComponent where you can establish a connec-tion to another symbol. The CODPortComponent class does not have a visual representation. You can use it to define the connection points on a symbol without changing its appearance. Alterna-tively, you can derive a class from it so the port appears on the screen.

8.8.2 CODCirclePortA circle port is derived from CODPortComponent. It is represented by a circle with a cross through it. Symbol Designer uses this symbol to define connection points on your symbols.

Chapter 8 Components 121

Page 136: Objective Views User’s Guide - Perforce

8.9 Other Types of Components

8.9.1 CODAnchorSymbolAnchor symbols provide hyperlinks to other objects. This class contains a virtual Open() method that defines the behavior when the symbol is double-clicked. Derived classes, such as CODDocViewAnchor, override Open() in order to implement the actual jump. The visual represen-tation of the anchor symbol is defined by its child components.

8.9.2 CODDocViewAnchorThis class derives from CODAnchorSymbol. It provides a hyperlink to an MFC document using a filename. It is associated with an MFC document template, which is used to create a new document and view when a jump occurs.

122

Page 137: Objective Views User’s Guide - Perforce

8.10 Component TrackingWhen a component is moved, rotated, or scaled the user is provided with visual feedback while the action is taking place. Components draw a tracking outline of themselves as they are moved. Links that are connected to a component that is tracking are also tracked.

Component tracker objects are used in order to avoid changing the original state of a component during tracking. A component tracker serves as a kind of proxy for the component while it is track-ing. The component tracker is transformed (i.e. moved, scaled, or rotated) instead of the component itself.

8.10.1 CODComponentTrackerThe component tracker class is responsible for drawing a component when it is manipulated. It does not monitor any links or other dependents that are associated with the component. The com-ponent tracker is used whether OLE drag and drop is used or not.

8.10.2 CODComponentSetTrackerThe component set tracker is responsible for tracking a whole set of components. It also tracks dependents. For example, if you had a link attached to component, CODComponentSetTracker would track it in addition to the component. The component set tracker is used whether OLE drag and drop is used or not.

Chapter 8 Components 123

Page 138: Objective Views User’s Guide - Perforce

8.11 TransformsTransforms, also known as transformation matrices, are an essential part of Objective Views. Trans-formation matrices keep track of how a component has been manipulated (moved, rotated and scaled). Every component can have a transformation matrix For CODPointComponents, the verti-ces of the components are transformed by the matrix before they are drawn to position the component. Figure 71 shows the class hierarchy for transforms.

Figure 71 – Transform class hierarchy

8.11.1 Transform ClassesObjective Views has two transform classes.

8.11.1.1CODTransform

This class encapsulates a two-dimensional transformation matrix. Manipulating these matrices is a simple process. You can change the matrix to reflect movement, rotation, and scaling. You can also combine matrices together to combine their effects. The transform class also provides methods for transforming points using the matrix.

8.11.1.2CODTransformStack

The transform stack is used to keep track of the effects of nested matrices. For example, a composite component might have children and grandchildren that have their own transformation matrices. To aid in the drawing of these components, a stack of transformation matrices and combinations of matrices are kept for drawing components at different levels in the hierarchy.

The transform stack is an internal detail of the Objective Views drawing system. In all likelihood, you will not need to use it.

8.11.2 Transformation MatricesTransformation matrices are used in two-dimensional graphics to apply movement, rotation, scal-ing and shearing to a series of points. Objective Views uses transformation matrices frequently to manipulate graphical components. For example, when you move a polygon across the screen, you

CObject

CODTransform

CNoTrackObject

CODTransformStack

124

Page 139: Objective Views User’s Guide - Perforce

are not changing the values of its vertices, you are changing the transformation matrix associated with the component. When the polygon is ready to draw itself, the transformation matrix is applied to the vertices of the polygon and each line appears in the proper place in the window.

If we were just moving the components around the screen, the overhead necessary to support a transformation matrix might be large. After all, the end result is that all of the vertices in a compo-nent have an integer offset added to them. The matrices are valuable for other operations: rotation, scaling and shearing. Although the points of components are stored in integer form, these three activities require floating point math. After several complex operations, the error resulting from rounding floating point results to integers for storage becomes apparent. This is most apparent when you use the undo and redo capabilities of Objective Views. If you use the undo and redo capability without using transformation matrices, a rotated component is not set to its original position when you undo the rotation due to a rounding error.

A transformation matrix is three by three. Because we are working in two dimensions, the last row is not used.

Figure 72 – Transformation matrix

In two-dimensional space, a set of x and y coordinates can be transformed using the formula shown in Figure 73.

Figure 73 – Formula for transforming a set of x and y coordinates

The individual elements have different meanings for different operations. C and F determine the translation (or movement) of a point. A, B, D and E address the rotation, scaling and shearing of a point.

For more information on transformation matrices, look up the XFORM structure in the Visual Stu-dio online help. XFORM is used in Windows to perform transforms when drawing to a device context.

8.11.3 Using CODTransformThe CODTransform object encapsulates a two-dimensional transformation matrix. To save space, only the first two rows of the matrix are stored. The class contains many methods that make it eas-ier to use transformation matrices. You can change the translation, rotation and scaling that the matrix represents. The class also includes overloaded operators that address matrix multiplication. When you are ready to transform a point or series of points, call the appropriate transform method in this object.

Chapter 8 Components 125

Page 140: Objective Views User’s Guide - Perforce

8.11.4 Components and Transformation MatricesEvery component can have a transformation matrix. When that component is manipulated by either the user or the programmer, its transformation matrix is updated. If the component did not have a transformation matrix initially, one is created for it. You can access the current transforma-tion matrix of any component by calling GetTransform(). If the component has no matrix, this method returns NULL.

Because the original points that comprise the component remain the same, you are changing the coordinate system of the component, not the coordinates themselves. For example, if you called Translate(50,50) on a rectangle component with its corners at (0,0) and (100,100), the application would create a transformation matrix that holds all the translation information for the component instead of moving the corners of the rectangle to (50,50) and (150,150). When the transformation matrix is created, the corners of the rectangle remain at (0,0) and (100,100), but the transformation matrix is applied to the coordinates so the rectangle appears at (50,50) to (150,150). The rectangle’s set of coordinates has not changed, but the meaning of the coordinates has changed. You have altered the coordinate system of the rectangle.

A transformation matrix for a component transforms the points of the component from its own, local coordinate system to its parent’s coordinate system. In this particular case, the transformation matrix is transforming (0,0) and (100,100) from the rectangle’s own local coordinate system to the world coordinates of the canvas, which appear as (50,50) and (150,150).

8.11.5 Child ComponentsNow consider adding a child component to the rectangle discussed in the last section. Let’s add another rectangle to the component to make it a composite component, which is a component com-prising several different primitive components. In this case, the original rectangle is the parent and the new rectangle is the child.

Now let’s position this new child rectangle at the upper left corner of the parent rectangle and then extend to the center. The composite component appears as in Figure 74.

Figure 74 – Composite component example

So, if the parent rectangle’s corners are at (0,0) and (100,100), and it has a transformation matrix that translates the rectangle (50,50), where should the corners of the child be?

126

Page 141: Objective Views User’s Guide - Perforce

Remember that the parent rectangle has its own coordinate system. When you add a child to a component, it is within its parent’s coordinate system. The child knows the parent’s corners are at (0,0) and (100,100). So, when you add a child, the new rectangle has its corners at (0,0) and (50,50).

The advantage of this system of nested transforms is two-fold:

The first advantage is that you can only manipulate the children of a composite component with respect to the parent. This ensures that you can always add a child rectangle from (0,0) to (50, 50) to the parent rectangle regardless of the parent rectangle’s location and properties (rotated, scaled or sheared).

The second advantage is that you do not need to store a transform for each child component of a composite object. For instance, if you rotated a composite composed of 100 child components, the application would only create a transformation matrix for the parent component. The 100 children would all remain relative to the parent’s coordinate system, so they could all rotate without storing their own transformation matrices. Figure 75 and Figure 76 show samples of component manipulation.

Figure 75 – Parent rectangle rotated 45 degrees clockwise

Figure 76 – Child rectangle added with corners at (0,0) and (50,50)

8.11.6 Nested Transformation MatricesYou can associate a transformation matrix with each component. If you want, you can combine these matrices. You can concatenate a series of transformation matrices into one matrix. For exam-ple, suppose the following list of conditions, pictured in Figure X, were true:

You have a rectangle (A) that has one child rectangle (B).

The child rectangle (B) contains another child rectangle (C), which is referred to as the grandchild.

Chapter 8 Components 127

Page 142: Objective Views User’s Guide - Perforce

Each triangle has its own transformation matrix (T0, T1, T2).

Figure 77 – Nested transformation example

To convert the grandchild into the child’s coordinate system, apply T2 to its coordinates. To convert those transformed coordinates to the parent’s coordinate system, you would transform the result of the first operation with T1. Finally, to convert those coordinates into the global coordinate system, you would transform the last result with the T0 matrix.

Alternatively, you could combine the three transformation matrices and then transform the grand-child’s points once. To do this, multiply the three matrices together:

T’ = T0 · T1 · T2

Then, you could transform the points of the grandchild with T to put them in the global coordinate system. Note that order does matter when multiplying matrices. If you reversed the order of the for-mula above, the grandchild would be placed in another section of the canvas.

Let’s consider another example. Again, suppose the following list of conditions were true:

You create a composite like the one described in the previous example.

You created the grandchild first.

Under these circumstances, you could combine the three matrices, apply that transformation to the grandchild’s points and then draw it. Next, we could take the combination of T0 and T1, apply the result to the child’s points and draw it. Finally, we could take T0, apply it to the parent’s coordinate and draw it. With more complex composites, this can lead to a lot of matrix combinations. To reduce the amount of matrix multiplication, Objective Views uses a transform stack to store interme-diate matrix calculations.

8.11.7 How the Transform Stack WorksThe CODTransformStack object is a thread-safe class that holds a list of transformation matrices. During the drawing process, CODTransformStack is used to cache the combined transformation matrices for the individual layers in a composite component like the one described in the previous section. If you were working with a component that consisted of a parent, a child and a grandchild, the drawing would follow this logic:

1. Move to the Parent level, and add the Parent’s matrix to the head of the list.

Transform Stack = [TO]

128

Page 143: Objective Views User’s Guide - Perforce

2. Move to the Child level, multiply the matrix at the head of the list by the Child’s matrix, and then add the result to the head of the list.

Transform Stack = [TO · T1] [T0]

3. Move to the Grandchild’s level, multiply the matrix at the head of the list by the Grand-child’s matrix and add the result to the head of the list.

Transform Stack = [TO · T1 · T2] [TO · T1] [T0]

4. Get the matrix at the head of the list, transform the Grandchild’s points and draw it.

Transform Stack = [TO · T1 · T2] [TO · T1] [T0]

5. Remove the matrix at the head of the list and move to the Child’s level.

Transform Stack = [TO · T1] [T0]

6. Get the matrix at the head of the list, transform the Child’s points and draw it.

Transform Stack = [TO · T1] [T0]

7. Remove the matrix at the head of the list and move to the Parent’s level.

Transform Stack = [T0]

8. Get the matrix at the head of the list, transform the Parent’s points and draw it.

Transform Stack = [T0]

9. Remove the matrix at the head of the list.

Transform Stack = empty

Chapter 8 Components 129

Page 144: Objective Views User’s Guide - Perforce

8.12 RegionsA region is an area in a viewport. In Objective Views, regions are typically used to track the exact portions of the viewport that a component is drawing in. Regions are used to detect if a component has been hit by the mouse, and also to invalidate the proper areas of the viewport for drawing.

Figure 78 – Region class hierarchy

8.12.1 CODRgnA region is just a collection of polygons. When the region of a component is calculated, the poly-gons of the individual drawing areas are calculated and assembled in the CODRgn object. Curves are approximated as polygons. The bounding rectangle of a component is calculated from the region and can be retrieved from the CODRgn object.

8.12.2 CODPolygonRgnPolygon regions are the individual polygons that comprise a CODRgn object. Typically, there is one polygon region for each primitive component that is part of a composite.

CODRgn

CODPolygonRgn

130

Page 145: Objective Views User’s Guide - Perforce

C

Chapter 9

Properties

9.1 Introduction to PropertiesA property is a piece of information that is associated with an object. Storing and retrieving all of the properties belonging to an object through a single interface provides a convenient and generic way to deal with any property. The ability to discover and access an object’s properties at run time makes it possible to write generic services for accessing properties. For example, the same serializa-tion code is used to store and retrieve the properties of all components. There is no need to change the serialization code when new properties are added. A generic property browser is also possible given a consistent interface to an object’s properties.

Objective Views uses the interfaces and classes provided by the SFL Properties package for defin-ing and accessing properties. Components are property containers that maintain a list of cached property values and a static register of property descriptions. Fonts, line drawing characteristics, fill (brush) characteristics, and editing capabilities are examples of the information treated as prop-erties. Refer to the Stingray Foundation Library User’s Guide for more information about the Properties package.

hapter 9 Properties 131

Page 146: Objective Views User’s Guide - Perforce

Figure 79 – Property class hierarchy

CODFillProperties

CODEditProperties

CObject

CODProperty

CODIntProperty

CODStringProperty

CODBoolProperty

CODFontProperties

CODLineOrientation

CODLineProperties

CODOrientationProperties

IODObject

IODPropertyContainer

CPropertyContainer

IPropertyContainer

CODPropertyCache

IQueryGuid

IProperty

CProperty

IRefCount

132

Page 147: Objective Views User’s Guide - Perforce

9.2 Property ObjectsObjective Views stores property values as objects in a cache. The CODProperty class is the base class for property values. Classes derived from CODProperty represent either specific data types or nested properties. A nested property is a container for other property values. The CODProperty class ties a property value and a property ID into a single object.

Property value objects are usually accessed only through a property container interface. The CODComponent class does provide methods for accessing property value objects directly, however it is usually more convenient to get and set property values through the property container inter-faces. It is sometimes useful to manipulate nested or compound properties directly.

The description of a property is maintained by a separate object, which is an instance of the CProperty class defined by the SFL Properties package. The CProperty class implements the IProperty interface, which provides access to the ID, name, description, data type, and other infor-mation that describes a property. Storing the value of a property separately from its registered description is more efficient in terms of space. The CODProperty class and its derivatives only store the property ID and property value and should not be confused with SFL’s CProperty class and IProperty interface. The CODProperty class and its derivatives are described below.

9.2.1 CODPropertyThe CODProperty class is the base class for property values. It stores a property ID and has a group of GetValue() and SetValue() methods for storing and retrieving the property value. The GetValue() and SetValue() methods are overloaded for various data types and the default implementation for these methods throws the exception CODPropertyConversionException. Classes derived from CODProperty override the appropriate GetValue() and SetValue() meth-ods. Classes derived from CODProperty represent either specific data types such as string, integer, or Boolean properties or they represent nested properties. A nested property is a property that con-tains other property values and implements the IODPropertyContainer interface.

9.2.2 CODBoolPropertyThe Boolean property represents a simple Boolean value.

9.2.3 CODEditPropertiesThe edit properties determine what actions the end-user can take on a particular component. This is a nested property that contains the following sub-properties.

OD_EDIT_READONLY – Indicates if the component can be modified.

OD_EDIT_CANSELECT – Indicates if the component can be selected.

OD_EDIT_CANMOVE – Indicates if the component can be moved.

OD_EDIT_CANROTATE – Indicates if the component can be rotated.

OD_EDIT_CANSCALE – Indicates if the component can be scaled.

Chapter 9 Properties 133

Page 148: Objective Views User’s Guide - Perforce

OD_EDIT_CANSTRETCH – Indicates if the component can be scaled out of proportion.

OD_EDIT_CANEDITPROPS – Indicates if the component’s properties can be modified.

OD_EDIT_CANCONTAIN – Indicates if the component supports containment.

OD_EDIT_CANEDITVERTICES – Indicates if the component’s vertices may be edited.

9.2.4 CODFillPropertiesThis is a nested property that describes the brush used to fill the interior of a component. Note that only components with closed interiors can be filled. The CODFillProperties class contains data members that describe a GDI brush. The CreateBrush() member function creates a brush using the fill properties and returns it to the caller. The GetBrush() member function returns a cached brush that matches the fill properties. The CODFillProperties class contains the following sub-properties.

OD_FILL_COLOR – RGB color value for brush.

OD_FILL_TRANSPARENT – Indicates whether to use transparent fill.

OD_FILL_STYLE – Indicates the GDI brush style (BS_SOLID, BS_HOLLOW, BS_HATCHED, BS_PATTERN, etc.)

OD_FILL_HATCH – Indicates the hatch style (HS_HORIZONTAL, HS_VERTICAL, HS_FDIAGONAL, etc.)

OD_FILL_BKMODE – Background fill mode (TRANSPARENT or OPAQUE)

OD_FILL_BKCOLOR – RGB color to use for background fill.

9.2.5 CODFontPropertiesThis is a nested property that describes the font used for text drawn by a component. The CODFontProperties class contains data members that describe a GDI font. The CreateFont() member function creates a font using the font properties and returns it to the caller. The GetFont() member function returns a cached font that matches the font properties. The CODFontProperties class contains the following sub-properties.

OD_FONT_FACE_NAME – Name of font (i.e. Times New Roman, Arial, etc.).

OD_FONT_POINT_SIZE – Size of font in points.

OD_FONT_COLOR – Text foreground color.

OD_FONT_WEIGHT – Font weight (FW_NORMAL, FW_BOLD, FW_THIN, etc.)

OD_FONT_ITALIC – Flag to indicate if italic should be used.

OD_FONT_UNDERLINE – Flag to indicate if underline should be used.

OD_FONT_STRIKEOUT – Flag to indicate if strikeout should be used.

OD_FONT_HEIGHT – Height of font in logical units.

134

Page 149: Objective Views User’s Guide - Perforce

Note that setting the point size of the font recalculates the font height and vice versa. The point size and the font height are two different ways of measuring the size of the font, so they are kept synchronized.

9.2.6 CODIntPropertyThe integer property represents a simple integer value.

9.2.7 CODLineOrientationThe line orientation property determines the orientation of an object in relation to a line. This class can be used to orient labels and other components along a given line or link. CODLineOrientation is a nested property that contains the following sub-properties.

OD_LINEORIENTATION_PCTALONG – Percentage along the line

OD_LINEORIENTATION_ANCHOR – Anchor point

OD_LINEORIENTATION_DISTANCE – Distance or offset from line

The orientation consists of a percentage along the given line, an anchor point, and an offset value. The percentage along value is used to calculate a position on the line based on a percentage of the line length. The anchor point is an OD_CONTROL_POINT value that indicates the point on the label or component that should coincide with the calculated point on the line. The offset value is a distance in logical units away from the line to offset the final calculated point. This is a distance along an imaginary perpendicular bisecting line.

9.2.8 CODLinePropertiesThis is a nested property that describes the pen used to draw the lines and vector graphics of a component. The CODLineProperties class contains data members that describe a GDI pen. The CreatePen() member function creates a pen using the line properties and returns it to the caller. The GetPen() member function returns a cached pen that matches the line properties. The CODLineProperties class contains the following sub-properties.

OD_LINE_COLOR – RGB value indicating the color of the pen

OD_LINE_TRANSPARENT – Indicates if lines are transparent or not

OD_LINE_WIDTH – Width of the pen in points

OD_LINE_STYLE – Pen style (PS_SOLID, PS_DASH, PS_DOT, etc.)

It is important to note that due to limitations in the MFC graphics implementation, only lines of width zero (meaning they are always drawn one pixel wide) can have a style other than solid.

Chapter 9 Properties 135

Page 150: Objective Views User’s Guide - Perforce

9.2.9 CODOrientationPropertiesThe orientation properties determine how a label component is positioned in relation to its associ-ated symbol component. You can set label components to appear at a predefined place, such as centered below the symbol, or they can be free floating. CODOrientationProperties is a nested property containing the following sub-properties.

OD_ORIENTATION_CTLPOINT – An OD_CONTROL_POINT value that indicates a position on the bounds of a component.

OD_ORIENTATION_HORZSPACING – Horizontal offset from the control point.

OD_ORIENTATION_VERTSPACING – Vertical offset from the control point.

9.2.10 CODStringPropertyThe string property represents a simple string value.

136

Page 151: Objective Views User’s Guide - Perforce

9.3 Property IDsEach property is assigned a unique identifier. Property IDs in the range of hex 0x0000 to 0xFFFF are reserved for use by Objective Views. Property IDs from hex 0x10000 and up can be used by cus-tomer applications to define custom properties. Nested properties that implement the IODPropertyContainer interface, such as CODFontProperties and CODLineProperties, define property IDs for their member variables, which are only unique within that property container. For example, the face name property in a CODFontProperties object has an ID of 1. The line color prop-erty in a CODLineProperties object also has an ID of 1. These identifiers are only unique within a given container. This allows the ID for a nested property to be added to an ID for one of its child properties to form a unique identifier for each individual property. For example, the ID for a com-ponent’s font property is 30. An ID of 31 represents the component’s font face name.

A component may have more than one property of the same type, as long as their IDs are unique. For example, it is possible for a component to have two font properties.

Property IDs are used to lookup properties within a container. This allows you to identify the prop-erty as being of a certain type, such as a font property. By default, the IDs are set to reflect the different property classes. For example, the line property object has an ID of OD_PROP_LINE. How-ever, you can change this ID to identify a specific property. For example, if you created a line property to draw the borders of components, you would want to assign it a descriptive name, such as OD_PROP_LINE_BORDER. Giving properties descriptive names enables you to use the default property names in addition to your customized names.

Chapter 9 Properties 137

Page 152: Objective Views User’s Guide - Perforce

9.4 Property ContainersA property container is an object that has properties. Property containers implement the IODPropertyContainer interface, which is derived from SFL’s IPropertyContainer interface. The IPropertyContainer interface is shown in Example 8.

Example 8 – IPropertyContainer interface

class IPropertyContainer : public IQueryGuid, public IRefCount{public: /* Get the number of properties in the container. */ virtual int GetPropertyCount() const = 0; /* Get the property using an index into the container. */ virtual IProperty* GetPropertyAt(const int nPropIdx) = 0; /* Retrieve a property by unique identifier. */ virtual IProperty* GetProperty(const PropertyId propId) = 0; /* Retrieve a property by name. */ virtual IProperty* GetPropertyByName(OLECHAR* propName) = 0; /* Return the string name of a property category. */ virtual bool GetCategoryName(const int nCatId, BSTR& catName) = 0; /* Get a property value using the property ID. */ virtual bool GetPropertyValue(const PropertyId propId, VARIANT& propVal) = 0; /* Get a property value as a string using the property ID. */ virtual bool GetPropertyString(const PropertyId propId, BSTR& propVal) = 0; /* Set a property value using the property ID. */ virtual bool PutPropertyValue(const PropertyId propId, VARIANT& propVal) = 0; /* Set a property value as string using the property ID. */ virtual bool PutPropertyString(const PropertyId propId, const BSTR& propVal) = 0;};

The IODPropertyContainer interface extends IPropertyContainer with a set of GetValue() and SetValue() methods that are overloaded for several common data types. The IODPropertyContainer interface is shown in Example 9.

Example 9 – IODPropertyContainer interface

class IODPropertyContainer : public sfl::IPropertyContainer{public: /* Gets the value of the given string property. */ virtual BOOL GetValue(const int nPropId, CString& strValue) const=0; /* Gets the value of the given integer property. */ virtual BOOL GetValue(const int nPropId, int& nValue) const = 0; /* Gets the value of the given unsigned integer property. */ virtual BOOL GetValue(const int nPropId, UINT& nValue) const = 0; /* Gets the value of the given DWORD property. */ virtual BOOL GetValue(const int nPropId, DWORD& dwValue) const = 0; /* Gets the value of the given float property. */ virtual BOOL GetValue(const int nPropId, float& fValue) const = 0;

138

Page 153: Objective Views User’s Guide - Perforce

/* Sets the value of the given string property. */ virtual BOOL SetValue(const int nPropId, LPCTSTR lpszValue) = 0; /* Sets the value of the given integer property. */ virtual BOOL SetValue(const int nPropId, const int nValue) = 0; /* Sets the value of the given unsigned integer property. */ virtual BOOL SetValue(const int nPropId, const UINT nValue) = 0; /* Sets the value of the given unsigned DWORD property. */ virtual BOOL SetValue(const int nPropId, const DWORD dwValue) = 0; /* Sets the value of the given float property. */ virtual BOOL SetValue(const int nPropId, const float fValue) = 0;};

The GetPropertyValue() and PutPropertyValue() methods in the sfl::IPropertyContainer inter-face store and retrieve property values as VARIANTs. The GetValue() and SetValue() methods in the IODPropertyContainer also set property values, but are usually more convenient to use since simple data types can be used instead of VARIANTs.

Components are property containers. Nested properties, such as CODFontProperties and CODLineProperties, are also property containers. The CODPropertyContainer class provides an implementation of the IODPropertyContainer interface and is mixed into the CODComponent class and into the nested property classes, such as CODFontProperties and CODLineProperties.

Chapter 9 Properties 139

Page 154: Objective Views User’s Guide - Perforce

9.5 Registering PropertiesThe CODPropertyContainer class implements the IODPropertyContainer interface. It maintains a map of registered properties in which each registered property ID maps onto an IProperty inter-face pointer. The methods defined by IPropertyContainer for retrieving properties, such as the GetPropertyCount(), GetPropertyAt(), GetProperty(), and GetPropertyByName() are imple-mented by performing lookups in the map.

The CODPropertyContainer class is identical to SFL’s CPropertyContainer class, with the excep-tion that it implements the IODPropertyContainer interface instead of IPropertyContainer. Properties are added to the property map by calling the RegisterProperty() method. Accessor objects can be associated with each property, which encapsulate pointers to a get and a put func-tion. The property map is declared as a static member by each property container class, so registering properties affects every instance of a given container class.

Refer to the Stingray Foundation Library User’s Guide for more information about property registration.

9.6 Getting and Setting Property ValuesThe property container interfaces IPropertyContainer and IODPropertyContainer both provide methods for getting and setting property values. The IPropertyContainer interface provides the GetPropertyValue() and PutPropertyValue() methods to get and set the property values as variants. Since dealing with VARIANTs can be cumbersome, the IODPropertyContainer interface provides a group of GetValue() and SetValue() methods, which are overloaded for several com-mon data types. Either interface is equally valid for accessing property values.

Example 10 uses the IODPropertyContainer interface to disable rotation for a symbol component. Notice that the rotation property is nested in the edit property object and is accessed by combining the base property ID for the edit properties with the property ID for the rotation property.

Example 10 – Setting property values

void CMyController::OnInsertMySymbol(){ CODSymbolComponent* pSymbol = new CODSymbolComponent(); pSymbol ->Create(IDR_MYSYMBOL); OnInsertSymbol(pSymbol); pSymbol->SetValue(OD_PROP_EDIT + OD_EDIT_CANROTATE, FALSE);}

The code segment in Example 11, taken from the CODController class, retrieves the values of two properties using the GetValue() method.

Example 11 – Getting property values

void CODController::DblHit(UINT nFlags, CPoint ptDev, int nButton){ CPoint ptLog = ptDev; VpDPtoLP(&ptLog); CODComponent* pCompHit = GetVp()->ComponentHitTest(ptLog);

140

Page 155: Objective Views User’s Guide - Perforce

if (pCompHit != NULL) { int nHorzAlignment; if (pCompHit->GetValue(OD_PROP_HORZ_ALIGNMENT, nHorzAlignment)) { // Component has the horizontal alignment property. Value is // is in the nHorzAlignment variable. } else { // Component doesn’t support the horizontal // alignment property. } BOOL bCanScale; if (pCompHit->GetValue(OD_PROP_EDIT + OD_EDIT_CANSCALE, bCanScale)) { // bScale contains a boolean value that indicates if // the component can be scaled. } else { // Component doesn’t have any edit properties. } }}

Chapter 9 Properties 141

Page 156: Objective Views User’s Guide - Perforce

9.7 The Property CacheCaching property values reduces memory overhead when multiple components have the same value for a property. For example, all components using the same font will share a single set of font property values through the cache rather than duplicating them for each component. This adds up to substantial savings in memory if you have a thousand text components that all use the same font. The property cache provides the most benefit for nested properties such as CODFontProperties, CODLineProperties, and CODEditProperties.

The CODPropertyCache class implements the property cache. Every Objective Views application must declare a global CODPropertyCache object. The following code segment declares a global property cache.

CODPropertyCache thePropCache;

The name assigned to the global property cache is unimportant because the constructor of the CODPropertyCache class assigns the “this” pointer to a static member variable.

The CODComponent class gets and sets property values by performing lookups in the property cache. If a lookup in the property cache results in a match then an existing cached property is returned. If the property value is not found in the cache, the CODPropertyCache class adds it to the cache. The IsEqual() function defined by the CODProperty class is used by the property cache to determine if two property values match. For a nested property such as CODFontProperties, IsEqual() compares all of the sub-properties.

You can purge the cache to free memory. This operation checks all of the property objects to find objects that are only referenced by the cache. If the operation finds any objects that only reference the cache, it removes them.

142

Page 157: Objective Views User’s Guide - Perforce

C

Chapter 10

Symbols

10.1 Introduction to SymbolsTypically, your end-user works with a symbol. You can use the primitive components to create a symbol component and then make it available to the user (on a toolbar, for example). In addition to having the same functionality as a primitive component, a symbol component can also:

Be linked to other symbols.

Possess connection points (port components).

Have labels associated with it.

You can create symbol objects in the Symbol Designer for use in your applications. You can either leave these symbol files on the disk drive and then load the symbols when you need them, or you can import them as resources in your project. In addition, you can also create a symbol component on the fly, by indicating which components you want to comprise the symbol. Choosing among these three options is as easy as choosing among different versions of the Create() method in CODSymbolComponent.

Figure 80 – Symbol Class Hierarchy

A symbol is a component that can have labels and connections to other symbols. Typically, it is a composite consisting of other components that define its appearance. You can create a set of sym-bols in the Symbol Designer, import them as resources into your application, and then make them available to the user.

CObject

CCmdTarget

CODComponent

CODSymbolComponent

MvcVisualComponent

IQueryGuid

IODPropertyContainer

IRefCount

IPropertyContainer

hapter 10 Symbols 143

Page 158: Objective Views User’s Guide - Perforce

The logic for connecting components was intentionally introduced at this level. Providing connect-ing logic in the base CODComponent class would require every component to support the overhead of connection code, regardless of size. Because components like lines and ellipses are usually used as children in more complex composite components, supporting this functionality would be excessive.

If you want to connect a simple component like a rectangle to another component, you need to cre-ate a symbol component that has a child that is a rectangle.

10.2 Accessing Symbol Files from DiskWhen you want to create a new symbol on your canvas from a symbol file, you can create a new symbol component and pass the file path into its Create() method.

CODSymbolComponent* pNewSymbol = new CODSymbolComponent();pNewSymbol->Create(“C:\MySymbols\Symbol1.sym”);

This method loads in the symbol from the file, and then copies the imported symbol’s information into the symbol object. You can place this symbol onto the canvas by using a CODInsertCommand or by calling CODModel::InsertComponents().

144

Page 159: Objective Views User’s Guide - Perforce

10.3 Using Symbols as ResourcesTo import a symbol into your application’s resources, you need to have a symbol in a file. We sug-gest you place the symbol file in your project’s resource directory along with all of your other resources such as cursors, toolbars and bitmaps.

To use a symbol as a resource, complete the following steps:

1. After you place the symbol file in the resources directory, open the Resource View for your project. Expand project node, right click on *.rc node and select Add Resource.

Figure 81 – The Add Resource dialog

2. In the Add Resource dialog box (Figure 81), click on Import. Remember we want to import a resource, not create one.

3. Now you need to locate the file that holds your resource. Navigate to your symbol file and select it. Visual Studio detects that this is not one of its standard resource types and prompts you to define it in the Custom Resource Type dialog box.

4. Type SYMBOL in the Resource Type box and click OK.

Figure 82 – Resource Type dialog

Chapter 10 Symbols 145

Page 160: Objective Views User’s Guide - Perforce

5. Now the symbol is a part of your application’s resources. After you import a symbol resource the first time, SYMBOL appears as a choice in the Custom Resource Type dialog. Then, you can select it instead of typing SYMBOL each time.

6. To access the resource, pass in the resource ID of the symbol you want to the Create() method:

CODSymbolComponent* pNewSymbol = new CODSymbolComponent();pNewSymbol->Create(IDR_SYMBOL1);

10.4 Creating Symbols on the FlySymbols can also be created programmatically. Remember, a symbol is a component that has the capability of linking to another symbol and of bearing a label. Each component can also act as a composite, which means it can consist of other components. Usually, a symbol is a collection of primitive components.

You can create a new symbol by adding subcomponents to it. You can collect subcomponents into a set and then pass it to the Create() method, as in Example 12.

Example 12 – Adding a collection of subcomponents to a symbol

CODSymbolComponent* pNewSymbol = new CODSymbolComponent();pNewSymbol->Create(&setComponents);

Or, you can add the subcomponents one by one using the AppendChild() or InsertChild() methods, as in Example 13.

Example 13 – Adding subcomponents individually to a symbol

CODImageComponent* pImageComp = new CODImageComponent();pImageComp->Create(IDR_IMAGE1, pDC);

CODSymbolComponent* pNewSymbol = new CODSymbolComponent();pNewSymbol->AppenChild(pImageComp)

Remember that each composite component has its own coordinate system. If you added a rectangle with corners at (0,0) and (10,10), it would appear at the top left corner of the symbol whenever the symbol is displayed on the screen.

146

Page 161: Objective Views User’s Guide - Perforce

10.5 Creating a Symbol ClassDeriving new classes from the CODSymbolComponent class is an easy way to customize the behavior of the symbols on your canvas. Adding a symbol class enables you to:

Add new properties and methods that are specific to a certain class of symbols.

Base the appearance on certain inputs or data.

Respond to events that occur on the symbol.

Provide rules for connecting symbols.

Programmatically add ports or labels.

Derived symbol classes must support MFC serialization to ensure that they function properly. To achieve this, you need to use the VIEWS_DECLARE_SERIAL macro in your declaration and the IMPLEMENT_SERIAL macro in your implementation. If you add new persistent data members to your class, override the Serialize() method and add code to save and restore those data mem-bers. If you use custom properties to add new data to your symbols, you do not need to add code to the Serialize() function for those properties.

When creating a derived symbol class, consider adding a Create() method to your class. If a sym-bol is always loaded from the same file or application resource, then your Create() method can encapsulate that particular detail. The symbol can also be created programmatically by creating and adding components to the symbol. The Create() method is also a good place to insert that functionality and to add custom properties to the symbol.

There are many virtual functions in CODSymbolComponent that can be overridden by derived classes. Consult the Objective Views Class Reference for a complete list of virtual functions in CODSymbolComponent.

If your symbol class has custom properties or member variables that extend the serialization for-mat, you need to take special care if you are loading symbols created by the Symbol Designer. The Symbol Designer is not aware of your extended serialization format, so when you load a symbol from a file or application resource you may hit the end of file before you are finished with your serialization. As long as you initialize your member variables, this shouldn’t be a problem. You may also need to put a try/catch block in your serialization code to catch the CArchiveException, which will be thrown when you try to read past the end of file.

If you are using custom properties instead of member variables, the problem is slightly different. You need to ensure that you add the custom properties to the symbol when serializing them in—so that the Symbol Designer will not remove them. The best approach is to isolate the loading of the symbol in the Create() method and add custom properties to the symbol after serialization is complete. Note that this is not a problem when your application performs serialization, because it is linking to your symbol class and has your custom serialization routine. It only occurs when your application loads a symbol that was created by Symbol Designer.

The code in Example 14 is a symbol class that changes its line drawing color depending on whether there are connections to the symbol. Two custom properties are added to the symbol to store the colors for each connection state. The custom properties are added in the Create() method after the symbol has been loaded from the application resources. When a connection is added, the OnConnect() method is called and PROP_CONNECTED_COLOR value is applied. When a connection is

Chapter 10 Symbols 147

Page 162: Objective Views User’s Guide - Perforce

removed, the OnDisconnect() method is called and the PROP_DISCONNECTED_COLOR is applied. Notice that the color must be applied to each child, because each child may have its own set of line properties that override the parent symbol line properties.

Example 14 – Symbol class creation example

#define PROP_CONNECTED_COLOR OD_CUSTOM_PROPERTY_BASE + 10#define PROP_DISCONNECTED_COLOR OD_CUSTOM_PROPERTY_BASE + 11

class CConnectionSensitiveSymbol : public CODSymbolComponent{ VIEWS_DECLARE_SERIAL(CConnectionSensitiveSymbol);public: BOOL Create(UINT nID) { BOOL bSuccess = CODSymbolComponent::Create(nID);

// Add two custom color properties to indicate the // connection state of the symbol. CODDWordProperty propConnectedClr(PROP_CONNECTED_COLOR); propConnectedClr.SetValue(RGB(255,0,0)); AddProperty(propConnectedClr);

CODDWordProperty propDisconnectedClr(PROP_DISCONNECTED_COLOR); propDisconnectedClr.SetValue(RGB(0,0,0)); AddProperty(propDisconnectedClr);

ApplyLineColor(PROP_DISCONNECTED_COLOR);

return bSuccess; }

virtual void OnConnect(CODConnection* pConnection) { CODSymbolComponent::OnConnect(pConnection); ApplyLineColor(PROP_CONNECTED_COLOR); }

virtual void OnDisconnect(CODConnection* pConnection) { CODSymbolComponent::OnDisconnect(pConnection);

CODConnectionSet setConnections; GetAllConnections(setConnections); if (setConnections.GetSize() == 1) { ApplyLineColor(PROP_DISCONNECTED_COLOR); } }

148

Page 163: Objective Views User’s Guide - Perforce

void ApplyLineColor(const int nPropId) { // Apply the given color property to the line // properties of each child component. COLORREF crLineClr; if (GetValue(nPropId, crLineClr)) { for (int i = 0; i < GetChildCount(); i++) { CODComponent* pChild = GetChild(i); pChild->SetValue(OD_PROP_LINE+OD_LINE_COLOR, crLineClr); } } }};

IMPLEMENT_SERIAL(CConnectionSensitiveSymbol, CODSymbolComponent, 0)

Chapter 10 Symbols 149

Page 164: Objective Views User’s Guide - Perforce

10.6 Placing Symbols on a ToolbarUsing a toolbar or a similar control is an easy and effective way to give the end-user access to your library of symbols. The Objective Views samples use the standard CToolbar control extensively to place new symbols on the canvas; however, you do not need to use a toolbar control. Anything that can execute a command message is adequate. For example, the list bar control in Objective Toolkit could be used as well.

To use a toolbar as a means for accessing symbols, you need to create a toolbar resource that has buttons that represent your symbols. Then, you need to put command handlers in your CODController-derived class, which manages creating and inserting the symbols onto the canvas.

To add a symbol to a toolbar button, complete the following steps:

1. Draw a new button for it (the ‘X‘ in Figure 83).

Figure 83 – Drawing a new toolbar button

2. Then, give the toolbar button a meaningful resource ID and prompt, as in Figure 84.

Figure 84 – Specifying button ID and prompt

3. Before you add a symbol to a button, ensure that you have a CODController-derived class in your application. If you do not have a CODController-derived class, you need to create one in which to place the message handler. You can use the Class Wizard to create a new message handler for ID_SYMBOL1. In this message handler, place the code for creating the symbol and then hand it to the default controller implementation so that the user can place the symbol onto the canvas. The code in Example 15 loads a symbol from the application’s resources and then allows the user to add it to the canvas:

Example 15 – Adding a symbol to the canvas

void CMyController::OnSymbol1(){ CODSymbolComponent* pSymbol1 = new CODSymbolComponent(); pSymbol1->Create(ID_SYMBOL1);

OnInsertSymbol(pSymbol1);}

150

Page 165: Objective Views User’s Guide - Perforce

This message handler is called every time the end-user clicks the X button. It loads the sym-bol into memory so it is ready to be dropped onto the canvas.

10.7 PortsA port defines a location on a symbol at which other symbols can be connected. A port always belongs to exactly one symbol, and can be visible or invisible. Typically, a symbol component has at least one port defined in its center. Normally, this port is invisible. It enables you to make a connec-tion even if you have not defined another port on the symbol. Ports can be used to create connections between any two symbols. They are most frequently used to connect a link component with two symbols.

The CODPortComponent class encapsulates all the functionality of a port. A port object is the child of a symbol object. The symbol component is the owner of the port. A port has a location associated with it, which is relative to the symbol that owns it. If the application knows the owner and loca-tion of a port, it can detect where the ports are during a link operation so that a connection can be made. The link is kept intact even if the symbol is moved.

Note that the CODPortComponent object has no visual representation. It is a logical component used for linking. You can define connection points anywhere on your symbol without changing its appearance. If you want to create a visible port, you can derive from this class and override the OnDraw() method.

The circle port is a derivative of CODPortComponent that does have a visual representation. This port appears as a circle with a cross through it. Although a port retains its proper location on a symbol, it does not move when you rotate or scale a component. It is meant to identify a single point on a symbol.

The circle port is the port component used in Symbol Designer to define connection points on your symbols. If you would like to use a different port, you can add one to the symbol programmatically.

Chapter 10 Symbols 151

Page 166: Objective Views User’s Guide - Perforce

10.8 Symbol ConversionThe symbol files from Objective Diagram version 1.0 are not automatically compatible with the symbol files in Objective Views. The CODSymbolConverter class takes care of reading in the old version 1.0 format and producing a symbol. All that is needed is the proper archive from which to load the symbol, and the new symbol will be made. If an error is encountered during the conver-sion, a CODConverterException is thrown. The symbol converter can be accessed in the Symbol Designer from the File|Import Symbol menu item.

10.9 LabelsLabels are special text components that are associated with symbol components and are positioned in relation to them. You can associate a label with a symbol so that it appears in a predefined place, such as centered below the symbol. You can also allow the user to drag the label with the mouse to position it.

Labels, like ports, are children of a symbol component. As such, when you move a symbol, its label moves with it. However, labels have unique capabilities. For example, the user can select and manipulate a label independently of the symbol.

If the label is set at a predefined place in relation to the symbol, it will have an orientation property. The orientation property tells the label to position itself at one of nine points around the symbol. You can also define how much distance there should be between a label and its symbol.

152

Page 167: Objective Views User’s Guide - Perforce

10.10ConnectionsA connection is an object that binds together two ports. It establishes a relationship between two symbols through the two ports it connects. Think of connection objects as the glue that connects two ports. A port can have more than one connection on it, but a connection can only be associated with two ports.

The term dependent is used to refer to the port and symbol pair on the other side of a given connec-tion. In other words, the dependent ports for a given symbol are ports on other symbols that the given symbol has connections to. If symbol A is connected to symbol B, then symbol B is a depen-dent of A, and symbol A is a dependent of B. In other words, they are co-dependent.

Connections are used to send event notifications to dependent symbols. For example, if symbol A is connected to symbol B and symbol A moves, then symbol A must notify symbol B of the change so that B can take appropriate action. Links respond to this type of notification by following the symbol to which they are connected. If symbol A is connected to link B, and symbol A is moved, then link B is notified of the move and responds to this notification event by adjusting its endpoint to follow symbol A.

Figure 85 – Connection Class Hierarchy

CObject

CODConnection

CODConnectionMap

CMapPtrToPtr

Chapter 10 Symbols 153

Page 168: Objective Views User’s Guide - Perforce

10.11A Connection ScenarioFigure 86 shows a scenario in which connections are used to link two symbols together. A port on Symbol 1 is connected to a port on the link component. A port on Symbol 2 is also connected to a port on the link component. This establishes a link between the two symbols. Symbol 3 is con-nected directly to a port on Symbol 1. This demonstrates how any symbols can be connected together.

Figure 86 – Linking symbols using connections

154

Page 169: Objective Views User’s Guide - Perforce

10.12CODConnectionThe connection object maintains two pieces of information: a source port and a target port. Armed with this information, a CODConnection maintains the logical connection between the ports and the associated symbols. A connection knows to which symbol it is connected.

10.13CODConnectionMapConnection maps are used during the symbol notification process as a way to keep track of the con-nection and port pairs that have been traversed. The symbol notification process sends messages through a set of connections as a way to inform a symbol’s dependent symbols that an event has occurred. For example, when a symbol is moved, any link symbols that are connected to it must be notified of the move so that they can take appropriate action. The connection map ensures that cir-cular dependencies do not result in endless recursion.

10.14Additional SymbolsThe Views symbol repository can be expanded through the additional collections available at <stingray-installdir>\Samples\Views\Symbols. The additional collections are:

Electrical

Maps and floor plans

Flow charts

Networks and peripherals

These symbols may be imported into your Objective Views application or opened in the Views Symbol Designer as illustrated in the figure below.

Chapter 10 Symbols 155

Page 170: Objective Views User’s Guide - Perforce

Figure 87 – Importing Additional Symbols

Even though the file extension, .sym, is associated with the Symbol Designer executable, double-clicking these new symbols does not open the Symbol Designer as you might expect.

156

Page 171: Objective Views User’s Guide - Perforce

Chapter 11

Links

11.1 Introduction to LinksLink components are symbols that have a head and tail port. By default, the link component con-tains a single line as a child component and keeps the head and tail ports aligned with the endpoints of the line. However, other types of components can be used within the link component to render different shapes for the link.

The link component maintains a pointer to an interface called IODLinkShape. This interface pro-vides the link with methods for positioning the head and tail ports to match the shape. It also provides methods for adjusting the shape when the head and tail ports are moved. This interface is mixed into classes derived from CODComponent. The implementation of the interface depends on the type of component with which it is combined. The following link shape classes are included with the library: CODLineLinkShape and CODOrthogonalLinkShape. The CODLineLinkShape class implements IODLinkShape for straight lines. The CODOrthogonalLinkShape implements IODLinkShape for orthogonal lines.

To implement your own custom link shapes, derive a class from an existing component class and mix in the IODLinkShape interface. Example 16 shows the IODLinkShape interface.

Example 16 – The IODLinkShape interface

class IODLinkShape : public IODObject{public: /* Return a pointer to the component that implements the shape. */ virtual CODComponent* GetComponent() = 0; /* Return the point that represents the tail of the link. */ virtual CPoint GetTailPoint() const = 0; /* Return the point that represents the head of the link. */ virtual CPoint GetHeadPoint() const = 0; /* Adjusts the shape so that the head and tail dock with ports. */ virtual BOOL Dock(CODPortComponent* pSourcePort, CODPortComponent* pTargetPort) = 0; /* Adjust the shape when a vertex changes. */ virtual BOOL UpdateVertex(const int nVertexIdx, CODPortComponent* pSourcePort, CODPortComponent* pTargetPort) = 0;};

Chapter 11 Links 157

Page 172: Objective Views User’s Guide - Perforce

The GetTailPoint() and GetHeadPoint() methods return the tail and head points of the link shape. For a line, the tail and head points are the endpoints. The Dock() method adjusts the com-ponent so that it docks with the given ports. When the symbols that the link is connected to move, the Dock() method is called to adjust the shape so that it follows the symbols. The UpdateVertex() method is called when a vertex in the shape is moved or deleted. Updating a ver-tex in the shape may affect how the shape is docked with the connected symbols.

Use CODLineLinkShape and CODOrthogonalLinkShape as a guide to implementing the IODLinkShape interface. Example 17 shows the declaration of the CODLineLinkShape class.

Example 17 – CODLineLinkShape class

class CODLineLinkShape : public CODLineComponent, public IODLinkShape{ VIEWS_DECLARE_SERIAL(CODLineLinkShape)public: /* Constructor. */ CODLineLinkShape(); /* Copy constructor. */ CODLineLinkShape(const CODLineComponent& src);

/* Return a pointer to the component that implements the shape. */ virtual CODComponent* GetComponent(); /* Return the point that represents the tail of the link. */ virtual CPoint GetTailPoint() const; /* Return the point that represents the head of the link. */ virtual CPoint GetHeadPoint() const; /* Adjusts the shape so that the head and tail dock with ports. */ virtual BOOL Dock(CODPortComponent* pSourcePort, CODPortComponent* pTargetPort); /* Adjust the shape when a vertex changes. */ virtual BOOL UpdateVertex(const int nVertexIdx, CODPortComponent* pSourcePort, CODPortComponent* pTargetPort);. . .};

The method CODLinkComponent::AssignShape() is used to assign a link shape to a link compo-nent. If you want to assign a custom link shape to the link component, call AssignShape() before calling the CODLinkComponent::Create() method. If a link shape has not been assigned by the time Create() is called, Create() assigns a CODLineLinkShape (a straight line) to the link. To use an orthogonal line for the link shape, you can call CODLinkComponent::CreateOrthogonal().

158

Page 173: Objective Views User’s Guide - Perforce

11.2 Linking SymbolsA link is a type of symbol that has a line and maintains ports at the endpoints of the line. Links are used to draw relationships between two symbols. The link contains a line component as a child, so the link behaves like a line component. The link is also a symbol so it can have ports and labels, and be connected to symbols and possibly other links.

There are two ways to link symbols together programmatically. One is to use the CODLinkCommand class. This command is used by the controller when the end user links sym-bols together. The other way is to create a CODLinkComponent, set which symbols it should connect, and then place it onto the canvas.

Figure 88 – Link Class Hierarchy

MvcVisualComponent

CCmdTarget

CODComponent

CODSymbolComponent

CODLinkComponent

IRefCountCObject

IPropertyContainer

IODPropertyContainer

IQueryGuid

Chapter 11 Links 159

Page 174: Objective Views User’s Guide - Perforce

11.3 CODLinkComponentA link component shows the relationship between two symbols. It needs to define connections between itself and other components. Accordingly, it is derived from CODSymbolComponent so it has the connection logic.

A link comprises of a line component and two port components. The ports are set at either end of the line. They are always ready to connect to another symbol. Normally, a composite component like this would have eight selection handles instead of control handles on the vertices of the line. A link still looks and acts like a line component.

11.4 Changing EndpointsLinks, like lines, can be assigned special endpoints. By default, a link does not have any endpoints, but it is easy to add them. The link uses the same methods as the line component for setting end-points: SetSourceEndpoint() and SetTargetEndpoint(). You can create a CODEndpoint object to pass into these methods. An ideal place to pass a CODEndpoint is the EndLink() method in the main controller of your canvas. To pass in CODEndpoint, override the method, create the link object, and then set the endpoints. The <stingray-installdir>\Samples\Views\Showcase sam-ple illustrates this approach. You could even create a CODLinkComponent derivative that always uses certain endpoint types.

160

Page 175: Objective Views User’s Guide - Perforce

11.5 Orthogonal LinksAn orthogonal link is a link component that contains an orthogonal line component as a link shape. To create an orthogonal link, simply create a link using the CODLinkComponent::CreateOrthogonal method. Example 18 shows how to create an orthogonal link.

Example 18 – Creating an orthogonal link

CODLinkComponent* pLinkComp = new CODLinkComponent();pLinkComp->CreateOrthogonal();

Example 19 is equivalent to using the CreateOrthogonal method.

Example 19 – An equivalent method to Example 18

CODLinkComponent* pLinkComp = new CODLinkComponent();CODOrthogonalLinkShape* pOrthoLine = new CODOrthogonalLinkShape ();pOrthoLine->Create(pPointArray);pLinkComp->AssignShape(pOrthoLine);

Chapter 11 Links 161

Page 176: Objective Views User’s Guide - Perforce

162

Page 177: Objective Views User’s Guide - Perforce

Cha

Chapter 12

Commands

12.1 Introduction to CommandsCommand objects are a part of the undo/redo system in MVC and Objective Views. A command is an object that knows how to save and restore an event. When the end-user performs an action on a model, the application collects the information required to execute that action into a command. Then, the application executes the command (in other words, it performs the action) and then saves the executed command to a transaction model. Saving a command to a transaction model enables the application to retrieve the command from the transaction model and unexecute or undo what the command did initially.

pter 12 Commands 163

Page 178: Objective Views User’s Guide - Perforce

Figure 89 – Command Class Hierarchy

CODMoveCommand

CODCommand

CODRotateCommand

CODScaleCommand

CODInsertVertexCommand

MvcCommand

CODDeleteVertexCommand

CODMoveVertexCommand

CODMovePortCommand

CODNameCommand

CODTextCommand

CODTransparencyCommand

CODLinkCommand

CODUpdateCommand

CODInsertCommand

CODDeleteCommand

CODGroupCommand

CODUngroupCommand

CODIndexedCommand

CODMacroCommand

CODAlignCommand

CODPropertyCommand

CODFontCommand

CODOrderCommand

164

Page 179: Objective Views User’s Guide - Perforce

12.2 Type IDsEach command has a different type ID. Type IDs can be used to distinguish one type of command from another when you have a pointer to a generic CODCommand object. There is a default ID for each class. For example, a move command has an ID of OD_CMD_MOVE. You can change this ID if you want to distinguish among commands of the same class.

12.3 Executing and UnexecutingA command does not perform an action until its Execute() method is called. The command stores any additional information it might need to undo a command and then calls methods in the model to perform its action.

When a command is undone, its Unexecute() method is called. Stored information is retrieved from here and then the action is reversed. Some unexecute methods create a whole new command that performs the inverse action and then executes it.

12.4 Target ModelA command keeps a pointer to the model to which it pertains. It uses this pointer to get access to the methods that enable it to complete its action. For example, when a move command is executed, it calls the method MoveComponents() in CODModel.

12.5 Components in a CommandEvery command keeps a list of pointers to the components it affects. These components are refer-ence counted, so they cannot be deleted from memory before all the commands are done using them. For example, if the user selected a component and deleted it, the component would still be referenced by the delete command even though it is no longer in the model. If the component was deleted when it was removed from the model, the command would have a bad pointer to it. If the user tried to undo the delete command, the program would crash. Because the components are ref-erence counted, the component would remain in memory as long as the delete command was around.

Chapter 12 Commands 165

Page 180: Objective Views User’s Guide - Perforce

12.6 Using or Not Using Command ObjectsCommands are ideal for performing actions initiated by the end-user. When you manipulate the canvas programmatically, you can avoid contending with the overhead of creating command objects and then recording them in the transaction model for undo/redo.

Commands are the ideal approach for performing common actions. If you want to use commands without logging them in the transaction model, turn off logging in the model before you execute the command.

If you want to avoid using commands completely, call the methods in the model directly. Remem-ber that even though a command recalls what action it is performing, it always calls methods in the model to complete the action. Find the appropriate method for what you want to do in the model. The viewport displaying your canvas does not update automatically when you use commands. To update the viewport programmatically, call CODModel::UpdateComponents() to notify all of the model’s observers that a portion of the screen needs updating.

12.7 Command ClassesThis section outlines the various command classes available in Objective Views.

12.7.1 CODCommandThis is the base class of all the command objects in Objective Views. It monitors the model on which the command is executing. It also monitors a set of the CODComponent objects that it affects. Each command object has an ID associated with it so the code can distinguish among com-mands without using run-time type information.

12.7.2 CODMoveCommandThe move command moves a set of components. This command enables the end-user to move not only the component, but also its horizontal and vertical offsets. It applies a new offset to change the component's position. To undo the action, CODMoveCommand uses the negative of the offsets. When a macro command is executed, the class searches through the commands sequentially and then executes it. To undo an action, it searches through the commands in reverse order and then unexecutes it.

12.7.3 CODRotateCommandThe rotate command rotates a set of components. The only parameter it needs is the angle at which to rotate. Components always rotate from their centers. When you undo a rotate action, CODMoveCommand rotates the component by the negative of the former angle.

166

Page 181: Objective Views User’s Guide - Perforce

12.7.4 CODScaleCommandThe scale command scales a component to a different size. To scale, the horizontal and vertical scal-ing factors are needed, as well as the point of reference to use for scaling. To undo the action, the application calculates the inverses of the scaling factors as well as the point to use as a reference for the inverse scaling.

12.7.5 CODInsertVertexCommandThe insert vertex command adds a vertex to a primitive component. It needs the coordinates of the new vertex and the array index to insert the vertex. When you undo the action, a CODDeleteVertexCommand is created and executed.

12.7.6 CODDeleteVertexCommandThe delete vertex command removes a vertex from a primitive component. To delete, the index of the vertex is used. When you undo an action, a CODInsertVertexCommand is created and executed.

12.7.7 CODMoveVertexCommandThe move vertex command moves a single vertex of a component. It uses the index of the vertex, as well as the horizontal and vertical offsets, to move it. When you undo the action, the negatives of the offsets are used.

12.7.8 CODMovePortCommandThis command moves a port belonging to a symbol. Only one port can be moved at a time with this command. This command can also be used to connect the port being moved to another port.

12.7.9 CODSpacingCommand ClassThe spacing command allows you to evenly space a set of components horizontally, vertically, or both. Objective Views supports two types of spacing values: fixed values specified by the caller and values that are automatically calculated so that the components are spread evenly across the cur-rent range. The SetHorizontalSpacing() and SetVerticalSpacing() functions set the spacing mode and optional spacing value.

The command saves the position of each component in a map prior to execution, so that CODComponent::SetPosition() can be used by CODSizeCommand::Unexecute() to restore the position and size of the components.

Chapter 12 Commands 167

Page 182: Objective Views User’s Guide - Perforce

12.7.10CODSizeCommand ClassThe size command sets the size of one or more components. You can use the size command to set a component’s width, height, or both. Sizing occurs about a fixed control point on the components. The command saves the position of each component in a map prior to execution so that CODComponent::SetPosition() can be used by Unexecute() to restore the position and size of the component.

12.7.11CODNameCommandThe name command sets the name of a component. When you execute this command, it stores the former name in the model and then applies the new name to the component. When you undo the action, the former name is retrieved from storage and then set for the component.

12.7.12CODTextCommandThe text command sets the string for a text component. The old text is stored and then the new text is set for the component. When you undo the action, the old text is retrieved from storage and then set for the component.

12.7.13CODTransparencyCommandThe transparency command sets a color to transparent in a bitmap component. It stores previous transparency values for the bitmaps and then sets in the new ones. When you undo this action, the previous transparency settings are retrieved and set in the bitmap components.

12.7.14CODLinkCommandThe link command inserts a link object that defines a relationship between two symbols. It needs two ports to form the link. It can also use a set of points that define how the link lines are laid out. When you undo this action, a CODDeleteCommand is created and executed, which unhooks and deletes the link.

12.7.15CODUpdateCommandThis command is used by the model to report changes to its observers. CODUpdateCommand is not logged in the transaction model. Instead, it is passed to the viewport’s OnUpdate() method. The viewport determines which pieces of the screen to invalidate based on the components in the update command.

168

Page 183: Objective Views User’s Guide - Perforce

12.7.16CODIndexedCommandThere are several commands, like deleting and inserting, that affect the z-order, or stacking order, of the components. When the end-user undoes a command or redoes an undone command, the symbol is placed at the top of the stack unless the command is derived from CODIndexedCommand. CODIndexedCommand encapsulates the code so you can save and restore the z-order of the components affected by the command.

12.7.17CODInsertCommandUse this command to insert a new component into the model. When you execute this command, the components in its set are added to the model. When you undo the action, a CODDeleteCommand is created and executed.

12.7.18CODDeleteCommandThe delete command removes components from the model. When you execute this command, the components in its set are removed from the model. When you undo the action, a CODInsertCommand is created and executed.

12.7.19CODGroupCommandThe group command combines a set of components into one composite. The components are removed from the model and then replaced by the group. When you undo the action, the compo-nents are removed from the composite and inserted into the model.

12.7.20CODUngroupCommandThe ungroup command takes a set of composite components and then divides them into individ-ual child components. It removes the composites from the model and replaces them with the first level children. When you undo the action, the child components are grouped back into composites.

12.7.21CODOrderCommandThe order command changes the z-order of a set of components. You can change the order in four ways: move the component back one, move the component forward one, move the component to the back of the stack, move the components to the front of the stack.

The original order of the components is saved and then the components are moved within the stacking order. When you undo the action, the original orders are retrieved from memory and the components are moved back to their original positions.

Chapter 12 Commands 169

Page 184: Objective Views User’s Guide - Perforce

12.7.22CODMacroCommandThis macro command is a collection of CODCommands. It groups many commands into a single unit for execution. Organizing your commands into a single unit gives the end-user the ability to undo and redo multiple actions at once. This functionality is used frequently in the component property sheet to change many properties at once.

12.7.23CODAlignCommandThe alignment command aligns a set of components in relation to an anchor component. The anchor component is the last one in a set of components. There are six different ways to align a component: top, middle, bottom, left, center, and right.

The alignment command comprises many different move commands—which is why it is derived from CODMacroCommand. Each component in the set of selected components has a correspond-ing move command that moves it by the proper offsets to align it with the anchor. When you undo the action, the negative offsets of the move commands are used.

12.7.24CODPropertyCommandThe property command sets a property for each component in its set. When this object executes, it caches the previous property of the components, and then passes its CODProperty object to the components. When you undo this action, it retrieves the old properties from memory and sends them to the components.

12.7.25CODFontCommandThe font command is a special case of the property command. Because the font is being changed, the box surrounding the text may be changed as well. To undo this type of command, the old posi-tion of the box must be saved. The font command handles storing this information. The rest of the information is handled by CODPropertyCommand.

Commands are essential to the undo/redo capabilities of Objective Views. Each command encap-sulates an action performed on the model as well as the ability to reverse that action. When executed, the commands are logged in the model’s transaction model. The transaction model has the ability to unexecute the commands.

170

Page 185: Objective Views User’s Guide - Perforce

Chapter 13

Dialogs

13.1 Introduction to DialogsObjective Views provides several dialog and control classes for performing common user interface activities. These dialogs are used in the samples and in the Symbol Designer, and they are applica-ble to most applications developed with Objective Views. To add any of these dialogs to your application, you need to add a menu item or button with the appropriate command ID to your application. The base controller class already has message handlers that open these dialogs for you.

Chapter 13 Dialogs 171

Page 186: Objective Views User’s Guide - Perforce

Figure 90 – Dialog Class Hierarchy

CWnd

CCmdTarget

CDialog

CODComponentDlg

CODGridDlg

CObject

CODZoomDlg

CPropertyPage

CODEditCompPP

CODFillCompPP

CODFontCompPP

CODGeneralCompPP

CODLineCompPP

CODLabelCompPP

CODMeasurePropPage

CODCoordinateMappingPage

CODCanvasSizePage

CODDrawingScalePage

CODPosSizeCompPP

CODCompPropSheet

CODDefPropSheet

CODMeasurePropSheet

IODRuler

CPropertySheet

CListBox

CODComponentLB

CODFontListBox

CODHatchLB

CODLineSizeLB

CODLineStyleLB

CODSizeListBox

172

Page 187: Objective Views User’s Guide - Perforce

13.2 Component Property SheetThe component property sheet is a series of property pages that allow the user to edit the proper-ties of one or more components. The CODCompPropSheet class encapsulates the functionality of the component property sheet. Each property page in the property sheet has a corresponding class. This section describes each class used to implement the component property sheet.

13.2.1 CODCompPropSheetThe component property sheet handles a series of property pages that allow the user to change the attributes of a component or set of components. The pages that appear in this property sheet vary depending on the type of properties that the selected components possess. For example, although a rectangle component can be surrounded by lines and filled with color, it cannot be filled with text. Consequently, there is no text page in the property sheet when a rectangle is the selected object.

Figure 91 – Component property sheet

Chapter 13 Dialogs 173

Page 188: Objective Views User’s Guide - Perforce

13.2.2 CODDefPropSheetThe default property sheet shows a series of property pages like the pages in CODCompPropSheet. This sheet defines a set of default properties for new components. The default properties set the attributes of new components before they are placed on the canvas.

Figure 92 – Default property sheet

13.2.3 CODGeneralCompPPThe general property page appears for each component. This is where information such as the component type and its name appears.

Figure 93 – General property page

174

Page 189: Objective Views User’s Guide - Perforce

13.2.4 CODEditCompPPThe edit property page contains information about a component’s editing restrictions.From this page, the end-user can designate what functions can be performed on the selected component(s).

Figure 94 – Edit property page

13.2.5 CODLineCompPPThe line property page contains options the end-user can select to change the appearance of the lines that surround the selected component. The end-user can also set the color, style and width of the component in this dialog box.

Figure 95 – Line property page

Chapter 13 Dialogs 175

Page 190: Objective Views User’s Guide - Perforce

13.2.6 CODLineStyleLBThe line style list box appears on the line property page. It displays choices for the style of the line.

13.2.7 CODLineSizeLBThe line size list box appears on the line property page. It displays choices for the line width.

13.2.8 CODFillCompPPThe fill property page contains options that determine how the fill of a component appears. The end-user can alter the color and optional hatching settings in this dialog.

Figure 96 – Fill property page

13.2.9 CODHatchLBThis list box appears in the fill property page. It displays the hatching options for a fill.

176

Page 191: Objective Views User’s Guide - Perforce

13.2.10CODFontCompPPFrom this page, the end user can set the font type, point, color and several other effects, including bold, italic, underline and strikeout.

Figure 97 – Font property page

13.2.11CODFontListBoxThis list box appears in the font property page. It displays the available True Type fonts.

13.2.12CODSizeListBoxThis list box appears in the font property page. It displays the available point sizes for a font.

Chapter 13 Dialogs 177

Page 192: Objective Views User’s Guide - Perforce

13.2.13CODLabelCompPPThe label property page addresses the orientation properties of labels. You can set a label so that it always appears in a certain position relative to its associated symbol. This property page allows the user to choose that location.

Figure 98 – Labels property page

13.2.14CODPosSizeCompPPThe position and size property page shows the current position and size of a component.

Figure 99 – Position and Size property page

178

Page 193: Objective Views User’s Guide - Perforce

13.2.15CODTextCompPPThe text component property page allows the user to change the following properties: text value, multi-line text, word break, horizontal alignment, and vertical alignment. The text value is a single-line text edit in which the user can enter a string. The multi-line checkbox toggles between multiple lines of text and single-line text. If multi-line is checked, then the vertical alignment fields are dis-abled. The horizontal and vertical alignment values are set using radio buttons.

Figure 100 – Text component property page

Chapter 13 Dialogs 179

Page 194: Objective Views User’s Guide - Perforce

13.3 Measurement Property SheetThe measurement property sheet is a series of property pages that deal with setting the canvas size, units of measurement, drawing scale, and coordinate mapping. This section describes the classes used to implement the measurement property sheet.

Figure 101 – Measurement property sheet

13.3.1 CODMeasurePropSheetThis class encapsulates the measurement property sheet. It contains three property pages: canvas size, drawing scale, and coordinate mapping. A flag value passed into the constructor determines which pages are visible.

13.3.2 CODMeasurePropPageThe measure property page is the base class for all of the property pages dealing in the measure-ment property sheet. This class keeps a pointer to an IODRuler interface, so that all types of measurement property pages can perform conversions.

13.3.3 CODCoordinateMappingPageThe coordinate mapping page deals with the mapping mode and extents of the viewport. These can be changed on the fly to experiment with different mapping modes.

180

Page 195: Objective Views User’s Guide - Perforce

Figure 102 – Coordinate mapping page

13.3.4 CODCanvasSizePageThe canvas size page allows the user to set the size of the canvas in real world units, such as inches. This is dependent on the information in the coordinate mapping and drawing scale pages.

13.3.5 CODDrawingScalePageThe drawing scale page shows how logical units are translated into real world units. These can be changed dynamically to experiment with different settings.

Figure 103 – Drawing scale page

Chapter 13 Dialogs 181

Page 196: Objective Views User’s Guide - Perforce

13.4 Other Dialogs

13.4.1 CODComponentDlgThe component dialog displays a list of the names and types of the top-level components currently in the model. It allows the user to center the viewport over a component or set of components, to edit the component properties, and to delete the components. The base controller class opens this dialog when it receives the ID_OD_VIEW_COMPS command message.

Figure 104 – Component dialog

13.4.2 CODComponentLBThe component list box displays a list of components in the model in the component dialog. The list box uses several different bitmaps to identify the type of the components.

182

Page 197: Objective Views User’s Guide - Perforce

13.4.3 CODGridDlgThe grid dialog lets the user configure the grid. The user can set the spacing, the color, visibility, and snapping functionality. The base controller class opens this dialog when it receives the ID_OD_GRID_PROPS command message.

Figure 105 – Grid dialog

13.4.4 CODZoomDlgMost of the zoom options can be accessed through menu items, but the user can also specify a cus-tom zoom percentage through this dialog box. The base controller class opens this dialog when it receives the ID_OD_ZOOM_CUSTOM command message.

Figure 106 – Zoom dialog

Chapter 13 Dialogs 183

Page 198: Objective Views User’s Guide - Perforce

184

Page 199: Objective Views User’s Guide - Perforce

Chapte

Chapter 14

Utility Classes

14.1 CODGlobalThe global class comprises a wide range of utility classes for use in various sections of Objective Views. The header file also defines some global constants and enumerations.

14.2 CODPageSettingsThis object holds the page settings for the model. The page settings are configured in the standard Windows Page Settings dialog. The page settings are used by the viewport to determine page boundaries on the canvas and to initialize the printer when printing the components in the model.

14.3 IODIdGeneratorThis defines an interface for a component ID generator. You can mix this interface into a class that you want to have generate these IDs. The CODModel implements this interface.

r 14 Utility Classes 185

Page 200: Objective Views User’s Guide - Perforce

14.4 Smart PointersMany objects in Objective Views are reference counted. An object that is reference counted knows how many objects reference it. When an object’s reference count reaches zero, there are no longer any other objects that depend on it and the object can delete itself. All objects that are reference counted implement the IODObject interface to keep track of their references.

Reference counting can be prone to error. If the count is off, objects can be left in memory when the application exits, or they can be deleted before other objects are finished with them. To automate reference counting, smart pointers are used in many places throughout Objective Views.

The SmartPtr template encapsulates pointers to objects that support the functions AddRef() and Release(). The IODObject interface defines AddRef() and Release(), so SmartPtr works with any object that implements the IODObject interface. The SmartPtr automatically increments the reference count by calling AddRef() whenever it is assigned a pointer. The SmartPtr can be assigned a pointer through its constructor or through the assignment operator. When the SmartPtr is destroyed or when it is assigned a new pointer value, it decrements the reference count by calling Release(). The SmartPtr class overrides the pointer reference operator-> so that using the pointer value it encapsulates is transparent. In other words, the SmartPtr can be used as though it is a pointer value. Consider smart pointers as pointer objects that replace the standard pointers in C++.

14.5 Sets and IteratorsSets are collections of objects. We refer to sets throughout Objective Views. Sets use the CCArray_T template defined in the MVC section of the code. It is a CArray that is multiply inherited from the ICollection_T template, which allows it to have an iterator.

Iterators are objects that can step through collections. The sets used in Objective Views all use the ICollection_T template found in the MVC section of the code, which allows iterators to operate on them.

186

Page 201: Objective Views User’s Guide - Perforce

Chapter 15 OL

Chapter 15

OLE Document Servers

15.1 Introduction to OLE Document ServersAn OLE document server is an application that provides an interface for linking or embedding docu-ments inside other applications. A classic example of this is placing an MS Excel spreadsheet inside of an MS Word document. OLE document server and container applications use numerous COM interfaces to communicate with each other and negotiate this complex act of cooperation. Fortu-nately, MFC provides classes that hide this complexity and make it easy to implement both OLE document servers and containers.

This section explains how to add OLE document server support to an Objective Views application. It’s easy to do because MFC does most of the work. Using the Objective Views AppWizard and selecting either Full-Server or Both container and server for compound document support gener-ates an application with basic OLE document server support. If you use the Objective Views AppWizard to generate an OLE document server application, you do not need to follow the steps described in this section. However, you should still read this section if you want to understand the generated code.

E Document Servers 187

Page 202: Objective Views User’s Guide - Perforce

15.2 Server Document and ItemsThere are some basic services that an OLE document server must provide to a container applica-tion. MFC implements many of these services in the COleServerDoc and COleServerItem classes. Your application must contain classes that derive from these two base classes, and must override some of their methods to implement certain services.

The COleServerDoc class encapsulates a document that is either linked or embedded in one or more container documents. It derives from CDocument and is responsible for maintaining a list of CDocItem objects. The document class in your application should be derived from COleServerDoc.

The COleServerItem class derives from CDocItem, and has the same relationship to the COleServerDoc class as a CView. Server item objects are created by the COleServerDoc::OnGetEmbeddedItem() method, and each server item has a pointer back to the document that created it. A server item provides a view of the document when it is linked or embedded in a container application.

188

Page 203: Objective Views User’s Guide - Perforce

15.3 Declaring the COleServerDoc ClassThe document class in your application must derive from COleServerDoc. It should declare at least one member variable that is derived from CODModel. It should override the OnGetEmbeddedItem() method for creating server items. It should also override OnDeactivate(). The declaration of your COleServerDoc derived class should look like Example 20.

Example 20 – Declaration of a COleServerDoc derived class

class CMyAppDoc : public COleServerDoc{protected: // create from serialization only CMyAppDoc(); VIEWS_DECLARE_DYNCREATE(CMyAppDoc)

// Attributespublic: CMyAppSrvrItem* GetEmbeddedItem() { return (CMyAppSrvrItem*)COleServerDoc::GetEmbeddedItem(); }

protected: CMyAppModel m_mdlCanvas;

public: // Gets a pointer to the model of the diagram. CMyAppModel* GetModel() { return &m_mdlDiagram; } // Determines if the diagram has been modified. virtual BOOL IsModified();

// Operationspublic:

// Overrides // ClassWizard generated virtual function overrides //{{AFX_VIRTUAL(CMyAppDoc) virtual void DeleteContents(); protected: virtual COleServerItem* OnGetEmbeddedItem(); public: virtual BOOL OnNewDocument(); virtual void Serialize(CArchive& ar); virtual void OnDeactivate(); //}}AFX_VIRTUAL...}

Chapter 15 OLE Document Servers 189

Page 204: Objective Views User’s Guide - Perforce

15.4 Declaring the COleServerItem ClassYour application should contain a server item class derived from COleServerItem. It is important to override OnGetExtent(), OnDraw(), and Serialize(). The declaration of your COleServerItem derived class should look like Example 21.

Example 21 – Declaration of a COleServerItem derived class

class CMyAppSrvrItem : public COleServerItem{ VIEWS_DECLARE_DYNAMIC(CMyAppSrvrItem)

// Constructors public: CMyAppSrvrItem(CMyAppDoc* pContainerDoc);

// Attributes CMyAppDoc* GetDocument() const { return (CMyAppDoc*)COleServerItem::GetDocument(); }

CMyAppViewport* GetViewport();

// Overrides // ClassWizard generated virtual function overrides //{{AFX_VIRTUAL(CMyAppSrvrItem) public: virtual BOOL OnDraw(CDC* pDC, CSize& rSize); virtual BOOL OnGetExtent(DVASPECT dwDrawAspect, CSize& rSize); //}}AFX_VIRTUAL

// Implementationpublic: ~CMyAppSrvrItem();#ifdef _DEBUG virtual void AssertValid() const; virtual void Dump(CDumpContext& dc) const;#endif

protected: virtual void Serialize(CArchive& ar); // overridden for document i/o}

190

Page 205: Objective Views User’s Guide - Perforce

15.5 Server Item CreationOne of the services that the server provides to the container is document creation. MFC delegates this responsibility to COleServerDoc::OnGetEmbeddedItem(). Your COleServerDoc derived class must override this factory method to create instances of your server items, as shown in Example 22.

Example 22 – Creating server items

COleServerItem* CMyAppDoc::OnGetEmbeddedItem(){// OnGetEmbeddedItem is called by the framework to get// the ColeServerItem that is associated with the// document. It is only called when necessary.

CMyAppSrvrItem* pItem = new CMyAppSrvrItem(this); ASSERT_VALID(pItem); return pItem;}

Chapter 15 OLE Document Servers 191

Page 206: Objective Views User’s Guide - Perforce

15.6 Server Item SerializationThe OLE document server must provide persistence interfaces to the container item, so the linked or embedded document can be saved and restored by the container. This functionality is mapped by MFC to the COleServerItem::Serialize() method. You must override this method and make sure that it saves and restores the information in the document. If the item is embedded, then the entire document can be serialized using the Serialize() method of your COleServerDoc derived class. If the item is linked, then you must supply application-specific logic for serializing the link information.

Example 23 – Serializing server items

void CMyAppSrvrItem::Serialize(CArchive& ar){ if (!IsLinkedItem()) { CMyAppDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); pDoc->Serialize(ar); } else { // Serialize information need to link to the // document. This could be just a filename or // some other information that points to the // document. }}

Make sure the ColeServerDoc derived class serializes the model.

Example 24 – Serializing the model

void CMyAppDoc::Serialize(CArchive& ar){ // Serialize the model. m_mdlCanvas.Serialize(ar);}

192

Page 207: Objective Views User’s Guide - Perforce

15.7 Server Item ViewportTo render the information in the model, the server item needs a viewport. The CView derived class in your application either mixes in a viewport class, or it contains a viewport as a member. It is pos-sible to have your COleServerItem derived class either mix in or aggregate a viewport. However, it is easier to use the viewport that is already available from the active CView object attached to the document. When the document template is used to create the server document, it also creates a view. By retrieving the first view attached to the document, we can get a viewport to use for ren-dering the server item.

Example 25 – Server item viewport

CMyAppViewport* CMyAppSrvrItem::GetViewport(){ // // Find the first view attached to the document, and // use it to render the server item. //

CMyAppDoc* pDoc = GetDocument();

if (pDoc != NULL) { POSITION pos = pDoc->GetFirstViewPosition(); CMyAppView* pFirstView = (CMyAppView*) pDoc->GetNextView(pos); if (pFirstView != NULL) { return pFirstView->GetViewport(); } }

return NULL;}

Chapter 15 OLE Document Servers 193

Page 208: Objective Views User’s Guide - Perforce

15.8 Server Item OnGetExtent()The container must be able to query the server for the size of the item. The COleServerItem::OnGetExtent() method is called when the container requests the size of the item. The size of the item is always expressed in MM_HIMETRIC units (0.01 millimeters per logic unit). The viewport contains a method to return its bounds in MM_HIMETRIC units. All you need to do is get the viewport, make sure it is sized to display the entire model, and then retrieve the size.

Example 26 – OnGetExtent() method

BOOL CMyAppSrvrItem::OnGetExtent(DVASPECT dwDrawAspect, CSize& rSize){ // Most applications, like this one, only handle drawing the // content aspect of the item. If you wish to support other // aspects, such as DVASPECT_THUMBNAIL (by overriding OnDrawEx), // then this implementation of OnGetExtent should be modified // to handle the additional aspect(s).

if (dwDrawAspect != DVASPECT_CONTENT) return COleServerItem::OnGetExtent(dwDrawAspect, rSize);

// // This function is called to get the extent in HIMETRIC units of // the entire item. // CMyAppViewport* pViewport = GetViewport(); if (pViewport != NULL) { // Set the viewport size pViewport->SizeToModel(); CRect rcBounds = pViewport->GetHiMetricBounds(); rSize.cx = rcBounds.Width(); rSize.cy = rcBounds.Height(); return TRUE; }

return FALSE;}

194

Page 209: Objective Views User’s Guide - Perforce

15.9 Rendering the Server ItemWhen the container application asks the server to render the document, the server invokes the vir-tual OnDraw() method in the COleServerItem class. The COleServerItem::OnDraw() takes a device context and a size parameter, and the device context is typically a metafile DC. The view-port contains a DrawMetafile() method that draws the contents of the model to a metafile. The DrawMetafile() method excludes the grid, page boundary lines, and selection handles from being drawn, since these are artifacts used to edit objects on the canvas.

Example 27 – Rendering a server item

BOOL CMyAppSrvrItem::OnDraw(CDC* pDC, CSize& rSize){ // Remove this if you use rSize UNREFERENCED_PARAMETER(rSize);

// // Draw the viewport onto the metafile DC // CMyAppViewport* pViewport = GetViewport();

if (pViewport != NULL) { pDC->SetMapMode(MM_TEXT); pViewport->DrawMetafile(pDC); pDC->SetWindowExt(1,1); }

return TRUE;}

Chapter 15 OLE Document Servers 195

Page 210: Objective Views User’s Guide - Perforce

196

Page 211: Objective Views User’s Guide - Perforce

INDEX

Aaccessor objects 140adding

image 52text 52

Align Bottom button 54Align Center button 54Align Left button 54Align Middle button 54Align Right button 54Align Top button 54aligning

components 54anchor component

definition 53angle snap 67, 88

Bbezier curve 112binary space-partitioning tree 103Bring Forward button 56Bring to Front button 56Build Wizard 7

purpose 7Building 7building

Build Wizard 7MVC library 7Objective Views library 7Stingray Studio library 7

Ccanvas

background 66definition 1, 46grid 67

CODAlignCommand 170CODBoolProperty 133CODBspNode 103CODBspRect 103CODBspTree 103CODCanvasSizePage 181CODCommand 166

CODComponentDlg 182CODComponentLB 182CODCompPropSheet 173CODConnection 155CODConnectionMap 155CODCoordinateMappingPage 18

0CODDefPropSheet 174CODDeleteCommand 169CODDeleteVertexCommand 167CODDrawingScalePage 181CODDropSource 104CODDropTarget 104CODEditCompPP 175CODEditProperties 133CODFillCompPP 176CODFillProperties 134CODFontCommand 170CODFontCompPP 177CODFontListBox 177CODFontProperties 134, 137CODGeneralCompPP 174CODGlobal 185CODGridDlg 183CODGroupCommand 169CODHatchLB 176CODIndexedCommand 169CODInsertCommand 169CODInsertVertexCommand 167CODIntProperty 135CODLabelCompPP 178CODLineCompPP 175CODLineOrientation 135CODLineProperties 135, 137CODLineSizeLB 176CODLineStyleLB 176CODLinkCommand 168CODLinkComponent 102, 160CODMacroCommand 170CODMeasurePropPage 180CODMeasurePropSheet 180

CODModel 101CODMoveCommand 166CODMovePortCommand 167CODMoveVertexCommand 167CODNameCommand 168CODOrderCommand 169CODOrientationProperties 136CODPageSettings 185CODPolygonRgn 130CODPosSizeCompPP 178CODPropertyCommand 170CODRgn 130CODRotateCommand 166CODScaleCommand 167CODSizeCommand 168CODSizeListBox 177CODSpacingCommand 167CODStringProperty 136CODSymbolComponent 79CODTextCommand 168CODTextCompPP 179CODTransform 124, 125CODTransformStack 124CODTransparencyCommand 16

8CODUngroupCommand 169CODUpdateCommand 168CODZoomDlg 183COleServerDoc 189COleServerItem 190COM 81commands

class hierarchy 164classes 166components 165definition 163executing 165model 165type ids 165unexecuting 165

componentanchor 53

Index 197

Page 212: Objective Views User’s Guide - Perforce

definition 47component set tracker 123component tracker 123component tracking 89components 56

aligning 54children 126manipulating 53metafiles 117moving 53ordering 56rotating 55scaling 55selecting 53spacing 54

compositedefinition 47

connection 153definition 47sample 154

control handlesdefinition 47

control point 111controller 94

definition,MVCController 46coordinate mapping 90creating

item creation 191symbols 76

Ddefinition 68directed graph 100directed node traversal 101documentation

formats 3htmlhelp 3

drag-and-dropOLE 104

drawing 50closed curve 52components 51Drawing toolbar 76ellipse 52line 51polycurve 51polygon 51polyline 51rectange 51scale 92

Drawing Toolbar 76

Eedge 100endpoints

changing 160

Ffeatures

Objective Views 2Flip Horizontal button 56

Ggrab handles 111graph navigation

interfaces 100IODEdge 102IODEdgeCollection 101IODGraph 101IODNode 101IODNodeCollection 101node and edge

collections 101overview 100

gray selection handlesdefinition 53

gridangle snap 67canvas 67Snap to Grid 67

Group button 56grouping 56

components 56Group button 56

Hhit testing 94htmlhelp 3

Iimage 52image cache 117interface 81

IODEdge 102IODGraph 101IODNode 101

interface-based programmingas applies to objective

views 82definition 81

interfacesgraph navigation 100

introduction

Objective Views 1IODEdge 102

CODLinkComponent 102IODEdgeCollection 101IODGraph 101

CODModel 101IODIdGenerator 185IODNode 101IODNodeCollection 101IODPropertyContainer 137iterators

definition 186

Llabel 152

definition 48, 59manipulating text in 59

librariestypes 7

libraryMVC 8naming conventions 8

lifetime management 81link

definition 48introduction 157orthogonal 161

linkingsymbols 159

logical units 89

Mmanipulating

components 53measurement

property sheet 180Measurement and Size property

sheet 71Coordinate Mapping page 71Drawing Scale page 71Size and Units page 71

modeldefinition 46

Move Back button 56moving

components 53MVC library

purpose 8MVCModel 46MVCViewport 46

198 Index

Page 213: Objective Views User’s Guide - Perforce

Nnested property 133node 100node and edge collections 101Nudge Down button 54Nudge Left button 54Nudge Right button 54Nudge Up button 54

OObjective Diagram, conversion

from 152Objective Views

dependencies 3feature summary 2introduction 1

off-screen buffering 89OLE

document servers 187drag-and-drop 104metafiles 104

orderingBring Forward button 56Bring to Front button 56components 56Move Back button 56Send to Back button 56

orthogonal link 161

Ppage boundaries 88Page Layout 73pan 70

Pan tool button 70Pan tool button 70Pointers

smart 186port 151

definition 48ports 76, 151presentation model, defined 86property

definition 49property cache 142Property IDs 137property pages 61

Edit Properties page 61Fill Properties page 62Font Properties page 63General Properties page 61

Line Properties page 62Position and Size Properties

page 64Text Properties page 64

QQuick Tour

purpose 21

Rreference count 186reference counting 81Rotate Left button 55Rotate Right button 55Rotate tool button 55rotating

component 55Rotate Left button 55Rotate Right button 55Rotate tool button 55

Ruler 68run-time interface discovery 81

SSame Height button 55Same Size button 55Same Width button 55samples

on Rogue Wave Web site 2saving

symbols 78scaling

components 55selecting

components 53Selection tool button 53Send to Back button 56serializing

server item 192Server Document 188Server Item

OnGetExtent 194rendering 195

setsdefinition 186

smart pointer 186Snap to Grid 67Space Across button 54Space Down button 54

spacingcomponents 54

state machine 94Stingray Studio library 8symbol

definition 49, 59Symbol Designer 75–79

purpose 75symbols

accessing 144conversion 152creating 76creating on the fly 146introduction 143saving 78setting the type 76toolbars 150using as resources 145

system model, defined 86

Ttext 52toolbars

Alignment 16Canvas 18Drawing 15Layout 18Nudge 17Rotate 16Structure 17Zoom/Pan 15

tracking 97transaction model 87transform stack 124, 128transform, nested 127transformation matrices 124

nested 127transformation matrix 110, 124transforms 124

classes 124translation

definition 49trees

binary space partitioning 103tutorial

integrating Objective View into a project 38–43

simple ??–37

Uundirected graph 100

Index 199

Page 214: Objective Views User’s Guide - Perforce

undirected traversal functions 101

Ungroup button 56ungrouping 56

components 56Ungroup button 56

using in place of Symbol Designer 79

VVertices

editing 57viewport

definition 46server item 193

WWindows Enhanced Metafile For-

mat (EMF) 117

Zzoom 69

limits 88Zoom tool button 69

Zoom tool button 69z-order, changing 169

200 Index