Macromedia InDesign - CS4 Programming Guide

ADOBE® INDESIGN® CS4
ADOBE INDESIGN CS4 PRODUCTS
PROGRAMMING GUIDE
© 2008 Adobe Systems Incorporated. All rights reserved.
Adobe InDesign CS4 Products Programming Guide
The content of this guide is furnished for informational use only, is subject to change without notice, and should not be construed as a commitment by Adobe Systems Incorporated. Adobe Systems Incorporated assumes no responsibility or liability for any errors or inaccuracies that may appear in the informational content contained in this guide.
Pl ea se r eme mb er t hat ex ist ing ar two rk o r i mag es t ha t yo u m ay w ant to inc lud e i n yo ur p ro jec t ma y b e pr ote ct ed u nde r c opy ri ght law. The unauthorized incorporation of such material into your new work could be a violation of the rights of the copyright owner. Please be sure to obtain any permission required from the copyright owner.
Any references to company names in sample templates are for demonstration purposes only and are not intended to refer to any actual organization.
Adobe, the Adobe logo, Acrobat, Bridge, Creative Suite, Illustrator, InCopy, InDesign, Photoshop, and Reader are either registered trademarks or trademarks of Adobe Systems Incorporated in the United States and/or other countries. Microsoft and Windows are either registered trademarks or trademarks of Microsoft Corporation in the United States and/or other countries. Apple and Mac OS are trademarks of Apple Computer, Incorporated, registered in the United States and other countries. Java is a trademark of Sun Microsystems, Incorporated in the United States and other countries.All other trademarks are the property of their respective owners.
Adobe Systems Incorporated, 345 Park Avenue, San Jose, California 95110, USA. Notice to U.S. Government End Users. The Software and Documentation are “Commercial Items,” as that term is defined at 48 C.F.R. §2.101, consisting of “Commercial Computer Software” and “Commercial Computer Software Documentation,” as such terms are used in 48 C.F.R. §12.212 or 48 C.F.R. §227.7202, as applicable. Consistent with 48 C.F.R. §12.212 or 48 C.F.R. §§227.7202-1 through 227.7202-4, as applicable, the Commercial Computer Software and Commercial Computer Software Documentation are being license d to U.S. Gover nment end users (a) only as Commercial Items and (b) with only those rights as are granted to all other end users pursuant to the terms and conditions herein. Unpublished-rights reserved under the copyright laws of the United States. Adobe Systems Incorporated, 345 Park Avenue, San Jose, CA 95110-2704, USA. For U.S. Government End Users, Adobe agrees to comply with all applicable equal opportunity laws including, if appropriate, the provisions of Executive Order 11246, as amended, Section 402 of the Vietnam Era Veterans Readjustment Assistance Act of 1974 (38 USC 4212), and Section 503 of the Rehabilitation Act of 1973, as amended, and the regulations at 41 CFR Parts 60-1 through 60-60, 60-250, and 60-741. The affirmative action clause and regulations contained in the preceding sentence shall be incorporated by reference.
Contents
Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
For experienced InDesign developers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
For new InDesign developers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
Persistent Data and Data Conversion . . . . . . . . . . . . . . . . . . . . . . . . 29
Concepts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
Persistence . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
Databases. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
Persistent objects. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
Using persistent objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
Implementing persistent objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
Streams . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
IPMStream methods . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
Implementing a new stream . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
Missing plug-ins . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
Warning levels . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
Missing plug-in alert . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
Guidelines for handling a missing plug-in . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
Data handling for missing plug-ins . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
Conversion of persistent data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40
When to convert persistent data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
Converting data with the conversion manager . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
Converting data without the conversion manager . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52
Resources. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53
PluginVersion resource, format numbers, and their macros . . . . . . . . . . . . . . . . . . . . . . 53
Setting up resources . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
Schemas. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
SchemaList . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
DirectiveList . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58
Advanced schema topics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59
Arrays of values . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59
FieldArray . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60
Conditional-field inclusion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60
3
Contents
Commands . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63
Concepts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63
Command pattern . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63
Databases and undoability . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64
Models. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64
Commands. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68
Command parameters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69
Command undoability. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70
Command processing and the CmdUtils class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70
Command sequences . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71
Command managers, databases, and undo support. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73
The command processor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76
Scheduled commands. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78
Snapshots and interface implementation types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79
Command history . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 80
Merging changes with an existing step in the command history . . . . . . . . . . . . . . . . . . . 81
Undo and redo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81
Extension patterns involved in undo and redo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83
Notification within commands . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83
Error handling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83
Protective shutdown. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84
Key client APIs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84
Command facades and utilities . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84
Command-processing APIs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 86
Extension patterns . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 86
Command . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 86
Error string service . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 88
Persistent interface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89
Persistent boss. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91
Snapshot interface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92
Inval handler . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94
Snapshot view interface. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 99
4 Adobe InDesign CS4 Products Programming Guide
Contents
Notification . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101
Concepts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .101
Observer pattern . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .101
Responder pattern . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .102
Observers. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .102
Subjects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .103
Observers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .104
Message protocols . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .104
Subject and observer types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 105
Regular and lazy notification. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .106
Observers and undo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .111
Relating observers to subjects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .112
Document notification . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .113
Observers and the model . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .113
Responders. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 115
Signal manager . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .116
Responder . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .117
Responders and the model . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .117
Responders and global error state . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .118
Ordering of responders . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .118
Responders and undo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .119
Key client APIs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 119
Extension patterns . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .120
User-interface widget observer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 120
Model observer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .120
Selection observer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .122
Document observer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .122
Active context observer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .122
Subject . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .124
Responder . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .124
Selection . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 125
Concepts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .125
Selection . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 125
Selection format and target . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .125
Design patterns . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .126
Selection architecture . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .127
Abstract selection bosses and suites. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .130
Adobe InDesign CS4 Products Programming Guide 5
Contents
Concrete selection bosses . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .131
Layout selection. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .132
Table selection. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 133
Text selection . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 134
Galley text selection . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .135
Story-editor text selection . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .136
Note text selection . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .137
XML selection . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .138
Document defaults . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .140
Application defaults . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .141
Integrator suites. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .142
CSB suites. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .142
Encapsulation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 143
Suites and the user interface: an example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .143
Responsibilities . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .144
Basic client-code responsibilities . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .144
Selection-observer responsibilities . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .144
Custom-suite responsibilities . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .144
Custom suites . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .145
Selection extensions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .146
Caches . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 146
Selection change notification . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .146
Initialization . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .147
Communication with Integrator suite . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .147
Selection observers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .147
Selection-utility interface (ISelectionUtils) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .148
Layout Fundamentals . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 149
Terminology . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .149
Concepts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .150
Documents and the layout hierarchy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .152
Architecture . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .152
Parent and child objects and IHierarchy. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .155
Spreads and pages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .157
Layers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 161
Layers in a basic document . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .162
Layer options. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .165
Navigating spread content using ISpread. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .166
6 Adobe InDesign CS4 Products Programming Guide
Contents
Master spreads and master pages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .168
Master spreads and master pages in a basic document . . . . . . . . . . . . . . . . . . . . . . . . .169
Master-page item overrides . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .172
Basing one master page on another . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .172
Page items . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .173
Frames and paths . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .173
Graphic page items. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .177
Text page items . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .177
Interactive page items . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .178
Groups. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .178
Abstract page items and kPageItemBoss . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .179
Guides and grids . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .180
Ruler guides . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .180
Margin and column guides . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .180
Document grid . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .181
Baseline grid . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .181
Snap . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .181
Layout-related preferences. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .182
Coordinate systems . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .183
Transformation matrices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .183
Pasteboard coordinate space . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .184
Inner coordinate space and parent coordinate space . . . . . . . . . . . . . . . . . . . . . . . . . .185
Spread coordinate space . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .188
Page coordinate space. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .189
Page-item coordinate space . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .190
Bounding box and IGeometry . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .190
Transformation and ITransform . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 191
Measurement units. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .192
Geometrical data types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .194
The layout presentation and view . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .194
Layout presentation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .194
Layout view. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .196
Current spread and active layer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .197
Layout-presentation and layout-view coordinate spaces . . . . . . . . . . . . . . . . . . . . . . . .198
Key client APIs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 199
Extension patterns . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .202
New-page-item responder . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 202
Custom page item . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .203
Custom unit-of-measure service . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .203
Adobe InDesign CS4 Products Programming Guide 7
Contents
Commands that manipulate page items . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 204
Page-item creation commands . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .204
Page-item update commands . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .205
Page-item deletion commands . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 209
Graphics Fundamentals . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 211
Paths. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 211
Path concepts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .211
Paths data model . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .213
Path operations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .215
Graphic page items . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .217
Graphic page-item types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 217
Graphic page-item settings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 219
Graphic page-item data model . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .223
Graphic page-item examples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .226
Graphics import . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .238
Export to graphics file format . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .243
Colors and swatches . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .246
Architecture . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .246
Swatches . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .250
Solid colors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .250
Gradients . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .251
Swatch lists . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .251
Inks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .251
Color management . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .252
ICC profiles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .253
Color-management workflow . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .253
Data model for color management. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .253
Graphic attributes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .256
Graphic-attribute data model . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .256
Representation of graphic attributes. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .258
Graphic styles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .258
Graphic state . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 259
Mapping graphic attributes between domains . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .260
Rendering attributes. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .261
Color-rendering attributes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .261
Gradient attributes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 262
8 Adobe InDesign CS4 Products Programming Guide
Contents
Stroke effects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .262
Path stroker. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .262
Path corners . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .263
Path-end strokers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 263
Transparency effects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .263
Concepts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 263
Flattening. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 272
Transparency data model . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .272
Data model for drawing. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .276
Presentation views . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .276
Graphics context . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .277
Viewport . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .277
Dynamics of drawing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .278
Drawing the layout . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .278
Drawing page items . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 281
Drawing in user-interface widget windows . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .283
Offscreen drawing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .284
Client APIs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .285
Path-related client APIs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .285
Graphic page-item client APIs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .286
Key color-related client APIs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 287
Graphic-attribute client APIs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .288
Extension patterns . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .289
Custom graphic attributes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .289
Custom path-stroker effects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .289
Custom corner effects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .290
Custom path-end effects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .290
Custom page-item adornments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .291
Custom drawing-event handler . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .294
Swatch-list state. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .296
Initial state of swatch list and ink list . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .296
State of swatch list and ink list after adding a custom stop color . . . . . . . . . . . . . . . . . . .297
Swatch list and ink list after adding a gradient swatch. . . . . . . . . . . . . . . . . . . . . . . . . .299
Swatch list and ink list after applying an unnamed color to an object . . . . . . . . . . . . . . . .300
Color spaces . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 300
Catalog of graphic attributes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 301
Mappings between attribute domains . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .306
Spread-drawing sequence . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .307
Adobe InDesign CS4 Products Programming Guide 9
Contents
Controlling the settings in a graphics port . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .309
Drawing sequence for a page item . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .310
Text Fundamentals . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 313
Concepts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .313
Text content . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 315
Stories . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .315
Text formatting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .324
Class associations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .330
Text presentation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .331
Text layout . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .331
Text frame . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 331
Frame list . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .333
Threading and text frames . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .336
Parcels . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .339
Span . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .342
Text frames and the wax . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .343
Text-frame options . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .345
Text-frame geometry. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 345
Text Inset . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .346
Text wrap . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .347
Text on a path . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .350
The wax . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 354
Wax strand, wax line, and wax run . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .354
Examples of the wax . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .355
Text adornments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .358
Text composition . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .364
Phases of text composition . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .366
Damage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .367
Recomposition . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 369
Wax strand . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .370
Paragraph composers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .371
Shuffling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .371
Vertical justification . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .371
Background composition . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .371
Recomposition transactional model . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .372
Recomposition notification. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .372
Implementation notes for paragraph composers . . . . . . . . . . . . . . . . . . . . . . . . . . . . .372
10 Adobe InDesign CS4 Products Programming Guide
Contents
Fonts. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .389
Font-subsystem architecture. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .390
Fonts within the document. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .392
Composite fonts and international-font issues . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .395
Tables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 397
Concepts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .397
Table structure. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .397
Design and architecture. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .402
Table model versus text model . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .402
Table data model . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 404
Cell data model . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .406
Table attributes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 407
Table and cell styles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 409
Formatting tables, cells, and table text . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 413
Essential APIs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .414
Table commands . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .414
ITableSuite . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .414
ITableStyleSuite and ITableStylesFacade . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .415
ICellStyleSuite and ICellStylesFacade. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 415
Printing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 417
Concepts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .417
Printing is simply drawing to the printer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 417
Control can be shared . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .417
Inks and colors. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .417
Overprinting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .418
Trapping . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 418
Color management and proofing. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 418
Preflight and packaging . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .418
Exporting to EPS and PDF. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .419
Printing data model . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .419
Print settings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .419
Print preset styles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 420
Trap styles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .420
Utility APIs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 420
The print action sequence . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 421
Common print interfaces . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 422
Adobe InDesign CS4 Products Programming Guide 11
Contents
Print user interface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .423
Print dialog box . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .423
Print Presets dialog box . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .435
Extending the Print dialog box or the Print Presets selectable dialog box . . . . . . . . . . . . .435
Printing extension patterns . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .435
Print-setup provider . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .435
Print-insert-PostScript proc provider. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .436
Print-data helper-strategy provider . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .437
Draw-event handlers. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .438
Printing solutions. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 438
Getting started . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .438
Working with print-preset styles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .439
Working with trap styles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .441
Participating in the print process . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 443
Bosses that aggregate IPrintData . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .448
Print-action and supporting commands . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .448
Japanese page-mark files. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 449
Exporting to EPS and PDF . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .450
Exporting to EPS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .450
Exporting to PDF . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 453
PDF Import and Export . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 455
PDF import . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .455
PDF export . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .459
InDesign/InCopy document export . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .459
InDesign book export . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .468
Selected page-items export . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .469
PDF-style import and export. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .470
Adding, deleting, and editing styles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .471
Frequently asked questions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 472
How does the PDF export provider determine whether it should start the viewer
after the export? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .472
How do I set the PDF clipboard setting as seen in the File Handling preferences? . . . . . . . .472
How do I control which layer of a document should be exported? . . . . . . . . . . . . . . . . . . 472
How do I make the two-page spreads in my document export as two separate PDF pages? .473
Why does kPDFExportCmdBoss give me an assert after the command is processed
(ASSERT 'db != nil' in PDFExportController.cpp)? . . . . . . . . . . . . . . . . . . . . . . . . . . . . .473
How do I set up line ranges for output in InCopy Galley or Story mode? . . . . . . . . . . . . . .473
Is it possible to export only selected text from an InDesign document? . . . . . . . . . . . . . .473
12 Adobe InDesign CS4 Products Programming Guide
Contents
Implementing Preflight Rules . . . . . . . . . . . . . . . . . . . . . . . . . . . 475
Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .475
About preflight in InDesign CS4 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .475
About rules. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 475
Rule IDs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .476
Rule service . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .476
IPreflightRuleService example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 477
Rule bosses. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .478
IPreflightRuleVisitor interface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .479
IPreflightRuleVisitor method examples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .480
IPreflightRuleVisitor::GetClassesToVisit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 480
IPreflightRuleVisitor::Visit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .481
IPreflightRuleVisitor::AggregateResults . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 483
IPreflightRuleVisitor::UpdateRuleData . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 490
IPreflightRuleVisitor::ValidateRuleData . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 490
More on specific objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .491
Native, UID-based objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .491
Artwork . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .492
Text runs and ranges . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .494
Tables, rows, columns, and cells . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 495
XML Fundamentals . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 497
Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .497
XML-based workflow. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .497
Using XML with InDesign . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .498
Terminology . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .498
XML features at a glance . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .499
XML extension patterns . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .499
Tagging in tables and inline graphics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .499
Throw away unmatched existing (right). . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .499
Throw away unmatched incoming (left). . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .500
Importing repeating elements. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .500
Importing CALS table . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .500
Support for DOM core level 2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 500
Support table- and cell-styles import . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .500
Support XML-rules processing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .500
Snippets. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 500
Adobe InDesign CS4 Products Programming Guide 13
Contents
The user interface for XML . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .501
Structure view . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .501
Tags in layout view and story view . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .501
Tags panel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .502
Mapping between tags and styles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 503
Validation window . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .504
Other. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 504
XML model . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .505
Native document model and logical structure. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .505
Elements and attributes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .505
Content items . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .506
References to elements and content items . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 507
Document element and root element . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 508
Backing store. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 509
Persistence and the backing store . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 510
Importing XML . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .511
Import architecture. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .512
Importing a minimal XML file . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .515
Unplaced content versus placed content . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .518
XML template . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 519
Matching against an XML template . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .519
Importing repeating elements. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .519
Throwing away unmatched existing elements on import (delete unmatched right). . . . . . .520
Throwing away unmatched incoming elements on XML import . . . . . . . . . . . . . . . . . . . 522
Attribute-style mapping . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 522
Creating links on XML import . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .523
Sparse import . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .523
Importing a CALS table as an InDesign table. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .524
Support table and cell styles when importing an InDesign table . . . . . . . . . . . . . . . . . . .524
Exporting XML. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .524
Export architecture . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .525
Document order . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 526
Tagged graphic placeholder, exported . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .527
Tagged text range, exported . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .528
Tags . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .529
Architecture . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .530
Tag-to-style mapping . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .531
Style-to-tag mapping . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .532
14 Adobe InDesign CS4 Products Programming Guide
Contents
Elements and content . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 534
Tagged graphic placeholder . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 534
Tagged images . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .536
Tagged stories . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .537
Tagged text ranges . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .538
Tagged inline graphics. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .542
Tagged tables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .543
DTD. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .545
Processing instructions and comments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .547
Structural (container) elements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .549
XML-related preferences . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .549
Workspace-level XML preferences . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .549
Service-level XML preferences . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .551
Key client API . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .552
XML suites . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .552
Command facades and utilities . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 553
Extension patterns . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .553
XML acquirer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .553
XML transformer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .554
XMl-import matchmaker . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .555
Post-import responder . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .555
Custom suite for the structure view . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .556
SAX-content handler . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .556
SAX DOM serializer handler . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .557
Custom-tag service . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .557
SAX-entity resolver . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .557
XML-export handler . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 558
Commands and notification . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .558
Backing store and notification of changes in logical structure. . . . . . . . . . . . . . . . . . . . . 558
Entities supported . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .559
Assets from XSLT example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .560
Limitations of the InDesign XML architecture . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .561
Adobe InDesign CS4 Products Programming Guide 15
Contents
Scriptable Plug-in Fundamentals . . . . . . . . . . . . . . . . . . . . . . . . . 563
Terminology . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .563
Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .565
Scripting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .565
Benefits of making a plug-in scriptable . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 565
Scripting and IDML . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .566
Making a plug-in scriptable . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .566
Tools for making a plug-in scriptable . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .567
Scripting architecture . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 567
Scripting DOM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .568
Versioning the scripting DOM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .569
Scripting plug-in . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .570
Script interaction with the scripting DOM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .571
Scripting process overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .572
Script managers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .573
Scriptable plug-ins . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .573
Scripting resources . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 574
Script providers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .574
Scriptable boss classes. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .574
How to make your plug-in scriptable . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .575
Prerequisites . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 575
Defining IDs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 576
Adding a new property to an existing script object . . . . . . . . . . . . . . . . . . . . . . . . . . .576
Adding a new event to an existing script object . . . . . . . . . . . . . . . . . . . . . . . . . . . . .576
Adding a new script object to make preferences scriptable . . . . . . . . . . . . . . . . . . . . . .577
Adding a new singleton script object . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 578
Adding a new script object to make a boss with a UID scriptable. . . . . . . . . . . . . . . . . . .578
Adding a new script object to make a boss with no UID scriptable . . . . . . . . . . . . . . . . . .579
Adding a new script object to make a C++ object with no boss scriptable . . . . . . . . . . . . .580
Adding a new script object to make a panel scriptable . . . . . . . . . . . . . . . . . . . . . . . . .581
Adding an error-string service . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .582
Handling multiple concurrent requests . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .582
Reviewing scripting resources . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 583
Running versioned scripts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .586
Supporting IDML . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .588
Maintaining IDML forward and backward compatibility . . . . . . . . . . . . . . . . . . . . . . . .589
Verifying your plug-in’s data is round-tripped through IDML . . . . . . . . . . . . . . . . . . . . . 590
Tips for debugging the scripting architecture . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .591
16 Adobe InDesign CS4 Products Programming Guide
Contents
Scripting resources. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 591
VersionedScriptElementInfo resource . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 592
Object element . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .593
Event element . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .595
Property element . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .597
Struct element . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 601
TypeDef element . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .602
Enum element . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .603
Enumerator element . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .604
Metadata element . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .604
Provider element . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .606
Suite element . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .609
ScriptElementIDs, ScriptIDs, names, descriptions, and GUIDs . . . . . . . . . . . . . . . . . . . . .610
ScriptID/name registration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .612
Scripting data types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .615
Script-object inheritance . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .619
Overloading an existing event or property . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .621
Versioning of scripting resources . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 621
Client-specific scripting resources . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .632
Elements that are not applicable to a particular object . . . . . . . . . . . . . . . . . . . . . . . . .638
Key scripting APIs. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .639
Scripting DOM reference . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .641
Scripting DOM versioning . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .641
Dumping the scripting DOM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .642
Snippet Fundamentals . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 643
Conceptual overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .643
Snippets as self-contained assets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 643
Snippet types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .644
Features that depend on snippets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .644
User interface for snippets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .644
Drag and drop . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .644
Asset library . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .645
Export snippet from selection . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 645
Snippet model. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .645
INX, IDML, and snippets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .645
Boss DOM overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .646
Scripting DOM overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .647
From boss DOM to scripting DOM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 647
Adobe InDesign CS4 Products Programming Guide 17
Contents
Snippet types and policies . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .648
Export . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .648
Import . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .650
Snippet examples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .652
Filled-rectangle snippet . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .652
Image-item snippet . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .657
XML element snippet, tagged placeholder . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .660
Client API . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .663
Suites . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .663
Utilities . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .663
Extension patterns . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .664
Adding persistent data to snippet files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 664
Frequently asked questions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 664
What is a snippet, and how do I create one? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .664
What happens if I export a snippet of a placed image? . . . . . . . . . . . . . . . . . . . . . . . . . 664
What features are based on snippets? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .665
How accurately is data round-tripped through snippets?. . . . . . . . . . . . . . . . . . . . . . . .665
When do I have to care about snippets?. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .665
Can I export spreads or pages as snippets?. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .665
Should we generate snippet files from scratch? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .665
Can I import a snippet directly into a library? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 666
Can I import a snippet into the scrap database? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 666
Can we add our own new snippet types? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .666
Shared Application Resources . . . . . . . . . . . . . . . . . . . . . . . . . . . 667
Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .667
Terminology . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .667
Architecture . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .667
How it works . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 668
ISnippetExport. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .668
IAppPrefsExportDelegate . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .669
ISnippetImport . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 669
IAppPrefsImportOptions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .669
IAppPrefsImportDelegate. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .670
18 Adobe InDesign CS4 Products Programming Guide
Contents
Working with snippet APIs: frequently asked questions . . . . . . . . . . . . . . . . . . . . . . . . . . .670
How do I create streams for reading and writing snippets?. . . . . . . . . . . . . . . . . . . . . . . 670
How do I limit my export to those items in the preference panel? . . . . . . . . . . . . . . . . . .670
How do I export all text styles, object styles, XML tags, or swatches in the
application workspace? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .671
How do I import a snippet into the application? . . . . . . . . . . . . . . . . . . . . . . . . . . . . .671
How do I control whether existing objects like paragraph styles are replaced or
deleted on import. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .671
How do I determine the correct ScriptID to use for a preference I’m trying to include
or exclude? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 671
How do I know which list element types will be exported by default?. . . . . . . . . . . . . . . . 671
User-Interface Fundamentals . . . . . . . . . . . . . . . . . . . . . . . . . . . . 673
Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .673
Key concepts. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .674
Design objectives for user-interface API. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .674
Idioms and naming conventions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .674
Abstractions and re-use . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .675
Widgets versus platform controls . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .676
Commands, model plug-ins, and user-interface plug-ins . . . . . . . . . . . . . . . . . . . . . . .676
Suites and the user interface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .677
Finding widgets in the API . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .678
Notifications about control events or changes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 678
Sample user interface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .679
Type binding . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .680
Factorization of the user-interface model . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 683
Architecture . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .683
Control views . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .684
Control data models . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .684
Event handlers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .685
Attributes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .685
Relevant design patterns . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .686
Observer pattern . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .686
How event handlers implement controllers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .687
The role of MVC in the user-interface model . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .688
Chain of responsibility . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 689
Facade . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .689
Command . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .690
Widget-observer pattern . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .690
Persistence and widgets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .691
Adobe InDesign CS4 Products Programming Guide 19
Contents
Resource roadmap . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .692
Architecture . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .692
OpenDoc framework (ODF) resources . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .693
Top-level framework resources . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 694
Localizing framework resources . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 694
Resource compilers. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .695
Customizing a widget . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .696
Advanced event handling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 696
Writing a proxy event handler . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .696
Watching events . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 697
Key abstractions in the API . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .697
Suppressed User Interface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 699
Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .699
Architecture . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .699
XML-based implementation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .700
XML file format . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .701
SuppressedWidget . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .702
SuppressedAction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .702
SuppressedMenu . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .703
SuppressedDragDrop . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .703
SuppressPlatformDialogControl. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .704
SuppressedUI tool . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .704
SuppressedUI tool limitations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .706
Working with the ISuppressedUI API. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .706
Other user-interface “suppression” mechanisms . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .707
Using Adobe File Library . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 709
Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .709
Terminology . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .709
Adobe File Library architecture . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .711
Adobe File Library classes and utilities. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .711
Common file API . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 713
File API specific to InDesign . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .714
Debugging IDFile . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .716
Porting guidelines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .716
Creative Suite 2 porting concerns. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 716
Creative Suite 3 porting concerns. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 716
20 Adobe InDesign CS4 Products Programming Guide
Contents
Frequently asked questions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 717
Why should I use Adobe file library? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 717
Does Adobe file library support cross-platform path conversion? . . . . . . . . . . . . . . . . . . 717
Should I still use the ICoreFileName interface? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .717
Why was the GetSysFile method renamed GetIDFile in SDKFileHelper? . . . . . . . . . . . . . . .717
How do I navigate between IDFile and IDPath? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .717
What are the differences between a file and a directory? . . . . . . . . . . . . . . . . . . . . . . . .718
What are the relationships between IDPath and IDFile? . . . . . . . . . . . . . . . . . . . . . . . . .718
Why should IDFile not be treated as PMString? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .718
How do an invalid path and a nonexistent path differ? . . . . . . . . . . . . . . . . . . . . . . . . .718
Can I construct an AString from PMString? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .718
How can I convert a relative path to an absolute path? . . . . . . . . . . . . . . . . . . . . . . . . .719
Performance Tuning . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 721
Use profiling tools . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .721
Windows . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .721
Mac OS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .721
Commands. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .722
Commands should operate on lists of inputs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .722
Notify on the document subject instead of the page item object . . . . . . . . . . . . . . . . . .722
Mark commands that do not require undo support . . . . . . . . . . . . . . . . . . . . . . . . . . . 723
Observers. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .723
Attach to documents, not page items . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .723
Do work only when the command is done . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .723
Do not update the user interface from an observer . . . . . . . . . . . . . . . . . . . . . . . . . . . 724
Watch for lazy notification whenever possible. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .724
File input/output . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 724
Memory . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 724
Use memory caches for items accessed often . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .724
Avoid allocating too much memory . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .725
Idle tasks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 725
Honor the RunTask flags. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .725
Do a small amount of work during each RunTask call . . . . . . . . . . . . . . . . . . . . . . . . . .725
Adobe InDesign CS4 Products Programming Guide 21
Contents
Tools . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 727
Key concepts. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .727
The toolbox and the layout view . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 727
Tools . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .728
Cursors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .728
Tool tips . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .729
Trackers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 729
Tracker factory, tracking, and event handling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .729
Beyond the toolbox . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .730
Drawing and sprites . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .730
Documents, page items, and commands . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .731
Line-tool use scenario . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .731
Trackers with multiple behaviors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .734
Tool manager . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .735
Toolbox utilities . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 735
Tool type . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .735
Custom tools. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .736
Architecture . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .736
Class diagram . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 736
Partial implementation classes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .737
Default implementations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .737
ToolDef ODFRez type . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 738
Icons and cursors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .738
InDesign trackers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .739
Working with tools . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .740
Catching a mouse click or mouse drag on a document . . . . . . . . . . . . . . . . . . . . . . . . .740
Implementing a custom tool. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .740
Displaying a Tool Options dialog box . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .740
Finding the spread nearest the mouse position . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .740
Changing spreads. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .740
Performing a page-item hit test . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .740
Setting or getting the active tool . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .741
Observing when the active tool changes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 741
Changing the toolbox appearance from normal to skinny . . . . . . . . . . . . . . . . . . . . . . .741
Using default implementations for trackers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .741
Suppressing the application's default tracker for a custom toolbox . . . . . . . . . . . . . . . . .741
Tool-category information . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 742
Default implementations of tool-related interfaces . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .745
Tracker listings. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .746
22 Adobe InDesign CS4 Products Programming Guide
Contents
Diagnostics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 751
Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .751
Using the diagnostics plug-in . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .751
Diagnostics menu. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .752
Diagnostics > Command menu . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .752
Diagnostics > Document Structure menu . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .753
Diagnostics > INX DTD menu . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .754
Diagnostics > Object Model menu . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 755
Diagnostics > Scripting DOM menu . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 756
Running the Diagnostics plug-in in indesign/incopy with a script . . . . . . . . . . . . . . . . . .756
Running the Diagnostics plug-in in InDesign Server on Windows with a script . . . . . . . . . . 757
Running the Diagnostics plug-in in InDesign Server on Mac OS with a script . . . . . . . . . . .757
Frequently asked questions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 758
Where is the Diagnostics panel?. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .758
What is trace? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .758
Why don’t I get trace messages? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 758
InCopy: Getting Started . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 759
About InCopy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .759
Developing for InCopy. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .759
Using the combined InDesign/InCopy SDK . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .759
The InCopy API . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .760
Compiler settings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 760
Resources . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 760
Synchronization of design and architecture . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .760
File relationships . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .761
Stories . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .762
Page geometry . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .762
Metadata . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .762
The document model . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .763
User-interface differences. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .763
Checking the feature set . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .763
Workflow . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 764
Design and architecture . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 764
InCopyBridge plug-in . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .766
InCopyBridge . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .766
InCopyBridgeUI . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .767
Adobe InDesign CS4 Products Programming Guide 23
Contents
InCopy: Notes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 769
Concepts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .769
End-user requirements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .769
Capabilities . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .771
Data model for notes. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .773
Essential APIs. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .779
Useful commands and associated notification protocols . . . . . . . . . . . . . . . . . . . . . . . .783
Working with notes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .786
Adding a note at the current insertion-point position . . . . . . . . . . . . . . . . . . . . . . . . . .786
Inserting text into a note . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .787
Converting text to a new note . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 787
Converting note content to text. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .787
Navigating among notes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .788
Splitting a note . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .788
Expanding and collapsing notes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .788
Selecting a note . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 789
Getting kNoteDataBoss, given a text index whose position is anchored to note . . . . . . . . .789
Deleting notes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .790
Changing notes-palette content to reflect particular note data . . . . . . . . . . . . . . . . . . . .790
Checking note spelling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .790
Observing a note that is being modified . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .790
Using notes in InDesign . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .790
InCopy: Track Changes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 791
Concepts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .791
User interface for Track Changes feature . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 791
Data model for Track Changes. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .794
Redline strand . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 794
Tracking text insertion and deletion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .795
Example: Track Changes in action. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 799
Track Changes preferences . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .809
Key client APIs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 809
Track Changes utilities . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .809
Suite interfaces . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .809
RedlineIterator. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 811
kDeletedTextBoss . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .812
24 Adobe InDesign CS4 Products Programming Guide
Contents
Useful commands and associated notification protocols . . . . . . . . . . . . . . . . . . . . . . . . . . .814
kSetRedlineTrackingCmdBoss . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .814
kSetTrackChangesPrefsCmdBoss . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .814
kActivateRedlineCmdBoss . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 816
kDeactivateRedlineCmdBoss. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .816
kRejectAllRedlineCmdBoss . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .816
kRejectRangeRedlineCmdBoss . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .817
kRejectRedlineCmdBoss. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .817
kAcceptAllRedlineCmdBoss . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .818
kAcceptRangeRedlineCmdBoss . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .819
kAcceptRedlineCmdBoss . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .819
kMoveRedlineChangeCmdBoss . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .820
kRedlinePreserveDeletionCmdBoss . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .821
Working with Track Changes. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .821
Navigating tracked changes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .821
Accepting and rejecting tracked changes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .821
Understanding multiple change records in one location . . . . . . . . . . . . . . . . . . . . . . . .822
Avoid insignificant tracked changes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .822
Undoing accepted deleted text . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .822
Determining whether a location in a story is in deleted text . . . . . . . . . . . . . . . . . . . . . .822
Determining whether a primary story-thread location is at a deleted-text anchor . . . . . . . . 822
Getting kDeletedTextBoss, given a text index having deleted text . . . . . . . . . . . . . . . . . .823
Removing deleted text . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .823
Moving a change record from one story to another . . . . . . . . . . . . . . . . . . . . . . . . . . .823
Maintaining kRedlineStrandBoss text-run information . . . . . . . . . . . . . . . . . . . . . . . . .823
InCopy: Assignments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 825
Concepts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .825
Assignment workflow . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .826
Assignment-export options . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .826
Assignment . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .827
Assignment data model. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .829
Assignment hierarchy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 829
Object structure of an assignment . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .830
Moving assignment content . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 832
Assignment files and links . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .834
Assignment files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 834
Comparing assignment files to InDesign and InCopy files . . . . . . . . . . . . . . . . . . . . . . .835
Assignment-file format . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 835
Adobe InDesign CS4 Products Programming Guide 25
Contents
The assignment API . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .838
IAssignmentMgr. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 838
IAssignedDocument . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .838
IAssignment . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .838
IAssignedStory. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 838
IAssignmentSelectionSuite . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 839
IAssignmentUtils . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .839
IAssignmentUIUtils . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .839
IAssignmentPreferences. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .839
Common commands. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .839
Glossary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 841
26 Adobe InDesign CS4 Products Programming Guide

Introduction

This guide provides detailed information on the Adobe® InDesign® CS4 plug-in architecture. This C++-based SDK can be used for creating plug-ins compatible with the CS4 versions of InDesign, InDesign Server, and Adobe InCopy®.
This guide contains the most detailed information on plug-in development for InDesign prod­ucts. It is not designed to be a starting point. It picks up where Learning Adobe InDesign CS4 Plug-in Development leaves off, and it is more commonly used to understand particular sub­jects deeply.

For experienced InDesign developers

If you are an experienced InDesign plug-in developer, we recommend starting with Adobe InDesign CS4 Porting Guide.
Introduction
For experienced InDesign developers

For new InDesign developers

If you are new to InDesign development, we recommend approaching the documentation as follows:
1. Getting Started With the Adobe InDesign CS4 Products SDK provides an overview of the SDK, as well as a tutorial that takes you through the tools and steps to build your first plug­in.
2. Learning Adobe InDesign CS4 Plug-in Development introduces the most common program­ming constructs for InDesign development. This includes an introduction to the InDesign object model and basic information on user-interface options, scripting, localization, and best practices for structuring your plug-in.
3. The SDK itself includes several sample projects. All samples are described in the “Samples” section of the API reference. This is a great opportunity to find sample code that does some­thing similar to what you want to do, and study it.
4. Adobe InDesign CS4 Solutions provides step-by-step instructions (or “recipes”) for accom- plishing various tasks. If your particular task is covered by the Solutions guide, reading it can save you a lot of time.
5. This manual provides the most complete, in-depth information on plug-in development for InDesign CS4 products.
Introduction 27
Introduction
For new InDesign developers
28

Persistent Data and Data Conversion

Persistent Data and Data Conversion
This chapter describes how an application stores and refers to persistent data as objects and streams. The chapter also provides background information and implementation guidelines related to data conversion.
This chapter has the following objectives:
z Describe how Adobe InDesign® stores data.
z Explain how an object is made persistent.
z Show how to refer to a persistent object.
z Define a stream and explain how to create a new stream.
z Identify when data conversion is used.
z Describe the types of conversion providers.
z Show how conversion providers are defined.
z Describe schemas and their use.

Concepts

For common procedures and troubleshooting related to converting persistent data, see the “Versioning Persistent Data” chapter of Adobe InDesign CS4 Solutions.
Concepts

Persistence

A persistent object can be removed from main memory and returned again, unchanged. A per­sistent object can be part of a document (like a spread or page item) or part of the application (like a dialog box, menu item, or default setting). Persistent objects can be stored in a database, to last beyond the end of a session. Non-persistent objects last only until memory is freed, when the destructor for the object is called. Only persistent objects are stored in databases.

Databases

The application uses lightweight databases to store persistent objects. The host creates a data­base for each document created. The host also creates a database for the clipboard storage space, the object model information (the InDesign SavedData or Adobe InCopy® SavedData file), and the workspace information (the InDesign Defaults or InCopy Defaults file).
Each document is contained in its own database. Each persistent object in the database has a UID, a ClassID, and a stream of persistent data.
The stream with the persistent object data contains a series of records that correspond to the persistent object. The object’s UID is stored with the object, as a key for the record. The vari-
Persistent Data and Data Conversion 29
Persistent Data and Data Conversion
ImplID Length Data ImplID Length Data ImplID Length
k<Foo>Boss object persistent data record
UID

Persistent objects

able-length records have one segment for each persistent interface. Every segment has the same structure:
ImplementationID tag int32 length <data>
Figure 1 is a conceptual diagram of this structure. The figure is a conceptual diagram of the
database contents, and does not represent the actual contents of any database. The format and content of the data are determined by the implementation of the interface. See “Reading and
writing persistent data” on page 34.
FIGURE 1 Conceptual diagram of an object’s data
For each object, the ClassID value is stored in the table, and the ImplementationID values are stored in the stream, but the InterfaceID value is not stored with either. Adding an existing implementation (i.e., an implementation supplied by the SDK) to an existing class can cause problems if another software developer adds the same implementation to the class: one of the two plug-ins will fail on start-up. To avoid this collision, create a new implementation for any persistent interface to be added to a class, using ImplementationAlias. For an example, see <SDK>/source/sdksamples/dynamicpanel/DynPn.fr.
Persistent objects
This section discusses how persistent objects are created, deleted, and manipulated.
The application stores persistent objects in a database, and each object has a unique identifier within the database. The methods for creating, instantiating, and using a persistent object are different from the methods for non-persistent objects.

Using persistent objects

When a persistent object is created, its record exists in memory. Certain events, like a user’s request to save a document, trigger the writing of the record to storage. (See Figure 2) A count is maintained of the number of references to each persistent object. Any object with a reference count greater than zero remains active in memory. If the reference count for a persistent object reaches zero, the object may be asked to write itself to its database and be moved to the instance cache, which makes the object a candidate for deletion from memory. Events that require access to the object, like drawing or manipulating it, trigger the host to read the object back
30
Persistent Data and Data Conversion
Host Main memory Storage
Instantiate (no storage)
Dirty
ReadWrite
Instantiate (with storage)
NewUID
Reference count reaches zero
Persistent objects
into memory. Because individual objects can be saved and loaded, the host does not have to load the entire document into memory at once.
FIGURE 2 Creating and storing persistent objects
Creating a persistent object
Creating a new instance of a persistent object differs from creating a non-persistent object, because it requires a unique identifier to associate the object with its record in the database. For the CreateObject and CreateObject2 methods used to create persistent objects, see <SDK>/source/public/includes/CreateObject.h.
For examples of the creation of persistent objects, see the CreateWidgetForNode method in <SDK>/source/sdksamples/paneltreeview/PnlTrvTVWidgetMgr.cpp or the StartupSomePal-
Persistent Data and Data Conversion 31
ette method in <SDK>/source/sdksamples/dynamicpanel/DynPnPanelManager.cpp.
You also can call IDataBase::NewUID method to create a new UID in the database. It adds an entry to the database relating the UID to the class of the object being created; however, the object is not instantiated yet, and no other information about it exists in the database.
Instantiating a persistent object
Before you instantiate a new object, use the InterfacePtr template to retrieve one of the object’s interfaces. Pass the returned InterfacePtr to the IDatabase::Instantiate method, which calls the database to instantiate the object.
There is only one object in memory for any UID and database. This method checks whether the object already is in memory and, if so, returns a reference to that object. If the object is
Persistent Data and Data Conversion
Persistent objects
marked as changed, it is written to the database. For more information, see “Reading and writ-
ing persistent data” on page 34. If the object is not in memory, the method checks for previ-
ously stored data in the database. If data is found, the method instantiates the object from this data. Otherwise, the method instantiates the object from the object’s constructor. Each imple­mentation has a constructor, so the boss and all its implementations are instantiated.
An object is stored to the database only if it is changed, making the default object data invalid. A single object could exist and be used in several user sessions without ever being written to the database. A persistent object whose data is not stored in the database is constructed from the object’s constructor.
Whether it instantiates a new object or returns a reference to an object previously instantiated, IDatabase::Instantiate increments the reference count on the object and returns an IPMUn­known* to the requested interface, if the interface is available.
Using commands and wrappers
There are commands for creating new objects of many of the existing classes (e.g., kNewDocC­mdBoss, kNewPageItemCmdBoss, kNewStoryCmdBoss, and kNewUIDCmdBoss). When you need to create an object, first look for a suite interface, utility interface, or facade interface to make creating your object safe and easy. If no such interface exists, use a command if one is available, rather than creating the object with general functions.
Using a command to create an object protects the database. Commands are transaction based; if you use a command when the application already is in an error state, the command performs a protective shut-down, which quits the application rather than permitting a potentially cor­rupting change to be made to the document. Commands also provide notification for changes to the model, allowing observers to be updated when the change is made, including changes made with undo and redo operations.
When you implement a new type of persistent object, also implement a command to create objects of that type, using methods outlined in “Implementing persistent objects” on page 33.
Types of references to objects
There are four types of reference to a persistent object: UID, UIDRef, InterfacePtr, and UIDList. Each type of reference serves a different purpose. Understanding these reference types makes working with persistent objects easier.
z UID is the type used for a unique identifier within the scope of a database. The UID value
by itself is not sufficient to identify the object outside the scope of the database. Like a record number, a UID value has meaning only within a given database. UID values are use­ful for storing, passing, and otherwise referring to boss objects, because UID values have no run-time dependencies, and there is an instance cache ensuring fast access to the instanti­ated objects. kInvalidUID is a value used to identify a UID that does not point at a valid object. Any time a UID is retrieved and needs to be tested to see if it points at a valid object, the UID should be compared to kInvalidUID.
32
z A UIDRef object contains two pieces of information: a pointer to a database and the UID of
an object within this database. A UIDRef is useful for referring to objects, because it identi­fies both the database and the object. Using a UIDRef object is a common means of refer­ring to a persistent object, especially when the persistent object is to be passed around or
Persistent Data and Data Conversion
Persistent objects
stored, since a UIDRef does not require the referenced object to be instantiated. A UIDRef object cannot itself be persistent data, because it has a run-time dependency, the database pointer. An empty or invalid UIDRef object has kInvalidUID as its UID and a nil pointer as its database pointer.
z A InterfacePtr object contains a pointer to an interface (on any type of boss object) and
identify an instantiated object in main memory. While an InterfacePtr object on the boss is necessary for working with the boss, it should not be used to track a reference to a persistent object, because this forces the object to stay in memory. In many cases, a nil pointer returned from InterfacePtr does not indicate an error state but simply means the requested interface does not exist on the specified boss.
z A UIDList object contains a list of UIDs and a single pointer to a database. This means all
objects identified by a UIDList must be within the same database. A UIDList is a class object and should be used any time a list of objects is needed for a selection or a command.
Destroying an object
There are commands for deleting persistent objects. Use the command rather than calling the DeleteUID method directly, to be sure of cleaning up all references to the object or item refer­ences contained in the object.
When you implement a command to delete a persistent object, after you remove the references to the object, use DeleteUID to delete the object from the database, as follows:
IDataBase::DBResultCode dbResult = database->DeleteUID(uid);

Implementing persistent objects

To make a boss object persistent, add the IPMPersist interface. Any boss with this interface is persistent and, when an object of the boss is created, it is assigned a UID. Even though the object has a UID, and the UID has an entry in the (ClassID, UID) pairings in a database, the object does not automatically store data. It is up to the interface to store the data it needs. To implement this, add the ReadWrite method to the interface (see “Reading and writing persis-
tent data” on page 34), and make sure the PreDirty method is called before information is
changed (see “Marking changed data” on page 34).
NOTE: If you add an interface to an existing persistent boss, the interface also may be made
persistent. If so, you must obey the following implementation rules for it.
Adding the IPMPersist interface to a boss
All instances of IPMPersist must use the kPMPersistImpl implementation. For an example, see the kPstLstDataBoss boss class definition in <SDK>/source/sdksamples/persistentlist/PstLst.fr
Creating an interface factory for a persistent interface
For a persistent implementation, use the CREATE_PERSIST_PMINTERFACE macro.
Persistent Data and Data Conversion 33
Persistent Data and Data Conversion

Streams

Reading and writing persistent data
To store data, your interface must support the ReadWrite method. This method does the actual reading and writing of persistent data in the database. The method takes a stream argument containing the data to be transferred. Read and write stream methods are generalized, so one ReadWrite method handles transfers in both directions. For example, XferBool reads a boolean value for a read stream and writes a boolean value for a write stream. For an example, see the BPIDataPersist::ReadWrite method in <SDK>/source/sdksamples/basicpersistinterface/BPI­DataPersist.cpp.
Marking changed data
When data changes for a persistent object that resides in memory, there is a difference between the current version of the object and the object as it exists in the database’s storage. When this happens, the object in memory is said to be dirty, meaning it does not match the version in storage. Before a persistent object is modified, you must call the PreDirty method to mark the object as being changed, so it is written to the database. For an example, see the BPIDataPer­sist::Set method in <SDK>/source/sdksamples/basicpersistinterface/BPIDataPersist.cpp.
The PreDirty method called from within BPIDataPersist::Set is implementation-independent, so you can rely on the version provided by HELPER_METHODS macros defined in Helper­Interface.h (DECLARE_HELPER_METHODS, DEFINE_HELPER_METHODS, and HELPER_METHODS_INIT).
Streams
This section discusses how streams are used to move information into and out of a document.
Streams are used by persistent objects to store their information to a database. Streams also are used by the host application, to move data like placed images, information copied to the clip­board, and objects stored in the database. IPMStream is the public interface to streams. Imple­mentations of IPMStream typically use the IXferBytes interface to move data.
Stream utility methods (in StreamUtil.h) are helpers for creating all the common types of streams used to move information within or between InDesign databases. The stream utility methods and general read, write, and copy methods are needed any time you work with a stream.

IPMStream methods

IPMStream is a generalized class for both reading and writing streams. Any particular stream implementation is either a reading stream or a writing stream, and the type of stream can be determined with the IPMStream::IsReading and IPMStream::IsWriting methods.
Any persistent implementation has a ReadWrite method, which uses a set of data-transferring methods on the stream to read and write its data. (See “Reading and writing persistent data” on
page 34.) The IPMStream methods starting with the Xfer prefix are used for transferring the
34
data type identified in the method name. For example, XferByte transfers a byte, XferInt16 transfers a 16-bit integer, XferBool transfers a boolean value, and so on. All transferring meth­ods are overloaded, so they can take a single item or an array of items. (The XferByte(uchar, int32) version typically is used for buffers.) Streams also handle byte swapping, if required. If swapping is not set (SetSwapping(bool16)), the default is to not do byte-order swapping.
Additional IPMStream methods, XferObject and XferReference, transfer boss objects and ref­erences to objects. XferObject transfers an owned object, and XferReference transfers a refer­ence to an object not owned by the object using the stream. To decide which method to use, think about what should happen to the object if the owning object were deleted. If the object should still be available (as, for example, the color a page item refers to), use XferReference. If the item is owned by the object and should be deleted with the owner (as, for example, the page a document refers to), use XferObject.

Implementing a new stream

If you must read from or write to a location the host application does not recognize, you must create a new type of stream. For example, you might need to create a new stream type to import and export files stored on an FTP site or in a database.
Persistent Data and Data Conversion
Streams
Stream boss
The first step in implementing a new stream is to define the boss. Typically, a stream boss con­tains IPMStream and any interface required to identify the type of information in the stream, the target or source of the stream, or both. Example 1creates a pointer-based read-stream boss:
EXAMPLE 1 kExtLinkPointerStreamWriteBoss, a pointer based stream boss
Class {
kExtLinkPointerStreamWriteBoss, kInvalidClass, {
IID_IPMSTREAM, kExtLinkPointerStreamWriteImpl, IID_IPOINTERSTREAMDATA, kPointerStreamDataImpl, }
};
IPMStream is the only interface all stream bosses have in common. In Example 1, the IPointer- StreamData controls a stream that writes out to memory; it contains a buffer and a length.
Persistent Data and Data Conversion 35
Persistent Data and Data Conversion

Missing plug-ins

Example 2 is another example.
EXAMPLE 2 kFileStreamReadBoss, a stream commonly used in importing
Class { kFileStreamReadBoss, kInvalidClass, { IID_IPMSTREAM, kFileStreamReadLazyImpl, IID_IFILESTREAMDATA, kFileStreamDataImpl, } };
IPMStream interface and the IXferBytes class
When implementing your own stream, take advantage of the default implementations of IPM­Stream, CStreamRead, and CStreamWrite. These default implementations use an abstract base class, IXferBytes, to do the actual reading and writing. To implement a stream for a new data source, you must create an IXferBytes subclass that can read and write to that data source.
Missing plug-ins
This section discusses how to open a document that contains data saved by a plug-in that is no longer available.
Plug-ins you create can add data to the document. When your plug-in is present and loaded, it can open and interpret the data; however, if the user removes the plug-in and then opens the document, or gives the document to someone who does not have the plug-in, the plug-in is not available to interpret the data.
You have two ways to handle such situations:
z Control what warning is shown when the document is opened without the plug-in.
z Implement code to update the data the next time the document is opened with the plug-in.
The rest of this section describes these options.

Warning levels

The application can give a warning when it opens a document that contains data created by a plug-in that is not available. There are three warning levels: critical, default, and ignore. By set­ting the warning level, the plug-in can specify the relative importance of its data. Data created by the plug-in has the “default” warning level unless you override the setting and identify the data as more important (critical) or less important (ignored). This importance settings can be modified by adding resources to the plug-in’s boss definition file:
36
z CriticalTags — A “critical” warning tells the user the document contains data from missing
plug-ins and strongly advises the user not to open the document. If the user continues the
Persistent Data and Data Conversion
Missing plug-ins
open operation, the application opens an untitled document that is a copy of the original, to preserve the original document. Use this level when the data is visible in the document or contributes objects owned by another object in the database, like text attributes, owned by the text model.
z DefaultTags — A “default” warning tells the user the document contains data from missing
plug-ins and asks whether to continue the open operation. If the user continues the open operation, the application opens the original document. Use this level when the data is self­contained and invisible to the user, but the user might encounter missing function that would have been provided by the plug-in.
z IgnoreTags — An “ignore” warning provides no warning message at all; the application pro-
ceeds with the open operation as if there were no missing plug-ins. Use this level when the data is invisible to the user and completely self-contained. In this case, the user does not need to know the plug-in was involved in the construction of this document. If the plug-in stored data in the document, but that data is used only by this plug-in and does not refer­ence objects supplied by other plug-ins, the user sees no difference in the document when the plug-in is missing. For example, the plug-in might store preferences information in every document for its own use.
You can set these warnings to use ClassID (when the plug-in creates new bosses) or Implemen­tationID (when the plug-in adds interfaces to existing bosses) values as triggers. Use kImple­mentationIDSpace to specify a list of ImplementationID values, and kClassIDSpace for ClassID values. You can put any number of IDs in the list, but all the IDs must be of the same type. Use a second resource to mark IDs of another type. Example 3 and Example 4 set the warning level to ignore data stored by the PersistentList plug-in in the SDK by adding two resources to PstLst.fr:
EXAMPLE 3 Marking implementation IDs as ignored
resource IgnoreTags(1) { kImplementationIDSpace, { kPstLstDataPersistImpl, kPstLstUIDListImpl, } };
EXAMPLE 4 Marking boss classes as ignored
resource IgnoreTags(2) { kClassIDSpace, { kPstLstDataBoss, } };
You do not need to mark any IDs that do not appear in the document (for example, data that was written out to saved data) or implementations that are not persistent.
You do not need to mark IDs if you want the default behavior.
Persistent Data and Data Conversion 37
Persistent Data and Data Conversion
Missing plug-ins

Missing plug-in alert

This alert is activated when a document is opened and contains data from one or more missing plug-ins that cannot be ignored. The document contains a list of the plug-ins that added data to it. Each piece of data added has an importance attached to it; this may be critical, default, or ignorable. Data marked as ignorable does not cause the alert to be activated. Data marked as critical or default causes the alert to be activated. In the case of critical data, the alert works more strongly; this is the only difference between critical and default data.
The alert tells the user data is missing, presents a list of missing plug-ins, and allows the user to continue or cancel the open operation. Each missing plug-in has the chance to add a string to the alert that specifies additional useful information (e.g., a URL for purchasing or download­ing the plug-in). The alert is modeled on the missing-font alert.
The “Don’t Warn Again For These Plug-ins” option is de-selected by default. If this option is selected, the alert is not activated the next time a document is opened and any subset of the listed plug-ins is missing (and no other plug-ins are missing). This allows users accustomed to seeing (and ignoring) alerts concerning specific plug-ins to automatically bypass the alert, while still getting warned about data from any plug-ins newly found to be missing. The alert is activated again if a document is opened that uses other missing plug-ins. The alert is activated again if the “Don’t Warn Again For These Plug-ins” option is de-selected.

Guidelines for handling a missing plug-in

If a plug-in creates persistent data in a document, these guidelines ensure the document behaves gracefully if a user tries to open it when the plug-in is missing or if the document is edited by a user who did not have the plug-in:
If your plug-in does not store data in documents, you do not need to take any special precau­tions.
If the data stored by your plug-in does not reference other data in the document and does not appear visually in the document, mark the data as ignorable.
If editing the document without your plug-in could corrupt the document, mark the data as critical. You can specify a string that is displayed when the plug-in is missing and the user opens a document that contains data added by the plug-in. See the ExtraPluginInfo resource, which may provide information like the URL of a site from which the missing plug-in can be obtained. See an example of the use of this resource in <SDK>/source/sdksamples/transparen- cyeffect/TranFx.fr.
If there are checks your plug-in can do to restore the data’s integrity on opening a document edited without the plug-in, supply a FixUpData method. For an example, see <SDK>/source/sdksamples/persistentlist/PstLstPlugIn.cpp.
If you want your plug-in to handle the storage of its own data, use the application-supplied mechanism that treats the plug-in’s data like a black box. (See “Black-box data storage” on
page 39.)
38

Data handling for missing plug-ins

If a document contains data placed there by a plug-in that is not available, the user can choose to open the document anyway. If the data is completely self-contained, there may be no prob­lem; however, if the plug-in’s data depends on anything else in the document, undesirable things can happen.
Missing data not copied
InDesign maintains most data in a centrally managed model in which the core-content man­ager keeps track of what information is added to the document, handles conversion of the data, and provides a convenient mechanism for instantiating objects based on the data. This approach does not allow the data to be copied when the plug-in is missing, however, because the content manager would not be able to provide these services for the missing plug-in’s cop­ied data, and that potentially can leave the document in an invalid state. With the exception of those objects that hold onto only ClassID values, InDesign blocks copying data associated with missing plug-ins.
This means no attribute is copied if the plug-in that supplies the attribute is missing. This applies to all attributes: text, graphics, table, cjk, etc. Furthermore, if a plug-in attached a data interface to an existing attribute, and the plug-in is missing, the attribute is copied but the add­in data interface is not. This is consistent with how InDesign handles UID-based objects.
Persistent Data and Data Conversion
Missing plug-ins
Likewise, if a data interface is added to an XML element, the data interface is not copied if the plug-in that supplied it is missing.
There are several features based on an object from a required plug-in holding a ClassID from an optional plug-in, including adornments, text composer, pair-kern algorithm, section num­bers, and unit defaults. In these cases, the consequences of losing track of the plug-in that sup­plied the data is much less severe. Conversion of these ClassIDs is quite unusual and could be handled if necessary by issuing new ClassIDs. Error handling in the user interface when the plug-in is missing is much more graceful.
Black-box data storage
A second, simpler data-model storage mechanism was added for software developers requiring that data (like text attributes) is copied with the text, and for developers who want to attach data to other ID objects, such that it gets copied even when the source plug-in is missing. This mechanism is black-box data storage.
In the simplest case, the black box is just a new persistent interface that sits on the object. A plug-in can store data in the box or fetch data out of the box. The data is keyed by a ClassID, which is supplied by the plug-in. Multiple plug-ins can store their data in the same black box, and each plug-in gets its own, unique, streamed access to its data. The black box just keeps track of the key, the length of the data, and the data stream. The software developer is responsi­ble for handling everything else—conversion, swapping, etc. Users do not get a missing plug-in alert for data placed in a black box.
Any UID-based object could have a black box. In addition, attributes and small bosses (used for XML elements) also can have black boxes.
Persistent Data and Data Conversion 39
Persistent Data and Data Conversion

Conversion of persistent data

The following objects support black boxes:
z kDocBoss — The root object of the document does not get copied.
z kPageItemBoss — This includes all page item objects, including spreads, master pages,
splines, frames, images, and text frames.
z Attributes — This includes text, graphic, table, cjk, etc. (i.e., everything that appears in an
AttributeBossList).
For more information on the black-box mechanism, see IBlackBoxCommands, IBlackBoxCm­dData, and IBlackBoxData in the API reference documentation.
FixUpData
Suppose a hyperlink attribute is linked to another frame, and the user can double-click the link to go to the frame. A plug-in supplies an observer, so if the frame is deleted, the link is severed. Now suppose you give the document containing the hyperlinks to someone who does not have the hyperlink plug-in. This person edits the document, deletes the frame, saves the document, then returns the document to you. The document is now corrupted, because your plug-in was unable to delete the associated link, which now points to an undefined frame.
To restore the integrity of a document in this case, the plug-in can override the IPlugIn::FixUp­Data method. This method is called when the document is opened, if the plug-in was used to store data in the document and the document was edited and saved without the plug-in. In this case, the hyperlinks plug-in could override FixUpData to scan all its objects, checking whether the linked frame UIDs were deleted; when the document is opened with the plug-in, the method correctly severs the links.
40
Conversion of persistent data
This section describes types of conversion providers and the advantages of each type.
Converting persistent data from an old document to a new one is complex, because each plug­in can store data independently in the document. When the host opens a document created with an older version of the application or an older version of any plug-in used in the docu­ment, you must convert and update the older data to match the new format.
Versioning persistent data is the process of converting persistent data in a database from one format to another. The data in different formats usually resides in different databases; for example, data in a database (document) from a previous version of InDesign versus that in a database (document) from a newer version of InDesign. Just as each plug-in having a persistent data implementation is responsible for the order of reading and writing its own data (thus implicitly defining a data format), each plug-in also is responsible for converting its own data from one format to another. Whether data in a database requires conversion usually is deter­mined when the database is opened.
There are two approaches to converting persistent data:
z You can use the host’s conversion manager to manage the conversion process. This
approach is the most common. See “Converting data with the conversion manager” on
page 42.
z The plug-in that owns the data can manage when and how data is converted, using version
information or other data embedded with the object data. See “Converting data without the
conversion manager” on page 52.

When to convert persistent data

As a plug-in developer, you want to ensure your users can open documents with persistent data from an older version of your plug-in. To do this, your plug-in must provide data conversion function. The best time to consider your data-conversion strategy is when you realize your plug-in will store some data to a database. You need to implement data-conversion utilities in the following cases:
z You change the order of IPMStream::Xfer* calls in the ReadWrite method.
z You change a persistent object’s definition.
Persistent Data and Data Conversion
Conversion of persistent data
z You re-number (change the value of) an ImplementationID or ClassID identifier.
z You remove a plug-in and data from the removed plug-in might be in a document a user
wants to open.
In any of these cases, the conversion manager needs to be notified how to convert the persistent data for use by the loaded plug-in.
Specifying how the persistent data format changed is somewhat different from adding persis­tent data to or removing it from a document. Besides telling the conversion manager to add or delete any obsolete data, the conversion provider has to be able to tell the conversion manager about every implementation in the plug-in that was ever removed, to keep the content manager up to date about the various persistent data formats.
NOTE: To provide a document for use with an earlier version of InDesign, use the InDesign
Interchange file format.
At the very least, the resources required to support data conversion can help you keep a log of how your persistent data format has changed. Such a log can be useful.
Sample conversion scenario
Consider a plug-in with two released versions, 1 and 2, which use the same data format; in this case, both versions of the plug-in have the same format version number, 1. The new release of the plug-in, version 3, stores additional data, such as a time stamp. You must update the format version number to match the current plug-in version number; so, for plug-in version 3, the for­mat version also would be 3. Because you changed the format version number, you must create a converter that converts from version 1 to version 3. See Tab le 1.
Persistent Data and Data Conversion 41
Persistent Data and Data Conversion
Conversion of persistent data
TABLE 1 Version changes example
Plug-in version Format change Format version
1 N/A (new plug-in) 1.0
2No1.1
3 Ye s 3
4Yes4
For a fourth version of the plug-in, you again change the format, allowing a date stamp to be signed. Change the plug-in and format version numbers to 4, and add an additional converter to convert from version 3 to version 4. Conversions from version 1 to version 4 are done by the conversion manager, which chains the converters together; the first converts from format ver­sion 1 to format version 3, and the second converts from format version 3 to format version 4).

Converting data with the conversion manager

Each document contains header information about the content, which includes a list of all plug-ins that wrote data to the document and the version number of the plug-in last used to write that data. When a document is opened, the application checks whether any plug-ins are missing or out of date. If a plug-in is missing, it might provide an alert embedded in the docu­ment. (See “Missing plug-ins” on page 36.)
If a plug-in is out of date, data written by the old plug-in must be updated to match the format required by the loaded plug-in. A plug-in can register a conversion service to do the update. The InDesign conversion manager (IConversionMgr) determines which conversions are required for opening the document and calls the appropriate plug-in to do the conversion.
When the persistent data for any plug-in changes, this is a document format change. Any of the following can change the document format:
z Changes to the ReadWrite method — If the ReadWrite method is used to stream data to the
document, changing the ReadWrite method might change the document format; however, an implementation might have a ReadWrite method that works with some other database or other data source, not with the document itself. For example, a widget has a ReadWrite method used for streaming to and from resources and to and from the SavedData file. Changes to a method that does not work with the document database do not require any special conversion.
z Changes to an object’s definition — If you add an implementation to (or remove an imple-
mentation from) the definition of a persistent boss in the framework resource (.fr) file, you change how the object is streamed. If you add a new implementation, an old version of the object will stream, but it will not contain the data normally appearing for the implementa­tion you added. This is fine if the data can be initialized adequately from the implementa­tion’s constructor; otherwise, you may need to add a converter. If you change the implementation of an interface from one ImplementationID to another, you must convert the data. If you remove an ImplementationID from a class, you should add a converter to
42
Persistent Data and Data Conversion
Conversion of persistent data
strip the old data from the object; otherwise, the obsolete data is carried around with the object indefinitely.
z Re-numbering an ImplementationID or ClassID — If an ImplementationID or ClassID
changes, you must register a converter so occurrences of the ImplementationID or ClassID in old documents can be updated. In practice, re-numbering a ClassID or Implementa­tionID is a source of many bugs and typically leads to corrupt documents, so we strongly recommend you not re-number an ImplementationID or ClassID.
When you make a format change, you must do two things to maintain backward compatibility:
z Update the version number of the plug-in whose data format you changed.
z Provide a converter that can convert between the previous format and the new format.
Updating version numbers
Each plug-in has a plug-in version resource of type PluginVersion. The PluginVersion resource appears in the boss definition file. The first entry of this resource describes the application's build number; on the release build, this entry is the final-release version number. The second entry of the resource is the plug-in's ID, followed by three sets of version numbers, followed by an array of feature-set IDs. If any of the IDs in this list matches the current feature-set ID, the plug-in is loaded. To see an example, open any example .fr file in the SDK.
Each version number has a major number and a minor number. The first version number is the version of the plug-in, which gets updated for every release of the plug-in. The second version number is the version of the application with which the plug-in expects to run. This ensures the user does not drop a plug-in compiled for one version of the application into an installation of another version of the application. The last number is the format version number, which indicates the version of the plug-in that last changed the file format; this is the version number written into the document, and it is the number the conversion manager checks to see whether conversion is required.
The format version number does not always match the plug-in’s version number. The format version number does not generally change as often as the plug-in version number. The plug-in version number changes for every release of a plug-in, but the format version number changes only if the format for the data the plug-in stores in the document has changed and the conver­sion manager is required to convert the data.
Adding a converter
Converters can be implemented as conversion services. InDesign supports two types of ser­vice-provider-based data conversion:
z Schema-based provider — Schema-based converters are configured through resources, are
easier to use than code-based converters, and cover most format-change needs. Use this type of converter unless it cannot handle the special needs of your plug-in.
z Code-based provider — If your implementation uses a special data-compression algorithm
or other storage optimizations, involves data of variable length, or uses virtual object store (VOS) objects, schema-based converters cannot handle the necessary data format conver­sions. In this case, you must implement your own custom conversion provider.
Persistent Data and Data Conversion 43
Persistent Data and Data Conversion
Conversion of persistent data
A conversion service is responsible for all conversions done by the plug-in. A converter might at first handle only a single conversion, from the first format to the second. Later, if you change the format again, you can add another conversion to the converter, to convert from the second format to the third.
Suppose you market a plug-in that supplies a date stamp. You had released two versions (ver­sion 1.0 and version 2.0) of the plug-in without changing the persistent data created by the plug-in; so both releases have the same format version number (1.0). For the third released ver­sion of the plug-in, you add a time stamp. You must update the format version number to match the current plug-in version number; i.e., for plug-in version 3.0, the format version also must be 3.0.
Suppose for the fourth released version of the plug-in (version 4.0), you again change the for­mat, allowing a date stamp to be signed. You then change the format version number to 4.0 and add an additional converter, capable of converting from format version 3.0 to format version
4.0. Conversions from format version 1.0 to format version 4.0 can be done by the conversion
manager, which chains the two converters together, using the first converter to convert from format version 1.0 to format version 3.0, and using the second converter to convert format ver­sion 3.0 to format version 4.0.)
Adding a converter (either schema-based or code-based) to your plug-in means adding a new boss with two interfaces, IK2ServiceProvider and IConversionProvider. The IK2ServiceProvider implementation, kConversionServiceImpl, is provided by the application. You need to supply the IConversionProvider implementation. Here is a sample boss:
/** This boss provides a conversion service to the conversion manager to use the schema-based implementation. */ Class { kMyConversionProviderBoss, kInvalidClass, { IID_ICONVERSIONPROVIDER, kMySchemaBasedConversionImpl, IID_IK2SERVICEPROVIDER, kConversionServiceImpl, } },
44
Most of the work is done in the conversion provider supplied with the SDK.
The default implementation of IConversionMgr calls IConversionProvider::CountConversions and IConversionProvider::GetNthConversion to determine which conversions are supported by the converter. When you implement a new converter, CountConversions returns 1, and Get­NthConversion returns fromVersion set to the version number before your change and toVer­sion set to the version number having your change in it. VersionID is a data type in the Public library; it consists of the PluginID value, the major format version number, and the minor for­mat version number.
For a new converter, fromVersion should be VersionID(yourPluginID, kOldPersistMajorVer­sionNumber, kOldPersistMinorVersionNumber). The toVersion should be the new format ver­sion number.
Persistent Data and Data Conversion
Conversion of persistent data
Your new conversion is added as conversion index 0. For a new converter, it looks like this:
int32 TextConversionProvider::CountConversions() const { return 1; }
void TextConversionProvider::GetNthConversion( int32 i, VersionID* fromVersion, VersionID* toVersion) const { *fromVersion = VersionID(kTextPluginID, kOldPersistMajorVersionNumber, kOldPersistMinorVersionNumber); *toVersion = VersionID(kTextPluginID, kNewPersistMajorVersionNumber, kNewPersistMinorVersionNumber); }
When adding another change after a changed version already exists, the change numbers should chain together so the conversion manager can do changes across multiple formats. So, if your plug-in used three formats—starting with version 1, then changed in version 3, and changed again in version 4—your plug-in should register one converter that handles the con­version from format version 1 to format version 3 and another converter that handles the con­version from format version 3 to format version 4. If necessary, the conversion manager can chain them together to convert a document from version 1 to version 4. The methods would look like this:
const int32 kFirstFormatVersion = 1; const int32 kSecondFormatVersion = 3; const int32 kThirdFormatVersion = 4;
const int32 kFirstChange = 0; const int32 kNewChange = 1;
int32 TextConversionProvider::CountConversions() const { return 2; }
void TextConversionProvider::GetNthConversion( int32 i, VersionID* fromVersion, VersionID* toVersion) const { if (i == kFirstChange) { *fromVersion = VersionID(kTextPluginID, kMajorVersionNumber, kFirstPersistMinorVersionNumber); *toVersion = VersionID(kTextPluginID, kMajorVersionNumber, kSecondPersistMinorVersionNumber); } else if (i == kNewChange) { *fromVersion = VersionID(kTextPluginID, kMajorVersionNumber, kSecondPersistMinorVersionNumber); *toVersion = VersionID(kTextPluginID, kMajorVersionNumber, kThirdPersistMinorVersionNumber); } }
Persistent Data and Data Conversion 45
Persistent Data and Data Conversion
Conversion of persistent data
Next, tell the conversion manager which information you changed. The default implementa­tion of IConversionMgr calls IConversionProvider::ShouldConvertImplementation with each implementation in the document supplied by the plug-in. Depending on the data status of the implementation, the plug-in must return kMustConvert when the content must be modified, kMustRemove when the data is obsolete and must be removed, kMustStrip when the content must be stripped, or kNothingToConvert for all other cases.
Using kTextFrameImpl as an example, define a method for IConversionProvider::ShouldCon­vertImplementation, returning kMustConvert when the tag is kTextFrameImpl and kNothing­ToConvert in all other cases. The plug-in should do this when the conversion manager is converting that plug-in’s data and not performing another conversion, so check the conversion index and make sure it is the one that you added. It might look like the following:
IConversionProvider::ConversionStatus TextConversionProvider::ShouldConvertImplementation( ImplementationID tag, ClassID context, int32 conversionIndex) const { IConversionProvider::ConversionStatus status = IConversionProvider::kNothingToConvert;
switch (conversionIndex) { case 0: if (tag == kTextFrameImpl) status = IConversionProvider::kMustConvert; break; default: break; }
return status; }
Next, implement ConvertTag to do the actual conversion. Suppose the TextFrame ReadWrite method writes an integer value and a real value, and you are adding a boolean. The ConvertTag implementation might look like the following, which illustrates what most converters look like:
ImplementationID TextConversionProvider::ConvertTag( ImplementationID tag, ClassID forClass, int32 conversionIndex, int32 inLength, IPMStream* inStream, IPMStream* outStream, IterationStatus whichIteration) { ImplementationID outTag = tag; switch (conversionIndex) { case 0: if (tag == kTextFrameImpl) { if (inLength > 0) { int32 passThruInt; inStream->XferInt32(passThruInt); outStream->XferInt32(passThruInt); int32 passThruReal; inStream->XferInt32(passThruReal); outStream->XferInt32(passThruReal); // Adding new field bool16 smartQuotes = kTrue; outStream->XferInt32(smartQuotes);
46
Persistent Data and Data Conversion
Conversion of persistent data
} } break; default: break; } return outTag; }
If the converter needs to convert a class, it implements ShouldConvertClass and ConvertClass. This is necessary only if the class is being deleted or is a container for some other data. (See
“Containers and embedded data” on page 48.)
Removing classes or implementations
If you remove a ClassID or an ImplementationID from a version of your plug-in, the identifier also must be removed from documents as they are converted. The conversion manager removes an identifier for you if you implement your converter to return invalid status. For example, to remove a tag, implement ConvertTag as follows:
ImplementationID TextConversionProvider::ConvertTag( ImplementationID tag, ClassID forClass, int32 conversionIndex, int32 inLength, IPMStream* inStream, IPMStream* outStream, IterationStatus whichIteration) { ImplementationID outTag = tag; switch (conversionIndex) { case 0: if (tag == kTagToRemove) outTag = kInvalidImpl; break; default: break; } return outTag; }
Deleting a class is similar: implement ConvertClass to return kInvalidClass.
Changing an implementation in one class
Suppose a boss is defined with an IBoolData interface, implemented as kPersistBoolTrue, meaning it defaults to true. Suppose you change this to kPersistBoolFalse. When you read an old document with the new boss, you want it to use the new implementation. You would then write a converter to take the data stored as kPersistBoolTrue and switch it to be stored as kPer­sistBoolFalse. When you first access the boss, it has the old value. If you do not make a con­verter, the boss will not read the old data, because there is no interface in the new boss using the kPersistBoolTrue ImplementationID. Instead, the boss looks for kPersistBoolFalse but does not find it, because the old boss did not have it; therefore, the value is false, because it is the default value instead of the old value.
To change the ImplementationID of the data in the document, make a conversion method to catch the old ImplementationID and change it to the new one. Do this only for your boss; do not change other bosses using kPersistBoolTrue. Your method might look like this:
Persistent Data and Data Conversion 47
Persistent Data and Data Conversion
Conversion of persistent data
ImplementationID TextConversionProvider::ConvertTag( ImplementationID tag, ClassID forClass, int32 conversionIndex, int32 inLength, IPMStream* inStream, IPMStream* outStream, IterationStatus whichIteration) { ImplementationID outTag = tag; switch (conversionIndex) { case 0: if (tag == kPersistBoolTrue && forClass == kMyBoss) outTag = kPersistBoolFalse; bool16 theBool; inStream->XferBool(theBool); outStream->XferBool(theBool); break; default: break; } return outTag; }
forClass is the boss in which the data was found. The conversion should be done only if forClass is the one you want changed.
Also implement ShouldConvertImplementation. forClass is either the class in which the data was found or kInvalidClass if any class should match. The implementation of ShouldCon­vertImplementation looks like this:
IConversionProvider::ConversionStatus TextConversionProvider::ShouldConvertImplementation ( ImplementationID tag, ClassID forClass, int32 conversionIndex) const { IConversionProvider::ConversionStatus status = IConversionProvider::kNothingToConvert;
switch (conversionIndex){ case 0: if (tag == kTextFrameImpl && (forClass == kMyBoss || forClass == kInvalidClass)) status = IConversionProvider::kMustConvert; break; default: break; } return status; }
Containers and embedded data
InDesign does not have many instances of containers. One example is in the text attribute code. A text style is a UID-based boss object containing an implementation, TextAttributeList, that contains a list of attribute bosses (Bold, Point Size, Leading, and so on). These attribute bosses are not UID-based bosses; instead, TextAttributeList streams the ClassID for a boss, followed by the boss’s data, then streams the next boss in the list. TextAttributeList, therefore, must call the stream’s content tracker to notify the content manager that a new class was added to the document.
48
Persistent Data and Data Conversion
Conversion of persistent data
The following example illustrates why this is important.
Suppose a new Red-Line plug-in adds an attribute to the style and the text does not compose correctly if the Red-Line plug-in is removed. Red-Line can list the attribute as critical, so the host provides a strongly worded warning when the user tries to open the document without the Red-Line plug-in. However, if TextAttributeList does not register the attribute boss with the content manager, the application never knows the attribute is in the document and cannot warn the user. Suppose the Red-Line plug-in is updated, and the attribute boss in particular is updated to store its data differently. The Red-Line plug-in registers a converter handling the format change. If the host does not know the attribute appears in the document, the Red-Line converter is never called to perform the conversion. The document appears to open correctly, but it crashes on the attribute’s ReadWrite method the first time the style is read.
For the Red-Line attribute to be converted, TextAttributeList must register a converter. If the content manager was notified when the attribute was streamed, the conversion manager knows the attribute needs to be converted. It even knows the attribute was streamed by TextAt­tributeList. But the conversion manager has no way of knowing where the attribute is inside the data streamed by TextAttributeList; therefore, TextAttributeList should register a converter that calls back to the conversion manager to convert each piece of embedded data. Otherwise, the embedded data is not converted.
Content manager
The host has a content manager that tracks what data is stored in the document, which plug-in stored it, and the format version number of the plug-in last used to write the data.
Think of this as a table attached to the root of the document: every ImplementationID part of the document appears in the table. This table also includes all ClassID values in the document.
Ta bl e 2 and Tab le 3 are an example.
TABLE 2 Version information
ImplementationID PluginID Format version number (only
minor number)
kSpreadImpl kSpreadPluginID 0
kSpreadLayerImpl kLayerPluginID 0
kTextAttrAlignJustImpl kTextAttrPluginID 1
kCMSProfileListImpl kColorMgmtPluginID 3
...
Persistent Data and Data Conversion 49
Persistent Data and Data Conversion
Conversion of persistent data
TABLE 3 Class IDs in the document
ClassID Plug-in ID Format version number (only
kSpreadBoss kSpreadPluginID 1
kSpreadLayerBoss kLayerPluginID 1
kTextAttrAlignBodyBoss kTextAttrPluginID 3
kDocBoss kDocFrameworkPluginID 1
When an object is streamed to a document, the document receives the ClassID of the object and the data streamed by each of the object’s ReadWrite methods. The data written by a Read­Write method is marked with the ImplementationID of the ReadWrite implementation; this way, when the data is read later, the system knows which C++ class to instantiate to read the data. IContentMgr maintains an overall list of the ClassID and ImplementationID values used in the document. When a new ClassID or ImplementationID is added to the document, ICon­tentMgr checks which plug-in supplied the ClassID or ImplementationID, notes the plug-in ID and the format version number, and adds the new entry to the table.
minor number)
The plug-in supplying a ClassID is the one supplying the class definition. Only the plug-in sup­plying the original class definitions is considered; add-in classes do not count. The plug-in sup­plying an ImplementationID is the one that registered a factory for the ImplementationID.
This data is used to detect missing plug-ins and manage document conversion. When the user opens a document containing data supplied by a missing plug-in, the host alerts the user that the document contains data from a missing plug-in. The host detects missing plug-ins by look­ing in the content manager to see which plug-ins supplied data to the document and checking this list against the list of loaded plug-ins to see whether any are missing.
This data also is used for document conversion. When the user opens a document, the default implementation of IConversionMgr checks the format version number of the plug-ins supply­ing data to the document and compares it with the format version number of loaded plug-ins. Any mismatch means a conversion is required before the document can be opened. If there is a format version change without a supplied data converter, the document will not open.
Conversion manager
When a document is opened, the conversion manager is called to check whether any data in the document requires conversion. If the data requires conversion and a converter is available, the document is converted and opens as an untitled document. If a converter cannot be found, the host displays an alert message that warns the user the document cannot be opened because it cannot be converted.
This initial check, implemented in IConversionMgr::GetStatus, happens very early in the pro­cess of trying to open the document, before any objects in the document are accessed (i.e., before any of their ReadWrite methods are called). This is critical, because a ReadWrite method will not succeed if the object needs to be converted. The conversion manager accesses the content manager (converting it if necessary), and uses the content manager to find out what
50
Persistent Data and Data Conversion
Conversion of persistent data
plug-ins supplied data to the document. If any plug-ins used in the document have different formats than the formats of the loaded plug-ins, conversion is necessary. Next, the conversion manager sees whether there is a converter to convert from the format in the document to the format associated with the loaded plug-in. If such a converter is available, conversion is possi­ble; the document may be closed and opened again as an untitled document.
If the GetStatus method returns with a result indicating conversion is not necessary, the open operation proceeds without calling the conversion manager again. If the GetStatus method returns with a result indicating conversion is necessary but impossible, the open operation is aborted. If the GetStatus method returns with a result indicating conversion is required and a converter is available, the conversion manager’s ConvertDocument method is called to per­form the conversion.
The first thing ConvertDocument does is compile a list of the classes and implementations in the document that must be converted. A plug-in may have many different implementations that wrote data to the document, but only one of these implementations might require conver­sion. The conversion manager uses the content manager to iterate over classes and implemen­tations supplied by the plug-in, and the conversion manager calls the converter to find out which classes and implementations require conversion. Each class or implementation in the document that the converter says must be converted is added to the list of classes or list of implementations to be converted. Other data written by the plug-in is ignored by the converter; it is not converted.
The next step is to iterate over the UIDs in the document. For each UID, the conversion man­ager gets the class of the UID. If the class is on the list of classes to be converted, the conversion manager calls a converter for the class. If, as is more common, the class contains an implemen­tation needing to be converted, the conversion manager opens an input stream on the UID and iterates through the implementations in the UID. If any implementation in the UID requires conversion, an output stream is opened on the UID. Any implementation not requiring con­version is copied to the output stream. If an implementation requires conversion, its converter is called. The converter gets passed the input stream and the output stream. The converter reads from the input stream in the old format and writes to the output stream in the new for­mat.
After the UID iteration is completed, the content manager is called to update the format num­bers for all plug-ins that were outdated, to show their data was converted and is up to date. After this, it is safe for ReadWrite methods to be called on objects in the document.
If any converter requires access to another object to do its conversion, it is called in the last phase of conversion. For example, suppose there was one document-wide preference setting for whether text in frames has smart quotes turned on, but you want to make this a per-frame set­ting. The text frame must store a new flag that indicates whether smart quotes are on or off. The converter adds a new flag in the first phase of conversion, but the converter cannot set the correct value for the flag until the preferences are converted. So, the converter needs to be called once again, after the first phase is complete and it is safe to instantiate the preferences, to get the value of the document-wide smart-quotes setting so the converter can set the frame’s new smart-quotes setting accordingly.
Persistent Data and Data Conversion 51
Persistent Data and Data Conversion
ID Length ID Length
Data
k<Foo>Boss persistent data record
Vers. | Other
Data
Vers. | Other
Conversion of persistent data

Converting data without the conversion manager

To perform format conversion without the conversion manager, the persistent data itself must identify the version of the plug-in that originally wrote the information. To use this method, add a version number to the implementation classes, and implement the ReadWrite method to write the version number first whenever the method writes data, as shown in Figure 3. This method has the advantage of forward compatibility.
FIGURE 3 Persistent data with version number
For example, suppose the first version of your plug-in stores two-byte values, fOne and fTwo, and uses a byte value to store the data’s version number. The ReadWrite method for this imple­mentation would be something like Example 5:
EXAMPLE 5 ReadWrite method supporting multiple versions (version 1 of the plug-in)
FooStuff::ReadWrite(IPMStream* stream, ImplementationID implementation) { stream->XferByte(0x01); stream->XferByte(fOne); stream->XferByte(fTwo); }
The second version of this plug-in modifies the data format by adding a 16-bit integer value, fThree. In this version, your ReadWrite method must be able to read data in either format, but it always must write data back in the new format. See Example 6:
EXAMPLE 6 ReadWrite method supporting multiple versions (version 2 of the plug-in)
FooStuff::ReadWrite(IPMStream* stream, ImplementationID implementation) { uchar version = 0x02; //Always *write* version 2 data stream->XferByte(version); if (version == 0x01) { stream->XferByte(fOne); stream->XferByte(fTwo); } else { stream->XferByte(fOne); stream->XferByte(fTwo); stream->XferInt16(fThree); } }
52
This code both reads and writes all data for this implementation. It could check whether the stream is a reading or writing stream and perform only the needed operation, but the dual-pur­pose code actually is simpler and accomplishes the same thing. If the stream is a ReadStream, the version is initialized as 0x02 but immediately replaced by the contents of the first byte in the stream, and the rest of the stream is processed according to the version number found. If this plug-in encounters data claiming a version number greater than 2, only the data it under­stands (processed by the else clause) is read. This method allows the version 2 plug-in to work with data from both earlier and later versions. Each new version of the plug-in using this method must preserve the portion of the stream previous versions created and add new infor­mation only to the end.
When using this approach, the plug-in’s data version number must not change between ver­sions of the plug-in, but only when a data converter is being supplied to convert the data from one version to another.

Resources

Persistent Data and Data Conversion
Resources
This section explains the fundamental elements and ODFRez resources you need when incor­porating a converter in your plug-in.

PluginVersion resource, format numbers, and their macros

PluginVersion is a resource included in every InDesign and InCopy plug-in. Part of the resource is the declaration of a persistent data format number, like the following:
kSDKDefPersistMajorVersionNumber, kSDKDefPersistMinorVersionNumber,
For an example, see the resource definition in <SDK>/source/sdksamples/basicdia- log/BscDlg.fr.
Each plug-in specifies a different format number. These format numbers are stored in docu­ments, so when a document is opened, the content manager can determine whether data con­version is needed. This determination is made by comparing the format numbers stored in the document for each plug-in with the format numbers declared by loaded plug-ins. If the format numbers are different, the conversion manager is called upon to do a data conversion.
Format number values must meet the following criteria:
z Be greater than or equal to zero.
z Increase with each format change.
z Increment if the data format of any persistent class in a plug-in changes.
NOTE: If multiple persistent classes in a plug-in change their data formats at the same time, the
data-format version number needs to increment only once. How much you increment data format version numbers is up to you.
Format-number values are just numbers; however, you might find it easier to use #define mac­ros for format numbers instead of using their values directly.
Persistent Data and Data Conversion 53
Persistent Data and Data Conversion
Resources
Ta bl e 4 lists format-number macros and their values from previous InDesign SDKs. See
<SDK>/source/sdksamples/common/SDKDef.h.
TABLE 4 Format number macros from prior InDesign SDKs
Version Macro: Major Macro: Minor Tuple
1.0 kSDKDef_10_PersistMajorVersionNumber kSDKDef_10_PersistMinorVersionNumber {0, 307}
1.5 kSDKDef_15_PersistMajorVersionNumber kSDKDef_15_PersistMinorVersionNumber {1, 0}
1.0J kSDKDef_1J_PersistMajorVersionNumber kSDKDef_1J_PersistMinorVersionNumber {2, 1}
2.0 / 2.0J kSDKDef_20_PersistMajorVersionNumber kSDKDef_20_PersistMinorVersionNumber {4, 1}
CS / CS Japanese (3.0 /
3.0J)
kSDKDef_30_PersistMajorVersionNumber kSDKDef_30_PersistMinorVersionNumber {5, 1}

Setting up resources

With the first format change for a plug-in, you must add a converter (either schema-based or code-based) to your plug-in (only one converter per plug-in). See “Adding a converter” on
page 43.

Schemas

The schema resource defines which formats of which implementations the converter should handle. The schema resource is defined in your .fr file and compiled using the ODFRC (Open Document Framework Resource Compiler). See Example 7 and <SDK>/pub- lic/includes/Schema.fh.
EXAMPLE 7 Schema resource
resource Schema(uniqueResourceID) { ImplementationID, { schemaFormatMajorNumber, schemaFormatMinorNumber }, { // [0..n] SchemaFields go here (see SchemaFields.fh) } };
54
Examples
When you define a schema resource, you explicitly state which format number of which imple­mentation it defines. It knows which plug-in contains the implementation, because it is defined implicitly to be the plug-in that contains the schema resource. In other words, all schemas defined in plug-in A are for implementations provided by plug-in A. The schema-based con­verter uses the information in this resource (or the SchemaList resource) to determine how to map persistent data from one format to another.
Persistent Data and Data Conversion
Resources
In Example 8, (1) identifies the schema resource ID. The value does not matter, as long as it is unique among all schema resources compiled into the plug-in. The first item in the schema specifies the implementation ID, and the second item specifies the format number as a tuple {1, 0}. Next comes the schema field list. Curly brackets ( { } ) delimit the list, and commas separate the individual fields. Each field has a type, name, and default value. It is extremely important each field name is unique and these values are not re-used when a field is deleted. Field names must be unique among the schemas that describe different formats of the same implementa­tion, because this is what allows data mapping between different format numbers.
NOTE: Although it is not done in the example below, we recommend you use #define macros
for each field name, to enhance readability.
EXAMPLE 8 Schema resource from <SDK>/sdksamples/snapshot/Snap.fr
resource Schema(1) { kSnapPrefsDataPersistImpl, // ImplementationID {RezLong(1), RezLong(0)}, // format number { {PMString {0x0001, ""}}, // dialog default file name {ClassID {0x0002, 0}}, // format class ID, fFormatClassID {Real {0x0003, 1.0}}, // fScale {Real {0x0004, 72.0}}, // fResolution {Real {0x0005, 72.0}}, // fMinimumResolution {Real {0x0006, 0.0}}, // fBleed {Bool16 {0x0007, 0}}, // fDrawArea {Bool16 {0x0008, 0}}, // fFullResolutionGraphics {Bool16 {0x0009, 0}}, // fDrawGray {Bool16 {0x000a, 0}}, // fAddAlpha {Int32 {0x000b, 512}}, // fDrawingFlags, set default to IShape::kPrinting == 512 {Bool16 {0x000c, 0}}, // fIndexedColour } };
In Example 9 (based on the preceding Snap.fr example), there is a new schema resource ID (2). Inside the schema, the following changes occurred:
z The implementation ID has not changed, but the format number is specified as a tuple {1,
1}.
z schemaFormatMinorNumber changed from 0 to 1.
z In the schema field list, the fifth field (0x0005, fMinimumResolution) was deleted. During
conversion, the fifth field (Real) is stripped from the existing data.
z The seventh field changed its type. It uses the same name but is now of type Bool8. This
requires an implicit conversion. (For a table of valid and invalid type conversions, see the “Versioning Persistent Data” chapter of Adobe InDesign CS4 Solutions.)
z A new field (0x000d, fMaximumResolution) was added. On conversion, an element of type
Int32 (with a value of 3) is appended to the end of the existing data.
Persistent Data and Data Conversion 55
Persistent Data and Data Conversion
Resources
EXAMPLE 9 Hypothetical schema resource
resource Schema(2) { kSnapPrefsDataPersistImpl, // implementation ID {RezLong(1), RezLong(1)}, // format number { {PMString {0x0001, ""}}, // dialog default file name {ClassID {0x0002, 0}}, // format class ID, fFormatClassID {Real {0x0003, 1.0}}, // fScale {Real {0x0004, 72.0}}, // fResolution {Real {0x0006, 0.0}}, // fBleed {Bool8 {0x0007, 0}}, // fDrawArea {Bool16 {0x0008, 0}}, // fFullResolutionGraphics {Bool16 {0x0009, 0}}, // fDrawGray {Bool16 {0x000a, 0}}, // fAddAlpha {Int32 {0x000b, 512}}, // fDrawingFlags, set default IShape::kPrinting == 512 {Bool16 {0x000c, 0}}, // fIndexedColour {Int32 {0x000d, 3}}, // minimum resolution enum } };
Default values
Default values in a schema are used only when the associated field is added to the data stream by conversion. For example, if an implementation originally contained only one int32 value but now also needs a bool16 value, the first schema lists only the int32 and the second schema lists both the int32 and the bool16. When the conversion runs, the schema converter writes a bool16 into the output stream, using the value specified as the default. Because the int32 already existed, the default value specified by the schema is not used.
Suppose you have an implementation with two int32 values. In your constructor, you give them values of 11 and 52. The schema should reflect this. If you later decide 53 is a better default value for the second one, change the schema to match. In this case, however, you do not need a new schema.

SchemaList

The SchemaList resource allows you to specify several schemas in one resource, for conve­nience. Example 10 shows the two previous schema resources combined in one SchemaList.
Even if initially you have only one Schema inside your SchemaList, it is a good idea to create this resource because, over the course of development, this SchemaList resource acts as a per­sistent data format log.
56
EXAMPLE 10 Hypothetical SchemaList resource
resource SchemaList(uniqueResourceID) {{ Schema // schemaTypeIdentifier { kSnapPrefsDataPersistImpl, {RezLong(1), RezLong(0)}, { {PMString {0x0001, ""}}, {ClassID {0x0002, 0}}, {Real {0x0003, 1.0}}, {Real {0x0004, 72.0}}, {Real {0x0005, 72.0}}, {Real {0x0006, 0.0}}, {Bool16 {0x0007, 0}}, {Bool16 {0x0008, 0}}, {Bool16 {0x0009, 0}}, {Bool16 {0x000a, 0}}, {Int32 {0x000b, 512}}, {Bool16 {0x000c, 0}}, } };
Schema // schemaTypeIdentifier { kSnapPrefsDataPersistImpl, {RezLong(1), RezLong(1)}, { {PMString {0x0001, ""}}, {ClassID {0x0002, 0}}, {Real {0x0003, 1.0}}, {Real {0x0004, 72.0}}, {Real {0x0006, 0.0}}, {Bool8 {0x0007, 0}}, {Bool16 {0x0008, 0}}, {Bool16 {0x0009, 0}}, {Bool16 {0x000a, 0}}, {Int32 {0x000b, 512}}, {Bool16 {0x000c, 0}}, {Int32 {0x000d, 3}}, } }; }}
Persistent Data and Data Conversion
Resources
The possible types for schemaTypeIdentifier (see Example 10) are listed below. See Schema.fh for their definitions.
z ClassSchema — Schema for classes in the current plug-in.
z OtherClassSchema — Like ClassSchema, but you can specify it for another plug-in by an
additional PluginID field.
z ImplementationSchema — Schema for implementations in the current plug-in.
Persistent Data and Data Conversion 57
Persistent Data and Data Conversion
Resources
z Schema — Another name for ImplementationSchema, because this is the most common
type.
z OtherImplementationSchema — Like ImplementationSchema, but you can specify it for
another plug-in by an additional PluginID field.

DirectiveList

To instruct the schema-based converter to add or remove implementations or an entire boss, specify a DirectiveList resource to your resource file, as shown in Example 11. (The Direc- tiveList resource formerly was known as BossDirective.) The DirectiveList resource is defined in your .fr file and compiled using ODFRC.
EXAMPLE 11 DirectiveList syntax
resource DirectiveList(uniqueResourceID) { { // [0..n] Directives go here } };
A DirectiveList resource is required each time you do any of the following:
z Add a new boss or remove an existing one.
z Add an implementation to a boss or remove one from a boss.
z Change the ID of a boss or implementation.
The DirectiveList resource serves several purposes:
z Helps the conversion manager delete unnecessary data from a document when a boss or
implementation is removed.
z Keeps the content manager up to date regarding a document’s contents.
z Allows the conversion manager to do its job correctly, even when a boss or implementation
moves to a different plug-in.
The possible list of directives is in Tab l e 5.
TABLE 5 Possible list of directives
Directive Description
IgnorePlugin Mark a plug-in as ignorable.
MoveClass Moves a boss class from one plug-in to another.
MoveClassToPlugin A boss was moved from one plug-in to another.
MoveImplementation Moves an implementation from one plug-in to another.
58
MoveImplementationToPlugin An implementation was moved from one plug-in to another.
RemoveAllImplementation Removes an implementation from all boss classes.
RemoveAllOtherImplementation Removes an implementation from all boss classes.
Persistent Data and Data Conversion

Advanced schema topics

Directive Description
RemoveClass Removes a boss class from a plug-in.
RemoveImplementation Removes an implementation from a boss class.
RemoveOtherClass Removes a boss class from another plug-in.
RemoveOtherImplementation Removes an implementation from a boss class.
RemovePlugin Removes an entire plug-in.
RenumberPlugin Re-numbers an entire plug-in.
ReplaceAllImplementation Replaces one implementation with another in all plug-ins.
ReplaceClass Replaces one boss class with another.
ReplaceImplementation Replaces one implementation with another in a specific plug-in.
NOTE: See Schema.fh. Fields vary by type of directive.
Advanced schema topics

Arrays of values

Suppose an implementation contains three boolean flags followed by four uint32 values. The schema could contain seven separate fields, or it could define two array fields, as in
Example 12:
EXAMPLE 12 Schema resource with array fields
#define kBarOptions 1 #define kBarValues 2 resource Schema(2) { kBarImpl, {1, 0}, { {Bool16Array{kBarOptions, {kTrue, kFalse, kTrue}}}, {Uint32Array{kBarValues, {0, 0, 0, 0}}} } };
The number of default values statically determines the number of elements in each array. Note that the set of default values is enclosed in braces.
Persistent Data and Data Conversion 59
Persistent Data and Data Conversion
Advanced schema topics

FieldArray

If the quantity of array elements is dynamic or an array consists of structures rather than single elements, use a FieldArray, which is a type of field, like Bool16, Uint32Array, or any of the other types in Schema.fh.
In the following example, the Bar implementation differs slightly from the previous example. Instead of having three flags followed by four values, it has a value associated with each flag, and the number of (flag, value) pairs is dynamic:
EXAMPLE 13
#define kBarPairs 1 #define kBarOption 2 #define kBarValue 3 resource Schema(3) { kBarImpl, {1, 0}, { {FieldArray{kBarPairs, {Uint16{0}}, {{Bool16{kBarOption, kFalse}}, {Uint32{kBarValue, 0}}}}} } };
The syntax looks slightly complicated because of ODFRC limitations, but it is fairly straightfor­ward. The schema contains only one field; its type is FieldArray, and its name is kBarPairs.
Following the field's name is its iteration count. Because this is an attribute of the FieldArray, it has a type but not a name. It also has a default value, which usually is zero. The counter might be a signed or unsigned integer that is 8, 16, or 32 bits wide.
NOTE: The iteration count immediately precedes the iterated values. (If your implementation's
persistent data requires the count be elsewhere, you must write your own conversion provider.)
Following the iteration count is the list of iterated fields. Each has a type, name, and default value, like any other field. The default value is not used unless the iteration count has a nonzero default. In the preceding example, the output stream would simply be “0.” If the default itera­tion count were 2, the output would be “2, kFalse, 0, kFalse, 0.”
FieldArrays can be nested up to three levels deep.

Conditional-field inclusion

An important variant of the FieldArray type is the FieldIf type. Use this construct to include a block of fields zero times if a condition is not met or once if the condition is met. The condi­tional value can be of type Bool8, Bool16, ClassID, or ImplementationID. If the conditional value is of type ClassID or ImplementationID, the fields are included if the ID is valid.
60
Persistent Data and Data Conversion
Advanced schema topics
Example 14 is a slight variant of Example 13:
EXAMPLE 14
resource Schema(4) { kBarImpl, {1, 0}, { {FieldIf{kBarPairs, {Bool16{kFalse}}, {{Bool16{kBarOption, kFalse}}, {Uint32{kBarValue, 0}}}}} } };
In this case, kBarOption and kBarValue are included zero or one times, depending on the Bool16 value.
FieldIf constructs can be nested up to three levels deep.
Persistent Data and Data Conversion 61
Persistent Data and Data Conversion
Advanced schema topics
62

Commands

Client Invoker Command
+ Execute() : void
Receiver
+ Action() : void
ConcreteCommand
+ Execute() : void
receiver->Action();
This chapter describes InDesign’s command architecture. It also outlines how to find and use the commands provided by the InDesign API, how to implement new commands of your own, and other extension patterns associated with commands.

Concepts

This section introduces the generic command pattern, databases that provide persistence to the application’s objects, and models that represent the application’s objects in memory.

Command pattern

The intent of the command pattern is as follows: “Encapsulate a request as an object, thereby letting you parameterize clients with different requests, queue or log requests and support undoable operations.” (This is described in Gamma, Helm, Johnson, and Vlissides, Design Pat- terns, Addison-Wesley, 1995.) The structure of this pattern is shown in Figure 4.
Commands
Concepts
FIGURE 4 Command Pattern Structure
This pattern decouples the object that invokes an operation from the object that implements it. The client wants an operation to be performed, the receiver knows how to perform the opera­tion, and the two are decoupled by this pattern. The command declares an interface for execut­ing an operation. The client does not send messages directly to the receiver; rather, the client creates a concrete command object and sets its receiver. The concrete command implements execute by calling the corresponding operation on the receiver. The invoker asks the command to carry out the request, which causes the receiver to perform the operation.
Within the InDesign API, an implementation of the command pattern is used in situations where preventing data corruption is paramount and users must be able to undo or redo changes. See “Commands” on page 68.
Commands 63
Commands
Concepts

Databases and undoability

A persistent object has its state maintained outside the application runtime. It can be removed from main memory and returned again, unchanged. The application maintains persistent objects in a database. A database on disk is an opaque binary file in the operating system’s file system. This database file stores the serialized state of a collection of objects. The set of objects stored in a particular database is collectively known as a model. For example, an InDesign doc­ument file like Untitled-1.indd is a database file that represents the state of an instance of a doc­ument model. See “Models” on page 64.
Objects are stored in a database in the following format:
z Objects that persist are stored as a tree of objects, each of which is associated with and per-
sisted by a database.
z Each persistent object has a identifier, the UID, that identifies it uniquely within its data-
base.
z Each persistent object (except the root object) is owned and referred to by another object,
the parent. A persistent object also can be referenced by other objects, though this does not indicate any form of ownership.

Models

The class that represents a database is IDataBase.
For more detail, see the “Persistent Data and Data Conversion” chapter.
Databases must be consistent and stable. Some databases also need to support undoability—the ability for a user to undo or redo changes. For example, the ability to undo changes made to a document is required; however, there is no requirement to undo changes made to the database that persists the user interface state.
Ta bl e 6 shows the databases that exist and their support for undoability. If a database supports
undoability, that support cannot be turned off. All changes to objects that persist in the data­base must be undo-able. Turning off undo support is not allowed, because it would disable error handling and increase the risk of document corruption.
NOTE: To change objects that persist in a database that supports undo, we recommend using
commands. If, however, you need to change data without showing something in the Edit > Undo menu, you can bypass commands and wrap your changes in calls to CmdUtils::BeginAutoUndoSequence and CmdUtils::EndAutoUndoSequence.
A model is a collection of objects backed by a database for persistent storage. A model is a tree­structured graph of objects. The ownership relationships between objects in a model defines this tree structure. Ownership relationships are just parent-child relationships within the tree.
64
Document model
UID 75 :
kDocWorkspaceBoss
IWorkspace
UID 91 :
kPMColorBoss
IColorData
UID 125 :kStyleBoss
IStyleInfo
ITextAttributes
UID 1 :kDocBoss
IDocument
UID 60 :kSpreadBoss
ISpread
UID 41 :
kTextStoryBoss
ITextModel
Documen t co ntent such as layout and text.
Document preference settings such as styles and swatches.
IStyleGroupManager
IDocument::GetDocWorkSpace
ISwatchList
ISpreadList IStoryList
Documents are represented by the document model. Figure 5 shows an example.
FIGURE 5 Objects in a document model (instance diagram)
Commands
Concepts
The document (kDocBoss) is the root object in the document model. It owns a collection of spreads (kSpreadBoss), stories (kTextStoryBoss), a workspace (kDocWorkspaceBoss), and so on. These objects may own further objects specific to their domain. The document’s workspace owns objects like styles and swatches, which can be used throughout the document.
The database file that provides persistence for a document model is an end-user document file; for example, a file Untitled-1.indd saved from InDesign.
Commands 65
Commands
UID 1 :
kWorkspaceBoss
IWorkspace
UID 27 :kStyleBoss
IStyleInfo
ITextAttributes
UID 42 :
kPMColorBoss
IColorData
Global default preference settings such as styles and swatches.
ISwatchList
IStyleGroupManager
Concepts
Defaults model
Global preference settings are represented by the defaults model. Figure 6 shows an example.
FIGURE 6 Objects in the defaults model (instance diagram)
The workspace (kWorkspaceBoss) is the root object in a defaults model. It owns the objects that represent default preference settings like styles, swatches and so on. The defaults model is global and is accessed from the session (kSessionBoss) via the ISession interface. When a new document is created, preference settings can be copied from the defaults model into the docu­ment’s workspace (kDocWorkspaceBoss).
The database file that provides persistence for this model is an application defaults file. For example, the file named InDesign Defaults is the database file used by InDesign to persist the defaults model.
66
Commands
UID 2 :kAppBoss
UID 3 :
kActionManagerBoss
UID 4 :
kPanelManagerBoss
UID 5 :
kToolManagerBoss
UID 6 :
kDocumentListBoss
UID 1 :kSessionBoss
ISession
IApplication
Concepts
Session model
A session of an application is represented by the session model. Figure 7 shows an example.
FIGURE 7 Objects in the session model (instance diagram)
The session (kSessionBoss) is the root object in the session model. This model owns applica­tion-related objects that must persist from session to session. For instance, user interface objects are found here, together with other objects that store the application’s type system (the boss classes provided by all registered plug-ins).
The database file that persists objects in this model is the application’s saved data file. For example, the file named InDesign SavedData is the database file used by InDesign to persist the session model.
NOTE: Objects in the session model can be modified by calling mutator methods on their
interfaces directly. There is no need to modify them using commands. The database that persists this model does not support undo.
Books, asset libraries, and other models
Several other features in an application have their own dedicated model, together with a data­base that provides that model with persistence. Prominent examples are books, asset libraries, and the scrap. See Ta b le 6 for the level of undo support provided by their databases.
Commands 67

Commands

Commands
Commands
This section describes how commands are used in the application. It includes sections on the CmdUtils class, which is fundamental to the processing of commands, and how to use com­mand sequences to group multiple commands into one logical unit.
Within the application, the most prevalent use of commands by client code is to modify persis­tent objects in the document model or defaults model. For example, plug-ins use commands to create frames in a document or modify the default text style.
Commands encapsulate the changes made to persistent objects into a database transaction. Encapsulating changes in this way helps prevent corruption. Furthermore, any change to the state of persistent objects that needs to support undo must be made using a command.
Commands change persistent objects by doing the following:
z Calling mutator methods on interfaces that exist on persistent objects.
z Processing other commands (that call mutator methods on interfaces that exist on persis-
tent objects).
z Calling utilities that process commands (that call mutator methods on interfaces that exist
on persistent objects).
z A mixture of the above.
A command is processed by the application; this means an instance of the command is passed to the application to be executed. A command can change persistent data within only one data­base each time it is processed. The processing of a command moves the database from one con­sistent state to another.
When a command is used to modify objects that persist in a database that supports undo, that command can manifest on the undo and redo menu items, and the database automatically reverts the state of affected objects on undo and restore the changed state on redo.
NOTE: Before InDesign CS4, commands were directly responsible for reverting or restoring
the changes they made to persistent objects on undo and redo. The application has taken over this responsibility.
The InDesign API provides commands for plug-ins to use. See “Command processing and the
CmdUtils class” on page 70 and “Key client APIs” on page 84.
Plug-ins also can introduce new commands using the command extension pattern. See “Com-
mand” on page 86. This is required when a plug-in adds custom persistent data to a document,
defaults, or other objects that persist in a database that supports undo. The extension patterns named persistent interface and persistent boss are ways in which custom persistent data can be added to a database. See “Persistent interface” on page 89 and “Persistent boss” on page 91.
68

Command parameters

«boss»
kSomeCommandBoss
«interface»
ICommand
+ GetItemList() : const UIDList* + SetItemList(const UIDList&) : void
«interface»
ISomeData
+ GetData() + SetData()
Commands implement the protocol used to modify objects that persist in a database that sup- ports undo. A client initiates this protocol by instantiating a command and passing it off to the application for processing. The client also is responsible for initializing the state of the com­mand, including the setting of parameters. In general, the command pattern supports two mechanisms for parameter passing:
1. The UIDList in the ICommand interface (the “item list”), which identifies a set of persistent objects; see ICommand::SetItemList. On input, this might identify the set of page items on which the command operates. For example, a page item move command (kMoveAbso­luteCmdBoss) would use this to identify the set of items to be moved. On output, the item list might identify the set of object manipulated by a command. For example, a page item create command (kNewPageItemCmdBoss) would provide the UIDs of the objects created as a result of the command being processed. The use of the command’s item list is specific to each command; a command is not required to use the item list.
2. Data-carrying interfaces on the command’s boss class. For example, the command used to apply a particular text style aggregates an IBoolData interface to define whether character styles should be overridden, and an IRangeData interface to indicate the range of text that should be updated by the command.
Commands
Commands
These two approaches for passing parameters are shown in Figure 8. There is a command boss class showing two aggregated interfaces, ICommand and a data-carrying interface (ISome­Data). Parameters can be passed through the item list in ICommand, the data-carrying inter­face, or both.
FIGURE 8 Passing parameters to commands
Commands 69
Commands
Commands

Command undoability

Each command has a property called undoability (see ICommand::Undoability), which deter­mines whether the command name can appear in undo and redo menu items (i.e., whether the changes made by the command can be undone or redone in a distinct step).
z An undoability of kRegularUndo is used by commands whose changes need to appear as a
separate named step in undo and redo menu items. This is the default behavior.
z An undoability of kAutoUndo is used by commands whose changes do not appear as a sep-
arate named step; for example, commands whose changes should be undone or redone with an existing step.
Changes made to objects that persist in a database that supports undo must be undoable. To achieve this, the various extension patterns involved, such as commands and persistent inter­faces, must be implemented following the rules described in this chapter. The database then automatically reverts the state of affected objects on undo and restores the changed state on redo. The undoability of a command (kRegularUndo / kAutoUndo) has no effect on this behavior. It affects only whether the command appears as a distinct step in undo and redo menu items.

Command processing and the CmdUtils class

Client code uses commands when changing objects that persist state in any database that sup­ports undo. For example, commands are used to change objects in the document model or the defaults model. The level of support for undo of each database is given in Ta bl e 6 .
To change the objects, client code creates instances of one or more commands and submits these instances to the application for execution. For example, to create frames in a document, a plug-in either creates commands to be processed and passes them to the application or calls a helper class that encapsulates both the creation and request for processing. The helper classes provided by the InDesign API are introduced in “Command facades and utilities” on page 84.
Client code that must create commands uses the CmdUtils class. CmdUtils::CreateCommand creates an instance of a specific command. The client code parameterizes the command, using the command’s item list and data interfaces. The client code submits the command to the appli­cation for execution, by calling CmdUtils::ProcessCommand. Client code can group the com­mands it processes into command sequences, using methods and classes provided by CmdUtils. Guidance on processing commands and command sequences is in “Command-pro-
cessing APIs” on page 86 and the “Commands” chapter of Adobe InDesign CS4 Solutions.
The sequence of calls involved in processing a command is shown in Figure 9. The client code creates the command, populates the item list and other data interfaces, then passes the com­mand off for processing.
70
FIGURE 9 Client processing a command
Client code CmdUtils A Command A Persistent
Interface
Some client code creates an instance of a command using CmdUtils::CreateCommand
The client sets the command parameters, both through the item list (shown here) or through data carrying interfaces.
The processing of the command is initiated through the client calling CmdUtils::ProcessCommand.
Client code creates command, sets parameters and passes it for processing. The client should also test error state on return, before processing further commands.
CmdUtils should be used for all client interactions with the commands sub-system. The rest of the internals are not shown in this diagram.
The update to some interface on a (UID based) boss object. The call to PreDirty allows the application to track the changes made so that the application can undo or redo the changes automatically.
CreateCommand
construct
SetItemList
ProcessCommand
Do
Set
PreDirty
Commands
Commands

Command sequences

Commands 71
A command sequence (see ICommandSequence) groups a set of commands into a single undoable step that changes the model from one consistent state into another. The command sequence manifests on the undo and redo menu items as a single item.
Commands
Client code CmdUtils ICommandSequence
The client creates a new command sequence.
The client gives the sequence
a name, otherwise the sequence uses the name of the first command processed.
Multiple commands are processed within the scope of a sequence.
The client indicates the sequence is complete.
BeginCommandSequence
ICommandSequence*=
SetName
ProcessCommand
ProcessCommand
EndCommandSequence
Commands
Command sequences can be nested. For example, say you begin a sequence in one method, then call a second method that begins a second sequence. The second sequence is said to be nested within the first. When sequences are nested, only one sequence—the outermost one— appears on undo and redo menu items.
Command sequences assimilate all commands are processed within their scope, whether the command is processed directly from within the sequence or indirectly through subcommands (commands processed by a command). See the “Commands” chapter of Adobe InDesign CS4 Solutions for how to write code that uses command sequences.
A typical scenario for a command sequence is shown in Figure 10. Between the BeginCom­mandSequence and EndCommandSequence calls, all commands processed act as a single set of changes; only one element will appear on undo and redo menu items.
FIGURE 10 Calls made for a command sequence
A command sequence can change persistent objects in more that one database. (A command, on the other hand, can change objects only in one database each time it is processed.) Opera­tions that change objects in two or more documents can be implemented using a command sequence. Such a set of modifications manifests in undo and redo menu items for all affected documents.
72

Command managers, databases, and undo support

A command sequence has limited support for error handling: the sequence either succeeds entirely or fails. An abortable command sequence (see IAbortableCmdSeq) allows more sophisticated error handling, to allow for fail/retry semantics. Abortable command sequences incur a significant performance overhead and should be used only where absolutely necessary. Guidance on using these types of sequence is in the “Commands” chapter of Adobe InDesign CS4 Solutions.
Command managers, databases, and undo support
This section describes how command managers relate to the application’s databases.
The application object model realizes a tree-structured graph of boss objects. Within this tree are several distinct models, notably the session model, the defaults model, and one or more document models (see “Models” on page 64). Each model has a distinct database that provides persistence for its objects (see “Databases and undoability” on page 64). Each database has an associated boss, called a command manager. When commands are used to change objects in a model, the command manager is responsible for executing the commands.
Commands
Figure 11 shows that the application object model has several distinct databases that provide
persistence for its objects. The diagram shows some of the objects in an InDesign session (with two open documents) and the databases with which these objects are associated. Each UID­based object refers to its associated database through its IPMPersist interface. The defaults model, represented by an instance of kWorkspaceBoss, persists in the InDesign Defaults data­base file. Each document model, represented by an instance of kDocBoss, persists in an InDe­sign document database file. The session model, represented by the instance of kSessionBoss and the child objects that do not belong to any other model, persists in the InDesign SavedData database file.
Each database has an associated command manager (see objects in Figure 11 that have an ICommandMgr interface). The command manager is responsible for managing database transactions and executing the commands that change the objects that persist in the database. If an object has an ICommandMgr interface, it is the root object of its associated database. This is shown in Figure 11. Key objects that are command managers are listed in Ta bl e 6 ; for the com- plete list, see ICommandMgr in the API Reference.
NOTE: The class that represents a database is IDataBase. This class is an abstract C++ class, but
it is not an IPMUnknown interface.
Commands 73
Commands
UID 1 :kSessionBoss
ICommandMgr
UID 2 :kAppBoss
UID 3 :kDocumentListBoss UID 1 :kWorkspaceBoss
ICommandMgr
UID 1 :kDocBoss
ICommandMgr
UID 1 :kDocBoss
ICommandMgr
InDesign SavedData :
IDataBase
Untitled-1.indd :
IDataBase
Untitled-2.indd :
IDataBase
InDesign Defaults :
IDataBase
IPMPersist
IPMPersist
IPMPersist
IPMPersist
IPMPersist IPMPersist
IDocumentList::GetNthDoc(1)
IDocumentList::GetNthDoc(0)
ISession::QueryWorkspace
IApplication::QueryDocumentList
ISession::QueryApplication
Command managers, databases, and undo support
FIGURE 11 Models and databases in an indesign session (object diagram)
74
Command managers, databases, and undo support
TABLE 6 Frequently Used Databases and their Support for Undoability
Commands
Command manager / root boss class
kSessionBoss Application SavedData None InDesign SavedData User interface objects like
kWorkspaceBoss Application Defaults Full InDesign Defaults Default resources like
kDocBoss InDesign Document Full Your.indd Document content like spreads,
kBookBoss InDesign Book Partial Your.indb A collection of InDesign documents
kCatalogBoss InDesign Asset Library Partial Your.indl A collection of page items.
Clipboard/scrap Application ClipboardScrap Partial
Database Undo
support
Example filename and use
tools, menus, panels, dialogs, controls, and string translations. Objects that define the application object model, like plug-ins and boss classes.
swatches, fonts, and styles inherited by new documents.
pages, page items, and text.
and associated resources.
Each database has a level of support for undo which is fixed when the database is created and can be one of the following:
z Full — The database fully supports undoable operations. The changes made by a transac-
tion can be reversed automatically on undo and restored on redo. Undo and redo menu items are fully supported.
z Partial — The database can undo only the most recent operation. If an error occurs, the
database is rolled back to its state before the transaction began; however, once a transaction is committed, it is irreversible. There is no support for undo and redo menu items.
z None — The database does not support undoable operations. There is no support for error
handling, abortable command sequences, or undo and redo menu items.
NOTE: Undo support varies by product. In InDesign and InCopy, full undo support is
provided for documents and defaults. In InDesign Server, only partial undo support is provided for these databases; the server has no concept of user undo and redo.
Objects that persist in a database with full or partial support for undo must be modified using commands. For example, a plug-in must process commands to change document content such as spreads, pages, or page items.
Objects that persist in a database without support for undo can be modified by calling mutator methods on persistent interfaces directly. Commands are not required. For example, a plug-in can call interfaces on user interface objects, such as widgets, that set state directly.
Commands 75
Commands
«boss»
kSessionBoss
«boss»
kCommandProcessorBoss
ICommandProcessor
«boss»
kSomeCommandBoss
ICommand
«boss»
kSomeModelRootBoss
ICommandMgr
IDataBase
IDataBase::GetRootUID 1
IPMPersist::GetDataBase 1
changes objects that persist in
1
1..*
1
ISession::QueryCommandProcessor
1

The command processor

The command processor
This section describes how a command is passed through the application until it is processed.
The session (see the ISession interface) has a singleton instance of the command processor (see kCommandProcessorBoss and the ICommandProcessor interface). The command processor is the core application component to which all commands are submitted via CmdUtils.
The command processor’s structure is shown in Figure 12. A command targets one or more objects for change, and these objects persist in a particular database. Normally, client code cre­ates a command instance and sets this target by passing parameters to the command (see
“Command parameters” on page 69). The client code submits the command instance for pro-
cessing using CmdUtils. Figure 13 shows the internal collaboration between the objects involved.
FIGURE 12 Command processor (class diagram)
76
The command processor examines the command and determines which database contains the objects the command changes. Each database has an associated command manager boss (see ICommandMgr interface), shown in Figure 12 as the boss class named kSomeModelRootBoss. For example, the root of the document model is kDocBoss, and kDocBoss is a command man­ager. The command processor calls the associated command manager to execute the com­mand.
Commands
A CommandCmdUtils A Command
Manager
CommandProcessor A Persistent
Interface
The command is passed to the session wide command processor which determines the target database and calls ICmdManager::Do for that database.
The command manager invokes the command.
The command updates the persistent interface. Generally the command will derive from the Command class, providing an implementation of Do().
The persistent interface calls PreDirty before making any update to the data.
ProcessCommand
ProcessCommand
Do
DoImmediate
Set
PreDirty
The command processor
Figure 13 shows the internal processing of a command. The call to process a command is
passed to the session-wide command processor. This determines which database is targeted by the command, and the command is passed to the command manager for the specified data­base. The command manager processes the command, and the command updates an interface on a persistent (UID based) boss object. On completion, control returns to the client that initi­ated the process.
FIGURE 13 Internals of command processing (sequence diagram)
NOTE: Third party plug-ins should not interact directly with the command processor or
command manager interfaces. CmdUtils provides all methods needed by third parties for processing commands.
Commands 77
Commands
A CommandA CmdManagerCommandProcessorCmdUtils A Persistent
Interface
Some client code schedules the command. The command is processed as part of the main event loop after all other processing has completed, and before idle tasks are processed.
Processing of a scheduled command is identical to that of a non-scheduled command. The only difference is with a non-scheduled command, client code is responsible for the initiation, upon completion, control returns to the client. With a scheduled command the
event loop initiates processing, upon completion control returns to the main event loop. If a scheduled command returns an error, it is reported to the user, the error condition is cleared and processing resumes.
ScheduleCommand
ProcessScheduledCmds
ProcessCommand
Do
DoImmediate
Set
PreDirty

Scheduled commands

Scheduled commands
Commands can be scheduled for later processing, using CmdUtils::ScheduleCommand. The command is placed in a queue and processed when the application is idle as part of the main event loop, before idle tasks are processed. The sequence of calls involved in processing a scheduled command is shown in Figure 14. Compare this with the more normal case of imme­diately processing a command, shown in Figure 13. In Figure 14, the scheduled command is passed to the command processor (through the CmdUtils::ScheduleCommand call). At some later time, after all other processing is complete and control is returned to the main application event loop, all scheduled commands are processed.
Guidance on using scheduled commands is in the “Commands” chapter of Adobe InDesign CS4 Solutions.
FIGURE 14 Processing a scheduled command
78

Snapshots and interface implementation types

Snapshots and interface implementation types
A snapshot is a copy of the state of an interface at a particular time. Undo and redo are achieved automatically by the application, which keeps snapshots of the interfaces changed within an undoable transaction. The snapshots are kept in the command history (see “Command his-
tory” on page 80) of the database with which the interface is associated.
The way in which an IPMUnknown interface is implemented determines whether its data is persistent and/or needs a snapshot to support undo or redo:
z Regular interfaces store transient data that is not maintained on undo or redo. They are
declared to the object model using CREATE_PMINTERFACE, and their state is lost if they are removed from memory. Data in a regular interface is not persistent, and no snapshot is taken.
z Persistent interfaces are declared to the object model using the
CREATE_PERSIST_PMINTERFACE macro. They serialize their state to their associated database via the ReadWrite method and can be removed from memory and returned again unchanged. Persistent interfaces that are part of a database that supports undo also are called to serialize their state (again via their ReadWrite method) to a snapshot. This mecha­nism is required to support undo and redo. See “Persistent interface” on page 89.
Commands
z Snapshot interfaces store transient data that must be maintained on undo and redo. They
are declared to the object model using the CREATE_SNAPSHOT_PMINTERFACE macro, and they serialize their state in a snapshot via the SnapshotReadWrite method. Snapshot interfaces are aggregated on a boss that persists in a database that supports undo; however, their data is not persistent. Data maintained by a snapshot interface is lost whenever the associated database is closed or when the command history for the database is cleared. See
“Snapshot interface” on page 92.
z Snapshot view interfaces are similar to snapshot interfaces, which also store transient data
that must be maintained on undo and redo. The distinction is that a snapshot view interface depends on model objects that persist in another database. A snapshot view interface is part of a user interface object and must explicitly identify the database containing the model of interest. Also, the database on which a snapshot view interface depends can change. For example, a widget that tracks some state in the front document must change the database on which its snapshot view interface depends when the front document changes. Snapshot view interfaces are declared to the object model using the CREATE_VIEW_PMINTERFACE macro. See “Snapshot view interface” on page 99.
z It also is possible to create a hybrid interface to allow the data that persists in the database to
differ from the data of which a snapshot is taken for undo and redo. This can be used by complex data structures, like collections that need to optimize performance. Such an inter­face is declared to the object model using the CREATE_PERSIST_SNAPSHOT_PMINTERFACE macro. Data is serialized to the data­base via the ReadWrite method and to the snapshot via the SnapshotReadWrite method. For example, consider this approach if you have a collection of some sort and want to serial­ize only those objects that changed relative to the snapshot (rather than the entire collec­tion).
Commands 79
Commands

Command history

Command history
Consider a database to be the state of the persistent object model. For example, a document database is the state of the document object model (kDocBoss and all its dependents) at a par­ticular time. Persistent interfaces (on dependent objects) are called to serialize their state to the database when necessary, via their ReadWrite method.
The command history (ICmdHistory) provides a history of the undoable operations that were performed on each database. It records the state changes made by a particular command or command sequence, for the purposes of undo and redo. The name of the first command or command sequence processed to perform an operation on the model appears as a named step in the command history. These steps manifest as undo and redo menu items. The command history is used to automatically revert the state of affected objects on undo and to restore the changed state on redo.
The database and its command history are related but distinct states.
To maintain the command history, the database monitors which of its objects change when commands are processed. It tracks the UIDs that are deleted, created, or un-deleted. It tracks persistent interfaces, snapshot interfaces and snapshot view interfaces that are modified, and it takes snapshots of them. This information is kept in the command history as a set of CmdStac­kItem objects. (CmdStackItem is opaque on the SDK; third parties cannot access its data.) When undo is invoked, the application automatically reverts the database state to its previous revision, using this information. When redo is invoked, the application automatically restores the database state to its next revision.
See Figure 15. The command processor (kCommandProcessorBoss) aggregates the command history (interface ICmdHistory), which is responsible for maintaining the state changes made by a particular command or command sequence (which manifests on the undo and redo menu). This state, represented as CmdStackItems, is used to move the model to previous and next states on undo and redo. The CmdStackItem encapsulates all data required for an undo and redo that occurred while processing a command or command sequence.
80
FIGURE 15 Command history
«boss»
kCommandProcessorBoss
«interface»
ICmdHistory
CmdStackItem
The command processor aggregates a command history interface.
The command history maintains a set of CmdStackItems (opaque in the SDK). These items represent the set of UIDs added, deleted and modified. For the modified persistent interfaces, the changes are captured through a call to ReadWrite.
Any UID based object that has an associated snapshot interface
that has been modified, will have its state
captured through a call to its SnapshotReadWrite.
On undo/redo, the state that is maintained in the CmdStackItem (opaque in the SDK), which is used to reset the UID based objects (through calls to ReadWrite and
SnapshotReadWrite).
0..*
1
1
1
Commands

Undo and redo

Merging changes with an existing step in the command history

Sometimes it is desirable to extend the scope of an existing step shown in the undo/redo menu to include functionality that occurs after the step finished. This can be done using either of the following:
z A command with undoability of kAutoUndo.
z A command sequence with undoability of kAutoUndo.
Undo and redo
To enable a user to undo or redo a change, the objects changed must:
z Persist in a database that supports undo (see Tab l e 6).
z Be modified by processing commands.
The application maintains the state required for undo/redo of changes made to persistent objects, as commands are processed. Each database that supports undo has a command history in which the necessary information is recorded, as described in “Command history” on
page 80. Each persistent interface on a UID-based boss object has its ReadWrite method called
to add the state to the command history (for undo and redo) and to the database (to persist its
Commands 81
Commands
CmdHistory Internals
«interface»
ICmdHistory
DB1:
CmdStackItem1
DB1:
CmdStackItem2
DB1:
CmdStackItemN
DB2:
CmdStackItem1
DB2:
CmdStackItem2
DB2:
CmdStackItemN
DBN:
CmdStackItem1
DBN:
CmdStackItem2
DBN:
CmdStackItemN
kCommandProcessorBoss
1
1
Undo and redo
state). On undo, the ReadWrite method is called to reset the state back to that from before the action, and on Redo, the ReadWrite method is called again to set the state back to that from the initial action. The sequence of calls to a persistent interface is shown in Figure 17. Snapshot interfaces are called on their SnapshotReadWrite method using a similar approach; see
Figure 18.
The command processor records in the command history the set of undoable operations it has performed (see the ICmdHistory interface on kCommandProcessorBoss). The steps in the command history appear in undo and redo menu items and are modelled internally using CmdStackItems. (These are internal only. Discussion is provided here to give some notion of how the command processor works.) This is shown in Figure 16.
FIGURE 16 Command history internals (instance diagram)
82
The command history maintains a stack of CmdStackItem objects for each database that sup­ports undo; see Figure 16. A CmdStackItem (opaque in the SDK) represents the set of changes made by the sequence or command that manifests on the undo/redo menu. It contains data gathered during a database transaction for the purposes of undo and redo. On undo/redo, the “current” CmdStackItem is used to revert the state of the model. The CmdStackItem encapsu­lates all data required for an undo/redo that occurred while processing a command or com­mand sequence. This includes all changes to persistent interface and snapshot interface data that were pre-dirtied. The CmdStackItem also maintains any inval handler cookies (see “Inval
handler” on page 94) created as part of the sequence.
Each step has a name of either a command or a command sequence that performed the opera­tion. On undo, the application automatically reverts the database to its state before the opera­tion was performed. On redo, the application automatically restores the database to its state after the operation was performed.

Extension patterns involved in undo and redo

The following extension patterns are called at undo or redo:
z Persistent interfaces; see “Persistent interface” on page 89.
z Snapshot interfaces; see “Snapshot interface” on page 92 (introduced in InDesign CS4).
z Snapshot view interfaces; see “Snapshot view interface” on page 99 (introduced in InDesign
CS4).
z Inval cookies; see “Inval handler” on page 94 (introduced in InDesign CS4).
z Observers, via their LazyUpdate method (introduced in InDesign CS4); see the “Notifica-
tion” chapter.
Commands

Notification within commands

Notification within commands
A command can initiate notification, so observers interested in changes to the objects it modi­fies are notified. See the “Notification” chapter.
Commands also can be processed within observers and responders. Take care with commands that modify the model in this way. See the “Notification” chapter for further discussion of model changes within the context of notification.
If you are implementing your own command, see “Command” on page 86 for additional infor­mation on notification in the command extension pattern.

Error handling

In response to a user gesture or another event, the application calls a plug-in to carry out an action. For example, the user creates a text frame. In this case, the plug-in creates and processes the commands that perform the action. On detecting an error, a plug-in normally sets the glo­bal error code (see ErrorUtils) to something other than kSuccess and returns. When control returns to the application, the global error code is checked. If it is set, the database is reverted to the state it had before the modifications began. Extension patterns that participated in the transaction being rolled back are called as follows:
Commands 83
Commands

Key client APIs

1. Persistent interfaces, snapshot interfaces, and snapshot view interfaces modified by the transaction are called to revert their state. See “Persistent interface” on page 89, “Snapshot
interface” on page 92, and “Snapshot view interface” on page 99.
2. Inval cookies created during the transaction are called to undo. See “Inval handler” on
page 94).
When the application returns to its main event loop, it informs the user through an alert, using the string associated with the error code that is set (see “Error string service” on page 88). The global error code is then cleared, and the application continues.
Plug-in code that processes commands or command sequences must check for errors. CmdU­tils::ProcessCommand returns an error code that should be checked for kSuccess before con­tinuing. Alternatively, you can check the global error code using ErrorUtils. Details are in the “Commands” chapter of Adobe InDesign CS4 Solutions. If a plug-in tries to process a command while the global error code is set, protective shutdown occurs to protect the integrity of the document or defaults databases (see “Protective shutdown” on page 84).
Command implementation code also must check for errors. If a command encounters an error condition within the scope of its Command::Do method, it should set the global error code using ErrorUtils and return. Details on error handling is in the command extension pattern; see “Command” on page 86.
Plug-in code that requires more sophisticated error handling, to allow for fail/retry semantics, must use an abortable command sequence. For information on using abortable command sequences, see the “Commands” chapter of Adobe InDesign CS4 Solutions.

Protective shutdown

Protective shutdown is a mechanism that helps prevent document corruption. Any attempt to process a command when the global error code is set (to something other than kSuccess) causes a protective shutdown. The application creates a log file describing the problem it encountered and then exits.
Key client APIs
This section summarizes the APIs a plug-in can use to interact with commands.

Command facades and utilities

There are many command-related boss classes named k<whatever>CmdBoss, but in many cases you do not need to instantiate these commands, as there are command facades and utili­ties in the API that encapsulate parameterizing and processing these commands.
84
Interfaces like those in Ta bl e 7 are examples of command facades and utilities. These encapsu­late processing of many commands required by plug-in code. These interfaces are aggregated
Commands
Key client APIs
on kUtilsBoss; the smart pointer class Utils makes it straightforward to acquire and call meth­ods on these interfaces. You can call their methods by writing code that follows this pattern:
Utils<IDocumentCommands>()->MethodName(...)
TABLE 7 Useful command facades and utilities
API Used for manipulating...
IDocumentCommands Documents.
IPathUtils Frames and splines. See the “Layout Fundamentals” chapter
for other APIs that help with layout.
IGraphicAttributeUtils Graphic attributes. See the “Graphics Fundamentals”
chapter for other APIs that help with graphics.
ITextModelCmds Text. See the “Text Fundamentals” chapter for other APIs
that help with text.
ITableCommands Tables. See the “Tables” chapter for other APIs that help
with tables.
IXMLUtils XML. See the “XML Fundamentals” chapter for other APIs
that help with XML.
kUtilsBoss See kUtilsBoss in the API Reference for a complete list of
command facades and utilities.
These utility classes abstract over low-level commands. Before using commands, always look for such a utility to see if there is a method that serves your purpose on one of these interfaces. By doing so, you avoid the increased chance of confusion and error that comes with processing commands. Your use case may require you to process some commands, if the utilities do not provide all of the functionality you require.
As used in the application, command “facade” and “utility” are just different names for the same thing, a class that reduces and simplifies the amount of client code you need to write to change objects in the model. They decouple client code from command creation, initialization, and processing.
When implementing custom commands, it is advisable to provide your own command facade or utility. If you want to share your class with other plug-ins, implement it as an add-in inter­face on kUtilsBoss; for example, see XDocBkFacade. If the class is used only by one plug-in, a C++ class is sufficient; for example, see BPIHelper.
Commands 85
Commands

Extension patterns

Command-processing APIs

The classes used when writing client code to process commands are listed in Tab le 8.
TABLE 8 Useful classes for processing commands
API Description
CmdUtils Provides methods that create, process, or schedule commands and
manage command sequences.
PersistUtils Provides methods like GetDataBase, GetUID, and GetUIDRef, which
are used to identify the objects to be operated on by a command.
ErrorUtils Provides access to the global error code.
NOTE: You must use CmdUtils to process commands. Do not use the ICommandProcessor or
ICommandMgr interfaces for this. Misuse of these interfaces can easily cause document corruption.
For information on finding and processing the commands provided by the API, see the “Com­mands” chapter of Adobe InDesign CS4 Solutions.
Extension patterns
This section summarizes the mechanisms a plug-in can use to extend the command subsystem.

Command

Description
Suppose:
z You added a new persistent boss to a document or a persistent interface to an object in a
document, and you need to set custom data in these objects.
z The API does not provide a command that sets the model data you need to change.
z You want do some processing, and you concluded that a command provides the best pattern
in which to encapsulate it.
Architecture
To implement a command, follow these steps:
z Define a new boss class in your plug-in that aggregates IID_ICOMMAND. If you require
input parameters over and above the command’s item list, aggregate further data interfaces to the boss through which the parameters can be passed.
z Provide an implementation of ICommand using Command as a base class.
86
Commands
Extension patterns
z Add client code that processes your new command. See the “Commands” chapter of Adobe
InDesign CS4 Solutions.
z For more guidance, see the Command page in the API Reference and “Best Practice” below.
Best practices
z The Do method contains the code that modifies the model. The model is changed by calling
mutator methods on model interfaces, processing commands, processing commands in a command sequence, or calling utilities that process commands for you.
z If you encounter an error condition within your Do method, set the global error code
(ErrorUtils::PMSetGlobalErrorCode) and return. The application is responsible for revert­ing the model back to its state before the Do method was called and informing the user of the error.
z If you need more sophisticated flow control that allows for fail/retry semantics, use an
abortable command sequence (see IAbortableCmdSeq).
z The Do method can change objects in only one database each time it is called. To ch ang e
objects in more than one database in one undoable step, use a command sequence (ICom­mandSequence).
z Normally, the database containing the objects to be changed is passed using the command’s
item list. Alternatively, a command can target a predetermined database, by calling Com­mand::SetTarget in its constructor. It also can override Command::SetUpTarget and deter­mine the database containing the objects to be changed when the command is processed.
z Normally, the DoNotify method contains the code that initiates notification, should you
require it. Initiate notification by calling ISubject::ModelChange (not ISubject::Change). Calling ISubject::ModelChange when model objects are changed broadcasts regular and lazy notification (see the “Notification” chapter). The application calls DoNotify after the Do method of the command is called; however, notification need not be restricted to this method.
z Notification can be performed for each object that was modified using the ISubject inter-
face of affected objects. Notification also can be performed centrally. For example, many commands that modify the document model notify change using the ISubject interface of the document (kDocBoss). Sometimes commands use both these approaches. The benefit of using a centralized approach is that an observer needs to attach to only one subject to receive the notification.
z If you need to pre-notify observers before the model is changed, call your DoNotify method
from your Do method before making any changes to the model.
z Notification can result in the processing of further commands, which can result in global
error code being set. If further commands are processed, application shutdown occurs. If multiple subjects are notified by a command, the global error code should be tested between notifications. If the error code is set, the DoNotify method should return without calling further subjects, or it should consume the error and reset the global error code.
z The undoability of a command should be fixed at command construction (see ICom-
mand::GetUndoability). Its default value is kRegularUndo. If a different undoability is
Commands 87
Commands
Extension patterns
z A command must have a name (see Command::CreateName), if it has an undoability of
z Commands with undoability of kAutoUndo do not need a name, because their changes
z The destructor of a command normally is empty. Do not change the model within the
See also
z For documentation on commands: Command and ICommand in the API Reference.
required, it should be set in the command’s constructor. See ICommand::Undoability in the API Reference.
kRegularUndo and it returns kTrue for IsNameRequired. Such commands can appear in undo and redo menu items. The name must have a translation, so it can be displayed in undo and redo menu items in a localized form. Commands with an undoability of kRegu­larUndo that override IsNameRequired to return kFalse must pick up their name from a subcommand. Some commands create and process other commands (subcommands) to make their changes and want to pick up the name of the first subcommand called within their scope instead of providing their own name.
merge with an existing step in the undo and redo menu items.
destructor.
z For documentation on notification: ISubject and IObserver in the API Reference.
z If you need error codes set by your command to map onto strings that describe the error
condition: “Error string service” on page 88.
z For sample code: kBPISetDataCmdBoss, BPISetDataCmd, and BPIHelper from the
BasicPersistInterface plug-in.

Error string service

Description
Suppose error conditions can occur in your plug-in, and you need to inform the user of these errors.
Architecture
Sometimes, error conditions can occur in your plug-in, often within commands or command sequences. When control is returned to the application by your plug-in, and the global error code is set to something other than kSuccess, the user is informed and the model is reverted back to the last consistent state. An error string service provides the ability to map error codes onto error strings. To handle this, follow these steps:
z You Provide an error string service. This service allows ODFRez resources in your plug-in
to map error codes onto strings that describe the error. Detailed documentation on how to define the error codes, resources, and implementations involved is the API Reference for IErrorStringService.
88
z On detecting the error condition, call ErrorUtils::PMSetGlobalErrorCode to set your error
and return control to the application. The application informs the user of the error.
See also
For sample code: BPIErrorStringService from the BasicPersistInterface plug-in.

Persistent interface

Description
Suppose you need to add custom data to an existing object in the model and have that persist. For example, you want frames in a document to have a set of custom properties that you con­trol.
Architecture
The state of a persistent interface that is associated with a database that supports undo is cap­tured by the application before it is changed; its state is reverted on undo and restored on redo. The state is saved in the command history (see “Command history” on page 80) for undo and redo, and in the database for persistence. Figure 17 shows the typical sequence of calls made to modify persistent interface, and when that modification subsequently is undone or redone.
Commands
Extension patterns
Commands 89
Commands
Application core ICmdHistory CmdUtils A Command A Persistent
Interface
Some entity processes a command which results in a persistent interface being modified. The persistent interface calls PreDirty before mutating the data, which allows the application core to snapshot the state of the interface for the command history before it is changed (to allow the modification
to be undone), and to require it to be streamed to the database afterwards.
The application calls on the persistent interface to stream its data to the database.
On undo, the command history reverts the persistent interface to the state it had before the modification was made.
On redo, the command history restores the persistent interface to the state it had after the modification was made.
ProcessCommand
DoImmediate
Set
PreDirty
PreDirty
ReadWrite
Push
Modify
ReadWrite
Undo
ReadWrite
Redo
ReadWrite
Extension patterns
FIGURE 17 Sequence of calls to a persistent interface
90
Commands
Extension patterns
To implement a persistent interface, follow these steps:
1. Aggregate your interface on the boss class in the model to which you want to add custom data that persists. Use an add-in interface (an ODFRez AddIn statement) if you are adding the interface to an existing boss class. To define a new type of persistent boss, see “Persistent
boss” on page 91.
2. Provide an abstract interface that uses IPMUnknown as a base class.
3. Provide an implementation of this abstract interface.
4. Use CREATE_PERSIST_PMINTERFACE to make your implementation class available to the application (instead of CREATE_PMINTERFACE).
5. Define a ReadWrite method for your implementation class. It gets called to serialize your data when needed.
6. Call PreDirty within mutator methods before changing member variables that need to be serialized. This gives the application the ability to recognize that this interface is about to change.
7. Call mutator methods to update the state of your interface. The application calls your Read­Write method to serialize your data when needed.
NOTE: If your interface persists in a document, you must consider what should happen when
users who do not have your plug-in open documents that contain your plug-in’s data. See the section on missing plug-ins in the “Persistent Data and Data Conversion” chapter.
See also
z “Command” on page 86.
z For sample code: IBPIData, BPIDataPersist and BPISetDataCmd from the BasicPersistInt-
erface plug-in.
z For documentation on persistence: the “Persistent Data and Data Conversion” chapter.

Persistent boss

Description
Suppose you need to add a new type of persistent object to the model. For example, you need to add a list of custom style objects to defaults.
Architecture
To implement a persistent boss that has a UID, follow these steps:
1. Define a new boss class.
2. Aggregate IID_IPMPERSIST, and use the kPMPersistImpl implementation provided by the API.
Commands 91
Commands
Extension patterns
3. Add persistent interfaces to the boss to store your custom data. See “Persistent interface” on
4. Choose a boss class to own the instances of your new persistent boss. Add a persistent inter-
NOTE: If your boss persists within a database that supports undo, such as a document or
See also
z For sample code: kPstLstDataBoss and PstLstUIDList from the PersistentList plug-in.
z For documentation on persistence: the “Persistent Data and Data Conversion” chapter.
z “Command” on page 86.
page 89.
face into the boss class you have chosen that stores the UIDs of the new persistent boss. For example, to add custom styles to defaults, add this interface into kWorkspaceBoss.
defaults, you must create, modify, and delete the persistent boss using commands. Implement a create command to allocate a new UID for each new instance of the peristent boss, and store this UID in an interface on boss that owns it. The delete command deletes all child UIDs owned by the persistent boss, removes all references to the persistent boss from the model, then deletes the UID.

Snapshot interface

Description
Suppose you have an object containing transient data, which depends on model objects that persist in a database that supports undo, and:
z Your object needs to be updated when the model objects are modified initially and on any
subsequent undo or redo.
z You cannot use lazy notification to update your object, because it must be kept up to date
with changes to the model at all times.
z Your object must be updated on undo or redo, before observers get called.
For example, the text state (see the ITextState interface) caches the text attributes that are applied to the “text caret”; the next text insertion uses these attributes. This cache is imple­mented as a snapshot interface and maintained on undo and redo.
Architecture
The state of an snapshot interface is captured by the application before it is changed; its state is reverted on undo and restored on redo. The state is saved in the command history (see “Com-
mand history” on page 80) for undo and redo. Figure 18 shows a typical sequence of calls for a
snapshot interface when it is modified, and when that modification is subsequently undone or redone.
92
FIGURE 18 Sequence of calls for a snapshot interface
Application core ICmdHistory An Observer A Snapshot
Interface
Some change causes an observer to be called which results in a snapshot interface being modified. The snapshot interface calls PreDirty before mutating the data, which allows the application core to capture the state of the interface for the command history before it is changed
(to allow the modification
to be undone).
On undo, the command history is invoked. This leads to a SnapshotReadWrite call on the snapshot interface, to revert the state of the interface back to the was it was before the modification.
Similarly, on redo, the snapshot interface has the SnapshotReadWrite method called to restore the state to the way it was after the modification.
Update
Set
PreDirty
PreDirty
SnapshotReadWrite
Push
Modify
Undo
Undo
SnapshotReadWrite
Redo
Redo
SnapshotReadWrite
Commands
Extension patterns
Often, an observer or responder is used to modify a snapshot interface, as shown in Figure 18. Before changing any data, the snapshot interface implementation calls PreDirty, indicating to the application that the SnapshotReadWrite method should be called to capture the state of the interface (this state is associated with the CmdStackItem for the current sequence)). On undo
Commands 93
Commands
Extension patterns
or redo, the SnapshotReadWrite method is invoked with the data associated with that particu­lar sequence on the undo/redo menu.
To implement a snapshot interface, follow these steps:
1. Add your interface to a persistent boss class that is part of the model on whose state your
2. Provide an abstract interface that uses IPMUnknown as a base class.
3. Provide an implementation of this abstract interface.
4. Use CREATE_SNAPSHOT_PMINTERFACE to make your implementation class available
5. Define a SnapshotReadWrite method for your implementation class. It gets called to serial-
6. Call PreDirty within mutator methods before changing member variables you serialize in
interface depends. Check that this class aggregates IPMPersist, since the boss must have a UID to support a snapshot interface. For example, if your object depends on objects in a document, you might choose kDocBoss.
to the application (instead of CREATE_PMINTERFACE).
ize snapshots of your data when needed.
SnapshotReadWrite.
7. When the model objects you depend on are changed, call mutator methods to modify the state of your interface. You might need to track the change to the object using regular notifi­cation. The application takes a snapshot of your interface, reverts the state on undo, and restores it on redo.
NOTE: Even though this extension pattern is very similar in its implementation to a persistent
See also
z For sample code: LnkWtchCache in the LinkWatcher plug-in and GTTxtEdtSnapshotInter-
fa ce in th e G oTo L as tTe xt Ed it plu g- in .
z The “Notification” chapter.

Inval handler

Description
Suppose you have an object that depends on model objects that persist in a database that sup­ports undo, and:
z Your object must be updated at undo and at redo when the model objects it depends on
change.
interface, its effect is very different. The information in your snapshot interface is transient and not saved persistently with a document, defaults, or whatever other model it is associated.
94
z You cannot use lazy notification (see the “Notification” chapter) to update your object,
because you need it to be kept up to date with changes to the model at all times.
Commands
Extension patterns
z You cannot use a snapshot interface (see “Snapshot interface” on page 92) because you need
to do more than restore the state of an object within the application.
z You need to program behavior that runs at undo and redo.
NOTE: This extension pattern is very rare. This is an advanced pattern and should be used only
if absolutely necessary.
For example, an observer might watch a subject that can be deleted from the model. Typically, such observers are attached to the subject when it is created and detached just before it gets deleted. If an object is created, the observer is attached. If there is an undo at this point, the observer should be detached; a subsequent redo should result in the observer being re­attached. Similarly, if an object is deleted, the observer is detached. At this point, an undo should result in the observer being attached; a subsequent redo should result in the observer being detached.
Consider an observer that attaches to a spread (see kSpreadBoss). When a spread is created, the observer gets attached to the new spread. If the creation of the spread is undone, this observer must be detached before the undo takes place. If the creation of the spread is redone, the observer must be re-attached after the redo takes place. The inval handler extension pattern allows for this. The GoToLastTextExit plug-in provides sample code that shows how to use an inval handler to manage the attachment and detachment of an observer that watches stories in a document.
Architecture
Inval handlers allow plug-in code to be called at undo and redo. There are two parts to the mechanism:
z An inval handler (see IInvalHandler) that registers interest in a database that supports
undo.
z An inval cookie that gets called on undo and redo. The inval cookie is created by the inval
handler at the end of a transaction that contained changes in which the plug-in was inter­ested.
Inval handlers are used in situations where a plug-in needs to achieve more than the restoration of the state (through persistent interfaces and snapshot interfaces), and the lazy notification broadcast occurs too late to meet this need. The plug-in has code that must be called immedi­ately at undo or redo.
To implement an inval handler, follow these steps:
z Provide an implementation of an inval handler (see the IInvalHandler class in the API Ref-
erence for details. See GTTxtEdtInvalHandler for sample code).
z Provide an implementation of an inval cookie (see the IInvalCookie class in the API Refer-
ence for details. See GTTxtEdtInvalCookie for sample code).
z Create an instance of the inval handler, and call DBUtils::AttachInvalHandler to associate
this instance with the database that persists the objects in which you are interested. The scope of this association can be defined by the lifetime of the database or the enabling of particular functionality. For example, an inval handler might be attached to a database when a document is opened.
Commands 95
Commands
Extension patterns
z Once an inval handler is attached to a database, call DBUtils::StartCollectingInvals to indi-
z The plug-in code records the semantics of the change. Where this is recorded is implemen-
z Further changes of interest can occur within the same transaction. The plug-in code should
z At the completion of the transaction, the IInvalHandler::EndCollectingInvals method is
z The inval cookie is called on undo and redo of the transaction.
cate the inval handler is interested in participating in undo and redo. This usually occurs on some event (through an observer or some other means). The StartCollectingInvals call informs the database that the inval handler should be called at the end of the current trans­action. If an undoable transaction is ongoing, the inval handler is said to be “collecting invals.”
tation-dependent: it could be in the state associated with the inval handler (recommended), an inval handler cookie, or elsewhere.
record the semantics of the changes; for example, by adding state to a list within the inval handler.
called. The inval handler can return an instance of an inval cookie representing the change(s) of interest that occurred. This inval cookie is kept in the command history for this database transaction. The inval handler is now said to be “not collecting invals.”
z When the lifetime of an inval handler is over, call DBUtils::DetachInvalHandler to detach
the inval handler from the database. For example, an inval handler might be detached from a document database when a document is closed.
Figure 19 shows the lifetime of a typical inval handler. Figure 20 shows the typical sequence of
calls made to an inval cookie on undo. On undo, any inval cookies that were previously associ­ated with the CmdStackItem are called. The inval cookie setting the error state aborts the undo (the model is reset to the state from before the undo).
96
FIGURE 19 Typicalinval handler calls (sequence diagram)
Observer (or
other type of
object)
An Inval HandlerApplication core An Inval CookieICmdHistory
New events in the model of interest for undo / redo cause the above sequence to be repeated and a new inval cookie to be associated with the transaction.
An inval handler is created and associated with the database that persists the objects of interest. For example, an inval handler might be attached when a document is opened.
More events of interest for undo / redo can occur within the same transaction. The inval handler must be called to record each event. At the end of the transaction, EndCollectingInvals is called. The inval handler returns the cookie to be
called on undo and redo of the transaction. See sequence diagram showing inval cookie calls.
When the lifetime of an inval handler is over, DetachInvalHandler is called to detach the inval handler from the database. For example, an inval handler might be detached when a document is closed.
StartCollectingInvals is called to indicate that the inval handler is interested in participating in undo and redo of a transaction. This usually occurs on some event (through an observer, or some other means).
Event that causes attach to the model
new
DBUtils::AttachInvalHandler
Event in the model of interest for undo / redo
AddInvalInfo(info)
bool16= DBUtils::StartCollectingInvals
IInvalCookie*= EndCollectingInvals
new
AddInvalInfo(vector of info)
Push
Event that causes detach from the model
DBUtils::DetachInvalHandler
delete
Commands
Extension patterns
Commands 97
Commands
Application core ICmdHistory An Inval CookieModel
Prior to the model state being reverted, all inval cookies are called.
After all inval cookies are called, the model is reverted (assuming no error).
After the model has been reverted, all inval cookies are called. Setting error here will undo the "Undo".
Undo
ErrorCode= InvalBeforeUndo
ReadWrite / SnapshotReadWrite
ErrorCode= InvalAfterUndo
Extension patterns
FIGURE 20 Inval cookie calls on undo
There are times where the lifetime of an inval handler does not match that of the command his­tory. Inval handlers can be attached and detached at any time, asynchronously with anything else happening in the model. This means there are entries in the command history that do not have corresponding inval cookies for a particular inval handler. In this situation, the inval han­dler’s BeforeRevert_InvalAll and AfterRevert_InvalAll methods are used to provide the oppor­tunity to rebuild the required state directly.
There are times when an inval cookie instance can be asked to merge another instance. This causes the IInvalCookie::Merge method to be called, to merge cookies that were returned by each call to IInvalHander::EndCollectingInvals within one undoable transaction. For example, this can happen at the end of an abortable command sequence.
See also
z IInvalHandler, IInvalCookie, DBUtils::AttachInvalHandler, DBUtils::StartCollectingInvals,
and DBUtils::DetachInvalHandler in the API Reference.
z For sample code: GTTxtEdtInvalHandler in the GoToLastTextEdit plug-in.
z For documentation on how to detect change in other objects using observers and respond-
ers: the “Notification” chapter.
98

Snapshot view interface

Description
Suppose you have a user interface object like a widget, which has data that depends on model objects that persist in a database that supports undo, and:
z Your data needs to be updated when the model objects it depends on are modified or when
modifications are undone or redone.
z You cannot use lazy notification to update your data, because it must be kept up to date with
changes to the model at all times.
NOTE: Use of this pattern is extremely rare in the application codebase. For example, it is used
by interface ILayoutControlData on the layout widget. The data in this interface is depended on by many other objects and always must be kept in tight synchronzsation with the database. This is an advanced pattern and should be used only if absolutely necessary.
Architecture
A snapshot is taken of the state of a snapshot view interface, before it is changed, reverted on undo, and restored on redo. It is very similar to a snapshot interface (see “Snapshot interface”
on page 92). The distinction is that the database with which a snapshot interface is associated is
fixed and implicitly defined by the persistent boss on which it is aggregated. A snapshot view interface, on the other hand, is part of a user interface object and must explicitly identify the database containing the model objects on which it depends. Also, it is not one specific data­base. For example, a widget that tracks some state in the front document must change the data­base on which its snapshot view interface depends, when the front document changes.
Commands
Extension patterns
To implement a snapshot view interface, follow the steps described under CViewInterface in the API Reference.
See also
The CViewInterface template class in the API Reference.
Commands 99
Commands
Extension patterns
100
Loading...