Adobe InDesign CS4 Porting Guide
Adobe InDesign CS4 Porting Guide
Contents
Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
Before you begin . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
Notation. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
Terminology . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
Key concepts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
Major Changes in CS4 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
Links Architecture . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
Summary of changes. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
What is a link in InDesign? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
Architecture . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
Frequently asked questions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
Porting CS3 links to the CS4 links architecture. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
Scripting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
doScript . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
IScriptRunner . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
IScriptEngine . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
IScriptProvider . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
IScriptErrorUtils . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
IScriptEventData . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
Metadata resource . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
RepresentScriptProvider . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
Text-attribute scripting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
TypeDef and TypeDefType . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
Changes to Support Rotated Spreads . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
A new enumerator for commonly referenced coordinate systems . . . . . . . . . . . . . . . . . . 32
ISpread::GetPagesBounds and ILayoutUtils::GetIntersectingPageUID . . . . . . . . . . . . . . . . 33
IShape::GetPaintedBBox and GetPrintedBBOx . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
IMasterSpreadUtils::AppendMasterPageItems. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
IDrawMgr . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
gSession Removed . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
User Interface APIs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
Workspace preference reading/writing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
Palette management. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
Document management . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
Contents
General Changes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
SDK folder structure . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
MLocaleIds.h and WLocaleIds.h . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
Replace gSession with GetExecutionContextSession() . . . . . . . . . . . . . . . . . . . . . . . . . 40
Bring resource definitions up-to-date . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40
PMString constructor change . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
Replace IScriptEventData::SetReturnData. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
Utility APIs are accessed only through kUtilsBoss . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
XCode Warning . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
Porting Recipes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
IDFile . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
IImportManager. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
IInCopyBridgeCmdSuite. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
ISnippetExport. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
IStaticTextAttributes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
IStyleGroupListControlData . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
ITextColumnSizer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
kInvalidUIDRef . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
PMString . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
Style matching. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
XML parser . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48
Custom story thread . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48
kHyperlinkTextMarkerBoss and kHyperlinkTextSourceEndMarkerBoss deprecated . . . . . . . 49
ISnippetExportSuite . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49
Miscellaneous changes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49
Notation
z
SDK root folder <SDK> refers to your local installed SDK root folder. The actual file path
of the root depends on the operating system.
Menu names For example, Tools > Options refers to the Options menu item in the Tools
menu.
Computer input or output, including source code, is presented in a monospace font. For
example:
> sh dollyxsgui.sh
Cannot find specified file
Terminology
z
Applications Members of the InDesign CS4 family of applications (Adobe InDesign CS4,
Adobe InCopy CS4, and Adobe InDesign CS4 Server).
ODFRC OpenDoc Development Framework Resource Compiler, the compiler for framework resource .fr files. This is included with the SDK.
Key concepts
SDK organization
The InDesign CS4 SDK inherits its folder structure from the InDesign CS3 SDK with a few
modifications as outlined in SDK folder structure on page 39.
Development environment
Table 1 lists the components required to build SDK plug-ins.
TABLE 1 Required components
Required component
Notes
OpenDoc Development
Framework Resource Compiler
(ODFRC)
Required component
Notes
Mac OS:
G3 processor (minimum), G4
processor (recommended)
Mac OS 10.4 or later
Xcode 2.4.1
Apple Safari
CHM viewer
There also are changes that affect all plug-ins but do not involve a major feature change. These
are described in General Changes on page 39.
Links Architecture
Datalink is re-engineered in CS4. The core mechanisms for storing and maintaining links was
replaced with new code. All pre-CS4 main datalink interfaces, like IDataLink and ICoreFilename, are deprecated.
Summary of changes
The new link architecture in CS4 offers the following advantages:
z
Removes the assumptions that all links are file-based, so we can support links to URLs,
databases, etc.
Provides three new link types import only, export only, and bi-directional.
A link client ID identifies a link client, You should use the same link client ID when
creating the link resource and the link. If you use kIDLinkClientID, the link shows up
in the Links UI panel. If you do not want to have your links in the Links UI panel, use
an ID other than kIDLinkClientID when you create the link and link resource.
The ILinkManager will query a resource handler based on the URIs scheme. The first resource
handler that knows how to handle (import, export, and resolve) the particular URI scheme is
used to import the resource. The resource handler is asked to supply a resources read stream,
and it is given to an import provider that knows how to import the particular file format. Once
the file is imported, a series of checks is performed to determine if a link is wanted before a link
is created. For example, by default, a text file always is embedded, not linked, unless it is an
Adobe InCopy file. Figure 1 illustrate the sequence of how the link and link resource are created during the processing of a kImportAndLoadPlaceGunCmdBoss.
Does link
resource
(kLinkResourceB
oss) exist?
No
start
Yes
Check link resource state
Check using
ILinkResource::GetState()
against
ILinkResource::kMissing
Resource
missing?
Yes
No
link state is managed by
ILinkState on the link object
boss such as kTextStoryBoss.
If a link is wanted,
ILinkState::SetIsLinkWanted is
used to set the status.
Resource
available & a
valid read stream
is available
No
Yes
Yes
If the link
already
exists?
Yes
Is it InCopy
import?
No
No
Yes
Identify an import
provider that knows
how to handle the le
format, and give it the
stream for import.
Import to an
existing page
item?
Is link
wanted?
No
Yes
Yes
Import
successful?
Yes
Yes
10
Is the import le
a text le?
end
No
What if you do not store your graphics as desktop files? For example, many workflows store
their assets in a database. The CS4 link architecture supports generalized, abstract links: it
allows data to come from a file, URL, database record, or any external or internal source that
can be read or written via a stream. In the remainder of this document, we refer to the resource
data as a link resource. Link resources are referenced using an abstract URI.
Architecture
What is a link?
A link establishes a relationship between a linked resource and a link object. When an image is
placed in an InDesign publication, a link is created between the image file and the page item
that contains the image. Think of a link as a bridge that connects a source to a destination: on
one side is the link resource (the source), and we call the other, destination side the link object.
A link object should be an InDesign object, but it is not limited to a page item; it can be an
XML element, swatch, style set, chunk of text, etc.
Types of links
InDesign supports three types of links:
z
Bi-directional link This is represented by kBidirectionalLinkBoss, which maintains a bidirectional association between an object and a linked resource. If the object changes, the
linked resource can be updated via an export. If the linked resource changes, the object can
be updated via an import. A bi-directional link requires conflict-resolution handling in the
case when both the object and the linked asset change.
NOTE:
A link is created and maintained by ILinkManager. All the overridden ILinkManager::CreateLink methods create a link between a given link object and linked resource.
11
kLinkResourceBoss
ILinkResource
ILink::
GetResource
kImportLinkBoss
ILink
...
kTextStoryBoss
ILinkObject
ILink::
GetObject
The resource handler in CustomDataLink declares it knows how to handle resources whose
URI scheme is CSVLink. When CustomDataLinks client asks to place a resource from the CSV,
CustomDataLink processes a kImportAndLoadPlaceGunCmdBoss by giving the command a
IImportResourceCmdData that consists of an URI to the resource client specified. kImportAndLoadPlaceGunCmdBoss does all the ground work for an import action; when it comes
time to import the real resource, it sends the URI to the link manager. The link manager que-
12
ries all the service providers that support kLinkResourceService, to see if anyone can handle a
URI scheme of CSVLink. Since CustomDataLink implements one, it is chosen to import the
data from the URI. The CustomDataLinks implementation of ILinkResourceHandler defines
methods like CreateResourceReadStream(), which returns an IPMStream to the resource to
which the selected CSV record points. Since CustomDataLink knows how to access the CSV,
given its own URI, it knows exactly what record its client is requesting and handles the request.
Table 2 lists the URI schemes handled by a default InDesign resource handler.
TABLE 2 InDesign URI schemes and their resource handler
Scheme
Purpose
file
adobevc
ADBEapli
If you provide you own resource handler, you should implement your own Place dialog and
add it under your own Place menu.
Link object
A link object is any boss that aggregates the ILinkObject interface. ILinkObject is a proxy used
to represent the item in an InDesign publication being linked to; for example, a page item,
XML element, or range of text. Depending on the type of link associated with the item,
ILinkObject specifies how the item is imported, exported, or resolved. A link (ILink) stores the
UID of the link object with which it is associated, and the link object can be retrieved from the
ILink::GetObject() method. Normally, if your link object is a regular page item, it has an
ILinkObject with kPageItemLinkObjectImpl as its default implementation. kPageItemLinkObjectImpl specifies kPageItemUpdateLinkServiceProviderBoss as its import provider. When the
link needs an update, kPageItemUpdateLinkServiceProviderBoss is used to update the link.
Internally, kPageItemUpdateLinkServiceProviderBosss IUpdateLinkService implementation
(kPageItemUpdateLinkServiceImpl) processes a kReimportCmdBoss to update the link. Eventually, kReimportCmdBoss uses the link resources resource handler to provide a data stream to
the resource, just like the initial Place.
Table 3 lists the InDesign bosses that aggregates an ILinkObject by default.
TABLE 3 Default InDesign bosses that aggregates ILinkObject
Boss name
Note
kDocBoss
kPageItemLinkObjectImpl
kTextStoryBoss
kPageItemLinkObjectImpl
kSplineItemBoss
kPageItemLinkObjectImpl
kMediaPageItemBoss
kPageItemLinkObjectImpl
kGroupItemBoss
kPageItemLinkObjectImpl
13
Boss name
Note
kDisplayListPageItemBoss
kPageItemLinkObjectImpl
kImageItem
kPageItemLinkObjectImpl
kPlacedPDFItemBoss
kPageItemLinkObjectImpl
kXMLLinkObjectReferenceBoss
kXMLElementLinkObjectImpl
kTestSplineItemBoss
kPageItemLinkObjectImpl
kSPPlaceHolderPageItemBoss
kPageItemLinkObjectImpl
kBookContentBoss
kBookLinkObjectImpl
NOTE:
If you are trying to create a link on an object not listed in Table 3, make sure you aggregate
ILinkObject to the objects boss. The SDK sample ExtendedLink illustrates this situation, where
a link object is derived from kXMLLinkObjectReferenceBoss.
Link manager
There is a link manager, represented by ILinkManager, in every InDesign document (kDocBoss). ILinkManager is used to create and delete links and link resources. ILinkManager also
provides many ways to query links and link resources.
To query links through ILinkManager, first you should construct a LinkQuery object.
LinkQuery is a class that allows you to easily specify what you want the ILinkManager to
search for and pass the LinkQuery object to the ILinkManager::QueryLinks method. ILinkManager returns the query result in a ILinkManager::QueryResult, which is a std::vector that
contains the UID of the links. Once you have the UID of a link, you can query its ILink interface.
ILinkManager also uses the link client ID as a filter when it returns the LinkQuery result. If you
specify a client ID, ILinkManager::QueryLinks returns the link with the same client ID. This is
convenient if you used a unique client ID to identify your link and link resource: you can easily
query all your links with an empty LinkQuery and your client ID.
To query a link resource through ILinkManager, construct a LinkResourceQuery object.
LinkResourceQuery is similar to LinkQuery, in that it allows you to specify the criteria (such as
resource URI scheme) to look for when ILinkManager searches for a link resource in a document. Once you construct a LinkResourceQuery, you then pass it to ILinkManager::QueryResources for the query. ILinkManager also returns the query result in a
ILinkManager::QueryResult.
Link status
For every link resource handler made available in the link architecture through the kLinkResourceService service provider, you should provide an implementation of ILinkResourceStateUpdater, which provides the link manager with link-resource status information. There are
times when link manager will ask each link resource to provide a status update; for example,
14
when the application resumes from background to foreground. ILinkManager calls ILinkResourceStateUpdater::UpdateResourceStateAsync. ILinkResourceStateUpdater should be aggregated on the boss where ILinkResourceHandler is aggregated. In Linked resource and
ILinkResourceHandler on page 12, we discuss how ILinkResourceHandler normally is instantiated through the ILinkResourceFactory. ILinkResourceFactory has a method called QueryStateUpdater, which is used to instantiate a status updater for the URI scheme supported by the
same ILinkResourceFactory.
ILinkManager may call for a link-resource status report synchronously or asynchronously,
depending on the situation; therefore ILinkResourceStateUpdater declares two update methods: UpdateResourceStateSync and UpdateResourceStateAsync. In UpdateResourceStateSync,
the status update should be completed on the return of the function. In UpdateResourceStateAsync, it is expected that status update is done in the background or during idle time.
Both ILinkResourceStateUpdater::UpdateResourceStateSync and ILinkResourceStateUpdater::UpdateResourceStateAsync are passed in an UIDRef of a link resource (kLinkResourceBoss). ILinkResource stores resource-status information like resource state
(ILinkResource::ResourceState), modification time, and size.
Also, there is a stamp (of type ResourceStamp, which is essentially a WideString) stored in
ILinkResource. You can use the ResourceStamp to construct any custom stamp you need for
status-update purposes. ILinkResource has declared get/set methods for maintaining these
resource attributes.
In UpdateResourceStateSync/UpdateResourceStateAsync, a comparison should be made
between the link-resource object passed in and the external link resource (available from the
URI, which can be queried through the link-resource object). If you decide the link is out of
date, a kLinkResourceStateUpdateCmdBoss should be processed. This causes the link resource
to be updated with the new status data. The corresponding link (ILink) also maintains a
linked-resource modification state, which is set to ILink::kResourceModified, indicating the
link resource was modified since the last update. If the link is displayed in the Links UI panel,
the status shows it is out of date, and the Update Link option becomes available; this allows the
user to manually update the link on demand.
NOTE:
There are several approaches you can take to accomplish link-state updates. For example, Version Cue links are updating via a push approach. Version Cue notifies InDesign whenever the
state of a Version Cue link changes. File links use a pull approach to update link states, by getting current information from the file system. The SDK ExtLink sample uses an idle-taskbased solution. It is important to consider the case where there are many links in a document.
When the link architecture asks for a link-status update, it asks all links to provide updates;
therefore, the performance issue is critical and deserves a good implementation strategy.
Link update
When a link status is outdated, a link-update action becomes available. If the link information
is available on the Links UI panel, a contextual-menu item, Update Link, is enabled when a
15
link is selected in the panel. When the Update Link menu action is selected on an import
link, kLinkUpdateCmdBoss is processed; this queries the ILink on the kImportLinkBoss and
calls its ILink::Update() method. Inside the ILink::Update(), it queries its associated link object
(ILinkObject) to see if there is an import provider available for the link object through the
ILinkObject::GetImportProvider(). If there is one, that import provider is used to re-import
the link resource; otherwise, ILinkObject::Import() is called. In ILinkObject::GetImportProvider(), you can specify a update-link service-provider boss that implements IUpdateLinkService or kInvalidClass. In the later case, you should then implement ILinkObject::Import. For
example, if the link object is a kPageItemLinkObjectImpl, it defines an kPageItemUpdateLinkServiceProviderBoss in its GetImportProvider, which is used to update the link. kPageItemUpdateLinkServiceProviderBoss processes a kReimportCmdBoss, which asks the link-resource
handler to create a read stream from the resource for import purposes.
What if your link object is not a page-item type, or you do not want to (or cannot) use kReimportCmdBoss to update your link? In these cases, you must implement your own link object
that will use your own IUpdateLinkService or ILinkObject::Import.
Link Notification
When a link or link resource is added, deleted, or changed, a lazy notification is sent on the
protocol of IID_ILINK or IID_ILINKRESOURCE (depending on what was changed). The
UID of the link or link resource is sent in the notification via the notification cookie, LazyNotificationData. Using LazyNotificationData::BreakoutChanges, you can determine which items
(UIDs) were added, deleted, or changed.
There is another lazy notification sent via the IID_ILINKDATA_CHANGED protocol. This
occurs not only when a link or link resource is added, deleted, or changed, but also when a
links link resource is changed. The notification cookie is passed in a type called ILinkManager::ChangeData, a wrapper of UID, which tells you what kind of UID is referenced.
You need not send any links-related notification from your plug-inthe links manager takes
care of that.
16
Once you have access to the old data-link object, you should try to convert the link using the
new link architecture. That is, an ILink should be instantiated to connect an ILinkResource and
an ILinkObject. You should be able to figure out the link resource for the old link through the
old IDataLink. The kDataLinkBoss also aggregates an ILinkObjectReference, which is a reference to the InDesign object, such as a page item, with which the link is associated. Link
object on page 13 discusses objects that have aggregated an ILinkObject beginning in CS4; in
such cases, the UID of the InDesign object should be used as the link object associated with the
link.
The ILink and ILinkResource created from the old kDataLinkBoss should be initiated with the
data saved in IDataLink from the same boss. Both ILink and ILinkResource have a method
called CopyAttributes, which can be used to copy the data from the old kDataLinkBoss. For
conversion purposes, you can aggregate an ILink and ILinkResource in your old data-link boss.
Then, you initialize ILink and ILinkResource with the data from IDataLink. Finally, you call
the ILink::CopyAttributes, and ILinkResource::CopyAttributes, passing in the UIDRef of the
old data-link boss. In this way, the new ILink and ILinkResource are initialized properly.
Note that you still need a schema-based null converter.
17
Does the links architecture support the ability to support a permissionsbased, bi-directional, update solution?
Bi-directional linking is supported. ExtLink SDK sample uses bi-directional linking to update
database content with data from an InDesign linked object. You must manage the access right
to the update, as there is no built-in mechanism for that purpose. One way to achieve this is
through the suppressed user interface, enabling the feature only for a specific user.
How can I search and create/define custom sorts for the links user
interface?
CS4 does not support the search and custom-sort functions for the links user interface.
Can I define how links are displayed in the links user interface, so I can
provide a hierarchical view of my links?
There is no easy way to achieve this in CS4. Only parent/children links are grouped together.
An example of this is a placed InDesign file which has links in it. These links show up as child
links in the Links panel, and its parent, the InDesign file that is placed, is shown as the top-level
node in the links user interface. In theory, you can manage the user interface by manipulating
the links model; in reality, this is very complicated.
18
key for the asset stored in the database; in this case, a CSV file. When the user tried to place an
asset from the CSV file, CustomDataLink formed a unique identifier key based on the users
selection, instantiated a kCusDtLnkAliasedDataLinkBoss object, and initialized the IDataLink
on the object with the unique keys information. IDataLink used the NameInfo class to identify
a link, so CustomDataLink formed a NameInfo based on the unique key. If the unique key
really referenced a file, it got the file path and used it to populate NameInfo; otherwise, it populated the NameInfos filename with the unique key, and the volume name was set to 0. This is
fine, because the IDataLink implementation, CusDtLnkAliasedDataLink, knows how the
NameInfo is formatted, so it can provide operations like Combine and CompareBaseName.
CusDtLnkAliasedDataLink also implemented IDataLink::GetCurrentState, which provided
link-status information to the old links manager. kCusDtLnkAliasedDataLinkBoss also aggregated ILinkedStream, which created an IPMStream read stream from the linked asset when
requested. It primarily used the unique key stored in the kCusDtLnkAliasedDataLinkBoss to
get access to the file the key references. Finally, kCusDtLnkAliasedDataLinkBoss also aggregated IDataLinkAction, which provided functions for most of the contextual menu in the old
Links Panel when a link was right-clicked. To place the file selected by the user, CustomDataLink processed kImportAndLoadPlaceGunCmdBoss, whose command-data interface,
IImportFileCmdData, took an IDataLink pointer that was created from the unique identifier
key.
CustomDataLink also implemented IUpdateLinkService with kCusDtLnkUpdateLinkServiceImpl, which was called by the old links manager when the link was out of date and the user
requested an update on the link. Essentially, it re-imported the linked resource, created a new
kCusDtLnkAliasedDataLinkBoss, and re-initialized the IDataLink. Also, to support copying
and pasting of the page item with the custom data link, CustomDataLink implemented an
IReferenceConverter, which added or embedded the link to the copied page item.
When the user tries to place an asset from the CSV file, the new CustomDataLink forms a URI,
then processes a kImportAndLoadPlaceGunCmdBoss. Notice that the kImportAndLoadPlaceGunCmdBoss now aggregates an IImportResourceCmdData as its command-data interface
instead of IImportFileCmdData. IImportResourceCmdData takes a URI as an input parameter,
and that is all you need to do to process kImportAndLoadPlaceGunCmdBoss. As discussed in
What is a link in InDesign? on page 8, when it is time to import the resource during the processing of kImportAndLoadPlaceGunCmdBoss, a link-resource handler that knows how to
handle the type of URI scheme of the resource the user is trying to place is queried to provide a
resource read stream for the import provider that is doing the import. Since CustomDataLink
is the client that creates the scheme CSVLink, it needs to provide a link-resource handler
(ILinkResourceHandler), which is implemented and aggregated by the kCusDtLnkLinkRe-
19
20
Table 4 provides a high level comparison of links-related tasks in InDesign CS3 and CS4.
TABLE 4 Comparison of common link tasks in InDesign CS3 and CS4
Task
CS3
CS4
Implement
IDataLink::GetCurrentState.
Support updating
a link from the
Links UI panel
Implement an
IUpdateLinkService service
provider.
Implement a
IReferenceConverter, which
adds or embeds a link in the
new page item.
Notes
ICoreFilename
IDataLink
IDataLinkHelper
21
Deprecated API
Notes
IDataLinkReference
IEditFile
ILinkObjectReference
This was used mainly to get to the associated page item from a
kDataLinkBoss. In CS4, use ILink::GetObject.
ILinksManager
ILinkState
IUpdateLink
Porting recipe: Getting to the associated InDesign link object like page item from a link
CS3:
Given an IDataLink, query the ILinkObjectReference on the kDataLinkBoss and call ILinkObjectReference::GetUID.
CS4:
Given an ILink, use ILink::GetObject to return the UID of the object.
22
CS4:
Use ILinkManager::QueryLinksByObjectUID to get to ILink. It returns the result in an ILinkManager::QueryResult, which is a UID vector that holds the ILink UID. For details, see Link
manager on page 14.
InterfacePtr<IHierarchy> childHierarchy(frameHierarchy->QueryChild(0));
// If we're on a placed image we should have a data link to source item
InterfacePtr<ILinkObject> iLinkObject(childHierarchy,UseDefaultIID());
// get the link for this object
IDataBase* iDataBase = ::GetDataBase(childHierarchy);
InterfacePtr<ILinkManager> iLinkManager(iDataBase,iDataBase>GetRootUID(),UseDefaultIID());
ILinkManager::QueryResult linkQueryResult;
if (iLinkManager->QueryLinksByObjectUID(::GetUID(childHierarchy), linkQueryResult))
{
ASSERT_MSG(linkQueryResult.size()==1,"Only expecting single link with this
object");
ILinkManager::QueryResult::const_iterator iter = linkQueryResult.begin();
InterfacePtr<ILink> iLink (iDataBase, *iter,UseDefaultIID());
if (iLink!=nil)
{
InterfacePtr<ILinkResource> iLinkResource(iLinkManager>QueryResourceByUID(iLink->GetResource()));
ASSERT_MSG(iLinkResource,"CHMLFiltHelper::addGraphicFrameDescription - Link
with no associated asset?");
if(iLinkResource!=nil)
PMString datalinkPath = iLinkResource->GetLongName();
}
}
CS4:
Use ILinkFacade::UpdateLinks, which processes (or schedules) a kLinkUpdateCmdBoss. You
need to pass in the UID of a kImportLinkBoss.
23
Scripting
New for CS4 is the ability to undo an entire script in one step. A script typically contains many
undoable operations - one for each script request. For CS4, all of these operations can be stored
and undone as a single undo operation. This feature is accessed from IScriptRunner and from
the doScript method of the scripting DOM.
This feature also provides the ability to access the error code for individual scripting requests,
as defined in RepresentScriptProvider. The sections below explain the modified scriptingrelated APIs surrounding these new features, along with other changes to improve the scripting
API.
doScript
The doScript method of the scripting DOM has two additional parameters:
z
Possible values for undoMode are defined by the undoMode enumType, including:
z
scriptRequest This is the default value. An undo history entry is added for every script
transaction that occurs within your script. After executing the example script below, the
Edit menu holds an item corresponding to the last script transaction that occurred within
myScript.jsx. If that transaction creates a new rectangle, for example, the undo menu item is
Undo Add New Item.
app.doScript( File("C:\\myScript.jsx"), ScriptLanguage.JAVASCRIPT, undefined,
UndoModes.scriptRequest);
entireScript One undo history entry is added for your entire script. The name of the entry
is defined by the undoName parameter. If undoName is undefined, Script is used by
default. After executing the example script below, the Edit menu holds the item Undo my
script.
app.doScript( File("C:\\myScript.jsx"), ScriptLanguage.JAVASCRIPT, undefined,
UndoModes.entireScript, "my script");
autoUndo No undo history entry is added for the script. Instead, all script transactions
within the script are attached to the preceding history entry and undone when that entry is
undone. After executing the example script below, the Edit menu holds the item Undo Add
New Item for the rectangles.add transaction. No item is added for doScript.
app.activeDocument.rectangles.add(undefined, undefined, undefined,
{geometricBounds:[10, 10, 20, 20], contentType:ContentType.graphicType});
app.doScript( File("C:\\myScript.jsx"), ScriptLanguage.JAVASCRIPT, undefined,
UndoModes.autoUndo);
24
IScriptRunner
IScriptRunner provides the C++ API functionality for running a script. In CS4, this functionality includes the new entireScript undo functionality. When this new feature was implemented,
the parameter lists of the methods in IScriptRunner got too long. To solve this problem, a new
RunScriptParameter class was developed to contain parameters related to running a script. For
example:
CS3:
virtual ErrorCode RunFile(const IDFile& idFile, bool16 showErrorAlert = kTrue,
bool16 invokeDebugger = kFalse) = 0;
Call to RunFile:
ErrorCode err = scriptRunner->RunFile(scriptFile, kFalse, kTrue);
CS4:
virtual ErrorCode RunFile(const IDFile& idFile, const RunScriptParams& params) = 0;
Call to RunFile:
RunScriptParams params( scriptRunner);
params.SetInvokeDebugger(kTrue);
ErrorCode err = scriptRunner->RunFile(scriptFile, params);
IScriptEngine
CS4 introduces a new scripting interface, IScriptEngine. As its name suggests, IScriptEngine
provides support for engine-specific information within the scripting architecture. For example, several methods that were on the IScriptManager interface for CS3 were moved to
IScriptEngine:
z
GetRequestContext()
CreateScriptEventData()
IncrementActiveScriptCount()
DecrementActiveScriptCount()
GetShowAlerts()
GetShowDialogs()
In addition, the IScriptPreferences and IScriptRunner interfaces were moved from the IScriptManager boss to the IScriptEngine boss. In practice, most scripting clients have only one
engine. These clients will be able to aggregate IScriptEngine with their existing IScriptManager
boss and use a default implementation of IScriptEngine intended for single-engine clients.
The main beneficiary of these changes will be the JavaScript client, which supports an arbitrary
number of engines. In CA3, all engines inherit identical preferences, including the active
scripting DOM version. That means if one engine sets the current scripting DOM version to
4.0, the scripts running in all JavaScript engines suddenly will be executed against the Firedrake DOM. With the CS4 change, each engine has its own DOM version. Prior to CS4, there
was no way to determine which engine initiated a scripting request. The biggest problem with
this was that when an engine executed a DoScript request, the sub-script was processed in the
25
default (main) engine instead of the originating engine. For CS4, the RequestContext class is
updated to include a pointer to the IScriptEngine for the engine that initiated the request; thus,
a DoScript request is processed in the engine that initiated it.
With this change, it is conceivable that versioned scripts may break in the case where script A
executes script B in a different engine (i.e., by calling DoScript). In CS3, if script A changes the
current scripting DOM version in engine A, script B inherits that change in engine B. In CS4,
engine B and, thus, script B no longer inherit that change; script B executes against the scripting DOM version in engine B.
Furthermore, in CS3, the preferences for the JavaScript, AppleScript, and VBScript engines
were all tied together; that is, changing the current scripting DOM version in AppleScript also
affected JavaScripts and VBScripts (and vice versa for all combinations). In CS4, the engines for
these clients each have separate preferences. This change in behavior (from application-wide to
engine-specific) also includes the preference for user interaction level (that is, whether alerts
and dialogs are displayed during script execution); however, the enable redraw preference
remains a global setting.
IScriptProvider
Previously, CScriptProvider overloaded the HandleEvent, AccessProperty, and AccessProperties methods. Subclasses were forced to override these methods, but generally only one of the
overloads. This resulted in hidden virtual functions, which generate an error when the relevant
flag is turned on in XCode.
In CS4, the versions of HandleEvent and AccessProperty that accepted a list of objects were
renamed to HandleEventOnObjects and AccessPropertyOnObjects, and the version of
AccessProperties that accepted a list of objects was removed. These methods also were
renamed in classes that implement IScriptProvider (e.g., CScriptProvider) and those that
inherit from CScriptProvider.
CS3:
virtual ErrorCode HandleEvent(ScriptID eventID, IScriptEventData* data,
const ScriptList& scriptList);
virtual ErrorCode HandleEvent(ScriptID eventID, IScriptEventData* data,
IScript* script);
virtual ErrorCode AccessProperty(ScriptID propID, IScriptEventData* data,
const ScriptList& scriptList);
virtual ErrorCode AccessProperty(ScriptID propID, IScriptEventData* data,
IScript* script);
virtual ErrorCode AccessProperties(IScriptEventData* data,
const ScriptList& scriptList);
virtual ErrorCode AccessProperties(IScriptEventData* data,
IScript* script);
CS4:
virtual ErrorCode HandleEventOnObjects(ScriptID eventID, IScriptEventData* data,
const ScriptList& scriptList);
virtual ErrorCode HandleEvent(
ScriptID eventID, IScriptEventData* data, IScript* script);
26
The CS3 code above now causes the following compiler error:
Error C2664: 'CScriptProvider::HandleEvent' : cannot convert parameter 3 from
'const ScriptList' to 'IScript *'
No user-defined-conversion operator available that can perform this
conversion, or the operator cannot be called
Both the name of the subclass method and the call to the base-class method must be
changed to maintain the desired overridden virtual function behavior.
IScriptErrorUtils
All script providers that returned kReadOnlyPropertyError in CS3 should now use the SetReadOnlyPropertyErrorData API instead. The following example is from the BasicShape SDK
sample, in BscShpScriptProvider::AccessParentStory().
CS3:
if (data->IsPropertyPut())
{
return kReadOnlyPropertyError;
}
CS4:
if (data->IsPropertyPut())
{
27
IScriptEventData
As part of the change to give INX (and other scripting clients) access to the error code for every
script request (e.g., each individual property when doing a get or set of multiple properties), the
APIs in IScriptEventData related to return data were revised.
These changes will require edits in every script provider. The highest impact change is the
requirement to call IScriptEventData::AppendReturnData() with multiple parameters, in place
of IScriptEventData::SetReturnData() with a single parameter, to return a result from a scripting request. (The methods were renamed to enforce the change via the compiler and clarify the
implementationappend and replace rather than set.)
Previously, the return data comprised a list of return values (K2Vector<ScriptData>) accessed
via one method IScriptEventData::GetReturnData(). One error code and error string were
available via the IScriptError interface on the same boss. (For certain requests to get/set multiple properties at once, it was possible to retrieve a list of error codes through IScriptRequestHandler, but there was no way to tell which properties generated which results.)
Now, the return data comprises a list of ScriptReturnData objects. The declaration of this fairly
straightforward class is available at <SDK>/source/public/includes/ScriptReturnData.h. These
objects record the request (property/event) ID, return value, error code, and error string. For
reasons of compiler enforcement, performance, and precision, the method to retrieve the
return data was replaced with separate IScriptEventData::GetNumReturnData(), GetNthReturnData(), and GetAllReturnData() APIs. Furthermore, all return-data APIs take a target
parameter corresponding to the object in the scripting DOM on which the request was processed.
Therefore, it is now possible to determine which requests were processed on which targets with
which results. (Note: The IScriptError interface remains as a way to pass back a single, overall
error code and error string from the IScriptRequestHandler to scripting clients that do not care
about the new functionality.)
CS3 IScriptEventData API:
virtual void ClearReturnData() = 0 ;
virtual
virtual
virtual
virtual
virtual
void
void
void
void
void
SetReturnData(
SetReturnData(
SetReturnData(
SetReturnData(
SetReturnData(
;
;
) = 0 ;
= 0 ;
28
29
Metadata resource
Metadata resources are used to add arbitrary information to elements in the scripting DOM.
INX uses them extensively to customize the handling of various objects during import and
export. They also are used to control type information, to support properties on the
find/change objects for scripting clients.
Adding a ScriptElementID to metadata scripting resources makes it possible to version the
metadata resources included in a DOM based on the client. For example, we can indicate that
the INX client does not want certain metadata included in its DOMs. The addition of the
ScriptElementID requires all existing metadata scripting resources to add this field.
Below is an example from the TransparencyEffect sample plug-in (TranFX.fr).
CS3:
Metadata
{
{
kTranFxSettingsObjectScriptElement,
}
{
m_INXSnippetAttrImportState, Int32Value(e_SetElementAttributes),
}
}
CS4:
Metadata
{
kTranFxSettingsINXPoliciesMetadataScriptElement,
{
kTranFxSettingsObjectScriptElement,
}
{
m_INXSnippetAttrImportState, Int32Value(e_SetElementAttributes),
}
}
RepresentScriptProvider
CS4 gives scripting clients the ability to access the error code for every script request. The RepresentScriptProvider base class was modified to clarify expectations about how the methods'
implementations should return data and error codes. This change affects every subclass of RepresentScriptProvider. Note that two of these methods are pure virtual functions, so the compiler will enforce the change in existing implementations. Also, the compiler will catch the
AppendAllObjects method if the hidden virtual functions warning is enabled.
CS3:
virtual int32 GetNumObjects( IScriptEventData* data, IScript* parent) = 0;
virtual ErrorCode AppendNthObject( IScriptEventData* data, IScript* parent,
int32 n, ScriptList& objectList) = 0;
virtual ErrorCode AppendAllObjects( IScriptEventData* data, IScript* parent,
ScriptList& objectList);
30
CS4:
virtual int32 GetNumObjects( const IScriptEventData* data, IScript* parent) = 0;
virtual ErrorCode AppendNthObject( const IScriptEventData* data, IScript* parent,
int32 n, ScriptList& objectList) = 0;
virtual ErrorCode AppendAllObjects( const IScriptEventData* data, IScript* parent,
ScriptList& objectList);
Text-attribute scripting
Script-provider implementations that get and set text attributes should use the new TextAttrScriptUtility class. This ensures consistent handling of text attributes across scripting objects.
Use of TextAttrScriptUtility is demonstrated in the BasicTextAdornment samples script provider (BscTAScriptProvider.cpp). Notice that this code implements the PreAccessProperty and
PostAccessProperty methods that use a TextAttrScriptUtility instance to access and modify text
attributes.
Before moving to this code, the BasicTextAdornment sample used an ITextAttributeSuite to get
and set text attributes. This worked for scripting and INX, but it failed for IDML, because it
uses a new type of scripting object. Using the TextAttrScriptUtility class fixes that problem.
31
Because these types were re-implemented, the following old #defines were removed from
ScriptingScriptInfo.fh:
#define UIColorType TypeDefType(kInDesignUIColorTypeDefScriptElement)
#define UIColorDefaultType(def)
TypeDefDefaultType(kInDesignUIColorTypeDefScriptElement) EnumValue(def){}
#define InCopyUIColorType TypeDefType( kInCopyUIColorTypeDefScriptElement)
The old #define constants that were used in properties and events were replaced with the new
TypeDefs. For example:
Property
{
kWatermarkFontColorPropertyScriptElement,
p_WatermarkFontColor,
"watermark font color",
"Watermark font color for a document",
TypeDefType(kInDesignUIColorTypeDefScriptElement),
{},
kNoAttributeClass,
}
These named values are used throughout the transform and geometry API stacks. They are of
type Transform::CoordinateSpace. Here, pasteboard coordinates is the single coordinate system used to draw every spread on the floor within a layout window. It often is used as the
common ancestor of all page items on a spread. This was a mistake. Instead, spread coordinates
32
could have been used in most cases and must be used in some cases in the presence of rotated
spreads. Pasteboard coordinates really is of interest only to the layout control view.
In CS4, a new enumerator is added to TransformTypes.h:
Transform::SpreadCoordinates()
CS4:
PMRect ISpread::GetPagesBounds( Transform::CoordinateSpace coords =
Transform::PasteboardCoordinates());
The legal values for coords are the default PasteboardCoordinates() and SpreadCoordinates().
Its return type is changed to PMRect from PBPMRect. Actually, these are the same C++ type.
The PB in the name was just suggestive to clients that the return value was in pasteboard
coordinates. If you pass in default parameter, the function returns exactly the same data to all
unmodified existing callers.
A similar change was made to ILayoutUtils::GetIntersectingPageUID.
CS3:
ILayoutUtils::GetIntersectingPageUID(... const PMRect& itemBounds, ....)
CS4:
ILayoutUtils::GetIntersectingPageUID(... const PMRect& itemBounds, ....,
Transform::CoordinateSpace s = Transform::PasteboardCoordinates())
CS4:
PMRect GetPaintedBBox(const PMMatrix& m, Transform::CoordinateSpace coords =
Transform::PasteboardCoordinates());
PMRect GetPrintedBBox(const PMMatrix& m, Transform::CoordinateSpace coords =
Transform::PasteboardCoordinates());
The legal values for coords are the default PasteboardCoordinates() or SpreadCoordinates().
The previous behavior matches the new default, so previously correct code remains correct.
33
The previous behavior returns PMRects in pasteboard coordinates modified by the matrix m.
For example, if m were the pasteboard to view matrix, the result would be in view coordinates.
The new behavior allows one to optionally specify m relative to spread coordinates. For example, if m were the identity matrix and coords were SpreadCoordinates(), the resulting PMRects
would be in spread coordinates.
IMasterSpreadUtils::AppendMasterPageItems
The meaning of the pageBounds parameter to IMasterSpreadUtils::AppendMasterPageItems
has been changed, so the PMRects are provided in spread coordinates rather than pasteboard
coordinates. A typical caller of this function would have to make a change when asking for the
page bounds from IGeometryFacade using Transform::SpreadCoordinates() rather than Transform::PasteboardCoordinates().
IDrawMgr
For the draw manager's filter mechanism to be general enough for rotated spreads, the filter
rectangles passed to IDrawMgr::BeginFilter need to be able to be specified in coordinate systems other than view coordinates.
CS3:
void BeginFilter( const PMRect& r);
CS4:
void BeginFilter( const PMRect& r, const PMMatrix& m = PMMatrix());
where m, if provided, is the view-to-filter space transformation. Usually, this is the view-tospread matrix, provided by the default value; therefore, you old code probably will continue to
work without any change.
The member function IDrawMgr::GetFilter also changes from:
PMRect GetFilter();
to:
IDrawMgr::FilterInfo GetFilter();
where:
struct FilterInfo{
PMRect fFilterRect;
PMMatrix fFilterTransform;
}
Among other things, this fixes problems where master page items with transparency get drawn
twice, hence too dark.
34
gSession Removed
Beginning in CS4, InDesign is moving toward a multi-threading environment. Multi-threading
will not be complete until a future release, but in preparation, there have been minor changes to
the CS4 API. Namely, global and static variables were removed.
One of the most visible and widely used globals was gSession, a pointer of type ISession on the
session boss. The session boss aggregates multiple interfaces (such as workspace, application,
and preferences). In the multi-threading environment, there are multiple session objects, one
for each concurrent thread, so a single session global will no longer do.
Each thread of execution now has its own execution context (environment). Your code should
not make any assumptions about the context in which it runs, so your code must now access
the session pointer by using the global GetExecutionContextSession() method.
CS3:
InterfacePtr<IApplication> app(gSession->QueryApplication());
CS4:
InterfacePtr<IApplication> app(GetExecutionContextSession()->QueryApplication());
GetExecutionContextSession() has more overhead than de-referencing a pointer (gSession). In most cases, this overhead will not make any difference in the execution time. In
some cases, including drawing code and frequently called observers, it can make a difference if GetExecutionContextSession() is called carelessly.
When determining where it is necessary to optimize the number of calls to GetExecutionContextSession(), we recommend you use a profiler.
GetExecutionContextSession() can return nil in some extreme cases (very early on startup
or very late on shutdown). This should not affect you, but if you have code that you want to
execute very early on startup or very late on shutdown, check to make sure you have a valid
session before using it.
Do not cache the session pointer in a class static variable. This would prevent the code from
running concurrently in multiple threads. If possible, refrain from using statics.
You can and should store the result of GetExecutionContextSession() in a variable inside
your function, if the function queries the session for multiple things (like workspace, the
application, command processor, and error state). For example:
void Foo() {
// Use a regular variable. DO NOT use a static.
ISession* session = GetExecutionContextSession();
35
InterfacePtr<IApplication> theApp(session->QueryApplication());
InterfacePtr<IWorkspace> ws(session->QueryWorkspace());
...
InterfacePtr<IFoo> myFoo(session->QueryFoo());
}
Palette management
PaletteRef.h and PaletteRefUtils.h have detailed information about the palette hierarchy. Everything you see in the InDesign application workspace is an object hosted inside the palette
workspace.
The CS3 Tab group cluster is no longer a valid object in the palette hierarchy; instead there is a
new, floating-dock object to host a palette and a document. As a result PaletteRefUtils::NewTabGroupClusterPalette and PaletteRefUtils::IsTabGroupCluster are obsolete;
instead, PaletteRefUtils::NewFloatingTabGroupContainerPalette and PaletteRefUtils::IsFloatingTabbedPaletteDock are used.
Floating palette docks can contain multiple tab panes, whereas the cluster was the pane, so
code that walks the widget hierarchy must change. Also, in CS3, tab panes were always docked,
but in CS4, tab panes can live in the new floating docks.
Document management
In InDesign CS3, a document is hosted in an layout window, represented by kDocumentWindowBoss. The IWindow in the CS3 kDocumentWindowBoss actually uses the system window
to host the document. In CS4, kLayoutWindowBoss is deprecated; instead, a kDocumentPresentationBoss is used to host a document, and IDocumentPresentation replaces IWindow as
the new key interface for views onto documents.
36
IWindow is not completed deprecated; rather, is not used mainly in the document
window. It continues to serve as the main interface for things like kDialogWindowBoss,
which represents a dialog window.
CS4
IID_ICLOSELAYOUTWINCMDDATA
IID_IPRESENTATIONCMDDATA
IID_IDOCUMENTWINDOW
IID_IDOCUMENTPRESENTATION
IID_IDOCUMENTWINDOWTITLEPROVIDER
IID_IDOCUMENTPRESENTATONLABELPROVIDER
IID_IOPENLAYOUTWINCMDDATA
IID_IOPENLAYOUTCMDDATA
IID_IWINDOWLIST
IID_IPRESENTATIONLIST
kCloseLayoutWinCmdBoss
kCloseLayoutCmdBoss
kCloseLayoutWinCmdImpl
kCloseLayoutPresentationCmdImpl
kDocumentWindowBoss
kDocumentPresentationBoss
kDocumentWindowService
kDocumentPresentationService
kLayoutWindowBoss
kLayoutPresentationBoss
kOpenLayoutWinCmdBoss
kOpenLayoutCmdBoss
kOpenLayoutWinCmdDataImpl
kOpenLayoutPresentationCmdDataImpl
kOpenLayoutWinCmdImpl
kOpenLayoutPresentationCmdImpl
kOpenLayoutWinSignalBoss
kOpenLayoutSignalBoss
kOpenLayoutWinSignalRespServiceImpl
kOpenLayoutSignalRespServiceImpl
kOpenLayoutWinSignalServiceID
kOpenLayoutSignalServiceID
kUpdateDocWindowStateCmdBoss
kUpdateDocumentUIStateCmdBoss
CS4:
IDocumentPresentation* frontDocPresentation = Utils<IDocumentUIUtils>()>GetActivePresentation();
37
CS4:
InterfacePtr<IPresentationList> presList(document, UseDefaultIID());
if (presList && presList.size() > 0)
{
for (IPresentationList::iterator iter = presList.begin(); iter != presList.end();
++iter)
{
InterfacePtr<IControlView> containerView(*iter, UseDefaultIID()); ...
38
General Changes
This section lists some of the changes we recommend you make to your existing CS3 project
before you start working on specific porting tasks.
39
40
Widget interface or
resource with new
definition
Changes
Widgets affected
Action
StaticTextAttributes
StaticTextWidget,
StaticTextWidgetWithAction,
FittedStaticTextWidget,
StaticMultiLineTextWidget,
InLineEditBaseWidget,
KitViewData
KitPanelWidget,
ErasableKitPanelWidget,
DetailKitPanelWidget.
KitList and
PanelList
Widget interface or
resource with new
definition
Changes
StyleGroupDropDo
wnListWidget
ActionIDData and
CControlViewObservers
were added to the
definition of
StyleGroupDropDownLi
stWidget.
Widgets affected
Action
CS4 constructor:
PMString(ConstCString string, PMString::StringEncoding encoding);
For most cases in CS3, you probably created a PMString object like this:
PMString someString("SomeString", -1, PMString::kNoTranslate);
Replace IScriptEventData::SetReturnData
The APIs in IScriptEventData related to return data were modified to allow access to the error
code for every script request. Part of this change involves replacing IScriptEventData::SetReturnData with IScriptEventData::AppendReturnData. For details, see IScriptEventData on
page 28.
41
This also means you need to change your header include for the utility from:
include "SomeUtils.h"
to:
#include "ISomeUtils.h"
One implication of this change is that the often used inline, GetFrontDocument(), which is
defined in LayoutUIUtils.h, is no longer available Use Utils<ILayoutUIUtils>()->GetFrontDocument() instead.
PathUtils.h, PageItemUtils.h, and EncodingUtils.h are utilities used in the SDK. To work in
CS4, they needed to be ported using the above strategy.
XCode Warning
If you declare a variable with the same name more than once in the same scope, Xcode now will
warn: warning: declaration of 'myVar' shadows a member of 'this'. Rename the variable, or re-use
it if possible.
Porting Recipes
This section describes what changes are required to client code as a result of changes in the
InDesign CS4 API. If your code uses an affected API, follow these procedures to change your
code as required.
IDFile
The following APIs were removed from IDFile:
CString GrabCString();
ConstCString GrabCString() const;
WString GrabWString();
For CS4, you can get a CString for the files path using this code:
myIDFile.GetString().GetCString();
For CS4, you can get a WString for the files path using this code:
42
myIDFile.GetString().GrabUTF16Buffer(nil);
IImportManager
IImportManager::DoImportDialog() now requires the caller to supply a dialog for import. In
most cases (for regular file import), unless you are handling a specific type of resource for
import, you can provide the default file dialog in this manner:
InterfacePtr<IImportCore> iImportCore(importManager,IID_IIMPORTCORE);
InterfacePtr<IPlaceDialog> iPlaceDialog(iImportCore->QueryPlaceFileDialog());
Note that importManager used above can be obtained through IK2ServiceRegistry, with the ID
kImportManagerService.
The IImportManager::DoImportDialog() returns a list of URIs for import, as opposed to SysFileList. URI uniquely identifies a resource for import. If you know the URI represents a file,
and SysFileList is required for your situation, you can use IURIUtils::URIListToSysFileList to
convert the URIList to SysFileList.
IInCopyBridgeCmdSuite
For CS4, the IInCopyBridgeCmdSuite public interface was removed and replaced with a new,
ILiveEditFacade public interface. Rather than creating your own instance of the IInCopyBridgeCmdSuite, you can now use the ILiveEditFacade to check in/out. For an example, see the
incopyfileactions sample (InCopyDocUtils.cpp).
ISnippetExport
The ISnippetExport interface was modified to accommodate IDML export. The major change
is that the ExportToStream methods were changed to ExportXMLElements and ExportPageItems. For details, see ISnippetExport.h.
IStaticTextAttributes
The static-text widget was modified to allow/disallow automatic conversion of ampersands to
underlines. Two new, pure virtual methods were added to the IStaticTextAttributes interface
(see IStaticTextAttributes.h):
virtual void SetConvertAmpersandsToUnderline(bool16 convertAmpersands) = 0;
virtual bool16 GetConvertAmpersandsToUnderline() = 0;
43
IStyleGroupListControlData
A misspelled method name was corrected in the IStyleGroupListControlData interface. The
old method name (with Child misspelled) was:
virtual void AppendChlidTypeIID(const PMIID& childType) = 0;
The API functionality remains the same. To use the new API, simply change the spelling to the
new version.
ITextColumnSizer
The APIs for navigating MultiColumnTextFrame were changed. Of note is that the ITextColumnSizer class no longer has a method named GetLastFrameIndex. To check that a frame that
is being linked from is not the last one in its frame list, use IMultiColumnTextFrame::GetIsLastMCF instead of comparing ItextColumnSizer::GetLastFrameIndex() to the total frame
count.
kInvalidUIDRef
kInvalidUIDRef is now defined in UIDRef.h. Prior versions of the InDesign API allowed separate definitions of this constant; for example:
#ifndef kInvalidUIDRef
#define kInvalidUIDRef UIDRef(nil, kInvalidUID)
#endif
To avoid the possibility of getting multiply defined compile errors for kInvalidUIDRef,
replace your definition with:
#include "UIDRef.h".
44
PMString
Many APIs are continuing to move from PMString to WideString. To port your code to use
WideString, it is common to simply create a WideString by passing the PMString to the constructor:
PMString myOldString;
SomeAPI(WideString(myOldString));
Also, some clean-up work was done to PMString. This involved removing the APIs listed
below.
z
The constructor using translation parameter no longer uses a translation specifier. For CS4,
remove the TranslationSpecificer parameter if it is kNoTranslate. If it is kAutoTranslate,
remove encoding and pass kTranslateDuringCall. If it is kNeedsTranslate (keep in mind
that if nothing was passed, this was the default), remove kNeedsTranslate and the encoding
specifier.
CS3 API:
PMString(ConstCString string, PMString::StringEncoding encoding,
TranslationSpecifier translate = kNeedsTranslate);
CS4 API:
PMString(ConstCString string, PMString::StringEncoding encoding);
CS3 usage:
PMString someString("SomeString", -1, PMString::kNoTranslate);
CS4 usage:
PMString someString("Root", PMString::kUnknownEncoding);
Constructor specifying a character buffer, size, and encoding The encoding parameter was
removed. In CS4, use encoding only when you get the string as a platform string. At that
time, you can specify encoding.
Removed CS3 API:
PMString(const UTF16TextChar * string, int32 nDblBytes,
StringEncoding encoding);
CS4 API:
PMString(const UTF16TextChar * string, int32 nDblBytes);
45
Constructor using ConstPString parameter To port to CS4, use the default constructor,
then use SetPString to assign the value of the string.
Removed CS3 API:
explicit PMString(ConstPString p);
CS3:
PString pItsName = (PString) resPtr;
PMString itsName(pItsName);
CS4:
PMString itsName;
PString pItsName = (PString) resPtr;
itsName.SetPString (pItsName, PMString::kUnknownEncoding);
GrabPString When porting, first see if this API is used for a Mac OS API call, then see if
there is a new version of the Mac OS API that takes a CFString. If not, use GetPString.
Removed CS3 APIs:
PString GrabPString(void);
ConstPString GrabPString(void) const;
CS3:
err = FSMakeFSSpec(tSpec.vRefNum, tSpec.parID, tmpName.GrabPString(),
&fSpec);
CS4:
Str255 pstrTmpName;
tmpName.GetPString(pstrTmpName, 255);
err = FSMakeFSSpec(tSpec.vRefNum, tSpec.parID, pstrTmpName, &fSpec);
46
Style matching
IStyleSyncService and ISelectivelyLoadStyleCmdData were modified to allow you to set and
get the style-matching strategy. A new enum, StyleMatchingStrategyEnum, was added to StyleClashResolutionTypes, and two pure virtual methods were added to IStyleSyncService and ISelectivelyLoadStyleCmdData.
virtual void SetStyleMatchingStrategy(
StyleClashResolutionTypes::StyleMatchingStrategyEnum styleMatchingStrategy)=0;
virtual StyleClashResolutionTypes::StyleMatchingStrategyEnum
GetStyleMatchingStrategy() const = 0;
To add the style-matching strategy code to your implementation of IStyleSyncService or ISelectivelyLoadStyleCmdData, follow these steps:
1. Add a private data member (fUseStyleMatchingStrategy) to store a StyleClashResolutionTypes::StyleMatchingStrategyEnum.
2. Add SetStyleMatchingStrategy(), and set fUseStyleMatchingStrategy to the parameter value.
3. Add GetStyleMatchingStrategy(), and return fUseStyleMatchingStrategy.
4. Initialize fUseStyleMatchingStrategy in your constructor.
For example:
class MyStyleSyncService : public CPMUnknown<IStyleSyncService>
{
public:
MyStyleSyncService(IPMUnknown* boss) :
CPMUnknown<IStyleSyncService>(boss),
fUseStyleMatchingStrategy(StyleClashResolutionTypes::kMatchStyleFullPath)
{}
...
virtual void SetStyleMatchingStrategy(
StyleClashResolutionTypes::StyleMatchingStrategyEnum styleMatchingStrategy)
{ fUseStyleMatchingStrategy = styleMatchingStrategy; }
virtual StyleClashResolutionTypes::StyleMatchingStrategyEnum
GetStyleMatchingStrategy () const
47
{ return fUseStyleMatchingStrategy;}
private:
StyleClashResolutionTypes::StyleMatchingStrategyEnum
fUseStyleMatchingStrategy;
};
XML parser
The underlying XML parser library was changed from AXEParser to a new parser called Expat.
This new parser also uses SAX (Simple API for XML), so no changes to our parser interface,
ISAXContentHandler, were required; however, some parser options on ISAXParserOptions are
no longer available. The following methods in ISAXParserOptions were removed:
z
IsAutoValidationFeatureEnabled() and SetAutoValidationFeature() When both the validation option and this option were enabled, the parser validated the document if it contained a DTD. Again, a workaround is to import the XML file into InDesign, then use the
DTD validation support (IXMLValidator) in InDesign.
48
query the IScript interface that may be aggregated on the same boss as the ITextStoryThread, and return the interface pointer of the IScript.
z
ISnippetExportSuite
ISnippetExportSuite::DoExport now requires you to pass in an INXOptions, An INXOptions
can be initialized with an INXStyle, which is defined in INXOptions.h. Also, there is an
IID_ISNIPPETPREFERENCES on the session workspace, which indicates whether the INXOptions should be in traditional or expanded style as a fallback option. For an example of the
use of IID_ISNIPPETPREFERENCES, see SnpManipulateXMLSelection::ExportXMLSnippetFromSelection.
Miscellaneous changes
z
IXMLTagList::GetTag now asks for a WideString instead of PMString. Wrap the old
PMString in a WideString.
49
50
51
52