Adobe FDK Programmer’s Guide Frame Maker 12.0 Programmer’s Reference Fm 12 Rg En
User Manual: adobe FrameMaker - 12.0 - FDK Programmer’s Reference Free User Guide for Adobe FrameMaker Software, Manual
Open the PDF directly: View PDF .
Page Count: 560
Download | |
Open PDF In Browser | View PDF |
FDK Programmer’s Guide V E R S I O N 1 2 ADOBE SYSTEMS INCORPORATED Frame Developer’s Kit, January 2014 Corporate Headquarters 345 Park Avenue San Jose, CA 95110-2704 (408) 536-6000 I M P O R TA N T N O T I C E © Copyright 1986 - 2014 Adobe Systems Incorporated and its licensors. All rights reserved. Adobe, the Adobe logo & FrameMaker are either registered trademarks or trademarks of Adobe Systems Incorporated in the United States and/or other countries. Certain trademarks are owned by The Proximity Division of Franklin Electronic Publishers, Inc., and are used by permission. Merriam-Webster is a trademark of Merriam-Webster, Inc. Portion include technology under Inso Corporation. Portions include technology under copyright Right Hemisphere, Inc. Portions utilize Microsoft Windows Media Technologies. Copyright (c) 2006 Microsoft Corporation. All Rights Reserved. Notices, terms and conditions pertaining to third party software are located at http://www.adobe.com/go/thirdparty and incorporated by reference herein. Contents ..... .................................. PA RT I : G e t t i n g Sta r t e d U s i n g F r a m e D e v e l o p e r To o l s . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11 The Frame Developer’s Kit .......................................................................................... 11 Choosing the right Frame tools ..................................................................................... 13 FDK documentation ...................................................................................................... 14 Naming conventions ..................................................................................................... 14 Style conventions .......................................................................................................... 15 G e t t i n g S t a r t e d w i t h F D K 1 2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17 Downloading and installing the FDK ........................................................................... 18 System requirements ..................................................................................................... 18 Reviewing the sample programs in the samples/hello folder ....................................... 19 Getting familiar with how the FDK works on Windows .............................................. 20 Writing FDK clients for Windows ................................................................................ 21 Compiling, Registering, and Running FDK Clients ..................................................... 28 Writing an Asynchronous FDK Client ......................................................................... 39 Example: adding menus and commands ....................................................................... 55 Next Steps ..................................................................................................................... 57 PA RT I I : F ra m e P ro d u c t A rc h i t e c t u re 1 Frame Session Architecture ....................................................................................... 61 Identifying objects ........................................................................................................ 61 Representing object characteristics with properties ...................................................... 63 FrameMaker product sessions ...................................................................................... 67 2 Frame Document Architecture .................................................................................. 73 Documents .................................................................................................................... 73 Global document information ....................................................................................... 79 Pages ............................................................................................................................. 85 Graphic objects ............................................................................................................. 90 Flows ............................................................................................................................. 95 Paragraph Catalog formats .......................................................................................... 100 Paragraphs ................................................................................................................... 101 Character Catalog formats .......................................................................................... 106 Condition Formats ...................................................................................................... 110 FDK Programmer’s Guide 3 Contents Text ............................................................................................................................. 112 Markers ....................................................................................................................... 122 Cross-reference formats .............................................................................................. 125 Cross-references .......................................................................................................... 127 Variable formats .......................................................................................................... 129 Variables ...................................................................................................................... 131 Footnotes ..................................................................................................................... 132 Ruling Formats ........................................................................................................... 134 Table Catalog formats ................................................................................................. 136 Tables .......................................................................................................................... 138 Colors .......................................................................................................................... 147 Structural element definitions ..................................................................................... 150 Format rules and format rule clauses .......................................................................... 153 Format change lists ..................................................................................................... 155 Structural elements ..................................................................................................... 157 3 Frame Book Architecture ......................................................................................... 159 What the user sees ....................................................................................................... 159 How the API represents books .................................................................................... 160 Creating new books and components ......................................................................... 164 Updating a book .......................................................................................................... 165 Using the book error log ............................................................................................. 170 PA RT I I I : F r a m e A p p l i c a t i o n P ro g r a m I n t e r f a c e 4 FDK Programmer’s Guide 1 Introduction to the Frame API ................................................................................ 175 How the API works ..................................................................................................... 175 Special types of clients ............................................................................................... 177 Running clients with different FrameMaker product interfaces ................................. 179 Creating and running a client ...................................................................................... 179 A simple example ....................................................................................................... 181 Using old clients with FDK 12 ................................................................................... 185 2 API Client Initialization ........................................................................................... 187 Responding to the FrameMaker product’s initialization call ...................................... 187 Initialization types ....................................................................................................... 188 Disabling the API ........................................................................................................ 190 FrameMaker Product Activation by Asynchronous Clients ....................................... 190 3 Creating Your Client’s User Interface 193 Using API dialog boxes to prompt the user for input ................................................. 193 Using commands, menu items, and menus in your client .......................................... 203 Replacing FrameMaker product menus and commands ............................................. 211 Allowing users to configure your client’s interface .................................................... 211 ... Contents Using hypertext commands in your client’s user interface ......................................... 213 Responding to user-initiated events or FrameMaker product operations ................... 217 Implementing quick keys ............................................................................................ 228 Freeing system resources by bailing out ..................................................................... 230 4 Executing Commands with API Functions ............................................................ 233 Handling errors ........................................................................................................... 233 Handling messages and warnings ............................................................................... 233 Opening documents and books ................................................................................... 235 Creating documents .................................................................................................... 244 Printing documents and books .................................................................................... 249 Saving documents and books ...................................................................................... 251 Closing documents and books .................................................................................... 258 Quitting a Frame session ............................................................................................. 260 Comparing documents and books ............................................................................... 260 Updating and generating documents and books ......................................................... 263 Simulating user input .................................................................................................. 270 Straddling table cells ................................................................................................... 271 Executing FrameMaker commands ............................................................................ 272 5 Getting and Setting Properties ................................................................................ 277 What you can do with object properties ..................................................................... 277 Getting the IDs of the objects you want to change ..................................................... 278 Manipulating properties .............................................................................................. 288 Getting and setting session properties ........................................................................ 295 Getting and setting document properties .................................................................... 298 Getting and setting graphic object properties ............................................................. 301 Getting and setting paragraph properties .................................................................... 304 Getting and setting book properties ............................................................................ 308 Getting and setting FrameMaker properties ............................................................... 309 6 Manipulating Text ..................................................................................................... 317 Getting text ................................................................................................................. 317 Getting and setting the insertion point or text selection ............................................. 321 Adding and deleting text ............................................................................................. 331 Getting and setting text formatting ............................................................................. 334 Executing Clipboard functions ................................................................................... 339 7 Manipulating Asian Text .......................................................................................... 343 Creating a rubi group .................................................................................................. 343 Text encodings ............................................................................................................ 344 Using encoding data .................................................................................................... 346 Inspecting and manipulating encoded text .................................................................. 351 Parsing an encoded string ........................................................................................... 353 Getting the encoding for a text item ........................................................................... 355 Special issues with double byte encodings ................................................................. 355 FDK Programmer’s Guide 5 Contents 6 8 Creating and Deleting API Objects ......................................................................... 357 Creating objects .......................................................................................................... 357 Deleting objects .......................................................................................................... 377 Implicit property changes ........................................................................................... 379 9 Manipulating Commands and Menus with the API .............................................. 381 How the API represents commands and menus .......................................................... 381 Getting the IDs of commands and menus ................................................................... 385 Determining a session’s menu configuration .............................................................. 387 Arranging menus and menu items .............................................................................. 388 Getting and setting menu item labels .......................................................................... 395 Manipulating expandomatic menu items .................................................................... 397 Using check marks ...................................................................................................... 398 Using context-sensitive commands and menu items .................................................. 398 10 Creating Custom Dialog Boxes for Your Client ..................................................... 403 Overview ..................................................................................................................... 403 How to create a dialog box ......................................................................................... 408 Creating a DRE file ..................................................................................................... 408 Designing the layout of the dialog box ....................................................................... 411 Setting the properties of the dialog box ...................................................................... 415 Setting the properties of a dialog item ........................................................................ 419 Saving a DRE file ....................................................................................................... 427 Modeless Dialog Boxes .............................................................................................. 428 Testing a dialog box .................................................................................................... 429 A simple example ....................................................................................................... 431 General tips for dialog editing .................................................................................... 435 Summary of keyboard shortcuts ................................................................................. 435 11 Handling Custom Dialog Box Events ...................................................................... 437 How the API represents dialog boxes ......................................................................... 437 Overview of using a custom dialog box in your client ............................................... 440 Opening dialog resources ............................................................................................ 444 Initializing items in a dialog box ................................................................................ 445 Displaying a dialog box .............................................................................................. 446 Updating items in a dialog box ................................................................................... 447 Handling user actions in dialog boxes ........................................................................ 448 Closing a dialog box ................................................................................................... 457 12 Using Imported Files and Insets .............................................................................. 459 Types of imported files and insets .............................................................................. 459 Importing text and graphics ........................................................................................ 460 Updating text insets .................................................................................................... 467 Client text insets .......................................................................................................... 467 Writing filter clients .................................................................................................... 472 Specifying format IDs and filetype hint strings .......................................................... 476 FDK Programmer’s Guide ... Contents Associating a file format with signature bytes ............................................................ 488 13 Working with Unicode .............................................................................................. 501 Introduction to Unicode Support ................................................................................ 501 Unicode Mode ............................................................................................................. 501 Compatibility mode .................................................................................................... 511 International Components for Unicode (ICU) ............................................................ 519 Mixed Mode operations .............................................................................................. 521 Handling for special characters ................................................................................... 522 PA RT I V: F r a m e D e v e l o pment Envi ro nmen t (F DE) 14 Introduction to FDE ................................................................................................. 527 How the FDE works ................................................................................................... 527 How to make your client portable ............................................................................... 529 A simple FDE filter ..................................................................................................... 534 15 Making I/O and Memory Calls Portable ................................................................ 539 Initializing the FDE .................................................................................................... 539 Using platform-independent representations of pathnames ........................................ 539 Making I/O portable with channels ............................................................................ 543 Assertion-handler functions ........................................................................................ 543 Making memory allocation portable ........................................................................... 544 Error and progress reporting ....................................................................................... 545 16 FDE Utility Libraries ................................................................................................ 547 String library ............................................................................................................... 547 The string list library ................................................................................................... 548 Character library ......................................................................................................... 548 The I/O library ............................................................................................................ 549 The hash library .......................................................................................................... 549 Metric library .............................................................................................................. 551 MIF data structures and macros .................................................................................. 551 The MIF library .......................................................................................................... 553 Simple MIF library ..................................................................................................... 554 Glossary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 555 FDK Programmer’s Guide 7 Contents 8 FDK Programmer’s Guide PART I .......................................... Getting Started U s i n g F r a m e D e v e l o p e r To o l s ..... .................................. The Frame Developer’s Kit The Frame Developer’s Kit™ (FDK) provides tools for developers to enhance the functionality of FrameMaker. This chapter provides an overview of the FDK and other aspects of FrameMaker that are useful for developers. It also discusses the FDK documentation. The principal parts of the FDK are: Frame Application Program Interface™ (API) Frame Development Environment™ (FDE) Frame Structure Import/Export Application Program Interface (Structure Import/Export API) The following sections describe these parts and discuss how you can use them. Frame API The Frame API allows you to write C language programs, called FDK clients, that can take control of a FrameMaker product session and communicate interactively with the user. With the API, a client can do nearly anything an interactive user can do and more. The API gives a client direct access to the text and graphic objects in documents. The API includes a set of header files, libraries, and makefiles for each supported platform. Here are some examples of the types of clients you can create with the API: Grammar checkers Bibliography utilities FDK Programmer’s Guide 11 U s i n g F r a m e D e v e l o p e r To o l s The Frame Developer’s Kit Voice control utilities Document reporting utilities Version control systems for documents Table utilities, such as sorting and totaling Database publishing packages Interfaces to document management systems Filters to exchange files between other desktop publishing applications and FrameMaker products FDE The Frame Development Environment (FDE) provides platform-independent alternatives to platform-specific I/O, string, and memory allocation schemes. It also provides a variety of utility functions, such as Maker Interchange Format (MIF) writing functions. Structure Import/Export API The Structure Import/Export API allows you to write clients that control the import of markup documents into FrameMaker, and control the export of FrameMaker documents to markup. Other FrameMaker product features for developers FrameMaker provides other advanced features that are useful for developers. You do not need the FDK to use these features. MIF Maker Interchange Format (MIF) is an easily parsed ASCII format that describes a document’s text, graphics, formatting, and layout. FrameMaker can save a document or a book to a MIF file, and convert a MIF file back to a document or book, without losing any information. You can write applications or scripts that convert a MIF file to the format of another desktop publishing package, or convert other formats to MIF. Here are some examples of things you can use MIF for: 12 Sharing files with earlier releases of FrameMaker products Converting database files into Frame documents FDK Programmer’s Guide Choosing the right Frame tools ... U s i n g F r a m e D e v e l o p e r To o l s Filtering word processor documents into Frame documents You can find documentation for MIF in the online manuals folder for your FrameMaker installation. Choosing the right Frame tools There are often several tools or combinations of tools that you can use to solve a given problem. In particular, you can use the API to perform many of the tasks that MIF and fmbatch perform. The tool or combination of tools you should use depends on your needs. Generally, MIF and fmbatch are more useful for one-time solutions to small problems, whereas the API is more useful for full-scale applications or applications where interaction with the user is required. The following table summarizes the advantages and limitations of each Frame tool. Frame tool or feature Advantages Limitations Frame API Fast, interactive, and portable; easy to provide a user interface for your applications Must be compiled MIF Can be used by text-processing utilities. It can also be used to provide “backwards” compatibility allowing files to be opened in earlier releases of the product. Third-party MIF creators do not need to write complete MIF. FrameMaker will always write out complete MIF. Files must be saved as MIF; not interactive FDK Programmer’s Guide 13 U s i n g F r a m e D e v e l o p e r To o l s FDK documentation FDK documentation FDK documentation assumes that you have a thorough knowledge of FrameMaker . For background information on FrameMaker, see your user documentation. FDK documentation includes the following manuals, which are available in the doc folder of your FDK installation. FDK Programmer’s Reference The FDK Programmer’s Reference provides FDK reference information, such as error codes and data structure, function, and property descriptions. FDK Programmer’s Guide The FDK Programmer’s Guide is the guide you are reading now. It describes how to use the FDK to create clients for FrameMaker. To get the most from this guide, you should be familiar with the C programming language and event-driven programming. The FDK Programmer’s Guide is divided into four parts: Part I, "Getting Started," provides step-by-step guidance for getting familiar with the FDK. Part II, “Frame Product Architecture,” provides a conceptual overview of how the API represents sessions, books, and documents. Part III, "Frame Application Program Interface (API),” provides instructions for creating API clients. Part IV, "Frame Development Environment," provides instructions for making filters and API clients platform-independent. Naming conventions To help you identify the structures, constants, and functions defined by the FDK, this manual and the FDK adhere to the following naming conventions: 14 Type Naming convention Example API error codes Begin with FE_ FE_NotPgf API functions Begin with F_Api F_ApiGetInt() FDK Programmer’s Guide Style conventions ... U s i n g F r a m e D e v e l o p e r To o l s Type Naming convention Example API scriptable function property names Begin with FS_ FS_NewDoc FDE functions Begin with F_ F_StrNew() Flags used by API functions Begin with FF_ and all letters are uppercase FF_UFF_VAR Initialization constants Begin with FA_Init FA_Init_First Notification constants Begin with FA_Note FA_Note_PreFileType Object property names Begin with FP_ FP_Fill Object types Begin with FO_ FO_Doc Property value constants Begin with FV_ FV_Doc_Type_MIF Typedefs End with T MetricT This manual uses the term API graphic object to refer to objects (such as FO_Polygon and FO_TextFrame objects) that the API uses to represent the graphic objects (such as polygons and text frames) that appear on a page. Style conventions FDK manuals distinguish between you, the developer, and the user, the person for whom you write clients. FDK manuals may use the term FrameMaker product to refer to the FrameMaker software, as opposed to the software you write to work with the FrameMaker product. Structured program interface FrameMaker 7.0 and later ships with two program interfaces—Structured FrameMaker and FrameMaker. The structured program interface presents menus, icons, and commands for working with structured documents. The FDK includes some functions that only work on structured documents. For example, setting an element range makes no sense in a document that doesn’t contain any structure elements. Further, you can specify that an FDK client requires the Structured FrameMaker program interface. For example, assume you specify Structured FrameMaker when you register your client. If a user has your client installed, but is running the FrameMaker program interface (not structured), then his installation of FrameMaker will not initialize your client when it starts up. FDK Programmer’s Guide 15 U s i n g F r a m e D e v e l o p e r To o l s Style conventions The FDK Programmer’s Reference indicates those FDK functions that apply only to structured FrameMaker documents, as follows: Structured F_ApiGetAttributeDefs() In this example the word Structured appears to the left of the function name, indicating that this function applies only to the content of a structured document. If you register a client to work with the FrameMaker program interface, you should be sure that your client doesn’t use any functions identified as Structured, otherwise your client may exhibit unpredictable behavior. Typographic conventions This manual uses different fonts to represent different types of information. What you type is shown in text like this. Function names, property names, structure names, returned values, constants, filter names, program names, pathnames, and filenames are also shown in text like this. Placeholders (such as those representing names of files and directories) are shown in text like this. For example, this represents the name of your working directory: \Mydir Omitted code in source code examples is indicated with ellipses. For example, the ellipsis in the following code indicates that some of the code necessary to create a complete program is omitted: . . . F_ApiAlert((StringT)"Hello world.", FF_ALERT_CONTINUE_NOTE); . . . 16 FDK Programmer’s Guide G e t t i n g St a r t e d w i t h F D K 1 2 ..... .................................. This Getting Started section is intended to help you get familiar with the basics of FDK 12. It includes information on creating, compiling, running, and debugging FDK clients. Sample code snippets are provided as pointers that you can build upon and create your own FDK clients. In this section: "Downloading and installing the FDK" "System requirements" "Reviewing the sample programs in the samples/hello folder" "Getting familiar with how the FDK works on Windows" "Writing FDK clients for Windows" "Compiling, Registering, and Running FDK Clients" "Writing an Asynchronous FDK Client" "Example: adding menus and commands" "Next Steps" FDK Programmer’s Guide 17 5 G e t t i n g St a r t e d w i t h F D K 1 2 Downloading and installing the FDK Downloading and installing the FDK Download the FrameMaker FDK from the FrameMaker Developer Center http://www.adobe.com/devnet/framemaker.html System requirements Ensure that your system meets the following requirements: Intel Pentium IV Microsoft Windows XP, or Windows Vista or Windows 7 1GB of RAM 53MB of available hard-disk space In addition, you should have Microsoft Visual Studio 2010 installed on the system. 18 FDK Programmer’s Guide Reviewing the sample programs in the samples/hello folder ... G e t t i n g St a r t e d w i t h F D K 1 2 Reviewing the sample programs in the samples/hello folder The samples folder contains several programs that will help you get started. As an example, here is a code extract from the samples/hello/hello.c file: /* * Program Name: * hello * * General Description: * Greets the user at product startup time. * * Invocation: * Once the client is installed, launch FrameMaker. * * Install Info (Windows): * Add the following entry (all on one line) to the [APIClients] * section of your maker.ini file: * * * hello=Standard, Greets user at startup, fdk_install_dir\samples\hello\debug\hello.dll, all * * Replace fdk_install_dir with the path of the directory * in which you installed your copy of the FDK files. * Restart maker. * * Exceptions: * None. * **************************************************************** *******/ #include "fapi.h" /* required for all FDK client programs */ #include "fencode.h" /* Call back invoked at product startup time */ FDK Programmer’s Guide 19 5 G e t t i n g St a r t e d w i t h F D K 1 2 Getting familiar with how the FDK works on Windows VoidT F_ApiInitialize(init) IntT init; { /* Making it unicode enabled. */ F_FdeInit(); F_ApiEnableUnicode(True); F_FdeInitFontEncs("UTF-8"); Getting familiar with how the FDK works on Windows FDK clients on Windows are not implemented as true Windows clients. They are dynamic link libraries (DLLs) that provide entry points or callback functions, which FrameMaker can invoke. There are several types of FDK clients: A standard FDK client is an FDK client that initializes when FrameMaker starts and thenwaits to respond to specific user actions, such as menu choices. A take-control client is an FDK client that responds to a special initialization and takes complete control of a FrameMaker session. Many of the effectsyou can get with this type of client can also be realized by an asynchronous client. A filter is an FDK client that converts FrameMaker files to or from other file formats. FrameMaker calls a filter when the user attempts to open, import, or save a file with a particular format. A document report is an FDK client that provides information about a document. The user can start a document report by choosing Utilities>Document Reports from the File menu and selecting the report from the Document Reports dialog box. When FrameMaker starts, it reads the maker.ini file in the FrameMaker installation directory, and if applicable, the maker.ini file stored in the user’s Documents and Settings directory. The [APIClients] section of the maker.ini file contains entries describing the FDK clients to be loaded. FrameMaker then scans the fminit/Plugins directory and subdirectories and loads the FDK clients that have a .dll file extension and valid VERSIONINFO resource information. FrameMaker ignores all other files in the fminit/Plugins directory that do not have a .dll file extension and valid VERSIONINFO resource information. 20 FDK Programmer’s Guide Writing FDK clients for Windows ... G e t t i n g St a r t e d w i t h F D K 1 2 Writing FDK clients for Windows How to write an FDK client for Windows When you write an FDK client, you should do the following for it to compile and run correctly on Windows: Include the correct FDK header files in the correct order Replace platform-specific functions and data types with FDE equivalents Include calls to initialize the FDE if your client calls FDE functions The following sections discuss these tasks in greater detail. Including FDK header files The following table lists the header files you must include in your client in the order in which you must include them. If you are using Include Any FDK function or constant fapi.h Any FDE type fdetypes.h A specific FDE function Header file for the function’s group (for example, fhash.h for a hash function). For more information, see the function’s description in the FDK Programmer’s Reference. Any Structure Import/Export API fm_struct.h functions Constants for Frame f-codes fcodes.h .............................................................................. IMPORTANT: You must include the fapi.h header file before any other FDK header files. For example, if your client uses API functions and FDE metric utility functions, it must include header files as follows: .............................................................................. #include "fapi.h" #include "fdetypes.h" #include "fmetrics.h" If you need to include any C library header files or your own header files, include them before the FDK header files. FDK Programmer’s Guide 21 5 G e t t i n g St a r t e d w i t h F D K 1 2 Writing FDK clients for Windows Adding calls to initialize the FDE If your client calls FDE functions, it must call F_FdeInit() once before it calls the functions. The syntax for F_FdeInit() is: ErrorT F_FdeInit(VoidT); To call F_FdeInit(), your client must include the fdetypes.h header file. How to write filter clients You can use filter clients to translate documents from one format to another. FrameMaker invokes an import filter client when it recognizes a file of a particular format or when the file has a registered suffix. It invokes an export filter when you choose a particular format from the Format pop-up menu of the Save As dialog box or save a file using a registered suffix. For example, if you register a suffix for a text import filter and then open a file with that suffix, the Unknown File Type dialog box appears with the appropriate filter preselected. You must register your filter client before use. For information on registering clients, see "Compiling, Registering, and Running FDK Clients". You can also use your filter to import text or graphic files into a document. If you import a file by reference, FrameMaker stores in the document the registered format and vendor ID of the filter used in the import operation. If you import the file by copy, FrameMaker stores the facet name in the document. The information in both these cases ensures that FrameMaker invokes the correct filter for updating the next time you open the document. .............................................................................. IMPORTANT: If you are writing a filter client, FrameMaker will not fully recognize it unless you include function calls that actually cause the API library to link with your client. To make sure the client links properly, you can include the following as minimal code in your F_ApiNotification() function: .............................................................................. . . . F_ObjHandleT docId; docId = F_ApiGetId(0, FV_SessionId, FP_ActiveDoc); Identifying your filter To identify your filter to FrameMaker, you need to supply information in the line that registers the filter. This information identifies the filter on all platforms and identifies the original import filter when reimporting the file. FrameMaker uses several pieces of information that you specify for this purpose: 22 FDK Programmer’s Guide The vendor ID is a four-character string describing the provider of the filter. Writing FDK clients for Windows ... G e t t i n g St a r t e d w i t h F D K 1 2 The format ID is a four-character string describing the file format of files on which the filter operates. The facet name is an arbitrary-length string describing the filter. For example, assume you create a filter for Windows machines that translates Himyaritic documents to English. You give it the format ID "HIMF" and the vendor ID "FAPI". If you create a document and create a text inset using that filter, FrameMaker stores this information with the inset. The next time you open that document, FrameMaker knows to update the inset with your Himyaritic filter. FrameMaker reserves the following vendor IDs: "FRAM" "FFLT" "IMAG" "XTND" "AW4W" "ADBE" "ADBI" Your client cannot use these vendor IDs. FrameMaker recognizes FAPI as a valid ID for anyFDK filter client. However, you do not have to use this ID. You can use any other four-characterstring as your vendor ID. FrameMaker reserves format IDs for the indicated file formats. For a complete list of format Ids, see "Specifying format IDs and filetype hint strings". FrameMaker does not supply filters for all of these formats. However, to aid in portabilityof your clients, you should not use one of these format IDs unless it is for the specified file format. Automatic recognition of a file format Some graphic file formats have signature bytes. Signature bytes are a set of bytes that have a unique value and location in a particular file format. FrameMaker can use signature bytes to identify a graphic file’s format. The documentation for the file format that your graphics filter converts may contain information on the signature bytes for that format. If it does, you can register the signature bytes in the [FormatList] section of the maker.ini file. Each graphic file format description must be on a separate line and must have the following format: n=facet_name start_offset signature_size signature where n is any number, facet_name is the file format’s description (also used in the client registration), start_offset is how many bytes from the start of the file the signature begins, signature_size is the size in bytes of the signature, and signature is the hexadecimal value of the signature. You can enclose any of the FDK Programmer’s Guide 23 5 G e t t i n g St a r t e d w i t h F D K 1 2 Writing FDK clients for Windows arguments in double quotation marks. For example, you can register the file format for MIF with the following: [FormatList] 100="MIF" 0 8 0x3c4d494646696c65 where 0x3c4d494646696c65 is the hexadecimal encoding of the characters MIFFile. Using Windows pathnames The FDK delimits pathnames with backslashes (\). When you specify a pathname in an FDK function call, follow these rules: Follow the drive letter with a colon. Don’t terminate a pathname that specifies a file with a backslash. The following table lists examples of files and directories and the pathname strings that specify them. File or Directory Absolute Pathname Relative Pathname File named myfile.doc on the c:\myfile.doc myfile.doc c:\mydir mydir c: drive Directory named mydir on the c: drive Because the backslash is a special character, you must precede it with another backslash when you specify it in a string. For example, to open a file named c:\myfile.doc with F_ApiSimpleOpen(), use the following code: F_ApiSimpleOpen("c:\\myfile.doc", False); Using pathnames returned by FDK functions Pathnames returned by FDK functions don’t end with a backslash, unless they specify rootdirectories, such as c:\. Using F_PathNameToFilePath() To specify an absolute pathname when you call F_PathNameToFilePath(), you must specify a pathname that includes the drive and begins with the root directory of the drive. If the pathname does not include the drive and begin with the root directory of the drive, F_PathNameToFilePath() assumes the pathname is relative. If you call F_PathNameToFilePath() with anchor set to NULL and you do not specify an absolute pathname, F_PathNameToFilePath() adds the currently open 24 FDK Programmer’s Guide Writing FDK clients for Windows ... G e t t i n g St a r t e d w i t h F D K 1 2 directory or the currently open directory of the specified drive to the pathname. For example, if you specify c:myfile.c for pathname, F_PathNameToFilePath() generates: c:\cwd\myfile.c, where cwd is the currently open directory on drive c:. If you specify \\myfile.c for pathname, F_PathNameToFilePath() generates: current_drive:\myfile.c, where current_drive is the current drive. If you do not set anchor to NULL, F_PathNameToFilePath() constructs the filepath relative to the path specified by anchor. If the pathname you specify for pathname and the filepath you specify for anchor are inconsistent, F_PathNameToFilePath() ignores anchor and constructs the filepath with the currently open directory Using F_FilePathGetNext() The function F_FilePathGetNext() returns the next file in a specified directory. To do so, this function uses DOS system calls. As a result, since DOS is case-insensitive, the returned FilePathT structure uses only uppercase letters. This may not match a FilePathT structure you have created. FDK Programmer’s Guide 25 5 G e t t i n g St a r t e d w i t h F D K 1 2 Writing FDK clients for Windows For example, assume you want to create a filepath and then at some later time process all files in the same directory other than the one you created. You might be tempted to use this code: /* Bad code! */ . . . /* Create the new filepath */ newpath = F_PathNameToFilePath ("vpg.doc", NULL, FDosPath); . . . DirHandleT handle; FilePathT *path, *file; IntT statusp; pathname = StringT; handle = F_FilePathOpenDir(newpath, &statusp); if (handle) { pathname = F_FilePathToPathName (newpath); while ((file = F_FilePathGetNext (handle, &Statusp)) != NULL) { /* WRONG! This attempts to compare current file to the one you created. */ if ! (F_StrEqual (pathname, F_FilePathToPathName (file))) ProcessFile (file); F_FilePathFree (file); } } /* Bad code! */ . . .. The string returned by F_FilePathToPathName(newpath) contains the lowercase letters as specified in the earlier call to the function F_PathNameToFilePath(). On the other hand, the string returned by each call to F_FilePathToPathName() always contains only uppercase letters. Therefore, the call to F_StrEqual() never succeeds. Instead of calling F_StrEqual(), you should call F_StrIEqual(). Using menus and commands The following sections describe how to use menus and commands in your FDK client. 26 FDK Programmer’s Guide Writing FDK clients for Windows ... G e t t i n g St a r t e d w i t h F D K 1 2 Finding FrameMaker menu and command names The [Files] section of the maker.ini file specifies the location of the menu and command configuration files that list FrameMaker’s menus and commands. The following are the default entries in the maker.ini file: MathCharacterFile = fminit\mathchar.cfg ConfigCommandsFile = fminit\cmds.cfg MSWinConfigCommandsFile = fminit\wincmds.cfg ConfigMathFile = fminit\mathcmds.cfg ConfigMenuFile = fminit\maker\menus.cfg ConfigCustomUIFile = fminit\customui.cfg The following table lists the menus and commands each file contains. Menu or Command File Contents MathCharacterFile Special math characters ConfigCommandsFile Basic commands MSWinConfigCommandsFile Windows-specific commands ConfigMathFile Math commands ConfigMenuFile Standard menus ConfigCustomUIFile Custom menus Using FDK functions that write to FrameMaker console The following functions write output to the FrameMaker console on Windows: F_ApiPrintFAErrno() F_ApiPrintOpenStatus() F_ApiPrintPropVals() F_ApiPrintSaveStatus() F_Printf() with Channel set to NULL F_Warning() For descriptions of these functions, see the FDK Programmer’s Reference. As with printf(), the F_Printf() function does not automatically print a line feed ("\n") after the output. If you don’t end the output with "\n", the next call to one of the functions listed above begins printing on the last line printed by the F_Printf() call. FDK Programmer’s Guide 27 5 G e t t i n g St a r t e d w i t h F D K 1 2 Compiling, Registering, and Running FDK Clients Using platform-dependent session properties Session (FO_Session) objects have the following platform-dependent properties: Property Value FP_FM_BinDir Pathname of the bin directory in the FrameMaker installation directory FP_FM_CurrentDir Pathname of the FrameMaker installation directory FP_FM_HomeDir Pathname of the FrameMaker installation directory FP_FM_InitDir Pathname of the fminit directory in the FrameMaker installation directory FP_HostName Host name specified for PCName in the maker.ini file FP_OpenDir Pathname of the FrameMaker installation directory FP_Path Path specified by the $PATH environment variable FP_TmpDir Directory specified by the $TEMP environment variable FP_UserHomeDir Pathname of the FrameMaker installation directory FP_UserLogin The user name under which FrameMaker is registered FP_UserName The user name under which FrameMaker is registered Although the values of some of these properties specify directory pathnames, they are not terminated with a backslash. Compiling, Registering, and Running FDK Clients This section describes how to compile, register, and run FDK clients on Windows. It also briefly explains how to debug your FDK clients. Compiling FDK Clients The following sections describe how to compile FDK sample clients and your own clients. Supported compilers To compile FDK clients for Windows, you must use Microsoft Visual Studio 2010. 28 FDK Programmer’s Guide Compiling, Registering, and Running FDK Clients ... G e t t i n g St a r t e d w i t h F D K 1 2 Compiling and registering sample clients in Microsoft Visual Studio 2010 To compile and register a sample FDK client in Microsoft Visual Studio 2010, follow these steps: 1. Start Microsoft Visual Studio 2010 2. Open the Project and then choose the solution file for one of the sample clients.For example, to compile the aframes sample client, choose fdk_install_dir\samples\aframes\aframes.sln, where fdk_install_dir is the pathname of the directory in which the FDK is installed. NOTE: The project settings for the sample clients have relative paths to the FDK lib and include files already specified. If you open a sample project from its location in the FDK installation, these paths will be valid. If you move the sample client to a different location, you may need to specify new paths for the include and lib files. For more information, see "Compiling and registering your own FDK clients". 3. Use the build utility to build the client. Choose Rebuild Solution from the Build menu. Microsoft Visual Studio 2010 compiles your code into a DLL file named project.dll in the debug subdirectory of your client directory, where project is the name of the sample project. For example, the aframes sample client compiles into debug\aframes.dll. 4. Register the sample client. Each of the following sample clients includes a VERSIONINFO resource, and you register each by placing the DLL file in the Plugins folder: pickfmts elemutils dialog Because the remaining sample clients do not include a VERSIONINFO resource, you must register them in the maker.ini file. For more information see "Registering clients in the FrameMaker maker.ini file". Running the sample FDK clients It is best to store client DLL files in the FrameMaker Plugins folder (install_dir\FrameMaker\fminit\Plugins), or in a folder below it. If you register your clients via the VersionInfo resource, you must store them in this way. When you register a client in the .ini file, you can specify any location for the DLL file. After you have compiled and registered a sample FDK client, start FrameMaker to test the client. Some of the sample clients add menus and commands to the FrameMaker menus. For example, if you have compiled and registered the sample client described in FDK Programmer’s Guide 29 5 G e t t i n g St a r t e d w i t h F D K 1 2 Compiling, Registering, and Running FDK Clients "Introduction to the Frame API", a menu named API appears on the FrameMaker menu after you start FrameMaker. To test the commands on this menu, open or create a document, and choose each of the commands. Compiling and registering your own FDK clients To compile and register one of your own FDK clients, follow the instructions in this section. Compiling and registering the client To compile and register the FDK client, follow these general steps: 1. Create a project directory for your FDK client project. 2. Start Microsoft Visual Studio 2010 and create a new Win32 Dynamic- Link Library project. Choose New and then project from the File menu. The New dialog box appears. Select Visual C++ Projects and then Win32 from Project Types. Select Win32 Project, type your client's name in the Name field and then click OK. Win32 application wizard appears. Click on Application Settings, select DLL from Application Type and Empty project from Additional Options. 3. Create or place your source files in the project directory, then add those files to your project. 4. (Optional) Create a resource for any custom dialog boxes. If your client contains custom dialog boxes, you need to create a resource for them. For instructions, see "Handling Custom Dialog Box Events". 5. (Optional) Create a VERSIONINFO resource. Including a VERSIONINFO resource is one method for registering a client. For more information on registering clients, see "Registering FDK Clients". 6. Choose Properties from the Project menu to display the Properties Pages dialog box. In the Properties Pages dialog box, choose General . Set Use of MFC field to Use Standard Windows Libraries. .............................................................................. IMPORTANT: If you don’t set the Use of MFC field to "Use Standard Windows Libraries", your client will not link correctly. .............................................................................. 7. Set your project’s C/C++ Language options. In the Property Pages dialog box, choose C/C++. 30 FDK Programmer’s Guide Compiling, Registering, and Running FDK Clients ... G e t t i n g St a r t e d w i t h F D K 1 2 Choose Code Generation and choose 8 Byte or default from the Struct Member Alignment pull down menu. 8 bytes is also the default value for this field. .............................................................................. IMPORTANT: If you don’t set the Struct Member Alignment to 8 Bytes, your client may cause unexpected runtime errors. .............................................................................. With Code Generation still selected, choose Single-Threaded from the Runtime Library popup list. The FDK ships in a single-threaded version. By default, the project sets this option to Multi-threaded. Compiling the FDK with a multi-threaded runtime library produces the following warning: defaultlib "LIBC" conflicts with use of other libs; .............................................................................. IMPORTANT: For Version 7.0 and later of the FDK, it is important that you make this setting. Earlier versions of the FDK did not use symbols that conflicted with the multithreaded runtime library. However, for version 7.0 and later the FDK and the Structure Import/Export API use conflicting symbols. .............................................................................. In the General page under C/C++ language options, add path to the FDK include files in Additional Include Directories field. You can specify an absolute path or a relative path. For example, the Property Pages for the sample clients all use the following relative path: ..\..\include 8. Set your project’s Linker options: In the Property Pages dialog box, choose the Linker page. Choose General and then Input. Add the FDK libraries fdk.lib, api.lib, and fmdbms32.lib to the additional dependencies field. If you are compiling a structure import/export client, be sure to also link the Structure Import/Export API library. For more information, see "Linking the Structure Import/Export API library". .............................................................................. IMPORTANT: If your client includes custom dialog boxes, you must add /section:.rsrc,w to the Project Options. For more information, see “"Compiling clients with custom dialog boxes"”. .............................................................................. In the Category field, choose Input, then add the path to the FDK lib files in the Additional library path field. FDK Programmer’s Guide 31 5 G e t t i n g St a r t e d w i t h F D K 1 2 Compiling, Registering, and Running FDK Clients You can specify an absolute path or a relative path. For example, the project settings for the sample clients all use the following relative path: ..\..\lib As an alternative, you can specify access to the FDK include and lib directories for the Development Environment 2003. To do this, choose Tools > Options to display the Options dialog box. Select Project and then VC++ Directories, and enter the paths to the FDK include and lib directories for Include files and Library files. 9. Use Microsoft Visual Studio 2010 build utility to build your client. Choose Rebuild All from the Build menu. Visual Studio compiles your code into a dynamic link library file with the name you typed in the New dialog box. It puts this library file into the debug subdirectory of your client directory. 10. Register the client. You can register the client by using either of these two methods: As mentioned in step 5, create and include in your client’s project a VERSIONINFO resource that contains information about the client, and copy or move the compiled client into the fminit/Plugins directory. Add an entry for your client in the [APIClients] section of the maker.ini file inthe FrameMaker directory. For more information on registering clients, see "Registering FDK Clients". Using custom dialog boxes The FDK samples include a template document for designing custom dialog boxes. You open this document in FrameMaker and edit it with the FrameMaker graphic tools and commands. When you save a custom dialog box in a Windows version of FrameMaker, it generates two Windows resource definition files, a .dlg file and a .xdi file. The .dlg file is a text file containing resource statements. These statements are standard Windows descriptions of the dialog box and its controls. The .xdi file is a text file containing a user-defined resource statement. This statement contains data used by FrameMaker to manipulate the dialog boxes. When creating the .dlg and .xdi files, FrameMaker uses the name of the .dre file (without the extension) to name the files and the actual dialog resource. For example, when saving the file named mydlg.dre, FrameMaker creates the resource description files mydlg.dlgand mydlg.xdi. Both files describe the dialog resource named mydlg. To compile the .dlgand .xdifiles in your dll you must create a resource for the project, and provide directives to include these files in the resource. In the process of 32 FDK Programmer’s Guide Compiling, Registering, and Running FDK Clients ... G e t t i n g St a r t e d w i t h F D K 1 2 compiling the client, these resource definition files are compiled into a single resource file (.rc). This resource file is linked to your client. To set up the resource definition files to be compiled, follow these general steps: 1. Start Microsoft Visual Studio 2010. 2. If one doesn’t already exist for the project, create a resource script. Choose Add New Item from the File menu. The Add New Item dialog box appears. Choose Resource File. 3. Include the resource description files generated by FrameMaker. Choose Resource Includes from the Edit menu. The Resource Includes dialog box appears. In the Compile-Time Directives field, type #include statements to include the resource description files. For example, suppose you create two custom dialog boxes named pgftag.dre and chartag.dre. When FrameMaker saves these files it also creates the files pgftag.dlg, pgftag.xdi, chartag.dlg, and chartag.xdi. To include these files in the resource script, type the following in the Compile-Time Directives field: #include "pgftag.dlg" #include "pgftag.xdi" #include "chartag.dlg" #include "chartag.xdi" Compiling clients with custom dialog boxes If your FDK client uses custom dialog boxes, you need to specify a special link option before compiling it: 1. In Micrsoft Visual Studio, choose Project->Properties. This displays the Project Properties dialog box. 2. Choose Linker and then Command Line. 3. Add the following option to the Additional Options field: /section:.rsrc,w This link option makes the dialog resources writable. If you do not specify it before compiling, your DK client may exit unexpectedly when it attempts to display a custom dialog box. 4. Repeat steps 3 for each target in your project. Making adjustments to custom dialog boxes Since the .dlg files produced by FrameMaker are text files containing resource statements, you can open these files as resources. You can use the built-in tools for FDK Programmer’s Guide 33 5 G e t t i n g St a r t e d w i t h F D K 1 2 Compiling, Registering, and Running FDK Clients dialog editing to view, adjust, and test the dialog box. Because you are modifying the .dlg file but not the .xdi file, you should not make major changes to the dialog box (for example, do not add new items to the dialog box). If you do, the description in the .dlg file will not match the description in the .xdi file. Linking the Structure Import/Export API library To link the Structure Import/Export API library on Windows follow these steps: 1. In Microsoft Visual Studio 2010, open your client’s project. 2. Choose Properties from the Project menu to display the Properties Pages dialog box. 3. In the Property Pages dialog box, click on Linker and then Input. 4. Add the Structure Import/Export API library struct.lib and the resource fmstruct.res to the Additional Dependencies field. Add struct.lib before fdk.lib, and add fmstruct.res to the end of the Object/Library Modules field. 5. Add the following link option to the 'Additional Options' field in 'Command Line' property page: /section:.rsrc,w .............................................................................. IMPORTANT: This link option is required for some of the dialog boxes that are internal to the structure import/export functionality in FrameMaker. Without this link option, your client may crash when it interacts with these dialog boxes. .............................................................................. Registering FDK Clients For FrameMaker to recognize your client, you must register it on the system on which you intend to run it. When registering your client, you can name it anything you like, although the name cannot contain spaces. Also, you should not use a name that is already used by one of the clients that ships with FrameMaker. To register your client, you add an entry for your client in the [APIClients] section of the maker.ini file in the FrameMaker directory. The [APIClients] section of the maker.ini file lists the FDK clients to load when FrameMaker starts. For more information on registering your client using the maker.ini file, see "Registering clients in the FrameMaker maker.ini file". Registering clients in the FrameMaker maker.ini file You can register a client is by adding an entry for the client in the FrameMaker maker.ini file. The [APIClients] section of the maker.ini file lists the FDK clients 34 FDK Programmer’s Guide Compiling, Registering, and Running FDK Clients ... G e t t i n g St a r t e d w i t h F D K 1 2 to load when FrameMaker starts. Each client description must be on a separate line and cannot contain line breaks. Clients that are not filters use the following format: client = type, description, DLL_file, mode where For this statement Specify client the client’s name type the type of client—valid types for clients other than filters are Standard,TakeControl, and DocReport DLL_file the pathname of the client’s DLL file—can specify a full pathname or a relative pathname based on the FrameMaker installation directory. mode whether the client can run with FrameMaker in unstructured or structured mode. This fields can be one of maker, structured, or all. The mode field is required. The fields in this line are separated by a comma and zero or more spaces. For example, if you have compiled the aframes sample client into c:\fdk\samples\aframes\debug\aframes.dll, and you want to register it with FrameMaker, add the following to the maker.ini file in the FrameMaker installation directory (without any line breaks): AFrames=DocReport,Anchored Frames Report,c:\fdk\samples\aframes\ debug\aframes.dll, all If the client is a filter, register it with the following line: client = type, facet_name, format_id, vendor_id, display_name, description, DLL_file, mode, suffix where the variables are: FDK Programmer’s Guide 35 5 G e t t i n g St a r t e d w i t h F D K 1 2 Compiling, Registering, and Running FDK Clients For this statement Specify type One of: ● TextImport ● GFXImport ● Export ● FileToFileTextImport ● FileToFileTextExport ● FileToFileGFXImport ● FileToFileGFXExport facet_name the name of the file format supported by the client. format_id a four-character string that identifies the file format vendor_id a four-character string that identifies the client’s provider display_name the filter name to display in in dialog boxes when opening or saving a file of the given format. This name must match the client name. description a description of the client that appears when you choose About DLL_file the pathname of the client’s DLL file mode whether the client can run with FrameMaker in unstructured or structured mode. This fields can be one of maker, structured, or all. The mode field is required. suffix the filename extension of the file type that the client filters For information on format and vendor IDs, see "How to write filter clients". For example, assume you have a graphics import filter for the CGM format that uses ACGM as its facet name, has its executable stored in acgmflt.dll, and should be invoked on files with the suffix cgm. You can register this filter with this line: ACGMFILTER=GFXImport,ACGM,CGM,FAPI,ACGMFILTER,acgmflt.dll,all, cgm Specifying no description for a client When you register your client by using the FrameMaker maker.ini file, and you don’t want to specify a description, enter a space in the description field. For example: client= Standard, ,c:\clients\myclient\debug\myclient.dll, all 36 FDK Programmer’s Guide Compiling, Registering, and Running FDK Clients ... G e t t i n g St a r t e d w i t h F D K 1 2 The description field must contain at least one character. If no characters appear between the commas delimiting the description field, your client will not be registered. Running FDK Clients When FrameMaker starst, it reads the maker.ini file. The [APIClients] section of the maker.ini file contains entries describing the FDK clients to be loaded. FrameMaker then scans the fminit/Plugins directory and subdirectories and loads the FDK clients that have a .dll file extension and valid VERSIONINFO resource information. FrameMaker ignores any files in the fminit/Plugins directory and subdirectories that do not have a name with the .dll extension, or do not contain valid VERSIONINFO resource information. For information on how FrameMaker starts a client, see "API Client Initialization” in the FDK Programmer’s Guide. Compatibility between FDK and FrameMaker product releases To ensure your existing Windows clients are compatible with release 11 of FrameMaker, you should recompile them. It is possible to run a a client compiled in an earlier version of the FDK with FrameMaker 11, as long as the client does not use any functions or properties that have changed. However, it is recommended that you recompile your clients with the newer version of the FDK as soon as possible. Disabling FDK clients To disable all FDK clients, edit the following line in the maker.ini file in the FrameMaker installation directory, or in the version of the .ini file that is stored in the user’s Documents and Settings directory: API=On Replace On with Off. The next time you start FrameMaker, no FDK clients will be started. .............................................................................. IMPORTANT: Some FrameMaker features, such as the Word Count document report, Save As HTML, or import and export of XML are implemented as FDK clients. If you disable all FDK clients, these features will not be available. .............................................................................. FDK Programmer’s Guide 37 5 G e t t i n g St a r t e d w i t h F D K 1 2 Compiling, Registering, and Running FDK Clients Debugging FDK Clients You debug your client as part of the FrameMaker executable. The FrameMaker executable is not compiled with debugging information, so you don’t have access to any symbols within FrameMaker. To use Microsoft Visual Studio to debug your client as part of the FrameMaker executable, follow these general steps: 1. Start Microsoft Visual Studio 2010. 2. Open your client’s project and add breakpoints. 3. Select Project->Properties and then Debugging page. Go to Command Field and add the path to FrameMaker executable.pen the FrameMaker executable. For example, if FrameMaker is installed in c:\Program Files\Adobe\FrameMaker10, then to open its executable, open c:\Program Files\Adobe\FrameMaker10\FrameMaker.exe. 4. From the Build menu select Configuration Manager. Highlight the Debug Project Configuration. 5. From the Debug menu, choose Start. Alternately, if you have already started the debugger for your program, from the Debug menu choose Restart. If FrameMaker isn’t able to load your client, it displays the following error message in an alert box: File Error: Cannot find client_name.dll FrameMaker may not be able to load your client for the following reasons: The client is not located in the fminit/Plugins directory or subdirectories, or does not have a name with the .dll extension. The client’s VERSIONINFO resource information is missing or invalid. The maker.ini file doesn’t specify the correct full pathname for your client’s DLL. The FrameMaker release is incompatible with the FDK release that you used to compile the client. To check that your FDK client has control, you can have it display a string in the status bar of the document or book window. For more information, see the descriptions of FO_Book and FO_Doc in the FDK Programmer’s Reference. 38 FDK Programmer’s Guide Writing an Asynchronous FDK Client ... G e t t i n g St a r t e d w i t h F D K 1 2 Writing an Asynchronous FDK Client This section describes how to create asynchronous clients on Windows, and provides instructions for compiling and running a sample asynchronous client. Before writing an asynchronous API client you should be familiar with both the FrameMaker FDK andWindows API programming. The purpose of many FDK clients is to modify FrameMaker in some way, such as by changing or adding functionality. In these applications the main goal of the resultant application is still for the end user to use FrameMaker. A different kind of application is one that uses FrameMaker to support some aspect of the application’s functionality, but in which use of FrameMaker is not the goal. For example, you might create a data base and want to use FrameMaker to print catalogs from it. In this case, your application runs primarily independently of FrameMaker, but calls FrameMaker (possibly as a child process) during some part of its operation. The FDK allow you to create asynchronous applications that control a FrameMaker process. Even though the main purpose of the application may not be to run FrameMaker, this chapter refers to such an application as an FDK client, since it calls FDK functions. An asynchronous client does not run as part of the FrameMaker process nor as a child process. Instead, it is its own application in a separate process, communicating with a FrameMaker process via Microsoft RPC (Remote Procedure Calls). You should be aware of some consequences of this difference: An asynchronous client can be started independently of any FrameMaker product. It can be an EXE, or a DLL of some EXE other than FrameMaker. It must have its own main() function. You can use MFC or any other application framework to develop an asynchronous client. An asynchronous client can run on a machine other than that running the associated FrameMaker process. End user installations To run asynchronous clients, the executable applications or the DLL files must be installed correctly. An EXE can be installed wherever the user wants. A DLL that is a plugin for another application must be installed correctly for that application. A DLL that is a plugin for FrameMaker must be installed in the appropriate Plugins directory, or its path must be specified in the maker.ini file. The user also must have the following files installed in his or her FrameMaker installation directory, at the same level as the FrameMaker application: FDK Programmer’s Guide 39 5 G e t t i n g St a r t e d w i t h F D K 1 2 Writing an Asynchronous FDK Client afmfdk.dll fmrnclnt.exe In addition, the user must have the following entries in the maker.ini file: [Files] MarshallingDLL = afmfdk.dll RunWrappedPlugin = fmrnclnt.exe . . . [Preferences] ExecutablePlugins = EXE WrappedPlugins = DLX PluginExtensions = DLL, DLX, EXE The [Preferences] entries tell FrameMaker which filename extensions are valid for different types of clients. PluginExtensions must list extensions for all the files you want to be loaded as clients of any type. ExecutablePlugins lists extensions for clients that are built as executables which run outside of the FrameMaker process. WrappedPlugins lists extensions for clients that are built as DLLs, but will run in an address space that is external to the FrameMaker process. Such a client uses fmrnclnt.exe to wrap its DLL and runs in the fmrnclnt.exe address space. Note that you can substitute other extensions for the ones shown in the example above. For more information, see "Types of asynchronous clients". Registering asychronous clients You can register asynchronous clients just as you register other clients; you can store the registration data in the client’s VersionInfo resource, or you can make an entry in the maker.ini file for FrameMaker. Additionally, your client can pass an F_PropValsT structure to F_ApiWinConnectSession() that is a list of registration data. F_ApiWinConnectSession() is defined as: F_ApiWinConnectSession(const F_PropValsT *connectProps, ConStringT hostname, const struct _GUID *service); You can include the following properties in connectProps: 40 FDK Programmer’s Guide Writing an Asynchronous FDK Client ... G e t t i n g St a r t e d w i t h F D K 1 2 corresponds to this statement in a client’s VERSIONINFO resource This property FI_PLUGIN_NAME the name of the client. FI_PLUGIN_TYPE the type of client FI_PLUGIN_PRODUCTS s specifies structured or unstructured FrameMaker, using the names of FrameMaker products this client upports—use a space-delimited string with one or both of Maker and MakerSGML FI_PLUGIN_FACET the name of the file format supported by the client (filters, only) FI_PLUGIN_FORMATID a four-character string that identifies a file format (filters, only). FI_PLUGIN_VENDOR a four-character string that identifies the client’s provider. FI_PLUGIN_SUFFIX the filename extension of the file type that the client filters (filters, only). FI_PLUGIN_INFORMAT the file format for the file to filter (filters, only) FI_PLUGIN_OUTFORMAT the file format for the resulting file (filters, only) FI_PLUGIN_DESCRIPTION a description of the client that appears when you choose About FI_PLUGIN_PRODUCTNAME the name by which customers know your client. If connectProps is NULL, the FrameMaker process uses the client’s VersionInfo resource or the entries in the maker.ini file. If the client has no registration information in any of these sources, the FrameMaker process registers it as a standard client. Types of asynchronous clients Asynchronous clients can be executable applications (EXE), dynamically linked libraries (DLLs) that are a part of another application, or DLLs that are plugins for FrameMaker (wrapped plugins). FDK Programmer’s Guide 41 5 G e t t i n g St a r t e d w i t h F D K 1 2 Writing an Asynchronous FDK Client Asynchronous EXE applications An EXE can be either a console application or a Windows application. After connecting with the FrameMaker process, the EXE application passes calls to FrameMaker through afmfdk.dll. .............................................................................. IMPORTANT: Because they don’t have a Windows message processing loop, console applications cannot handle notifications from the FDK. For example, this means a console application cannot process commands from menus it adds to FrameMaker. Nor can it process notifications such as FA_Note_PreOpenDoc or FA_Note_PreSaveDoc. .............................................................................. Asynchronous DLLs A DLL that is part of another application can call F_ApiStartUp() to make a connection with a FrameMaker process. For example, you could write a plugin for Acrobat Exchange that writes the data from Acrobat Forms to a FrameMaker document. In that case, the DLL communicates with the FrameMaker process, as a part of its parent EXE, via afmfdk.dll. A DLL that runs as a wrapped plugin for FrameMaker runs in its own memory space. After connecting with the FrameMaker process, the DLL invokes fmrnclnt.exe to run as a wrapper for the DLL. The wrapped DLL then communicates with FrameMaker via afmfdk.dll, as though it is an EXE. Registering multiple FrameMaker processes as servers When you first run FrameMaker, it registers istelf in the system registry as the default instance of the FrameMaker instance on that machine. By default, asynchronous clients connect to this instance. You can register multiple instances of the FrameMaker process, each with a unique entry in the system registry. Then you can use these processes as a bank of servers, and your client can choose among them when making a connection. You identify a FrameMaker process as a server by its entry in the system registry. The entry can specify: A name to identify the GUID for that specific process. Whether the process starts up when called by a client, or whether it must already be running before the client can connect to it. To register a process, you start FrameMaker with specific commandline options. This creates an entry in the system registry for the machine on which you start FrameMaker. To start FrameMaker with commandline options: 1. Choose Run from the Start menu. 42 FDK Programmer’s Guide Writing an Asynchronous FDK Client ... G e t t i n g St a r t e d w i t h F D K 1 2 The Run Application dialog box appears. 2. In the text box, type the full pathname of the FrameMaker.exe file, followed by the commandline options. Alternately, you can start FrameMaker from a DOS Command Prompt window. For example, type FrameMaker_path\FrameMaker10 /option, where FrameMaker_path is the install path for the version of FrameMaker you want to run, and /option is one or more of: progid:process_name where process_name is a name you provide. This option registers a name for the FrameMaker process. auto This option allows the FrameMaker process to automatically start up if it isn’t running when another process calls it. noauto This option disallows automatic start-up. This creates an entry in the system registry for the machine on which you started FrameMaker. Registering a name for a FrameMaker process To specify a name for the process, use the /progid option. For example, type FrameMaker_path\FrameMaker10 /progid:MyProcess.Api1, where FrameMaker_path is the install path for the version of FrameMaker you want to run. This establishes a name, MyProcess.Api1, for the process. When you start FrameMaker with no /progid option, you create system registry entry with the default name of FrameMaker.API.1. Asynchronous clients running locally on the host can refer to processes by their names. In this way, your client can choose which process to run for a given task. .............................................................................. IMPORTANT: Clients connecting to a remote host cannot use the process name to connect to a FrameMaker process. Instead, they must use the GUID for that process, as it is specified in the system registry. .............................................................................. Registering automatic start-up for a process If the FrameMaker process is not running, an asynchronous client can still call it. If the process is so registered, it will start up when the client calls it. Alternatively, you can register the process in a way that does not allow automatic start-up. FDK Programmer’s Guide 43 5 G e t t i n g St a r t e d w i t h F D K 1 2 Writing an Asynchronous FDK Client To register the process for automatic start-up, use the /auto option. To disallow automatic start-up, use the /noauto option. For example, type FrameMaker_path\FrameMaker7.2 /progid:MyProcess.Api1 /auto, where FrameMaker_path is the install path for the version of FrameMaker you want to run. This establishes a process named MyProcess.Api1, which will start automatically when an asynchronous client calls it. Running asynchronous clients on remote hosts With systems that support DCOM, you can run a client on one machine (the client machine), connected to a FrameMaker process on another machine (the host machine). To accomplish this, you make use of the DCOM services provided with your operating system. Also, both machines must be in the same domain, and the same user must have the accounts on both machines. For an asynchronous client to connect to a FrameMaker process on a remote host: 1. Register the FrameMaker process as a server process on the host machine. This establishes entries on the host machine’s system registry for the FrameMaker processes you want to run as servers. For more information see “"Registering multiple FrameMaker processes as servers". 2. Run dcomcnfg on the host machine to configure DCOM accessibility for each process you want to run as a server. This enables DCOM connections to the FrameMaker server processes that are registered on the host machine. 3. Run dcomcnfg on the client machine to configure its DCOM accessibility. This enables the client machine to connect to the host machine via DCOM. Enabling DCOM for the server processes on the host To enable DCOM for a FrameMaker process on the host machine: 1. Choose Run from the Start menu. The Run dialog box appears. 2. In the Run dialog box, type dcomcnfg The DCOM Configuration Properties service application appears. 3. Select the Default Properties tab and click Enable Distributed COM on this Computer. 4. In the Applications list box, double-click the FrameMaker process you want to enable, then set the appropriate security options. 44 FDK Programmer’s Guide Writing an Asynchronous FDK Client ... G e t t i n g St a r t e d w i t h F D K 1 2 5. Click the Security tab and make sure Use default configuration permissions is turned on. 6. Apply any other settings to the FrameMaker process or your computer that are appropriate for your network configuration. You should check with the system administrator to ensure the options you set are compatible with his administration procedures. 7. Click OK. Enabling DCOM for client machine To enable DCOM on the client machine: 1. Choose Run from the Start menu. The Run dialog box appears. 2. In the Run dialog box, type dcomcnfg 3. The DCOM services application appears. 4. Select the Default Properties tab and click Enable Distributed COM on this Computer. 5. Apply any other settings to your computer that are appropriate for your network configuration.You should check with the system administrator to ensure the options you set are compatible with the administration procedures. 6. Click OK. To find more information on DCOM see the Windows Online Help. Connecting with a FrameMaker process Asynchronous clients connect with a FrameMaker process by calling F_ApiStartUp() or F_ApiWinConnectSession(). When connecting to a process on a local host, FrameMaker does not have to be registered as a server. For a process on remote host, your client must know the GUID for that process. A machine may have more than one FrameMaker process running at a time. In that case, the processes must be registered as servers, and they should be registered with a name for each process. For information about registering FrameMaker processes as servers, see "Registering multiple FrameMaker processes as servers". Asynchronous clients use COM to communicate with FrameMaker processes. If any FDK call returns FE_Busy, then you probably need to register a message filter. When using COM, an application should always register a message filter. If your code calls F_ApiStartUp() or F_ApiWinConnectSession() before initializing COM, these routines automatically initialize COM and register a message filter. However, if you initialized COM before calling these routines, they assume your application already FDK Programmer’s Guide 45 5 G e t t i n g St a r t e d w i t h F D K 1 2 Writing an Asynchronous FDK Client registered a message filter. If your application initializes COM but does not register a message filter, be sure to call F_ApiWinInstallDefaultMessageFilter(). Connecting to the default process on a local host You use F_ApiStartUp() when the desired FrameMaker process is running on the local machine. For example, a DLL that is a FrameMaker plugin calls F_ApiStartUp(). In that case, the FrameMaker process that invokes the DLL identifies itself by passing a globally unique identifier (GUID) via the FMGUID environment variable. Likewise, if you want an EXE to connect locally to the currently active FrameMaker process, use F_ApiStartUp(). The following call makes this connection: F_ApiStartUp(NULL); For more information, see F_ApiStartUp() in the FDK Programmer’s Reference. Connecting to a named process on a local host To connect to a named process on a local machine, you need to convert the process name to a GUID. Then you can pass that GUID to F_ApiWinConnectSession() to initiate communication between your client and the FrameMaker process. Note that F_ApiStartUp() makes a reliable connection only when the desired FrameMaker process is the only FrameMaker process running on the local host. If no FrameMaker process is running, F_ApiStartUp() will not work. Also, if more than one process is running, F_ApiStartUp() cannot determine which process will finally connect with your client. To choose one of many FrameMaker processes on a local host, you should have all of the processes registered as servers on that host. If you have registered the process as a named server, and your client is connecting to it on a local host, you can use the Win32 API to get the GUID associated with that name. Then you pass the GUID to F_ApiWinConnectSession(). The following example uses the Win32 API function CLSIDFromProgID() to get the GUID for a process named MyProcess.Api1. It then calls F_ApiWinConnectSession() to connect to the process. Note that you need a 46 FDK Programmer’s Guide Writing an Asynchronous FDK Client ... G e t t i n g St a r t e d w i t h F D K 1 2 Unicode string for the process name. The example uses the Win32 API call, MultiByteToWideChar() to convert a string to Unicode. #define WBUFLEN 512 OLECHAR progStr; CLSID serviceId; StringT myProcess = F_StrCopyString("MyProcess.API.1"); . . . progStr = (OLECHAR*)malloc( WBUFLEN*sizeof(wchar_t) ); MultiByteToWideChar(CP_ACP, 0, (char *)opt_progid, -1, progStr, WBUFLEN ); if(CLSIDFromProgID(progStr, &serviceId)) F_ApiConnectWinSession(0, 0, &serviceId); . . . Note that F_ApiWinConnectSession() takes three parameters. In the first parameter you can pass a list of properties that correspond to the entries you provide when registering a FrameMaker client. The second parameter is for the address of a remote host, when making a connection to a remote host. If this parameter is NULL or 0, F_ApiWinConnectSession() connects to the local host. The third parameter specifies the desired FrameMaker process on the host machine. If this parameter is NULL or 0, F_ApiWinConnectSession() uses the value of the FMGUID environment variable on the specified host. For more information, see F_ApiWinConnectSession() in the FDK Programmer’s Reference. Connecting to a remote host To connect to a remote machine, you need the address of that machine. Once you have the address, you can call F_ApiWinConnectSession() to initiate communication between your client process and the FrameMaker process on the host machine. The following call makes this connection to the currently running FrameMaker process on the remote host: F_ApiWinConnectSession(0, remote, 0); where remote is the address of the remote host. The above call only works when the desired FrameMaker process is the only FrameMaker process running on the remote host. If no FrameMaker process is running, this will not work. Also, if more than one process is running, you cannot predict which process will finally connect with your client. FDK Programmer’s Guide 47 5 G e t t i n g St a r t e d w i t h F D K 1 2 Writing an Asynchronous FDK Client To choose one of many FrameMaker processes on a remote host, you should have all of the processes registered as servers on that host. To choose a registered process, you must know the GUID for that process ahead of time; you pass that GUID to F_ApiWinConnectSession(). Assuming you have specified a GUID in serviceId, the following call connects to a specific process on the remote host: stringT remote;‘ CLSID serviceId; . . . F_ApiWinConnectSession(0, remote, &serviceId); where remote is the address string of the machine that is running the FrameMaker process. How to write an asynchronous FDK client To write an asynchronous client that communicates with FrameMaker, you proceed as you would for any C application, providing a main() function and adding whatever functionality you need. A Windows client can get control of a FrameMaker process by invoking F_ApiCallClient() to call itself. For the duration of the notification, that is while the client is processing the resulting callback, the client has exclusive control of FrameMaker. At some point in its processing, your client needs to communicate with a FrameMaker process. To do so, it follows these general steps: 1. Connect to the FrameMaker process. To connect to a local host, use F_ApiStartUp() or F_ApiWinConnectSession(). To connect to a remote host, use F_ApiWinConnectSession(). For information about connecting to FrameMaker processes, see "Connecting with a FrameMaker process". For information about the functions to connect to FrameMaker processes, see F_ApiWinConnectSession() and F_ApiStartUp() in the FDK Programmer’s Reference. 2. Depending on your client, wait for requests from FrameMaker or perform some operations using FrameMaker. Once connected to a running FrameMaker process, your client can use the FDK to control the FrameMaker process, or receive notifications from it. However, bear in mind that console programs cannot handle notifications from the FDK. (This is because console programs do not have a Windows message processing loop; applications running in console programs must not request notifications.) 48 FDK Programmer’s Guide Writing an Asynchronous FDK Client ... G e t t i n g St a r t e d w i t h F D K 1 2 Note that a client can take exclusive control of the FrameMaker process by requesting notification for FA_Note_ClientCall and then calling itself via F_ApiCallClient(). While handling the notification, no other clients can take control of the FrameMaker process. 3. When done, disconnect from the FrameMaker process. How your client disconnects depends on the situation. With a client that is a plugin for FrameMaker, you can call F_ApiBailOut() to terminate the client. After calling F_ApiBailOut(), the client’s notification points are still registered with the FrameMaker process. If a notification event occurs, the FrameMaker process restarts the client by calling F_ApiInitialize() with initialization set to FA_Init_Subsequent. When it starts up subsequently, the client’s global variable settings are lost. If the FrameMaker process still exists when your client is completely done communicating with it, your client should call the function F_ApiDisconnectFromSession() to break the RPC connection. Alternatively, the FrameMaker process may have shut down when your client wants to break the connection (for example, due to a user request or due to a command from your client). If so, your client should call the function F_ApiShutDown() to close its side of the RPC connection. FDK Programmer’s Guide 49 5 G e t t i n g St a r t e d w i t h F D K 1 2 Writing an Asynchronous FDK Client Writing a Main routine in Windows. Windows does not provide a default main routine for remote plugins. You must provide your own main routine. Simply include the following lines in your client: #define DONT_REDEFINE /* We need to use native types. */ #include ‘fapi.h’ #include int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { return F_ApiRun(); } The routine F_ApiRun() is documented in the FDK manuals and is implemented as follows: IntT F_ApiRun(VoidT) { ConStringT s = F_ApiStartUp(NULL); if (s) F_ApiErr(s); else while (!FA_bailout) F_ApiService(NULL); F_ApiShutDown(); return s !=NULL; } F_ApiStartup() and F_ApiService() ignore their parameters and should be passed NULL. It is not necessary to call F_ApiRun(). You may choose to implement your main routine using these primitives directly. If your program has a windows message loop you need only call F_ApiStartup(NULL). However if your remote plugin does not call F_ApiRun(), it must either periodically check the FA_bailout flag or arrange to terminate based on the FA_NotePostQuitSession notification. You must make these checks, otherwise FrameMaker can terminate leaving your client running. 50 FDK Programmer’s Guide Writing an Asynchronous FDK Client ... G e t t i n g St a r t e d w i t h F D K 1 2 Compiling and running a sample client The following code sample is a console application that connects to the default FrameMaker session and gets the name of the active FrameMaker document. Following the code is a lineby-line description of how it works. 1. #define DONT_REDEFINE // Console app needs native types 2. #define WBUFLEN 512 3. 4. #include "fdetypes.h" 5. #include "futils.h" 6. #include "fapi.h" 7. #include "fstrings.h" 8. #include 9. #include //not required 10. #include //not required 11. 12. int main(int argc, char **argv) 13. { 14. StringT opt_progid; 15. CLSID pclsid; 16. LPOLESTR progStr; 17. HRESULT res; 18. F_ObjHandleT docId; 19. 20. // Get the process name. 21. if(argc == 2) 22. 23. opt_progid = F_StrCopyString((StringT)argv[1]); else { 24. fprintf(stderr, "You must provide a process name."); 25. return(1); 26. } 27. 28. // Convert the process name into a GUID 29. progStr = (OLECHAR*)malloc( WBUFLEN*sizeof(wchar_t) ); 30. if(0 == MultiByteToWideChar(CP_ACP, 0, (char *)opt_progid, -1, 31. progStr, WBUFLEN )) { 32. fprintf(stderr, "failed to allocate\n"); FDK Programmer’s Guide 51 5 G e t t i n g St a r t e d w i t h F D K 1 2 Writing an Asynchronous FDK Client 33. return(1); 34. } 35. if (progStr[0] == '{') // hex-codes within brackets 36. 37. res = CLSIDFromString(progStr, &pclsid); else 38. res = CLSIDFromProgID(progStr, &pclsid); 39. 40. if(res == S_OK) 41. 42. F_ApiWinConnectSession(NULL, NULL, &pclsid); if (!F_ApiAlive()) { 43. fprintf(stderr, "No connection: %s\n", opt_progid); 44. return 1; 45. } 46. // Print the name of the current document. 47. docId = F_ApiGetId(0, FV_SessionId, FP_ActiveDoc); 48. if (docId) { 49. StringT docname = F_ApiGetString(FO_Session, docId, FP_Name); 50. fprintf(stderr, "Current document: %s\n", docname); 51. 52. F_ApiDeallocateString(&docname); } else 53. fprintf(stderr, "No active document\n"); 54. 55. return 0; 56. } Line 1 To compile this client as a console application, you need to use types that are native to the C language. This statement keeps the FDE from redefining those types. Lines 20–26 These lines parse the commandline options you pass to the client when you invoke it. You invoke the exe with the name of a FrameMaker process as an argument. To run the default process, use the name FrameMaker.API.1. For example, assuming the exe is named fmRemote.exe, type the following to invoke it with the default FrameMaker process: fmRemote.exe FrameMaker.API.1 For more information, see "Registering a name for a FrameMaker process". 52 FDK Programmer’s Guide Writing an Asynchronous FDK Client ... G e t t i n g St a r t e d w i t h F D K 1 2 Lines 28–38 These lines convert the process name into a valid GUID. Note that you need a Unicode string for the process name. The code uses the Win32 API call, ultiByteToWideChar() to convert the process name to Unicode. It then uses the Win32 API functions CLSIDFromProgID() or CLSIDFromString() to get the GUID for the specified process. Lines 40–45 If you successfully retrieve a GUID for the process, these lines make the connection to a FrameMaker session. Lines 46–56 Now that the client has connected with a session, it can use the FDK to interact with that session. These lines are standard FDK code to get the name of the active document for the current session. You can add code to perform other actions such as adding menus to the application window, manipulating the active document, or anything else you can do via the FDK. .............................................................................. IMPORTANT: Because they don’t have a Windows message processing loop, console applications cannot handle notifications from the FDK, such as menu commands or notifications such as FA_Note_PreSaveDoc. .............................................................................. Compiling and registering the sample client To compile the sample client in Microsoft Visual Studio 2010, follow these steps: 1. Create a project for a console application. Use the Project Wizard to create a new project for a console application. 2. Set up the project options and settings as described in "Compiling, Registering, and Running FDK Clients". .............................................................................. IMPORTANT: Your link settings must include fdk.lib and api.lib. but neither fmdbms32.lib nor fmdebug.lib. In previous versions of the FDK, fmdbms32.lib and fmdebug.lib were required to compile. These libraries are now obsolete, but we include them so you don’t have to change the link settings to compile existing FDK projects. If a remote client fails to start up and you see these libraries mentioned in the error text, then you must remove them from your link settings and recompile. .............................................................................. Compile the client. FDK Programmer’s Guide 53 5 G e t t i n g St a r t e d w i t h F D K 1 2 Writing an Asynchronous FDK Client 4. Register the client There are three ways to register an asynchronous client. See "Registering asychronous clients". You must also be sure the end user has a correct installation to run asynchronous clients. See "End user installations". 5. Connect the client with a named FrameMaker process. To connect with a named FrameMaker process: – On your machine, register the FrameMaker process as a server. See "Registering multiple FrameMaker processes as servers". Be sure to register it with a name. See "Registering a name for a FrameMaker process". – In a command window, type the filename for the client, followed with the name of the FrameMaker process the argument. – To connect to the default FrameMaker process, use the process name, FrameMaker.API.1. For example, type remote.exe process_name, where process_name is the name you assigned to a FrameMaker process. Note that unlss you registered the process to start up automatically, that process must be running when you invoke the sample client. Summary of supporting functionality To support communication with a FrameMaker process, the FDK provides the following functions: Function 54 Purpose F_ApiWinConnectSession() Initiates communication between the calling process and an identified FrameMaker process F_ApiDisconnectFromSession() Severs communication with a FrameMaker process F_ApiSetClientDir() Identifies a directory the FrameMaker process associates with an unregistered client F_ApiShutDown() Closes a client’s connection with the API F_ApiWinInstallDefaultMessag eFilter() Registers the default FDK message filter for a COM session. F_ApiService() useful if you are providing a replacement for F_ApiRun(). F_ApiStartup() See the description after the table FDK Programmer’s Guide Example: adding menus and commands Function ... G e t t i n g St a r t e d w i t h F D K 1 2 Purpose F_ApiAlive() F_ApiErr(message) Prints client name and message to console. F_ApiRun provides the minimum functionality required in an FDK client’s main() function Using F_ApiStartup(F_FdFuncT) the F_FdFuncT argument is ignored because Windows RPC is not based on sockets. F_ApiStartup queries the application’s ersion information for client configuration data, if present, and connects to FrameMaker. For information on these functions and properties, see the FDK Programmer’s Reference. Example: adding menus and commands The following code adds a menu named “Database” to the Special menu. The menu has two commands “Load Database” and “Query Database”. FDK Programmer’s Guide 55 5 G e t t i n g St a r t e d w i t h F D K 1 2 Example: adding menus and commands When the user selects either of the commands, a prompt is displayed. #include "fapi.h" #define LOAD 1 #define QUERY 2 VoidT F_ApiInitialize(initialization) IntT initialization; { F_ObjHandleT specialMenuId, databaseMenuId; /* Get the ID of the special menu. */ specialMenuId = F_ApiGetNamedObject(FV_SessionId, FO_Menu, "SpecialMenu"); /* Define the menu and add it to the Edit menu. */ databaseMenuId = F_ApiDefineAndAddMenu(specialMenuId, "DatabaseMenu", "Database"); /* Define the commands and add them to the Special menu. */ F_ApiDefineAndAddCommand(LOAD, databaseMenuId, "LoadDatabase", "Load Database","\\!LD"); F_ApiDefineAndAddCommand(QUERY, databaseMenuId, "QueryDatabase", "Query Database", "\\!QD"); } VoidT F_ApiCommand(command) IntT command; { switch(command) { case LOAD: /* Code to load database goes here. */ F_ApiAlert((ConStringT)"Load Command Executed!!\n" , 56 FDK Programmer’s Guide Next Steps ... G e t t i n g St a r t e d w i t h F D K 1 2 FF_ALERT_CONTINUE_NOTE); break; case QUERY: /* Code to query database goes here. */ F_ApiAlert((ConStringT)"Query Command Executed!!\n" , FF_ALERT_CONTINUE_NOTE); break; } } Next Steps By now, you would have become familiar with the basic operations of the FDK. Here are the suggested next steps that will help you use the FDK more effectively: Study the Programmer’s Guide to understand the detailed flow and usage model Review the samples provided (available in the samples folder of the FDK installation) and write your own program modeled on them. Refer to the FDK Programmer’s Reference for details of syntax and examples FDK Programmer’s Guide 57 5 58 G e t t i n g St a r t e d w i t h F D K 1 2 Next Steps FDK Programmer’s Guide PART II .......................................... Frame Product Architecture 1 Frame Session Architecture .................................. ..... 1 This chapter discusses the general organization of FrameMaker product sessions from a programmer’s perspective. It provides useful background information for programmers who want to use the Frame API. Identifying objects The API assigns a unique ID to each object. Most API functions that manipulate objects require you to specify this ID. An object’s ID is valid only as long as the object is available in the current FrameMaker product session. For example, suppose you have a document with a rectangle drawn in it. When you open the document, the API assigns an ID to the FO_Rectangle object that represents the rectangle. As long as the document is open, the ID of the FO_Rectangle object remains the same. However, if you exit the document and then reopen it, the API may assign a new ID to the rectangle. In addition to IDs, there are two types of identifiers that are persistent between sessions: Unique object names Unique persistent identifiers (UIDs) Each object generally has either an FP_Name property specifying a unique object name or an FP_Unique property specifying a UID. Unique object names There are many types of objects that you can assign unique names to in the user interface. These objects, which are called named objects, include: FO_Book FO_CharFmt FO_Color FO_CombinedFontDfn FO_Command FO_CondFmt FDK Programmer’s Guide 61 1 Frame Session Architecture Identifying objects FO_ElementDef FO_FmtChangeList FO_MarkerType FO_MasterPage FO_Menu FO_MenuItemSeparator FO_PgfFmt FO_RefPage FO_RulingFmt FO_TiFlow FO_TiText FO_TblFmt FO_UnanchoredFrame (named frames on reference pages only) FO_VarFmt FO_XRefFmt The API provides a function named F_ApiGetNamedObject(), which gets the ID of a named object with a specified name. .............................................................................. IMPORTANT: A document can contain several flows with the same name. For example, a document can contain several A flows. To get the ID of a specific flow, first get the ID of a text frame in that flow, for example, the text frame for the current text location, and then query the text frame’s FP_Flow property. .............................................................................. Unique persistent identifiers (UIDs) The API and MIF identify unnamed objects with UIDs. An unnamed object is an object that doesn’t have a unique name. For example, FO_Pgf objects are unnamed. UIDs are unique within documents. An object’s UID remains the same as long as the object is in the same document. The API provides a function named F_ApiGetUniqueObject(), which gets an object’s ID from its UID. .............................................................................. IMPORTANT: If you copy an object and then paste it, the FrameMaker product considers the pasted object a new object and assigns a new UID to it. This is also true true for a paragraph that is conditionalized. If the entire paragraph is of a given 62 FDK Programmer’s Guide Representing object characteristics with properties ... Frame Session Architecture condition, and that condition is hidden and then shown, the paragraph will have a new UID. .............................................................................. Representing object characteristics with properties Each object has a property list, or set of properties that represent its characteristics. Each property has a value associated with it. For example, if a paragraph has two tabs, the value of its FP_NumTabs property is 2. A property value can be more than an integer. It can also be a string, a pointer to a structure that contains a set of strings, or a variety of other things. The following table summarizes the different data types property values can be. Property data type What the property value represents IntT An integer, enum, boolean, or ordinal value. For many IntT properties, the API provides defined constants, such as True and False. F_IntsT A set of integers or a set of IDs. F_UIntsT A set of unsigned integers. MetricT A measurement value. F_MetricsT A set of metrics. StringT A character string. F_StringsT A set of character strings. F_ObjHandleT The ID of another object. F_PointsT A set of x-y coordinate pairs. F_TabsT A set of tab descriptions. F_TextLocT A point (location) in text. F_TextRangeT A range or selection of text. F_ElementCatalogEntriesT The list of elements in the Element Catalog. F_AttributeDefsT An set of attribute definitions. F_AttributesT An set of attributes. F_ElementRangeT An element selection. FDK Programmer’s Guide 63 1 Frame Session Architecture Representing object characteristics with properties The API uses MetricT data to express measurement values. This manual uses constants to represent conventional measurement system units as MetricT data. For example, the constant in represents an inch and the constant pts represents a point in MetricT units, for example 5 inches (5* 4718592) are represented as 5*in. For more information on the MetricT type and other data types and data structures listed in the table above, see Chapter 4, “Data Types and Structures Reference,” of the FDK Programmer’s Reference. Many property values are pointers to data structures. For example, FO_Doc objects have a property named FP_Dictionary that specifies words that the Spelling Checker will permit in a document. FP_Dictionary is an FT_Strings property. Its value is a pointer to an F_StringsT structure, which is defined as: typedef struct { UIntT len; /* Number of permitted words */ StringT *val; /* Vector of permitted words */ } F_StringsT; Property lists At the highest level, the API represents each object’s property list with a F_PropValsT structure. The F_PropValsT structure is defined as: typedef struct { UIntT len; /* Number of properties in list */ F_PropValT *val; /* Property-value pairs */ } F_PropValsT; The F_PropValT structure, which provides an individual property-value pair, is defined as: typedef struct { F_PropIdentT propIdent; /* The property identifier */ F_TypedValT propVal; /* The property value */ } F_PropValT; The F_PropIdentT structure, which identifies a property by either its property number constant (one of the constants beginning with FP_) or a property name, is defined as: typedef struct { IntT num; /* The property number constant */ StringT name; /* The property name */ } F_PropIdentT; Most properties are identified by property number constants. Only inset facets, a special type of properties, are identified by names. For information on insets, see Chapter 12, 64 FDK Programmer’s Guide Representing object characteristics with properties ... Frame Session Architecture “Using Imported Files and Insets.” If a property is identified by a name, F_PropIdentT.num is 0. The F_TypedValT structure is defined as: typedef struct { IntT valType; /* The type of value. See table below */ union { StringT sval; /* String value */ F_StringsT ssval; /* Set of strings */ F_MetricsT msval; /* Set of metrics */ F_PointsT psval; /* Set of points */ F_TabsT tsval; /* Set of tabs */ F_TextLocT tlval; /* Text location */ F_TextRangeT trval; /* Text range */ F_ElementCatalogEntriesT csval; /* Element Catalog */ F_AttributeDefsT adsval; /* Attribute definitions */ F_AttributesT asval; /* Attribute values */ F_ElementRangeT *erng; /* Element range */ F_IntsT isval; /* Set of integers */ F_UIntsT uisval; /* Set of unsigned integers */ IntT ival; /* Integer */ } u; } F_TypedValT; The constants used in the valType field are described in the following table. valType constant Property data type u field FT_Integer IntT ival FT_Ints F_IntsT isval FT_Metric MetricT ival FT_Metrics F_MetricsT msval FT_String StringT sval FT_Strings F_StringsT ssval FT_Id F_ObjHandleT ival FT_Points F_PointsT psval FT_Tabs F_TabsT tsval FT_TextLoc F_TextLocT tlval FT_TextRange F_TextRangeT trval FDK Programmer’s Guide 65 1 Frame Session Architecture Representing object characteristics with properties valType constant Property data type u field FT_UInts F_UIntsT uisval FT_UBytes F_UBytesT No field FT_ElementCatalog F_ElementCatalogEntriesT csval FT_AttributeDefs F_AttributeDefsT adsval FT_Attributes F_AttributesT asval FT_ElementRange F_ElementRangeT erng .............................................................................. IMPORTANT: Integer (IntT), metric (MetricT), and ID (F_ObjHandleT) values are all put in the ival field of the u union. .............................................................................. Example Suppose the user creates a paragraph format named Heading, which has a 1-inch left indent and has Keep With Next Paragraph turned on. The API represents this paragraph format with an FO_PgfFmt object. The following are some of the object’s properties and their values. 66 Property Data type Value FP_Name StringT Heading FP_KeepWithNext IntT True FP_LeftIndent MetricT 1*in FDK Programmer’s Guide FrameMaker product sessions ... Frame Session Architecture The property list for the FO_PgfFmt object and the properties in the previous table are represented graphically in Figure 1-1. FO_PgfFmt objects have many other properties that are not shown in the illustration. F_PropValsT len: 3 val: val[0] val[1] val[2] propIdent propIdent propIdent num: FP_Name name: NULL num: FP_KeepWithNext name: NULL num: FP_LeftIndent name: NULL propVal propVal propVal valType: FT_String valType: FT_Integer valType: FT_Metric u u u sval: Heading ival: True ival: 1*in Figure 1-1 Some FO_PgfFmt properties FrameMaker product sessions The fundamental entity in Frame architecture is a session. Each instance of a FrameMaker product that the user starts is a session. FrameMaker allows the user to have many open documents and books in a session. Of the open documents and books in a session, only one document or book is active at a time. An open document or book is active if it has the input focus. FDK Programmer’s Guide 67 1 Frame Session Architecture FrameMaker product sessions How the API represents sessions The API represents each FrameMaker product session with an FO_Session object, whose properties provide the following categories of information about the session: System information, such as the operating system, the current FrameMaker product version, and the current directory The automatic save settings Names of fonts available on the system IDs of the objects that represent open and active documents and books Whether the FrameMaker product reformats and redisplays documents after changes have been made Whether element reformatting and validation is turned on (for FrameMaker structured documents) Suppose you start FrameMaker on a Window System platform and open a document named mydoc. The API represents this session with an FO_Session object. The following are some of its properties. Property Type Value FP_ProductName FT_String FrameMaker FP_VersionMajor FT_Integer 5 FP_WindowSystem FT_String Windows FP_AutoSaveSeconds FT_Integer 300 FP_ActiveDoc FT_Id ID of the object that represents mydoc How the API indicates which documents and books are open The API represents a document with an FO_Doc object. The API maintains a linked list of the FO_Doc objects that represent a session’s open documents. The FO_Session property, FP_FirstOpenDoc, specifies the ID of the first FO_Doc object in the list. The FO_Doc property, FP_NextOpenDocInSession, specifies the ID of the next FO_Doc object in the list. The list of FO_Doc objects that represent open documents is not in any particular order. The FO_Doc object specified by FP_FirstOpenDoc does not necessarily represent the first document the user opened. 68 FDK Programmer’s Guide FrameMaker product sessions ... Frame Session Architecture The API represents a book with an FO_Book object. The API also maintains the FO_Book objects that represent the session’s open books in a linked list. The FO_Session property, FP_FirstOpenBook, specifies the ID of the first FO_Book object in the list. The FO_Book property, FP_NextOpenBookInSession, specifies the next FO_Book object in the list. As with the list of FO_Doc objects, the linked list of FO_Book objects is not in any particular order. How the API indicates which document or book is active FO_Session has two properties, FP_ActiveDoc and FP_ActiveBook, that specify the IDs of the objects that represent the active document and the active book. Only one document or one book can be active at a time. If there is no active document or book, these properties are set to 0. Invisible documents and books can’t be active. Example Suppose you start FrameMaker and open the books and documents shown in Figure 1-2. The Frame API represents the session with the objects shown in Figure 1-3. Figure 1-2 A FrameMaker\session with open documents and books FDK Programmer’s Guide 69 1 Frame Session Architecture FrameMaker product sessions FP_FirstOpenBook FO_Book (Manual.book) FP_NextOpenBookInSession FO_Book (Manual2.book) FO_Session FP_FirstOpenDoc FO_Doc (2Chapter) FP_NextOpenDocInSession FO_Doc FP_ActiveDoc (1Chapter) Figure 1-3 API representation of a session with open documents and books Although Manual.book is iconified, the API still considers it open. Although FP_FirstOpenDoc specifies 2Chapter, it is not necessarily the first document that was opened. How the API indicates which fonts are available in a session The following FO_Session properties specify which fonts are available in the current session: 70 FP_FontFamilyNames specifies the available families, for example, Helvetica and Times. FP_FontVariationNames specifies the available variations, for example, Narrow and Oblique. FP_FontWeightNames specifies the available weights, for example, Bold and Regular. FP_FontAngleNames specifies the available angles, for example, Italic and Regular. FDK Programmer’s Guide FrameMaker product sessions ... Frame Session Architecture The FP_FontFamilyNames, FP_FontVariationNames, FP_FontWeightNames, and FP_FontAngleNames properties determine which choices appear in the Family, Weight, Angle, and Variation fields of the Character Designer and Paragraph Designer, and the pull-right menu items in the Format menu. Each of the properties specifies an F_StringsT structure, which is defined as: typedef struct { UIntT len; /* Number of strings */ StringT *val; /* Font names */ } F_StringsT; For example, if Courier, Helvetica, and Times are the only font families available in the current session, the fields of the F_StringsT structure specified by FP_FontFamilyNames have the following values: len: 4 val: {" ","Courier","Helvetica","Times"} Properties that specify font families, angles, weights, and variations use the index of the val array. For example, the FO_CharFmt property, FP_FontFamily, specifies the font family for a character format. Given the F_StringsT values shown above, if the font family for a character format is Helvetica, the value of the format’s FP_FontFamily property is 2. Although a specific angle, weight, or variation may be in one of the lists described above, it may not be available for all combinations of font families, angles, weights, and variations. For example, the Bold weight may be available for Times and Helvetica, but not for Zapf Chancery. The FDK provides a convenience function named F_ApiFamilyFonts(), which returns all the permutations of font families, angles, weights, and variations in a FrameMaker product session. For more information, see “F_ApiFamilyFonts()” on page 158 of the FDK Programmer’s Reference. FDK Programmer’s Guide 71 2 Frame Document Architecture .................................. ..... 2 This chapter describes Frame documents and their components and shows how the Frame API represents them. Documents A document is a set of pages with graphic objects and text that the user creates with a FrameMaker product and stores in a file. What the user sees When you create a new document, you can use a template to create it, or you can create a custom document. Any document can be a template. Because the FrameMaker product copies everything from a template to a new document, most users prefer to use templates containing only layout and formatting information. FrameMaker provides ready-made templates for a variety of document types. You can’t create a document completely from scratch—the document must have a certain set of default objects for the FrameMaker product to work correctly. To ensure that all documents have this set of objects, the FrameMaker product always uses a template to create a new document. Even if you choose the Custom document option, the FrameMaker product creates the new document from a default template. This custom document template is specified in the maker.ini file. FDK Programmer’s Guide 73 2 Frame Document Architecture Documents When the user attempts to create a new document from an ASCII text file or a MIF file that doesn’t provide the necessary objects, FrameMaker uses the ASCII template specified in the maker.ini file. When you instruct FrameMaker to save a document, it lists the document’s objects and their properties in a file. By default, FrameMaker writes the information to a Frame binary format file. You can also choose to save a document as a MIF file. How the API represents documents A document actually consists of much more than text and graphic objects. It includes information specifying a variety of other things, such as formatting, user preferences, and the FrameMaker product’s default behavior. The API represents the information in a document with a set of objects. The following table summarizes the information a document can contain and the objects the API uses to represent it. 74 Types of objects that represent it Type of information Function Global document information Specifies the document’s general characteristics, some aspects of the FrameMaker product’s behavior when the document has input focus, and IDs of other objects that constitute the document FO_Doc Pages Organize text and graphic objects in the document FO_BodyPage FO_MasterPage FO_RefPage FO_HiddenPage Graphic objects Describe graphic objects in the document FO_UnanchoredFrame FO_AFrame FO_Group FO_Arc FO_Rectangle FO_Ellipse FO_RoundRect FO_Polyline FO_Polygon FO_Line FO_TextLine FO_TextFrame FO_Inset FO_Math Text columns Contain text FO_SubCol Text frames Contain text FO_TextFrame FDK Programmer’s Guide Documents ... Frame Document Architecture Types of objects that represent it Type of information Function Text flows Specify how text frames in the document are linked FO_Flow Paragraph Catalog formats Specify tags that the user can apply to a paragraph to change its formatting FO_PgfFmt Paragraphs Contain the document’s text and provide formatting information for individual paragraphs FO_Pgf Character Catalog formats Specify tags that the user can apply to a selection of characters to change its formatting FO_CharFmt Condition formats Specify tags that the user can apply to text to indicate that it belongs to a particular variation of the document FO_CondFmt Markers Describe placeholders that contain hidden text FO_Marker Marker types Specifies a named catagory of markers FO_MarkerType Cross-reference formats Specify the wording and typographic style of cross-references FO_XRefFmt Cross-reference instances Describe instances of cross-references in the document FO_XRef Variable formats Specify units of text and systemsupplied information that the user can use multiple times in a document FO_VarFmt Variable instances Describe instances of variables in the document FO_Var Footnotes Describe footnotes FO_Fn Table ruling formats Specify rulings and shadings that the user can apply to individual table cells FO_RulingFmt Table Catalog formats Specify table formats that the user can apply to a table and that provide default numbers of columns and rows for new tables FO_TblFmt Tables Describe instances of tables in the document and specify formatting information, such as alignment, ruling, and shading FO_Tbl FO_Row FO_Cell Colors Specify colors that the user can apply to graphic objects and text FO_Color FDK Programmer’s Guide 75 2 Frame Document Architecture Documents Types of objects that represent it Type of information Function Text insets Describe text that is imported by reference FO_TiApiClient FO_TiFlow FO_TiText FO_TiTextTable Structural element definitions Specify tags that specify the organization of parts of a structured document FO_ElementDef Structural element instances Describe instances of structural elements in a structured document FO_Element Format rules Specify sets of format rule clauses FO_FmtRule Format rule clauses Specify which formats to apply to elements in various contexts FO_FmtRuleClause Format change list Specify format changes applied to an element in a specific context FO_FmtChangeList Rubi composites Describe the oyamoji (base word) and rubi (phonetic spelling) of certain words in Asian text FO_Rubi Combined font definitions Describe pairs of Asian and Western fonts that are treated as a single font family FO_CombinedFontDfn The other sections of this chapter discuss the different types of information in a document. 76 FDK Programmer’s Guide Documents ... Frame Document Architecture How the API organizes the objects that constitute a document The API uses an FO_Doc object to organize the objects that constitute a document. FO_Doc objects have a number of properties that specify the IDs of other objects in the document. Many of these properties specify the ID of the first object in a linked list of objects. For example, FP_FirstPgfFmtInDoc specifies the first FO_PgfFmt object (Paragraph Catalog format) in the list of FO_PgfFmt objects in the document. Each FO_PgfFmt object has a FP_NextPgfFmtInDoc property that specifies the next FO_PgfFmt object in the list. If you want to get all the FO_PgfFmt objects in a document, you get the FO_PgfFmt object specified by FP_FirstPgfFmtInDoc and traverse the links to the other objects. Document object property Object that the property specifies FP_FirstGraphicInDoc The first graphic object (for example, FO_UnanchoredFrame or FO_Line) in the list of graphic objects FP_FirstColorInDoc The first FO_Color in the list of FO_Color objects FP_FirstPgfInDoc The first FO_Pgf in the list of FO_Pgf objects FP_FirstMarkerInDoc The first FO_Marker in the list of FO_Marker objects FP_FirstMarkerTypeInDoc The first FO_MarkerType, in the list of marker types FP_FirstVarInDoc The first FO_Var in the list of FO_Var objects FP_FirstVarFmtInDoc The first FO_VarFmt in the list of FO_VarFmt objects FP_FirstXRefInDoc The first FO_XRef in the list of FO_XRef objects FP_FirstXRefFmtInDoc The first FO_XRefFmt in the list of FO_XRefFmt objects FP_FirstFnInDoc The first FO_Fn in the list of FO_Fn objects FP_FirstTblInDoc The first FO_Tbl in the list of FO_Tbl objects FP_FirstFlowInDoc The first FO_Flow in the list of FO_Flow objects FP_FirstPgfFmtInDoc The first FO_PgfFmt in the list of FO_PgfFmt objects FP_FirstCharFmtInDoc The first FO_CharFmt in the list of FO_CharFmt objects FDK Programmer’s Guide 77 2 Frame Document Architecture Documents Document object property Object that the property specifies FP_FirstCondFmtInDoc The first FO_CondFmt in the list of FO_CondFmt objects FP_FirstTblFmtInDoc The first FO_TblFmt in the list of FO_TblFmt objects FP_FirstRulingFmtInDoc The first FO_RulingFmt in the list of FO_RulingFmt objects FP_FirstSelectedGraphicInDoc The first graphic object in the list of selected graphic objects FP_MainFlowInDoc FO_Flow that represents the main flow FP_FirstElementDefInDoc First structural element definition in the list of element definitions in a FrameMaker document FP_FirstFmtChangeListInDoc First format change list in the list of format change lists in a document FP_FirstBodyPageInDoc or FP_LastBodyPageInDoc The first or last FO_BodyPage in the list of FO_BodyPage objects FP_FirstMasterPageInDoc or FP_LastMasterPageInDoc The first or last FO_MasterPage in the list of FO_MasterPage objects FP_FirstRefPageInDoc or FP_LastRefPageInDoc The first or last FO_RefPage in the list of FO_RefPage objects FP_HiddenPage The hidden page (FO_HiddenPage) FP_SelectedTbl The selected table object FP_FirstTiInDoc The first FO_TiApiClient, FO_TiFlow, FO_TiText, or FO_TiTextTable in the list of text insets FP_FirstRubiInDoc The first FO_Rubi in the list of rubi composites FP_FirstCombinedFontDfnInDoc The first FO_CombinedFontDfn in the list of combined font definitions FP_FirstBodyPageInDoc, FP_FirstMasterPageInDoc, and FP_FirstRefPageInDoc point to the lists of pages in a document. These lists are ordered to reflect the order of the pages. All other lists (including the list of FO_Pgf objects) are not ordered. The terms first and last indicate only the position of the objects in an arbitrarily ordered list. There is no guarantee that a more recently added object will come later in a list, nor is there a guarantee that the order of a list will remain the same as the document is modified. 78 FDK Programmer’s Guide Global document information ... Frame Document Architecture Global document information FrameMaker products allow you to set global document information, characteristics that apply generally to an entire document. What the user sees Global document information includes the following formatting characteristics: Document page properties, which specify the document’s page numbering and pagination style Document condition properties, which specify whether conditional text appears and whether formatting associated with condition tags overrides other formatting Document and table footnote properties, which specify the appearance of the footnotes, such as the footnote numbering and the default paragraph format Change bar properties, which specify the appearance and position of change bars in the document The current text selection or insertion point There is also global document information that affects how the FrameMaker product behaves when the document is active. This type of global information includes: The document dictionary, which lists words that you want the FrameMaker product Spelling Checker to ignore Type-in properties, which specify whether Smart Spaces or Smart Quotes is enabled Equation properties, which specify default symbol sizes and fonts the FrameMaker product uses when you add equations to the document Printing properties, which specify the defaults that appear in the Print dialog box, such as the printer name and the range of pages to print View properties, which specify how FrameMaker displays and scrolls the document in the window Structure properties, which specify whether element boundaries appear and how the Element Catalog appears for a structured document in a session. FrameMaker saves most of the global document information with each document. For example, if you set the zoom for a document to 140 percent and save and exit a document, the next time you open the document, the zoom will be set to 140 percent. FDK Programmer’s Guide 79 2 Frame Document Architecture Global document information How the API represents global document information The Frame API represents global document information with FO_Doc object properties. How the API represents the selection in a document The API uses several properties to specify what is selected in a document: FP_TextSelection specifies a structure that provides the location of the insertion point or the beginning and end of a text selection. FP_FirstSelectedGraphicInDoc specifies the ID of the first graphic in the list of selected graphics in a document. FP_SelectedTbl specifies the ID of a table that contains the insertion point or some selected cells. FP_ElementSelection specifies the range of elements selected if the document is a structured document in a session. The following table summarizes the different types of selection in an unstructured document and how these properties are set to represent them. Selection state How selection properties are set No object is selected. There is no text selection or insertion point. FP_TextSelection specifies an F_TextRangeT structure for which the objId and offset fields of F_TextRangeT.beg and F_TextRangeT.end are set to 0. FP_FirstSelectedGraphicInDoc is 0. FP_SelectedTbl is 0. One or more graphic objects are selected. FP_TextSelection specifies an F_TextRangeT structure for which the objId and offset fields of F_TextRangeT.beg and F_TextRangeT.end are set to 0. FP_FirstSelectedGraphicInDoc specifies the ID of the first selected graphic in the document’s list of selected graphics. FP_SelectedTbl is 0. There is an insertion point or text selection (that isn’t in a table cell, but may include table anchors). 80 FDK Programmer’s Guide FP_TextSelection specifies the location of the text selection or insertion point FP_FirstSelectedGraphicInDoc is 0. FP_SelectedTbl is 0. Global document information Selection state How selection properties are set There is an insertion point or text selection within a single table cell.a FP_TextSelection specifies the location of the text ... Frame Document Architecture selection or insertion point within the cell; for example, the ID of the paragraph containing the insertion point, and the offset within that paragraph. FP_FirstSelectedGraphicInDoc is 0. FP_SelectedTbl specifies the ID of the table containing the cell. If the current selection is in a paragraph, the paragraph´s FP_InTextObj property specifies the ID of the cell that contains the selection. The cell’s FP_CellColNum property specifies the column number, and the cell’s FP_CellRow property specifies the ID of its row. An entire cell or set of cells is selected. FP_TextSelection specifies an F_TextRangeT structure for which the objId and offset fields of F_TextRangeT.beg and F_TextRangeT.end are set to 0. FP_FirstSelectedGraphicInDoc is 0. FP_SelectedTbl specifies the ID of the table containing the cell. The table properties FP_TopRowSelection and FP_BottomRowSelection specify the IDs of the first and last rows containing selected cells. The FP_LeftColNum and FP_RightColNum properties of the table specify the index numbers of the outermost columns in the selection. a. If an entire cell is selected, there is no text selection. How the API represents the element selection in a structured FrameMaker document In a structured FrameMaker document, the selection properties described in the previous section behave as they would in an unstructured document. However, structured FrameMaker documents have an additional selection property, FP_ElementSelection, which specifies the selection in terms of the selected element range or F_ElementRangeT structure. The F_ElementRangeT structure is defined as: typedef struct { F_ElementLocT beg; /* Beginning of the element range. */ F_ElementLocT end; /* End of the element range. */ } F_ElementRangeT; FDK Programmer’s Guide 81 2 Frame Document Architecture Global document information The F_ElementLocT structure specifies a location within an element. It is defined as: typedef struct { F_ObjHandleT parentId; /* Parent element ID. */ F_ObjHandleT childId; /* Child element ID. */ IntT offset; /* Offset within child/parent element. */ } F_ElementLocT; The following table summarizes the different types of selection in a structured FrameMaker document and how the fields of the F_ElementRangeT structure specified by the FP_ElementSelection property are set to represent them. Selection state What the fields of the F_ElementRangeT structure specify No object is selected. There is no text selection or insertion point. beg.parentId: 0 beg.childId: 0 beg.offset: 0 end.parentId: 0 end.childId: 0 end.offset: 0 One or more graphic objects are selected. There is an insertion point or text selection within an element that has no subelements. beg.parentId: ID of the element containing the insertion point or selection beg.childId: ID of the child element immediately following the insertion point or the beginning of the text selection beg.offset: offset of the beginning of the selection or insertion point from the beginning of the element containing it end.parentId: ID of the element containing the insertion point or selection end.childId: ID of the child element immediately following the insertion point or the end of the text selection end.offset: offset of the end of the selection or insertion point from the beginning of the element containing it 82 FDK Programmer’s Guide Global document information Selection state An entire element or range of elements (excluding the highest level element) is selected. ... Frame Document Architecture What the fields of the F_ElementRangeT structure specify beg.parentId: ID of the element containing the first selected element beg.childId: ID of the first selected element beg.offset: 0 end.parentId: ID of the element containing the first selected element end.childId: ID of the sibling element following the last selected element, or 0 if there is no sibling element following the last selected element end.offset: 0 The highest level element is selected. beg.parentId: 0 beg.childId: ID of the highest-level element beg.offset: 0 end.parentId:: 0 end.childId: 0 end.offset: 0 Example Suppose you create the document shown in Figure 2-1. Figure 2-1 A document FDK Programmer’s Guide 83 2 Frame Document Architecture Global document information The API represents the document with an FO_Doc object. The following table lists some of its properties. 84 Property Type Value FP_Name StringT C:\Sales\Training\1Chapter FP_ViewBorders IntT True FP_ViewRulers IntT True FP_ViewPageScrolling IntT FV_SCROLL_VERTICAL FP_Zoom MetricT 1 << 16 FP_IsIconified IntT False FP_ViewTextSymbols IntT True FP_IsOnScreen IntT True FDK Programmer’s Guide Pages ... Frame Document Architecture Pages Frame documents have three kinds of visible pages: body pages, master pages, and reference pages. What the user sees With FrameMaker, the user can change any of the visible pages. Body pages Body pages are what a user normally thinks of as the document’s pages. They organize the text and graphic objects that appear in the body of a document. Master pages Master pages control the layout of body pages. Each body page is associated with one master page, and each master page can be associated with zero or more body pages. A master page provides the following for the body page: The text frame layout, which defines the number, size, and placement of the page’s text frames and the column layout within each text frame The page background, which includes graphic objects and text frames (such as headers and footers) with unnamed flows By default, single-sided documents have at least one master page, which is named Right. Double-sided documents have two master pages, named Right and Left. FrameMaker products allow you to add your own custom master pages to both singlesided and double-sided documents. When a FrameMaker product adds a body page, it uses a left or right master page object as a background. It also copies all the text frames with named flows from that master page to the body page. Once the FrameMaker product copies these text frames to the body page, they are independent of the text frames on the master page from which they were copied. If you change the text frames, it does not affect the master page. A body page’s background appears when you view a body page on the screen or print it. However, the background is part of the master page and not the body page. The FrameMaker product superimposes the body page on the background for displaying and printing. If you go to the master page and change the graphic objects that constitute the background, the changes appear when you view or print the body pages associated with the master page. FDK Programmer’s Guide 85 2 Frame Document Architecture Pages Reference pages Reference pages can contain named graphic frames. Named graphic frames provide decoration, such as a thick line ruling, for paragraphs in the body pages. The Paragraph Designer provides two settings, Frame Above and Frame Below, that allow you to specify the named graphic frames you want to appear above or below a paragraph. Reference pages can also contain special flows that control the appearance of generated documents. For example, a Table of Contents document normally has a flow named TOC on one of its reference pages. How the API represents pages FrameMaker represents body pages, master pages, and reference pages with FO_BodyPage, FO_MasterPage, and FO_RefPage objects, respectively. In addition to these pages, a document can also have a hidden page, which stores hidden conditional text. The user cannot see or directly modify hidden pages. FrameMaker represents each hidden page with an FO_HiddenPage object. Page objects have a number of common properties. These properties specify the following characteristics of a page: The dimensions of the page Its type (body, master, reference, or hidden) Its numbering IDs of the objects that represent its page frame and its sibling pages A page object does not actually contain the text and graphic objects that appear on a page. Instead, it has a property named FP_PageFrame, which specifies the ID of a page frame. A page frame is an invisible unanchored frame whose dimensions match those of the page. (For more information on unanchored frames, see “Graphic objects” on page 90.) The API represents a page frame with an FO_UnanchoredFrame object. This FO_UnanchoredFrame object has properties that specify the IDs of the first and last objects in the linked list of API graphic objects that appear directly on the page. 86 FDK Programmer’s Guide Pages ... Frame Document Architecture Suppose you create a body page with a single text frame as shown in Figure 2-2. Figure 2-2 Single text frame on a body page The API represents the body page in Figure 2-2 with the objects shown in Figure 2-3. The FO_BodyPage object does not have a property that specifies the ID of the FO_TextFrame object. Instead, it has a property, named FP_PageFrame, that specifies the ID of its page frame (an FO_UnanchoredFrame object). The page frame properties, FP_FirstGraphicInFrame and FP_LastGraphicInFrame, both specify the ID of the FO_TextFrame object, since it is the only object that appears directly on the page. FO_BodyPage FP_PageFrame FO_UnanchoredFrame (page frame) FP_FirstGraphicInFrame FO_TextFrame FP_LastGraphicInFrame Figure 2-3 Objects for a body page with a single text frame A FrameMaker product automatically creates and destroys the page frame when it creates and destroys the page. The page frame is not accessible to the user. However, as a developer, you need to use it to get the objects on a page. FDK Programmer’s Guide 87 2 Frame Document Architecture Pages How the API organizes pages The API maintains the different types of visible pages in a document (body pages, master pages, and reference pages) in separate linked lists. FO_Doc objects have the following properties that specify the first and last page object in each list: FP_FirstBodyPageInDoc and FP_LastBodyPageInDoc FP_FirstMasterPageInDoc and FP_LastMasterPageInDoc FP_FirstRefPageInDoc and FP_LastRefPageInDoc Each page object has two properties, FP_PagePrev and FP_PageNext, that specify the IDs of the page objects before and after it in the list. When you delete a page, the API removes the object that represents it and updates the FP_PagePrev and FP_PageNext properties for all the FO_Page objects before and after it. FO_Doc objects also have a property named FP_CurrentPage that specifies the ID of the current page. The current page is the page that appears on the screen. If more than one page appears on the screen, it is the page that appears with a dark border around it. Suppose you create a double-sided document that has three body pages, two master pages (Left and Right), and a single reference page, as shown in Figure 2-4. The current page is the Right master page. 1 Body Pages Right Master Pages 1 Reference Page Figure 2-4 Document with body, master, and reference pages 88 FDK Programmer’s Guide Pages ... Frame Document Architecture FrameMaker products organize the objects as shown in Figure 2-5. FP_FirstBodyPageInDoc FO_BodyPage FP_PagePrev FP_PageNext (Body page 1) FO_BodyPage FP_PagePrev FP_PageNext (Body page 2) FO_BodyPage FP_LastBodyPageInDoc (Body page 3) FO_Doc FP_FirstRefPageInDoc FO_RefPage (Reference page) FP_LastRefPageInDoc FP_CurrentPage FO_MasterPage FP_PagePrev (Right master page) FP_PageNext FP_FirstMasterPageInDoc FO_MasterPage FP_LastMasterPageInDoc (Left master page) Figure 2-5 Example document and page objects FDK Programmer’s Guide 89 2 Frame Document Architecture Graphic objects How the API represents hidden pages If the user chooses to hide conditional text in the document, the FrameMaker product adds a hidden page to the document to store the hidden text. A document can have only one hidden page. FrameMaker products represent the hidden page with an FO_HiddenPage object. The FO_Doc property FP_HiddenPage specifies its ID. The hidden page has only one text flow, named HIDDEN. For more information on how the API represents hidden conditional text, see page 120. How the API represents master pages Both single-sided and double-sided documents have default master pages, named Right and Left. In single-sided documents, the Left master page is not visible to the user. However, you can get and set its properties with the API. Graphic objects A graphic object is anything the user can draw with the Tools palette, or an imported graphic. What the user sees A graphic object can be: 90 An anchored frame, which is a container for graphic objects that is tied to a specific location in text. An unanchored frame, which is a container for graphic objects that is not tied to a specific location in text. A simple geometric shape, which is a line, an arc, a rectangle, a rounded rectangle, an ellipse, a polyline, or a polygon. A group, which is an invisible graphic object that holds together a set of other graphic objects. A text line, which is a single line of text that isn’t in a paragraph or flow (for more information on text lines, see “Text” on page 112). A text frame, which is a container for text in a flow (for more information on text frames, see “Text” on page 112). An imported graphic such as a bitmap or a PostScript file created with another application. An inset or imported graphic. A math equation, which describes a formatted equation. FDK Programmer’s Guide Graphic objects ... Frame Document Architecture You can draw a graphic object directly on a page in a document. A graphic object drawn directly on a page doesn’t move as you edit the text around it. You can also draw a graphic object inside an anchored or unanchored frame. When you move a frame, all the graphic objects inside it move with it. You can nest frames; that is, you can draw a frame within a frame within a frame. Draw order The graphic objects in a frame have a back-to-front order or draw order that specifies the order in which the FrameMaker product draws them. By default, the draw order is the same as the order in which you created the objects. When graphic objects overlap, the ones in front (at the end of the draw order) obscure those in back. You can change the draw order by selecting a graphic object and choosing Front or Back from the Tools palette. Groups You can create a group from one or more graphic objects. This allows you to manipulate them as a single object. When you resize the group, the FrameMaker product automatically resizes the group’s component objects proportionally. Anchored frames You can draw graphic objects in anchored frames, which are tied to text symbols named anchor symbols (). An anchor symbol (and its anchored frame) moves with the text to which it is attached. You can specify a variety of parameters that determine where a frame appears in relation to its anchor symbol. For example, it can be below the line containing the anchor symbol or at the bottom of the text frame containing the anchor symbol. Unlike other graphic objects, the anchored frame cannot be drawn directly on a page or into another frame; it can only be created in text. How the API represents graphic objects The API represents each type of graphic object with a different type of API object. For example, it represents polygons with FO_Polygon objects and text frames with FO_TextFrame objects. All types of API graphic objects1 have properties that provide the following information: The graphic object’s format—that is, characteristics such as its fill pattern and border width The graphic object’s location and angle ................................. 1. This manual uses the term API graphic object to refer to objects (such as FO_Polygon and FO_TextFrame objects) that the API uses to represent the graphic objects (such as polygons and text frames) that appear on a page. FDK Programmer’s Guide 91 2 Frame Document Architecture Graphic objects IDs of the graphic object’s parent, sibling, and child objects Some format properties do not affect some graphic objects. For example, an FO_Rectangle object, like all other objects, has an FP_ArrowType property. This property can have a value, but that value will not affect the appearance of the rectangle that the object represents. All types of API graphic objects also have several properties that are specific to them. For example, FO_Arc objects have a property named FP_Theta that specifies an arc’s theta value. Suppose you create the arrow shown in Figure 2-6. Figure 2-6 Arrow in an unanchored frame The API represents the arrow with an FO_Line object, whose properties include those shown in the following table. Property Type Value FP_FrameParent F_ObjHandleT ID of the frame containing the arrow FP_Pen IntT FV_FILL_BLACK FP_LocX MetricT .25*in FP_LocY MetricT 1.125*in FP_HeadArrow IntT True FP_ArrowType IntT FV_ARROW_HOLLOW How the API organizes graphic objects The API maintains each API graphic object in at least two linked lists: The list of all the API graphic objects in the document For convenience, the API maintains a linked list of all the API graphic objects in a document. The FO_Doc property FP_FirstGraphicInDoc specifies the ID of the first object in the list. API graphic objects have a property named FP_NextGraphicInDoc, which specifies the ID of the next API graphic object in 92 FDK Programmer’s Guide Graphic objects ... Frame Document Architecture the list. If you traverse this list, you will cover every graphic object in a document. The order of the list is completely random. The list of API graphic objects in the graphic object’s parent frame Each API graphic object (except an anchored frame and a page frame) has exactly one parent frame object. The parent frame is the frame that contains the graphic object. The API maintains a linked list of the child objects in each frame. FO_UnanchoredFrame and FO_AFrame objects have FP_FirstGraphicInFrame and FP_LastGraphicInFrame properties, which specify the first and last objects in the list of their child objects. All API graphic objects have FP_PrevGraphicInFrame and FP_NextGraphicInFrame properties, which specify the objects before and after them in the list. The order of the objects in the linked list is the same as the draw order of the graphic objects in a frame. Like the frames they represent, API frame objects can be nested: that is, an FO_UnanchoredFrame or FO_AFrame object can be the parent of another FO_UnanchoredFrame object. Every API graphic object (except an object that represents a page frame or an anchored frame) is a descendant of exactly one API page frame object. Suppose you create a page that contains: An unanchored frame that contains an oval, a rectangle, and a text frame with some text in it A text line that overlaps the unanchored frame, but is drawn directly on the page FrameMaker products organize the objects as shown in Figure 2-7. FDK Programmer’s Guide 93 2 Frame Document Architecture Graphic objects Draw Order FP_FirstGraphicInFrame FO_TextLine FP_LastGraphicInFrame FP_LastGraphicInFrame FP_PrevGraphicInFrame FP_NextGraphicInFrame FO_Rectangle FP_PrevGraphicInFrame (Page frame) FP_NextGraphicInFrame FP_PageFrame FP_PrevGraphicInFrame FO_UnanchoredFrame FO_UnanchoredFrame FP_NextGraphicInFrame FP_FirstGraphicInFrame FO_BodyPage FO_Ellipse FO_TextFrame Figure 2-7 API objects that represent a page and the graphic objects on it How the API represents groups The API represents a grouped set of graphic objects with an FO_Group object. It maintains the objects that constitute a group in a linked list. The FO_Group properties, FP_FirstGraphicInGroup and FP_LastGraphicInGroup, specify the first and last objects in the list. Each graphic object has FP_PrevGraphicInGroup and FP_NextGraphicInGroup properties, which specify the objects before and after it in the list. Grouping graphic objects does not affect their position in the linked list of API graphic objects in a frame. That is, it does not affect their position in the draw order. Group objects themselves have an arbitrary position in the draw order. 94 FDK Programmer’s Guide Flows ... Frame Document Architecture How the API represents selections of graphic objects The FO_Doc property, FP_FirstSelectedGraphicInDoc, specifies the ID of the object that represents the first selected graphic object in a document. If more than one graphic object is selected, the API forms a linked list of the API graphic objects that represent the selected graphic objects. API graphic objects have an FP_NextSelectedGraphicInDoc property that specifies the ID of the next selected graphic object. The order of the list is not necessarily the same as the order in which the graphic objects were selected. Although FP_FirstSelectedGraphicInDoc is a document property, you can only select graphic objects that are within the same frame. Flows FrameMaker products use flows to connect text frames in a document. What the user sees A flow tells the FrameMaker product where to put additional text when a text frame is full. In a simple document, there may be only one flow associated with the body pages. In complex documents such as newsletters, you may create multiple flows that have connected text frames on different pages. VIEWS 1 2 3 Figure 2-8 Multiflow document Flows have an Autoconnect setting that controls whether the FrameMaker product generates a new page when you fill the last text frame of a flow. If Autoconnect is on, the FrameMaker product creates a new page and connects a text frame on the new page with the text frame on the previous page. FDK Programmer’s Guide 95 2 Frame Document Architecture Flows Main flows Each document has a main flow. Normally, the FrameMaker product treats the main flow like any named flow in the document. However, there are cases when the FrameMaker product treats the main flow specially: When you generate a table of contents or an index, the FrameMaker product puts the generated text into the main flow of the generated document. When you run Compare Documents, the FrameMaker product puts the Summary text into the main flow. Usually the main flow is the default flow for the current language. For example, if the current language is English, the main flow is A. If there are several Autoconnect flows in the document with the default flow tag, the main flow is the one in the backmost text frame on the frontmost body page. How the API represents flows The API represents a flow with an FO_Flow object, whose properties provide the following information: The flow’s format characteristics, such as the feathering and whether Autoconnect is enabled The IDs of the first and last FO_TextFrame objects in the flow The ID of the next FO_Flow object in the document How the API organizes flows The API maintains a document’s FO_Flow objects in a linked list. The FO_Doc property, FP_FirstFlowInDoc, specifies the ID of the first FO_Flow object in the list. FO_Flow objects have a property named FP_NextFlowInDoc, which specifies the next FO_Flow object in the list. The order of the list is random; it does not correspond to the order in which the flows appear in the document. The API also maintains the objects that represent a flow’s text frames in a linked list. The FO_Flow properties, FP_FirstTextFrameInFlow and FP_LastTextFrameInFlow, specify the first and last FO_TextFrame objects in the list. Each FO_TextFrame object has an FP_PrevTextFrameInFlow property and a FP_NextTextFrameInFlow property, which specify the previous and next FO_TextFrame objects in the list. For more information on how flows, text frames, and paragraphs are organized, see “How the API organizes paragraphs” on page 104. 96 FDK Programmer’s Guide ... Frame Document Architecture Flows Suppose you create the document shown in Figure 2-9. The document has two flows: a main flow, named A, and a second flow that is unnamed. The A flow connects a twocolumn text frame on the first page and a two-column text frame on the second page. The unnamed flow appears only on the first page and has only one text frame. Flow A A A A A Unnamed flow 1 2 Figure 2-9 Document with a named and an unnamed flow Figure 2-10 shows how the API organizes the objects that represent the flows and text frames shown in Figure 2-9. FP_NextFlowInDoc (Unnamed flow) FO_Doc FP_FirstTextFrameInFlow FO_TextFrame FP_LastTextFrameInFlow FP_FirstTextFrameInFlow FO_Flow FP_MainFlowInDoc FO_TextFrame (Flow A) FP_LastTextFrameInFlow FP_PrevTextFrameInFlow FO_Flow FP_NextTextFrameInFlow FP_FirstFlowInDoc FO_TextFrame Figure 2-10 Objects that represent a document with two flows FDK Programmer’s Guide 97 2 Frame Document Architecture Flows Although the FP_FirstFlowInDoc property specifies the FO_Flow object for the unnamed flow in Figure 2-10, it could also specify the FO_Flow object that represents Flow A. The determination of which flow is first in the list is completely random. The API uses FO_SubCol objects to represent the column formatting of text as follows: Contiguous paragraphs in each column of a text frame are within a single FO_SubCol object. Contiguous paragraphs within sidehead area are within a single FO_SubCol. Each contiguous series of paragraphs that spans columns and/or sideheads is represented by a single FO_SubCol object. Following paragraphs that do not span columns and sideheads begin a new group of FO_SubCol objects. For example, Figure 14.11 shows a page that has seven FO_SubCol objects.two groups of three, plus one for the heading that spans all columns.. The FO_TextFrame properties, FP_FirstSubCol and FP_LastSubCol, specify the first and last FO_SubCol objects in a specific text frame. Each FO_SubCol object has an FP_PrevSubCol property and a FP_NextSubCol property, which specify the previous and next FO_SubCol objects in the flow. Each FO_SubCol object also has a FP_ParentTextFrame property, which specifies the text frame it is in. If a text frame has only one column, its FP_FirstSubCol and FP_LastSubCol properties both specify the ID of the FO_SubCol object that represents it. Figure 2-11 shows how the API organizes the objects that represent the two-column text frame on the first page of the document in Figure 2-9. FP_FirstSubCol x tF r FO_TextFrame FP_ Pa re n tT e x tF r ame FP_LastSubCol FO_SubCol Figure 2-11 Objects that represent a text frame with two columns 98 FDK Programmer’s Guide FP_PrevSubCol n tT e FP_NextSubCol Pa re FP_ FO_SubCol ame Flows ... Frame Document Architecture In structured FrameMaker, flows can be structured. If a flow is structured, the FO_Flow object that represents it has a FP_HighestLevelElement property that specifies the ID of the root element. For information on how the API organizes paragraphs and text in flows, text frames, and columns, see “How the API organizes paragraphs” on page 104. FDK Programmer’s Guide 99 2 Frame Document Architecture Paragraph Catalog formats Paragraph Catalog formats Each document has a Paragraph Catalog containing one or more Paragraph Catalog formats. What the user sees Each Paragraph Catalog format specifies aspects of a paragraph’s appearance, such as its indents, line spacing, and default font. Each format has a name or tag, which usually corresponds to a type of paragraph, such as title, body, or heading. To make a paragraph’s appearance conform to a format, you apply the format to the paragraph. You can apply the same format to multiple paragraphs to ensure consistency in your document. You can add formats to the Paragraph Catalog or modify or delete formats that are already in it. How the API represents Paragraph Catalog formats FrameMaker represents each Paragraph Catalog format with an FO_PgfFmt object, whose properties provide the following information: The name of the paragraph format Formatting information The ID of the next FO_PgfFmt object in the document Suppose you create the paragraph format described in the Paragraph Designer in Figure 2-12. Figure 2-12 Paragraph Designer 100 FDK Programmer’s Guide Paragraphs ... Frame Document Architecture The API represents this paragraph format with an FO_PgfFmt object. The following table lists some of its properties. Property Type Value FP_Name StringT Step FP_AutoNumString StringT .\t FP_AutoNumChar StringT "" FP_PgfIsAutoNum IntT True FP_NextPgfFmtInDoc F_ObjHandleT ID of the next Paragraph Catalog format in the document’s list of Paragraph Catalog formats The FP_AutoNumChar property specifies the character format to be applied to the string specified by FP_AutoNumString. When the default font is used, FP_AutoNumChar is set to a null string (""). How the API organizes Paragraph Catalog formats The API organizes the FO_PgfFmt objects in a document in a linked list. The FO_Doc property, FP_FirstPgfFmtInDoc, specifies the first FO_PgfFmt object in the list. FO_PgfFmt objects have an FP_NextPgfFmtInDoc property, which specifies the ID of the next FO_PgfFmt object in the list. The order of the list does not correspond with the order in which the formats appear in the Paragraph Catalog. Paragraphs A paragraph can be a body of text, a title, or an item in a list. What the user sees You can type a paragraph in a text frame, a footnote, or a table cell. Every paragraph has a paragraph format consisting of: A tag, which is the name of a format stored in the Paragraph Catalog Formatting information, which is the same information that a Paragraph Catalog format provides, such as indents and leading Every paragraph starts with a tag and formatting information that matches a Paragraph Catalog format. There are several ways you can change a paragraph’s format: FDK Programmer’s Guide 101 2 Frame Document Architecture Paragraphs Apply a different Paragraph Catalog format to the paragraph. When you do this, the FrameMaker product changes the paragraph’s formatting information to match that of the Paragraph Catalog format. This process is known as tagging. Change the paragraph’s formatting information. This does not affect the Paragraph Catalog format that you tagged the paragraph with. For example, if you tag a paragraph with a tag named indentbody that specifies a 1-inch indent and subsequently change the paragraph’s indent to 2 inches, the indentbody format and other paragraphs tagged as indentbody still have a 1-inch indent. This change is a format override, and it applies only to that paragraph instance. Change the Paragraph Catalog format’s formatting information. FrameMaker products allow you to update all the paragraphs that are tagged with the format you changed. You can choose whether you want to retain format overrides when FrameMaker updates all paragraphs in the document with the same tag. How the API represents paragraphs FrameMaker products represent each paragraph with an FO_Pgf object, whose properties provide the following information: The ID of the text frame and text column containing the paragraph The paragraph’s formatting information (the same set of properties that a Paragraph Catalog format provides) The paragraph’s tag The IDs of sibling FO_Pgf objects A flag indicating whether the paragraph has been successfully spell-checked since the last change was made to it Each paragraph object also contains an F_TextItemsT structure, which represents the text in the paragraph. For more information about text and the F_TextItemsT structure, see “How the API represents text” on page 112. 102 FDK Programmer’s Guide Paragraphs ... Frame Document Architecture Suppose you create the paragraph shown in Figure 2-13. Figure 2-13 A paragraph The API represents the paragraph with an FO_Pgf object. The following table lists some of its properties. Property Type Value FP_Name StringT Step FP_AutoNumString StringT .\t FP_PgfIsAutoNum IntT True FP_PgfNumber StringT 1. FA_LeftIndent MetricT 0 FP_InTextFrame F_ObjHandleT ID of the text frame the paragraph starts in FP_InTextObj F_ObjHandleT ID of the subcolumn (FO_SubCol object) the paragraph starts in A paragraph’s FP_InTextObj property does not always specify the ID of a subcolumn. If the paragraph appears in a table cell, it specifies the ID of the FO_Cell object representing the cell. If the paragraph appears in a footnote, FP_InTextObj specifies the ID of the FO_Fn object representing the footnote. How to apply formats to paragraphs To apply a format from the paragraph format catalog to a specific paragraph object, first get the ID of the FO_Pgf object in question. Then loop through the document looking for the FO_PgfFmt object with a name that matches the tag you want to apply to the paragraph. Then use F_ApiGetProps() to get the list of properties from the FO_PgfFmt object, and use F_ApiSetProps() to set the property list to the FO_Pgf in question. FDK Programmer’s Guide 103 2 Frame Document Architecture Paragraphs How the API organizes paragraphs The API maintains FO_Pgf objects in two linked lists: The list of all FO_Pgf objects in a document The list of FO_Pgf objects in a flow The list of paragraphs in a document The FO_Doc property, FP_FirstPgfInDoc, specifies the first FO_Pgf object in the list of FO_Pgf objects in a document. Each FO_Pgf object has an FP_NextPgfInDoc property, which specifies the next FO_Pgf object in the list. The order of the list of FO_Pgf objects in a document does not necessarily correspond to the actual order of the paragraphs in the document. The list of paragraphs in a flow FO_Flow objects do not have a property that specifies the first FO_Pgf object in a flow. To find the first FO_Pgf object in the flow, you must find the first FO_TextFrame object in the flow. Then you must get the FO_Pgf object specified by the FO_TextFrame object’s FP_FirstPgf property. In some cases, the first text frame in the flow may not contain any paragraphs. You must traverse subsequent text frames and check them to see if they contain any paragraphs. Each FO_Pgf object has FP_PrevPgfInFlow and FP_NextPgfInFlow properties, which specify the IDs of the FO_Pgf objects before and after it in the flow. To get the paragraphs in a flow in order, you traverse these properties. It is possible for a paragraph to begin in one text frame and end in another. When this happens, the ID of the FO_Pgf is specified by the FP_LastPgf property of the text frame in which it begins and the FP_FirstPgf property of the text frame in which it ends. Suppose you create two text frames and connect them with a flow. The first text frame has two paragraphs in it; the second paragraph continues into the next text frame as shown in Figure 2-14. Figure 2-14 Flow with two text frames 104 FDK Programmer’s Guide Paragraphs ... Frame Document Architecture The API organizes the objects that represent the flow, text frames, and paragraphs as shown in Figure 2-15. FO_Pgf FP_FirstPgf (Paragraph 1) FP_FirstPgf FO_TextFrame FP_LastTextFrameInFlow FO_Pgf FP_LastPgf (Paragraph 2) F_TextItemsT FP_NextPgfInFlow FO_Flow FP_PrevTextFrameInFlow FP_NextTextFrameInFlow (Left text frame) FP_PrevPgfInFlow FO_TextFrame (Right text frame) FP_PrevPgfInFlow FP_FirstTextFrameInFlow FP_NextPgfInFlow F_TextItemsT FO_Pgf (Paragraph 3) FP_LastPgf F_TextItemsT Figure 2-15 Objects that represent a flow with text frames and paragraphs Like text frames, subcolumns (FO_SubCol objects) have FP_FirstPgf and FP_LastPgf properties, which specify the first and last paragraphs in them. If a paragraph begins in one text column and ends in another, the paragraph’s ID is specified by the FP_LastPgf property of the subcolumn in which it begins and the FP_FirstPgf property of the subcolumn in which it ends. FDK Programmer’s Guide 105 2 Frame Document Architecture Character Catalog formats Character Catalog formats Each document has a Character Catalog containing one or more character formats. What the user sees Each character format has a name (or tag), which usually corresponds to a type of text, such as Emphasis, Usertype, or Booktitle. It also contains information about how text should look, such as its font family, weight, and angle. To make the appearance of a set of characters conform to a Character Catalog format, you apply the format to the set of characters. When you apply a character format to a set of characters, it overrides the default font setting of the paragraph format. If you reapply a Paragraph Catalog format to the paragraph, it does not affect the format of the characters that you previously tagged with the character format. FrameMaker products allow you to create character formats that override only some properties of the text to which they are applied. To leave one of the current text properties intact, you set the corresponding character format property to As Is. The Character Designer indicates the As Is state with the words As Is or a grayed (or stippled) checkbox. You can add character formats to the Character Catalog or modify or delete formats that are already in it. How the API represents Character Catalog formats FrameMaker products represent each Character Catalog format with an FO_CharFmt object, whose properties provide the following information: 106 The name of the character format Character formatting information, such as the font family, angle, and weight Whether the character format’s formatting overrides the default formatting of the text that the format is applied to The ID of the next FO_CharFmt object in the document FDK Programmer’s Guide Character Catalog formats ... Frame Document Architecture How the API represents fonts FO_Session objects have properties (such as FP_FontFamilyNames) that provide arrays of the names of the font families, variations, angles, and weights available in the current session. These lists are referenced by F_StringsT structures. F_StringsT is defined as: typedef struct { UIntT len; /* Number of strings */ StringT *val; /* Array of strings */ } F_StringsT; For example, if Bold and Regular are the only font weights available in the current session, the fields of the F_StringsT structure specified by the FO_Session property, FP_FontWeightNames, have the following values: len: 3 val: {" ","Regular","Bold"} To set a character format’s weight to Bold in this session, you set its FP_FontWeight property to 2. For more information on session font properties, see “How the API indicates which fonts are available in a session” on page 70. You can also use the following properties to specify a font: FP_FontPlatformName specifies a font name that uniquely identifies the font on the Windows platform. FP_FontPostScriptName specifies the name given to a font when it is sent to a PostScript printer (specifically, the name that is passed to the PostScript FindFont operator before any font coordination operations). The PostScript name is unique for all PostScript fonts, but may not be available for fonts that have no PostScript version. For the same Asian font, the PostScript name can be different on different platforms. This is because they might have slightly different extensions to the character mappings. For example, Ryumin-Light on the Macintosh is Ryumin-Light83pv-RKSJ-H, while it is Ryumin-Light-90ms-RKSJ-H on a Windows system. Since these are the same fonts, FrameMaker products will treat these as the same PostScript name. To do so, FrameMaker products ignore the following keywords in PostScript names: 83pv 90pv 90ms Ext FDK Programmer’s Guide 107 2 Frame Document Architecture Character Catalog formats Add NWP The FP_FontPlatformName property specifies a platform-specific ASCII string that uniquely identifies a font for a particular platform. The string consists of several fields separated by periods. On Windows, the string you specify for FP_FontPlatformName has the following syntax: W.FaceName.ItalicFlag.Weight.Variation This field Represents W Platform designator FaceName Windows face name (for more information, see your Windows documentation) ItalicFlag Whether font is italic; you can use one of the following flags: I (Italic) R (Regular) Weight Weight classification, for example 400 (Regular) or 700 (Bold) The following strings are valid representations of the Windows font, Helvetica Narrow Bold Oblique: W.Helvetica-Narrow.I.700 W.Helvetica.I.700.Narrow When reading in a document, a FrameMaker product determines a font name by checking font properties in the following order: FP_FontPlatformName Combination of FP_FontFamily, FP_FontVariation, FP_FontWeight, and FP_FontAngle FP_FontPostScriptName Your clients do not need to use all three methods to change fonts. You should always specify the PostScript name, if it is available. How the API represents As Is settings FO_CharFmt objects use two properties to represent a font characteristic: one to represent the characteristic’s As Is state and one to represent the characteristic itself. For example, FP_UseFontWeight specifies whether the character format’s font weight overrides the default font weight of the text that the format is applied to. 108 FDK Programmer’s Guide Character Catalog formats ... Frame Document Architecture FP_FontWeight specifies the character format’s font weight. If FP_UseFontWeight is True, the font weight specified by FP_FontWeight overrides the default font weight for the text. If FP_UseFontWeight is False (As Is), FP_FontWeight does not affect the text’s font weight. If an FP_UseCharacteristic property is False, the character format’s property list includes only the FP_UseCharacteristic property. It doesn’t include the FP_Characteristic property for the characteristic (since this property is not used). Suppose you create the character format specified in the Character Designer in Figure 2-16. Figure 2-16 Character Designer The API represents the character format with an FO_CharFmt object. The following table lists some of its properties. Property Type Value FP_CharTag StringT booktitle FP_FontAngle IntT Index of Italic font angle FP_UseFontAngle IntT True FP_UseFontFamily IntT False FP_UseFontVariation IntT False FP_UseFontWeight IntT False FP_UseUnderline IntT False FP_FontSize MetricT 36*pts FP_UseFontSize IntT True FDK Programmer’s Guide 109 2 Frame Document Architecture Condition Formats This character format overrides the default font angle setting and the size of the text to which it is applied. It does not override any of the text’s other default characteristics. How the API organizes Character Catalog formats The API organizes the formats in a document’s Character Catalog in a linked list. FO_Doc objects have an FP_FirstCharFmtInDoc property that specifies the first FO_CharFmt object in the list. FO_CharFmt objects have an FP_NextCharFmtInDoc property, which specifies the ID of the next FO_CharFmt object in the list. The order of the list does not correspond to the order in which the formats appear in the Character Catalog. Condition Formats FrameMaker products provide condition formats that allow the user to selectively show or hide text in a document. What the user sees To selectively show and hide text, you create a condition format (or tag) and apply it to selections of text. For example, you can create a condition tag named Comment and apply it to all the comments you add to a document. You can then instruct the FrameMaker product to hide all the text with the Comment tag when you print a final draft of the document. A document can have multiple condition tags. FrameMaker products allow you to specify a format override, or a special style and color for a condition. For example, you can make all text tagged with the Comment condition underlined and red. How the API represents condition formats The API represents each condition format with an FO_CondFmt object, whose properties provide the following information: The condition name Whether text tagged with the condition is currently visible The format overrides The ID of the next condition format in the document The API represents the condition setting of a location in text as a text property. For more information on text properties, see “How the API represents text” on page 112. 110 FDK Programmer’s Guide Condition Formats ... Frame Document Architecture If you choose to hide a condition tag, the FrameMaker product moves text with that tag to a hidden page and replaces it with markers. For more information on hidden conditional text, see “How the API represents hidden conditional text” on page 120. Suppose you create the condition tag specified in the Edit Condition Tag dialog box shown in Figure 2-17. Figure 2-17 Edit Condition Tag dialog box The API represents the condition with an FO_CondFmt object. The following table lists some of its properties. Property Type Value FP_Name StringT Comment FP_NextCondFmtInDoc F_ObjHandleT ID of next condition in list of document’s conditions FP_CondFmtIsShown IntT True FP_SepOverride F_ObjHandleT ID of the FO_Color object that represents red color FP_StyleOverride IntT FV_CN_SINGLE_UNDERLINE FP_UseSepOverride IntT True How the API organizes condition formats The API organizes a document’s FO_CondFmt objects in a linked list. The FO_Doc property FP_FirstCondFmtInDoc specifies the first FO_CondFmt object in the list. FO_CondFmt objects have a property named FP_NextCondFmtInDoc, which specifies the ID of the next FO_CondFmt object in the list. The order of the list does not correspond to the order in which the formats appear in the Conditional Text window. FDK Programmer’s Guide 111 2 Frame Document Architecture Text Text The user can type text into a text line or a paragraph in a text frame, table cell, or footnote. What the user sees FrameMaker products allow you to insert things, such as anchored frames, footnotes, tables, and cross-references into text. The point at which you insert these things is called an anchor. FrameMaker products represent an anchor with an anchor symbol ) on the screen. This symbol is not visible if the Text Symbols view option is turned off. The anchor moves with the text to which it is attached. All text has a set of properties that specify the following information about it: A tag, or the name of a character format stored in the Character Catalog Formatting information (the same information that a Character Catalog format provides, such as the font family and size) A set of conditional text formats that apply to it These properties are called text properties. Just as you can override a Paragraph Catalog tag by changing an individual paragraph’s format, you can also override a Character Catalog tag by changing the properties of a selection of text. You can also apply one or more conditions to a selection of text. This allows you to hide or display the text for particular versions of a document. How the API represents text The API represents the text in each paragraph or graphic text line with an F_TextItemsT structure, which is defined as: typedef struct { UIntT len; /* The number of text items */ F_TextItemT *val; /* Array of text items */ } F_TextItemsT; 112 FDK Programmer’s Guide Text ... Frame Document Architecture The API represents an individual text item with an F_TextItemT structure, which is defined as: typedef struct { IntT offset; /* Characters from the beginning */ IntT dataType; /* The type of text item, e.g. FTI_String */ union { StringT sdata; /* String if type is FTI_String */ IntT idata; /* An ID if the item specifies an object */ } u; } F_TextItemT; The offset value specifies the distance between the start of the text item and the beginning of the text line or paragraph. This distance is measured in the number of characters (both regular characters and anchor symbols). Each of the following constitutes a separate text item: A string of characters with common text properties A text item can contain a string that is as long as a line of text. However, the API uses a separate text item for each section of the text that has different text properties. If a single property (such as the font weight, font angle, or condition format) is different, the API starts a new text item. So a single line of text may require several text items to represent it. The beginning or end of a line, paragraph, flow, column, page, or structural element The API uses text items to indicate the beginning or end of the various entities that organize text. Most of these text items specify the ID of an object. Text items that indicate the end of a line specify whether the line end is a regular, hyphenated, or hard line end. An anchor for a table, footnote, marker, cross-reference, variable, or anchored frame The API represents tables, footnotes, markers, cross-references, variables, and anchored frames with separate objects. It uses a text item to represent the anchor for each of these entities. The text item specifies the ID of the object. For example, the API represents a table with an FO_Tbl object. It uses a table anchor (FTI_TblAnchor) text item to indicate where the table occurs in the text. A text properties change This type of text item identifies the point in text at which the text properties change. It specifies flags that indicate which text properties differ from the properties of the text immediately preceding the text item. FDK Programmer’s Guide 113 2 Frame Document Architecture Text The following table lists the values the F_TextItemT.dataType field can have and the types of data the corresponding text item provides. Text item type (dataType) What the text item represents Text item data FTI_TextObjId The object to which the offsets of all the text items are relative ID of an FO_Pgf, FO_Cell, FO_TextLine, FO_TiApiClient, FO_TiFlow, FO_TiText, or FO_TiTextTable FTI_String A string of characters with the same condition and character format A character string FTI_LineBegin The beginning of a line Nothing FTI_LineEnd The end of a line and the line end type If the line end is a normal line end, 0; if it is a forced line end, the FTI_HardLineEnd flag is set; if it is a hyphen line end, the FTI_HyphenLineEnd flag is set FTI_PgfBegin The beginning of a paragraph ID of an FO_Pgf FTI_PgfEnd The end of a paragraph ID of an FO_Pgf FTI_FlowBegin The beginning of a flow ID of an FO_Flow FTI_FlowEnd The end of a flow ID of an FO_Flow FTI_PageBegin The beginning of a page ID of an FO_BodyPage, FO_HiddenPage, FO_MasterPage, FO_RefPage FTI_PageEnd The end of a page ID of an FO_BodyPage, FO_HiddenPage, FO_MasterPage, FO_RefPage FTI_TextFrameBegin The beginning of a text frame ID of an FO_TextFrame FTI_TextFrameEnd The end of a text frame ID of an FO_TextFrame 114 FDK Programmer’s Guide Text ... Frame Document Architecture Text item type (dataType) What the text item represents Text item data FTI_SubColBegin The beginning of a column ID of an FO_SubCol FTI_SubColEnd The end of a column ID of an FO_SubCol FTI_FrameAnchor An anchored frame ID of an FO_AFrame FTI_FnAnchor A footnote ID of an FO_Fn FTI_TblAnchor A table ID of an FO_Tbl FTI_MarkerAnchor A marker ID of an FO_Marker FTI_XRefBegin The beginning of a crossreference instance ID of an FO_XRef FTI_XRefEnd The end of a cross-reference instance ID of an FO_XRef FTI_VarBegin The beginning of a variable instance ID of an FO_Var FTI_VarEnd The end of a variable instance ID of an FO_Var FTI_TextInsetBegin The beginning of a text inset ID of an FO_TiApiClient, FO_TiFlow, FO_TiText, or FO_TiTextTable FTI_TextInsetEnd The end of a text inset ID of an FO_TiApiClient, FO_TiFlow, FO_TiText, or FO_TiTextTable FTI_ElementBegin The beginning of a container element ID of an FO_Element FTI_ElementEnd The end of a container element ID of an FO_Element FTI_ElemPrefixBegin The beginning of an element’s prefix ID of an FO_Element FTI_ElemPrefixEnd The end of an element’s prefix ID of an FO_Element FTI_ElemSuffixBegin The beginning of an element’s suffix ID of an FO_Element FTI_ElemSuffixEnd The end of an element’s suffix ID of an FO_Element FTI_CharPropsChange A change in the text properties Flags indicating which properties have changed (see the table below) FDK Programmer’s Guide 115 2 Frame Document Architecture Text Text item type (dataType) What the text item represents Text item data FTI_RubiComposite Begin The beginning of a rubi composite (and the beginning of oyamoji text). ID of an FO_Rubi FTI_RubiComposite End The end of a rubi composite. ID of an FO_Rubi FTI_RubiTextBegin The beginning of rubi text (and the end of oyamoji text). ID of an FO_Rubi FTI_RubiTextEnd The end of rubi text. ID of an FO_Rubi The following table lists the bit flags that a client can bitwise AND with the idata field of an FTI_CharPropsChange text item and the types of text property changes each flag indicates. For example, to determine if the font family changed, bitwise AND the FTF_FAMILY flag with the idata field. 116 Flag Meaning FTF_FAMILY The font family has changed. FTF_VARIATION The font variation has changed. FTF_WEIGHT The font weight has changed. FTF_ANGLE The font angle has changed. FTF_UNDERLINING The underlining has changed. FTF_STRIKETHROUGH The strikethrough characteristic has changed. FTF_OVERLINE The overline characteristic has changed. FTF_CHANGEBAR The change bars have changed. FTF_OUTLINE The outline characteristic has changed. FTF_SHADOW The shadow characteristic has changed. FTF_PAIRKERN The pair kerning has changed. FTF_SIZE The font size has changed. FTF_KERNX The kern-x characteristic has changed. FTF_KERNY The kern-y characteristic has changed. FTF_SPREAD The font spread has changed. FTF_COLOR The color has changed. FTF_CHARTAG The Character Catalog format has changed. FDK Programmer’s Guide Text ... Frame Document Architecture Flag Meaning FTF_CAPITALIZATION The capitalization has changed. FTF_POSITION The character position has changed. FTF_CONDITIONTAG The condition tag has changed. FTF_STRETCH Font stretch value has changed FTF_LANGUAGE Character language has changed FTF_TSUME Tsume setting has changed FTF_IIF An internal flag having to do with asian text. input. If there is a non-zero value for this flag, a front end processor is controlling that text; you should not modify the associated text item. FTF_ENCODING The text encoding has changed. FTF_ALL OR of all the flags listed above. Figure 2-18 shows a paragraph and the text items the API uses to represent the paragraph’s text. offset: 0 offset: 0 offset: 0 offset: 5 offset: 5 offset: 17 dataType: FTI_PgfBegin dataType: FTI_LineBegin dataType: FTI_String dataType: FTI_CharPropsChange dataType: FTI_String dataType: dataType: FTI_Marker-Anchor FTI_LineEnd sdata: "This " idata: ID of FO_Pgf idata: FTF_WEIGHT sdata: "is a marker." idata: ID of FO_Marker offset: 18 idata: 0 offset: 18 dataType: FTI_PgfEnd idata: ID of FO_Pgf Figure 2-18 Paragraph text and the text items that represent it There are several important things to note about the text items shown in Figure 2-18: Because the string "This " and the string "is a marker." have different font weights, there are separate text items for them. The FTI_CharPropsChange text item indicates that the text properties have changed; the FTF_WEIGHT flag that it specifies indicates that the font weight has changed. FDK Programmer’s Guide 117 2 Frame Document Architecture Text The marker anchor is counted in the offset. How the API represents special characters The API uses the FrameMaker product character set. Some characters are either reserved by the C language or belong to the higher ASCII range. To represent these characters in a string, use octal (\) or hexadecimal (\x) sequences. Character Hexadecimal representation Octal representation > \x3e \76 " (straight double quotation mark) \x22 \42 “ (left curved quotation mark) \xd2 \322 ” (right curved quotation mark) \xd3 \323 For a complete list of the characters in the FrameMaker product character set and the corresponding hexadecimal codes, see your Frame product user’s manual. If you are using ANSI C, you can use these hexadecimal codes or their octal equivalents. If you are not using ANSI C, you must use octal (\) sequences. Suppose you want to represent the following text in the API: This is an em dash — If you are not using ANSI C, you must specify the string This is an em dash \321. If you are using ANSI C, you can also specify the string This is an em dash \xd1. How the API represents text properties The FTI_CharPropsChange text item only indicates that particular text properties have changed. It does not indicate what they have changed to. The API provides a function named F_ApiGetTextProps(), which allows you to retrieve the text properties for individual characters in text. You cannot retrieve the text properties for a range or selection of text, because they may be different for individual characters within the selection. You can, however, set the text properties for a range of text. For examples of how to get and set text properties, see “Getting and setting text formatting” on page 334. 118 FDK Programmer’s Guide Text ... Frame Document Architecture Suppose you retrieve the text properties at the insertion point shown in Figure 2-19. Figure 2-19 Text containing insertion point FDK Programmer’s Guide 119 2 Frame Document Architecture Text The following are some of the properties of the text at the insertion point. Property Type Value FP_CharTag StringT booktitle FP_FontFamily IntT Index of Times font (for more information on font name indexes, see “How the API indicates which fonts are available in a session” on page 70) FP_FontWeight IntT Index of Bold font weight FP_FontAngle IntT Index of Regular font angle FP_InCond F_IntsT NULL If the conditions Comment and MyComment are applied to the text location, the FP_InCond property specifies an F_IntsT structure with the following values: len: 2 val: { Comment_ID, MyComment_ID } where Comment_ID and MyComment_ID are the IDs of the FO_CondFmt objects that represent the Comment and MyComment condition formats. How the API represents hidden conditional text The user can choose to hide all the text with a specified condition format. If a document has hidden conditional text, the FrameMaker product automatically adds a hidden page to it. This hidden page is completely invisible to the user. It has a single flow, named HIDDEN. When the user chooses to hide text with a condition format, the FrameMaker product removes each block of text with that condition format and inserts a Conditional Text marker (type 10) in its place. This marker text consists of a plus sign (+) and a five-digit integer. The FrameMaker product places the blocks of hidden text in the HIDDEN text flow on the hidden page. The text begins with a Conditional Text marker containing a minus sign (?) and the integer. It ends with another Conditional Text marker containing an equal sign (=) and the integer. If the hidden conditional text doesn’t span paragraphs, it appears in one paragraph. If the hidden conditional text spans paragraphs, each paragraph of conditional text constitutes a separate paragraph in the HIDDEN flow. 120 FDK Programmer’s Guide Text ... Frame Document Architecture Suppose you have a body page with some conditional text and some unconditional text. The condition tag’s format overrides specify that the text appears underlined, as shown in Figure 2-20. Figure 2-20 Body page with conditional and unconditional text If you hide the text, the body page appears as shown in Figure 2-21. Marker text: +84974 Marker text: +95675 Marker text: +93024 Figure 2-21 Body page with the conditional text hidden If you could see the hidden page and the text in the HIDDEN flow, it would appear as shown in Figure 2-22. The numbers in the markers that represent the hidden conditional text on the body page correspond to the numbers in the markers on the hidden page. Marker text: -84974 Marker text: -95675 Marker text: -93024 Marker text: =84974 Marker text: =95675 Marker text: =93024 Figure 2-22 Hidden conditional text on the hidden page FDK Programmer’s Guide 121 2 Frame Document Architecture Markers Markers Markers are anchored objects that store data and associate that data with specific locations in the text. Various features in FrameMaker may refer to a marker, or you can use markers to store data for your FDK clients. What the user sees You can use markers to mark entries for a table of contents or an index. A marker’s position in text is indicated by a marker symbol. A marker contains text, which appears in the Marker window when you select the marker and choose Marker from the Special menu. Any number of marker types can be defined for a document; 11 of them are predefined by the FrameMaker product as a standard list of marker types, and the others are defined by the user. The list of defined marker types is saved with the document. How the API represents markers The API represents each marker with the following: An FTI_MarkerAnchor text item that specifies the ID of an FO_Marker object An FO_Marker object FO_Marker properties provide the following information: The marker type; the Id of an FO_MarkerType object The text the marker contains The ID of the next FO_Marker object in the document The location of the marker in text The element ID of the marker, if it is a structured marker in a structured document If included, the number of a marker type in versions earlier than 5.5; when opening the document in FrameMaker 5.5, this maps the old numbered marker type to the new named bmarker type FO_MarkerType properties provide the following information: 122 The ID of the next FO_MarkerType object in the document The name of the marker type, as it appears in the user interface The internal name of the marker type (usually the same as the name that appears in the user interface) FDK Programmer’s Guide Markers ... Frame Document Architecture If included, the number of a marker type in versions earlier than 5.5; when opening the document in FrameMaker 5.5, this maps the old numbered marker type to the new named marker type Whether the marker type appears in the user interface, whether it is saved with the document, and whether the marker type can be deleted The FO_Doc property, FP_MarkerTypeNames, specifies an F_StringsT structure, which provides the list of marker types available in the current document. The document object also has an FP_FirstMarkerTypeInDoc property as an entry into the document’s list of marker types. Given a marker type name, you can use F_ApiGetNamedObject() to get the ID of the associated FO_MarkerType. The following code returns the ID of the index marker type: ... F_ObjHandleT docId, markerId; /* Get ID of the active document. */ docId = F_ApiGetId(0, FV_SessionId, FP_ActiveDoc); markerId = F_ApiGetNamedObject(docId, FO_MarkerType, (StringT) "Index"); ... Figure 2-23 shows an index marker anchor and the text item that represents it. offset: 40 dataType: FTI_MarkerAnchor idata: FO_Marker ID Figure 2-23 A marker anchor and the text item that represents it FDK Programmer’s Guide 123 2 Frame Document Architecture Markers The following table lists some of the properties of the FO_Marker object specified by FTI_MarkerAnchor in Figure 2-23. Property Type Value FP_MarkerTypeId F_ObjHandleT ID of the FO_MarkerType for "Index" FP_MarkerText StringT presidents:past FP_NextMarkerInDoc F_ObjHandleT ID of the next FO_Marker object in the document Adding marker types to documents To add a marker type to a document, use F_ApiNewNamedObject(). Once you have the new marker type’s ID, you can set any properties that you want to be different from the default values. ... F_ObjHandleT docId, myMarkerTypeId; /* Get ID of the active document. */ docId = F_ApiGetId(0, FV_SessionId, FP_ActiveDoc); /* Create the marker type. */ myMarkerTypeId = F_ApiNewNamedObject(docId, FO_MarkerType, (StringT) "MyMarkerType"); ... To delete a marker type from a document, pass the document ID and the marker type ID to F_ApiDelete(). Mapping old marker types to named marker types In versions of FrameMaker earlier than 5.5, marker types were identified by number. Type 1 through Type 10 were reserved for FrameMaker, and given specific names; Header/Footer $1, Header/Footer $2, etc. Type 11 through Type 25 were for custom marker types. FO_MarkerType and FO_Marker objects have an FP_OldTypeNum property that maps the named marker type to what was a numbered marker type in earlier documents. In this way, you can ensure that your client handles markers in legacy data the way you want. 124 FDK Programmer’s Guide Cross-reference formats ... Frame Document Architecture For example, assume your client adds a marker type named MyMarkerType to a document, and you set the FP_OldTypeNum property of MyMarkerType to 11. The user might import or paste text from an older document into the document with MyMarkerType. If the older text has markers of type 11 in it, they will come into the new document as MyMarkerType. The standard list of marker types Every document includes a set of required marker types; Header/Footer $1, Header/Footer $2, Index, Comment, Subject, Author, Glossary, Equation, Hypertext Cross-Ref, and Conditional Text. These are required markers, and cannot be deleted. You can add an existing public marker type to the standard list by setting the name string to the FP_AddMarkerTypeToStandardMarkers property of the current session object. Once you add a marker type to this list, it remains for the entire session; you must quit the session to remove it. ... F_ApiSetInt(0, FV_SessionId, FP_OldTypeNum, (IntT) 17); F_ApiSetString(0, FV_SessionId, FP_AddMarkerTypeToStandardMarkers, (StringT) "MyMarkerType"); ... This example first sets a session integer for FP_OldTypeNum to 17. This ensures that for the rest of the current session, markers of type 17 (from earlier documents) will come into new documents as markers of type MyMarkerType. If the the FP_OldTypeNum you specify is taken, your new marker type will not be added to the list of standard marker types. To confirm that your marker type was added to the standard list, get the FP_MarkerNames property from the FV_SessionId object. It’s possible for the FP_OldTypeNum you specified to be taken; another API client may have already used that value when assigning a marker type to the standard list. For example, HTML export in FrameMaker 5.5 is performed by a client that adds the HTML Macro marker type to the standard list. The value of that marker’s FP_OldTypeNum is 11. After that client is initialized, no other clients can use the same value for FP_OldTypeNum when assigning a marker to the standard list. Cross-reference formats When you insert a cross-reference in a document, you choose a cross-reference format that specifies the information provided by the cross-reference. FDK Programmer’s Guide 125 2 Frame Document Architecture Cross-reference formats What the user sees A cross-reference format consists of a combination of text and cross-reference building blocks. Cross-reference building blocks are variables that provide information, such as the current page number or filename. Each document has a catalog of cross-reference formats. You can add or delete formats from this catalog. How the API represents cross-reference formats FrameMaker products represent each cross-reference format with an FO_XRefFmt object, whose properties provide the following information: The name of the cross-reference format A string containing the cross-reference’s text and cross-reference building blocks The ID of the next FO_XRefFmt object in the document Suppose you create a cross-reference format named See Heading & Page as shown in Figure 2-24. Figure 2-24 A cross-reference format 126 FDK Programmer’s Guide Cross-references ... Frame Document Architecture The following table lists some properties of the FO_XRefFmt object that represents this cross-reference format. Property Type Value FP_Name StringT See Heading & Page FP_Fmt StringT See \’<$paratext>\’ on page\ <$pagenum>. FP_NextXRefFmtInDoc F_ObjHandleT ID of the next FO_XRefFmt object in the document Cross-references A cross-reference refers to a specific location, known as a source, within the current document or another document. The source can be either a cross-reference marker (a type 9 marker) or a unique string of text. What the user sees When you insert a cross-reference, you select a cross-reference format, which specifies the information provided by the cross-reference. For more information on crossreference formats, see “Cross-reference formats” on page 125. How the API represents cross-reference instances The API represents each cross-reference instance with the following: FTI_XRefBegin and FTI_XRefEnd text items that specify the ID of the FO_XRef object An FTI_String text item, which provides the text that appears where the cross-reference is inserted An FO_XRef object FO_XRef properties provide the following information: The ID of an FO_XRefFmt object The ID of the next FO_XRef object in the document The name of the file in which the cross-reference source is located The element ID of the cross-reference, if it is in a structured flow in a document FDK Programmer’s Guide 127 2 Frame Document Architecture Cross-references Suppose you insert the cross-reference shown in Figure 2-25, using the See Heading & Page cross-reference format shown in Figure 2-24. offset: 0 offset: 0 offset: 1 offset: 47 dataType: FTI_MarkerAnchor dataType: FTI_XRefBegin dataType: FTI_String dataType: FTI_XRefEnd idata: FO_XRef ID sdata: "See \xd2This heading is idata: FO_XRef ID the x-ref source\ xd3 on page\x11 1." idata: FO_Marker ID Figure 2-25 A cross-reference and the text items that represent it The following are some properties of the FO_XRef object that represents the crossreference. Property Type Value FP_XRefFmt F_ObjHandleT ID of the FO_XRefFmt object representing the See Heading & Page crossreference format FP_NextXRefInDoc F_ObjHandleT ID of the next FO_XRef object in document FP_XRefFile StringT An empty string ("") Client-owned cross references A client can use the following properties of the FO_XRef object for identifying the cross-references it owns and to handle them specifically, as required: FP_XRefClientName FP_XRefClientType FP_XRefSrcElemNonUniqueId FP_XRefAltText. A client can create its own dialog for cross-references. The notification FA_Note_DisplayClientXRefDialog is sent to the client to display or update (in case it is already displayed) this dialog. If the client displays or updates its crossreference dialog, then it sets the return value as FR_DisplayedXRefDialog using the API, F_ApiReturnValue() to indicate this to FrameMaker. If the return value is not 128 FDK Programmer’s Guide Variable formats ... Frame Document Architecture set as explained, FrameMaker assumes that the client did not display any dialog. Consequently, FrameMaker’s standard cross-reference dialog is displayed. Variable formats The user can insert variables that represent a variety of information, such as the page number or the date, into text. The information a variable provides is specified by a variable format. What the user sees Each variable format can specify a combination of text and building blocks. Building blocks are FrameMaker product-defined variables that you can string together. FDK Programmer’s Guide 129 2 Frame Document Architecture Variable formats There are six principal classes of variable formats: Page number Date Filename Table Running header or footer User Each of these classes has a unique set of building blocks. You cannot use a building block from one class in another class. For example, you cannot use a date building block in a page number variable format. How the API represents variable formats FrameMaker products represent each variable format with an FO_VarFmt object, whose properties provide the following information: The name of the variable format The list of building blocks and text strings The type of variable it is (for example, page count or user variable) ID of the next FO_VarFmt object in the document Suppose you edit the Creation Date (Long) variable format so that its definition is as shown in Figure 2-26. Figure 2-26 Creation Date (Long) variable definition 130 FDK Programmer’s Guide Variables ... Frame Document Architecture The following are some properties of the FO_VarFmt object that represents the Creation Date (Long) variable format. Property Type Value FP_Fmt StringT <$monthname> <$daynum>, <$year> FP_SystemVar IntT FV_VAR_CREATION_DATE_LONG FP_NextVarFmtInDoc F_ObjHandleT ID of next FO_VarFmt object in the document Variables The user can insert variables in text. There are some restrictions on inserting some variable formats. For example, you can insert current page number, running header, and running footer variables only in an untagged flow on a master page. What the user sees The information an instance of a variable provides depends on its variable format. For example, if a variable’s format is Page Count and the current document has 27 pages, each time the variable occurs in text, it appears as 27. How the API represents instances of variables The API represents each variable instance with the following: An FTI_VarBegin text item and an FTI_VarEnd text item that specify the ID of an FO_Var object An FTI_String text item that provides the text that appears where the variable is inserted An FO_Var object FO_Var properties provide the following information: The ID of an FO_VarFmt object ID of the next FO_Var object in the document The element ID of the variable, if it is a structured variable in a document FDK Programmer’s Guide 131 2 Frame Document Architecture Footnotes Figure 2-27 shows an instance of the Creation Date (Long) variable and the text items that represent it. offset: 0 offset: 1 offset: 8 dataType: FTI_VarBegin dataType: FTI_String dataType: FTI_VarEnd idata: FO_Var ID sdata: "December 10, 1992" idata: FO_Var ID Figure 2-27 A variable instance and the text items that represent it The following table lists some of the properties of the FO_Var object specified by FTI_VarBegin and FTI_VarEnd in Figure 2-27. Property Type Value FP_VarFmt F_ObjHandleT ID of the FO_VarFmt object that represents the Creation Date (Long) variable format FP_NextVarInDoc F_ObjHandleT ID of the next FO_Var object in the document Footnotes A footnote is a type of special text column that appears at the bottom of a page. What the user sees A footnote reference (or anchor) appears in the main text as a number, letter, or special character. A footnote is visually separated from the main text by a separator (usually a horizontal line). The Footnote Properties dialog box allows you to change characteristics that apply to all the footnotes in a document, such as the type of numbering or special characters used to represent the anchor and the height of the footnote column. How the API represents footnotes When the user chooses the Footnote command, the FrameMaker product inserts a footnote anchor. It also creates a text frame with invisible borders at the bottom of the text frame in which the footnote was inserted. The user types the footnote text into the footnote text frame. 132 FDK Programmer’s Guide Footnotes ... Frame Document Architecture Characteristics, such as the footnote anchor’s numbering type, are represented as document properties because they apply to all the footnotes in a document and not just individual footnote instances. For more information on the document properties that govern footnote characteristics, see “How the API represents documents” on page 74. The API represents each footnote anchor with an FTI_FnAnchor text item, which specifies the ID of the FO_Fn object that represents the footnote. FO_Fn properties provide the following information: The footnote number The ID of the text frame in which the footnote text appears The ID of the next footnote in the list of footnotes in the document The IDs of the first and last paragraphs containing the footnote’s text The element ID of the footnote, if it is a structured footnote in a document Figure 2-28 shows a footnote and the text item that represents it. offset: 17 dataType: FTI_FnAnchor idata: FO_Fn ID Figure 2-28 A footnote and the text item that represents it FDK Programmer’s Guide 133 2 Frame Document Architecture Ruling Formats The following table lists the properties of the FO_Fn object specified by the FTI_FnAnchor text item in Figure 2-28. Property Type Value FP_InTextObj F_ObjHandleT The ID of the subcolumn (FO_SubCol) in which the footnote appears. FP_FnNum IntT 0. FP_PrevFn F_ObjHandleT ID of the previous footnote in the text frame (in this case, NULL). FP_NextFn F_ObjHandleT ID of the next footnote in the text frame (in this case, NULL). FP_NextFnInDoc F_ObjHandleT ID of the next footnote in the document. FP_FirstPgf F_ObjHandleT ID of the first paragraph (FO_Pgf) in the footnote. FP_LastPgf F_ObjHandleT ID of the last paragraph (FO_Pgf) in the footnote (in this example, it is the same as the one specified by FP_FirstPgf). Although FP_FnNum specifies an integer, the number that appears in the document can be one of several ordinal or special characters. For example, if you set the document’s FP_FnNumStyle property to FV_FN_NUM_ALPHA_UC, an A would appear instead of the 1 in the body text and at the beginning of the footnote. To get all the paragraphs in a footnote, you traverse the FP_NextPgfInFlow and FP_PrevPgfInFlow properties, just as you would to get the paragraphs in any other flow. Ruling Formats Each document has a Ruling Catalog containing several ruling formats. What the user sees Rulings are the lines that border a table cell or an entire table. A ruling format specifies a line type (such as Thin or Thick) and the gap between the line and the cell contents. 134 FDK Programmer’s Guide Ruling Formats ... Frame Document Architecture You can specify rulings for an entire table in the Table Designer or for individual table cells in the Custom Ruling and Shading dialog box. FrameMaker products provide default rulings, such as Thick and Thin. You can change these rulings or create your own. How the API represents ruling formats The API represents a ruling format with an FO_RulingFmt object, whose properties provide the following information: The name of the ruling format Its line width The gap between lines if the ruling specifies double lines The ID of the next FO_RulingFmt object in the document Suppose you create the Medium ruling format shown in Figure 2-29. Figure 2-29 Medium ruling format The API represents this ruling format with an FO_RulingFmt object. The following table lists some of its properties. Property Type Value FP_Name StringT Medium FP_RulingPenWidth MetricT 2*pts FP_RulingGap MetricT 0 FP_RulingLines IntT 2 FDK Programmer’s Guide 135 2 Frame Document Architecture Table Catalog formats How the API organizes ruling formats The API organizes the FO_RulingFmt objects in a document in a linked list. The FO_Doc property, FP_FirstRulingFmtInDoc, specifies the first FO_RulingFmt object in the list. Each FO_RulingFmt object has an FP_NextRulingFmtInDoc property, which specifies the ID of the next FO_RulingFmt object in the list. The order of the list does not correspond to the order in which the formats appear in the Custom Ruling and Shading dialog box. Table Catalog formats Each document has a Table Catalog containing table formats. What the user sees When you create a new table, you specify a format from the Table Catalog. The format provides the following information: The Table Catalog format name Format characteristics, such as the table position, alignment, and rulings The number of columns and rows If you tag an existing table with a Table Catalog format, the Table Catalog format provides only the format name and the format characteristics for the table; it does not affect the number of columns or rows. After you have created a new table or tagged an existing table, you can change the number of columns or rows or the format without affecting the Table Catalog tag. You can also instruct the FrameMaker product to apply the changes to the Table Catalog tag and other tables tagged with the format. You can modify or delete formats that are already in the Table Catalog, or you can add new formats. 136 FDK Programmer’s Guide Table Catalog formats ... Frame Document Architecture How the API represents Table Catalog formats FrameMaker products represent each Table Catalog format with an FO_TblFmt object, whose properties provide the following information: The name of the table format Format characteristics The default number of initial columns and rows The ID of the next FO_TblFmt object in the document Suppose you create the Table Catalog format described in the Table Designer and the Insert Table dialog box in Figure 2-30. Figure 2-30 Table Catalog format FDK Programmer’s Guide 137 2 Frame Document Architecture Tables The following table lists some of the properties of the FO_TblFmt object that represents Format A. Property Type Value FP_Name StringT Format A FP_TblInitNumCols IntT 5 FP_TblInitNumHRows IntT 1 FP_TblColRuling F_ObjHandleT ID of FO_RulingFmt object that represents the Thin line ruling FP_TblBodyRowRuling F_ObjHandleT ID of FO_RulingFmt object that represents the Thin line ruling FP_TblHFSeparatorRuling F_ObjHandleT ID of FO_RulingFmt object that represents the Double line ruling How the API organizes Table Catalog formats The API organizes the formats in the Table Catalog in a linked list. The FO_Doc object property, FP_FirstTblFmtInDoc, specifies the ID of the first FO_TblFmt object in the list. Each FO_TblFmt object has an FP_NextTblFmtInDoc property, which specifies the ID of the next FO_TblFmt object in the list. The order of the list does not correspond to the order in which the formats appear in the Table Designer. Tables FrameMaker products allow you to insert tables into text. When you insert a table, a table anchor symbol () appears on the screen at the point where you inserted it. What the user sees Tables are useful for organizing information in cells arranged in rows and columns. Tables can have titles and heading, body, and footing rows. FrameMaker products automatically repeat table titles and heading and footing rows on each page of a table. Each cell in a table is actually a type of text frame. It can contain text and nearly anything you insert in text, such as an anchored frame or a marker. You cannot insert another table directly into a table cell. Like a paragraph, each table has a tag and a format. The tag is the name of a Table Catalog format. A table format specifies the layout characteristics of a table, such as its 138 FDK Programmer’s Guide Tables ... Frame Document Architecture position in a text frame, its alignment, and the rulings and shadings of its columns and rows. The table format can specify different rulings for the different types of rows (for example, the body, heading, and footing rows). You can override a Table Catalog format by changing an individual table’s format. You can also override an individual table’s format by specifying a custom ruling, shading, or color for an individual cell or set of cells in the table. If you retag a table with a Table Catalog format after you have specified custom ruling for some of its cells, it does not affect the custom ruling for those cells. How the API represents tables The API represents a table anchor with an FTI_TblAnchor text item. For more information on text items, see “How the API represents text” on page 112. Each FTI_TblAnchor text item specifies the ID of an FO_Tbl object. The API represents the table itself with the following objects: An FO_Tbl object One or more FO_Row objects One or more FO_Cell objects FO_Tbl and table formats FO_Tbl properties provide the following information: The table format tag (name) Formatting (such as alignment and rulings) The number of columns and rows The ID of the paragraph in the table’s title IDs of FO_Row objects that represent the first and last rows in the table ID of the next FO_Tbl object in the document The element IDs of the table, table title, table heading, table body, table footing elements if the table is a structured table in a document FO_Tbl formatting properties are the same as FO_TblFmt formatting properties, except they do not include properties (such as FP_TblInitNumHRows) that specify the initial numbers of rows or columns. The table title If a table has a title, the FO_Tbl properties, FP_FirstPgf and FP_LastPgf, specify the IDs of the first and last FO_Pgf objects in the title. FDK Programmer’s Guide 139 2 Frame Document Architecture Tables Rows The API represents each row in a table with an FO_Row object. FO_Row properties provide the following information about a table row: Its type (heading, body, or footing) Whether it is kept with the previous row, the next row, or both when a page break occurs within the table Its maximum and minimum allowable height The IDs of the FO_Row objects that represent the rows before and after it in the table The ID of the FO_Cell object that represents the first (leftmost) cell in the row The conditions that apply to the row The element ID of the row, if it is a structured row in a document If a row has conditions applied to it, its FP_InCond property specifies an F_IntsT structure that includes the IDs of the FO_CondFmt objects that represent the conditions. Cells The API represents each cell in a table with an FO_Cell object, whose properties provide the following information: The ruling and shading that the cell inherits from the table format Custom ruling and shading Flags that indicate whether the cell’s custom shading and fill override the table’s shading and fill IDs of sibling FO_Cell objects IDs of the first and last paragraphs in the cell The element ID of the cell, if it is a structured cell in a FrameMaker document The FO_Cell object properties, FP_FirstPgf and FP_LastPgf, specify the IDs of the first and last paragraphs in the cell. If there is more than one paragraph in the cell, each paragraph’s FP_PrevPgfInFlow and FP_NextPgfInFlow properties specify the IDs of the paragraphs before and after it. FO_Cell objects have two properties for each ruling. For example, the properties for the top ruling are FP_CellDefaultTopRuling and FP_CellOverrideTopRuling. The default ruling is the ruling that the cell inherits from the FO_Tbl object that contains it. For example, the FP_CellDefaultTopRuling property for a cell in a body row inherits the value of the FP_TblBodyRowRuling property in the FO_Tbl object that contains it. An 140 FDK Programmer’s Guide Tables ... Frame Document Architecture override ruling is a ruling that the user specifies in the Custom Ruling and Shading dialog box for an individual cell. If a value is specified for an override ruling, it overrides the default ruling. The FO_Cell properties, FP_CellOverrideShading and FP_CellOverrideFill, specify the cell’s custom shading and fill. If the cell’s custom shading and fill override the table’s default shading and fill, FP_CellUseOverrideFill and FP_CellUseOverrideShading are True. How the API organizes the objects that represent tables Figure 2-31 shows a table anchor, a table, and the text item that represents the anchor. offset: 0 dataType: FTI_TblAnchor sdata: NULL Figure 2-31 A table and the text item that represents its anchor FDK Programmer’s Guide 141 2 Frame Document Architecture Tables The API represents the table with the objects shown in Figure 2-32. FP_FirstRowInTbl FP_FirstCellInRow FO_Row FP_FirstPgf FO_Cell (Heading Row) FO_Pgf (R1-C1) FP_PrevCellInRow FP_NextCellInRow FP_PrevRowInTbl FP_NextRowInTbl FP_LastPgf FP_FirstPgf FO_Cell FO_Pgf (R1-C2) FP_LastPgf FP_FirstCellInRow FO_Row FO_Tbl FP_FirstPgf FO_Cell (Body Row) FO_Pgf (R2-C1) FP_PrevCellInRow FP_NextCellInRow FP_PrevRowInTbl FP_NextRowInTbl FP_LastPgf FP_FirstPgf FO_Cell FO_Pgf (R2-C2) FP_LastPgf FO_Row FP_FirstCellInRow FO_Pgf (R3-C1) (Footer Row) FP_LastPgf FP_PrevCellInRow FP_NextCellInRow FP_LastRowInTbl FP_FirstPgf FO_Cell FO_Cell FP_FirstPgf FO_Pgf (R3-C2) FP_LastPgf Figure 2-32 Objects that represent a table 142 FDK Programmer’s Guide Tables ... Frame Document Architecture The following table lists some of the FO_Tbl object’s properties. Property Type Value FP_TblTag StringT Format A FP_TblTopRuling F_ObjHandleT NULL FP_TblHFSeparatorRuling F_ObjHandleT ID of FO_RulingFmt that represents Double line FP_TblBodyRowRuling F_ObjHandleT ID of FO_RulingFmt that represents Thin line FP_TblBodyFirstFill IntT 0 FP_FirstRowInTbl F_ObjHandleT ID of FO_Row that represents the heading row (row 1) FP_LastRowInTbl F_ObjHandleT ID of FO_Row that represents the footing row (row 3) The following are some of the properties of the FO_Row object that represents the table’s heading row. Property Type Value FP_PrevRowInTbl F_ObjHandleT NULL FP_NextRowInTbl F_ObjHandleT ID of FO_Row that represents row 2 FP_RowType IntT FV_ROW_HEADING FP_RowKeepWithNext IntT True FP_FirstCellInRow F_ObjHandleT ID of FO_Cell that represents the R1C1 cell FDK Programmer’s Guide 143 2 Frame Document Architecture Tables The following are some properties of the FO_Cell object that represents the R2-C2 cell. For the cell’s override fill and rulings to override the fill and ruling provided by the table’s format, the FP_CellUseOverrideCharacteristic properties must be set to True. 144 Property Type Value FP_CellOverrideFill IntT 5 FP_CellUseOverrideFill IntT True FA_CellDefaultLeftRuling F_ObjHandleT ID of FO_RulingFmt that represents the Medium line ruling FP_CellOverrideLeftRuling F_ObjHandleT ID of FO_RulingFmt that represents the Thick line ruling FP_CellDefaultBottomRuling F_ObjHandleT ID of FO_RulingFmt that represents the Medium line ruling FP_CellOverrideBottomRuling F_ObjHandleT ID of FO_RulingFmt that represents the Thick line ruling FDK Programmer’s Guide Tables ... Frame Document Architecture How the API represents straddle table cells When the user straddles a set of table cells, the FrameMaker product links all of the paragraphs in the cells. It changes the FP_FirstPgf and FP_LastPgf properties of the first cell (topmost and leftmost) so that it specifies the first and last paragraphs of the new linked list of paragraphs. All the other cells specify paragraph IDs of zero. It changes the properties of the first FO_Cell object in the straddle as listed in the following table. Property New value FP_CellIsStraddled False FP_CellNumRowsStraddled The number of rows in the straddle FP_CellNumColsStraddled The number of columns in the straddle It also changes the properties of cells other than the first cell in the straddle as listed in the following table. Property New value FP_CellIsStraddled True FP_CellNumRowsStraddled 1 FP_CellNumColsStraddled 1 The straddle uses the custom rulings and shadings of the first cell. When the user unstraddles the cells, the FrameMaker product leaves all the paragraphs that were in the straddle in the first cell. It gives each other cell a new empty paragraph. It leaves the original custom rulings and shadings of each cell intact. Suppose you straddle both cells in a table row that has two cells. Each cell contains a single paragraph before you straddle them. Figure 2-33 shows how the FO_Cell objects appear before and after they are straddled and unstraddled. The FrameMaker FDK Programmer’s Guide 145 2 Frame Document Architecture Tables product automatically inserts a new paragraph in the second cell after you unstraddle the cells. FO_Row FP_FirstPgf FP_FirstCellInRow FO_Pgf FO_Cell Before straddle FP_PrevCellInRow FP_NextCellInRow FP_LastPgf FP_FirstPgf FO_Pgf FO_Cell FP_LastPgf FP_FirstPgf FP_FirstCellInRow FP_PrevCellInRow After straddle FO_Pgf FO_Cell FP_NextCellInRow FO_Row FP _ La stP gf FP_NextPgfInFlow FP_PrevPgfInFlow FO_Pgf FP_FirstPgf = 0 FO_Cell FP_LastPgf = 0 FO_Pgf FO_Cell FP_PrevCellInRow After unstraddle FP_FirstPgf FP_FirstCellInRow FP_NextCellInRow FO_Row FP _ La stP gf FP_NextPgfInFlow FP_PrevPgfInFlow FO_Pgf FP_FirstPgf FO_Pgf FO_Cell FP_LastPgf Figure 2-33 Table cells before and after straddle 146 FDK Programmer’s Guide Colors ... Frame Document Architecture Colors You can assign spot colors to text and objects in a document, and you can print process color separations. You can also set up color views to specify which colors are visible in a document. What the user sees FrameMaker products provide a set of default colors. You can also define your own colors and store them in the document’s Color Catalog. The FrameMaker product provides three color models for creating your own colors: CMYK, RGB, and HLS. It also provides eight color libraries; Crayon, DIC, FOCOLTONE, Greys, MUNSELL, PANTONE® , TOYO, and TRUMATCH. How the API represents colors The API represents each default color and each user-defined color with an FO_Color object. Tints are special FO_Color objects because each tint includes a reference to a base color, which is itself an FO_Color object. For a tint, the FP_TintBaseColor property returns the object ID of the base FO_Color object. Paragraph formats, graphic objects, and other objects to which you can apply a color have properties that specify the ID of an FO_Color object. For example, all graphic objects have an FP_Color property that specifies the ID of an FO_Color object. The properties of FO_Color objects provide the following information: The name of the color The color library and associated pigment used for the color The CMYK values of the color Tint base color and percentage Whether the color overprints or knocks out when printing Library colors, FP_FamilyName, and FP_InkName When you specify a color from a library, the FP_Cyan, FP_Magenta, FP_Yellow, and FP_Black properties are set to represent the library color. If you later set FP_FamilyName and FP_InkName to NULL, the CMYK settings remain the same, but the FO_Color object no longer defines a library color. Both FP_FamilyName and FP_InkName are required to uniquely define a library color. The order in which you set the values of these properties is important. You must set a valid value for FP_FamilyName before you set FP_InkName. If you try to set the FDK Programmer’s Guide 147 2 Frame Document Architecture Colors ink name when the family name is set to NULL, F_ApiSetString() returns an error of FE_NoColorFamily. When you set a value for FP_FamilyName, two things can happen: If the current value for FP_InkName specifies a valid ink for the newly set FP_FamilyName, then FP_InkName does not change. If the current value for FP_InkName does not specify a valid ink for the newly set FP_FamilyName, then the value for FP_InkName automatically changes to the first ink name for the new color family. If you set FP_FamilyName to a color family that is not installed on your system, F_ApiSetString() returns an error of FE_BadFamilyName. If you set FP_InkName to a name that is not included in the current family, F_ApiSetString() returns an error of FE_BadInkName. If you set one of either FP_FamilyName or FP_InkName to NULL, then the other property value automatically changes to NULL. Formal color library names and ink names Note that you must specify the family name as the as the formal color library name, including the registered trademark symbol. For example, the following sets the color library for a color to MUNSELL® Book of Color; note the code (\xa8) for the “®” character. F_ApiSetString(docId, baseId, FP_FamilyName, "MUNSELL\xa8 Book of Color"); When specifying an ink name, you don’t necessarily provide the full ink name as described in the color library’s reference material. Some ink names have prefixes or suffixes that are not used by the API. The following table lists the formal name for each color library that FrameMaker products support, along with an example of a legal string to specify an ink name via the FDK: 148 Color library name Ink name Crayon Apricot DIC COLOR GUIDE SPOT 2298p* FOCOLTONE 1070 Greys 49% Grey.prcs MUNSELL® High Chrome Colors 2.5R 7:10 MUNSELL® Book of Color 2.5R 9:1 FDK Programmer’s Guide Colors Color library name Ink name PANTONE® Coated Yellow 012 PANTONE® ProSim Process Yellow PANTONE® Uncoated Yellow 012 PANTONE ProSim EURO® Process Yellow PANTONE® Process CSG 1-1 PANTONE® Process Euro E 1-1 TOYO COLOR FINDER 0001pc* TRUMATCH 4-Color Selector 1-a ... Frame Document Architecture Tinted colors In FO_Color objects that are tints, the following properties have no meaning: FP_FamilyName FP_InkName FP_Cyan FP_Magenta FP_Yellow FP_Black Changing these properties in a tinted color will turn the FO_Color object into an untinted color. If you want to change the hue of a tinted FO_Color object, you must select a new base color or change the hue of the base color. Also, you cannot change FP_ColorPrintCtl and FP_ColorViewCtl in a tinted color; if you try to change them, the FDK returns an error of FE_TintedColor. To change these properties, you must change them in the tint’s base color. FP_TintPercent You can set FP_TintPercent to a metric value from 0.00 to 100.0 (representing 0% to 100%), or to FV_COLOR_NOT_TINTED. If you set it to FV_COLOR_NOT_TINTED, then FP_TintBaseColor automatically changes to FV_NO_BASE_COLOR. When you set a percentage value for FP_TintPercent, if FP_TintBaseColor was set to FV_NO_BASE_COLOR, then it automatically changes to the object ID for the color Black. FDK Programmer’s Guide 149 2 Frame Document Architecture Structural element definitions FP_TintBaseColor Every tint has a base color. Note that you cannot use a tint as a base color for some other tint. If you set the base color to FV_NO_BASE_COLOR, then the FP_TintPercent for the current FO_Color object is set to FV_COLOR_NOT_TINTED. When you set a valid color for FP_TintBaseColor, if FP_TintPercent was initially set to FV_COLOR_NOT_TINTED, then it will auatomatically be set to the metric value of 100.0 (for 100%). Be sure to change the tint percent if you want less than 100%. Reserved colors FrameMaker products have eight reserved colors. FO_Color objects have a read-only property named FP_ReservedColor to specify whether the object represents a reserved color or not. Unless the color is one of the eight reserved colors, FP_ReservedColor will always be FV_COLOR_NOT_RESERVED. FP_ReservedColor can have one of the following values: FV_COLOR_NOT_RESERVED FV_COLOR_CYAN FV_COLOR_MAGENTA FV_COLOR_YELLOW FV_COLOR_BLACK FV_COLOR_WHITE FV_COLOR_RED FV_COLOR_GREEN FV_COLOR_BLUE For a reserved color, all the properties are read-only except FP_ColorOverPrint, FP_ColorPrintCtl,and FP_ColorViewCtl. If you try to change any of the readonly properties, the FDK returns an error of FE_ReservedColor (except for properties that normally return FE_ReadOnly for unreserved colors). Structural element definitions A structured FrameMaker document has an Element Catalog, which contains structural element definitions and named format change lists. There are two ways to test whether a document is structured via the API. To test whether a document contains structure elements, get the FP_HighestLevelElement property for the main FO_Flow object in the document. To test whether the document contains 150 FDK Programmer’s Guide Structural element definitions ... Frame Document Architecture an element catalog, get the FP_FirstElementDefInDoc property for the FO_Doc object. If you get legal values for these properties, then the document contains structure elements or an element catalog. What the user sees Each structural element definition has a name (tag), which usually corresponds to a type of document component or structural element, such as Section, List, Quotation, or BodyPara. An element definition specifies an element’s relationship to other elements in a structured document. An element definition can also contain formatting information about the element. The parts of an element definition that specify an element’s format are known as the format rules. The part of an element definition that specifies a container element’s contents is known as a content rule. The content rule includes the following: A general rule, which specifies what elements are inside the container and in what order A list of inclusions, which specifies other elements that can appear anywhere in a container or the elements it includes (its descendants) A list of exclusions, which specifies elements that cannot appear in a container or in its descendants Element definitions also specify attribute definitions, which describe attributes or separate units of information that the user can store with an element. An attribute definition can specify that an attribute is required for all elements with the element definition. It can also provide a list of the values an attribute can have, as well as a default value. How the API represents structural element definitions FrameMaker represents each element definition with an FO_ElementDef object. FO_ElementDef properties provide the following information about an element definition: Its name Its format rules Comments which describe its use Its attribute definitions Its content rule The type of element it defines (for example, a container or a system variable) FDK Programmer’s Guide 151 2 Frame Document Architecture Structural element definitions Flags indicating whether the element definition is defined in the Element Catalog and whether it can be used as the highest-level element for a flow The ID of the next FO_ElementDef object in the document Initial structure rules for automatic insertion of child elements Initial pattern rules for table components The API uses an FO_FmtRule object to represent each of an element definition’s format rules. The FO_ElementDef object has the following properties that specify an element definition’s format rules: FP_FirstPgfRules FP_LastPgfRules FP_ObjectFmtRules FP_PrefixRules FP_SuffixRules FP_TextFmtRules Each of these properties specifies an F_IntsT structure, which provides a list of FO_FmtRule IDs. For example, suppose you create the element definition shown in Figure 2-34. Element type and name Element (Container): Item General rule: Text format rules Element paragraph format: item 1. If context is: BulletList Numbering properties Autonumber format: \b\t Else, if context is: NumberList Numbering properties Autonumber format: \t Comment: For normal body paragraphs. Content rule Text format rules Optional comment Figure 2-34 Element definition for Item element 152 FDK Programmer’s Guide Format rules and format rule clauses ... Frame Document Architecture The API represents the element definition in Figure 2-34 as an FO_ElementDef object with the following properties: Property Type Value FP_Name StringT Item. FP_ElementPgfFormat StringT item. FP_NextElementDefInDoc F_ObjHandleT ID of the next FO_ElementDef object in the Element Catalog. FP_ElementInCatalog IntT True. FP_GeneralRule StringT . FP_ObjectType IntT FV_FO_CONTAINER. FP_Comment StringT For normal body paragraphs. FP_TextFmtRules F_IntsT The ID of the element definition’s text format rule. For a list of this format rule’s properties, see “How the API represents format rules and format rule clauses” on page 154. Format rules and format rule clauses An element definition can contain several format rules, each of which can contain several format rule clauses. What the user sees Format rules and format rule clauses allow the template builder to specify the formats an element has in specific circumstances. A format rule can be either a context rule or a level rule. A context rule contains clauses that specify an element’s formatting based on its parent and sibling elements. For example, one clause of a format rule could specify that a Para element has the FirstBody paragraph format if it is the first child of a Heading element. Another clause could specify that a Para element has the Body paragraph format in all other contexts. A level rule contains clauses that specify an element’s formatting based on the level to which it is nested within specific types of ancestor elements. For example, one clause of FDK Programmer’s Guide 153 2 Frame Document Architecture Format rules and format rule clauses a level rule could specify that a Para element appears in 12-point type if has only one Section element among its ancestors. Another clause could specify that a Para element appears in 10 point type if there are two Section elements among its ancestors. A format rule clause can use any of the following to specify an element’s formatting in specific contexts: A formatting tag or name, such as a paragraph tag, a character tag, or a marker name A subformat rule A format change list A named format change list How the API represents format rules and format rule clauses The API uses an FO_FmtRule object to represent each format rule in an element definition, and an FO_FmtRuleClause object to represent each format rule clause in a format rule. Each FO_FmtRule object has an FP_FmtRuleClauses property, which specifies its format rule clause. FO_FmtRule properties provide the following information about a format rule: A list of its format rule clauses An indication of whether it is a context rule or a level rule If the format rule is a level rule, the element tags to count among the element’s ancestors and the tag at which to stop counting FO_FmtRuleClause properties provide the following information about a format rule clause: 154 A flag indicating how the rule clause specifies formatting, such as a paragraph tag or a format change list The formatting tag or name, subformat rule, or change list the rule clause uses to specify the element’s formatting The circumstances under which the rule clause applies: if it is in a context rule, the context; if it is in a level rule, the level The context label FDK Programmer’s Guide Format change lists ... Frame Document Architecture For example, the element definition shown in Figure 2-34 on page 152 includes a single format rule. The following table lists some of the properties of that format rule. Property Type Value FP_ElementDef F_ObjHandleT ID of the FO_ElementDef object that contains the format rule. FP_FmtRuleClauses F_IntsT The IDs of the format rule clauses in the format rule. For a list of the rule clause’s properties, see the table below. FP_FmtRuleType IntT FV_CONTEXT_RULE. The F_IntsT structure specified by the FO_FmtRule object’s FP_FmtRuleClauses property provides an array, which includes the IDs of two format rule clauses. The following table lists some of the properties of the first format rule clause. Property Type Value FP_ContextLabel StringT BulletList. FP_FmtChangeList F_ObjHandleT The ID of the format change list (FO_FmtChangeList object) that is applied to the element when the specified context is valid. For a list of the change list’s properties, see “How the API represents format change lists” on page 156. FP_FmtRule F_ObjHandleT ID of the FO_Rule object that contains the format rule clause. FP_RuleClauseType IntT FV_RC_CHANGELIST. Format change lists A format change list describes a set of changes to paragraph format properties. What the user sees A format rule clause can use format change lists to specify how a paragraph format changes when the format rule clause applies. A change list can specify a change to just a single paragraph property, or it can specify changes to a long list of properties. FDK Programmer’s Guide 155 2 Frame Document Architecture Format change lists A change list can specify absolute values or relative values. For example, it can specify that the paragraph left indent is one inch, or it can specify that it is one inch greater than the inherited left indent. A change list can be named or unnamed. A named change list appears in the Element Catalog. Format rule clauses that use a named change list specify its name (or tag). Multiple rule clauses can specify the same named change list. An unnamed change list appears in a rule clause. It is used only by the rule clause in which it appears. How the API represents format change lists The API uses an FO_FmtChangeList object to represent each change list in a document. FO_FmtChangeList properties provide the following information about a change list: Its name if it is a named change list The ID of the next change list in the document’s list of change lists A paragraph format tag if the change list specifies one A change list has one property for each paragraph format property it changes. For example, if it changes only the first indent, it has the properties described above and just an FP_FirstIndent property. If it changes the space below and the leading, it has the properties described above and the FP_SpaceBelow and FP_Leading properties. If a change list changes a paragraph property to an absolute value, the property it uses has the same name as the corresponding paragraph format property (for example, FP_FirstIndent). If the change list changes a property with a relative value, the property it uses has the name of the corresponding paragraph format property with the word Change appended to it (for example, FP_FirstIndentChange). For example, the format rule clause in the element definition in Figure 2-34 on page 152 includes an unnamed change list. The following table lists the change list’s properties. Property Type Value FP_Name StringT NULL FP_NextFmtChangeListInDoc F_ObjHandleT ID of the next FO_FmtChangeList object in the document 156 FP_PgfCatalogReference StringT NULL FP_AutoNumString StringT \b\t FDK Programmer’s Guide Structural elements ... Frame Document Architecture Structural elements Structured Framemaker documents contain structural elements, which are instances of structural element definitions. What the user sees Each structural element is a component of a document. A structural element can consist of one or more paragraphs, a text range, one or more child elements, or anything you can insert in text (such as variables or tables). Each structural element has an element definition specifying what its format and contents should be. Elements in a document can have the same element definition. For example, a document may have several elements with a Para element definition. For more information on element definitions, see “Structural element definitions” on page 150. The elements in a container element are called its child elements. Child elements can also be containers; container elements can be nested. The element definition’s general rule specifies a container’s allowable child elements or text and the order in which they should occur. A container element can violate its content rule by omitting required child elements, by including excluded child elements, or by having the elements in the wrong order. If a container element obeys its content rule, it is said to be valid. Elements can also have attributes, which correspond to XML attributes. An attribute can be a defined attribute, which is defined in the element’s element definition, or an undefined attribute, which is not defined in the element’s element definition. How the API represents structural elements FrameMaker represents a structural element with an FO_Element object, whose properties provide the following information: Its attributes The ID of the object that represents its element definition The IDs of its parent and immediate sibling elements The IDs of the first and last FO_Element objects in the linked list of its child FO_Element objects Whether the element is collapsed Whether the element is valid; and if it is invalid, the reasons it is invalid FDK Programmer’s Guide 157 2 Frame Document Architecture Structural elements The ID of the object associated with the FO_Element object, if the element is a noncontainer element, such as a marker or a system variable The element’s context label The format rule clauses that apply to the element How the API represents a structural element’s validity An element can be invalid in several ways. For example, its parent’s content rule may not allow it, or it may contain a child element that is not allowed. FO_Element objects have validation properties that indicate the extent of an element’s validity. For example, an element has a property named FP_ElementIsInvalidInParent, which is set to True if the element is not allowed by its parent element. Changing an element When using FrameMaker, an author can select elements and wrap, merge, or change them. The API provides functions to wrap and merge elements directly; for example, F_ApiMergeIntoFirst(). However, there is no corresponding function to directly change an element. Changing an element corresponds to a user selecting an element in the document, selecting an element name in the Element catalog, and then clicking Change on the element catalog. To change an element via the API, you must change the FP_ElementDef property of the FO_Element object. You can traverse the list of element definitions in the document by starting with the FP_FirstElementDefInDoc property of the FO_Doc object, and then using the FP_NextElementDefInDoc property of the resulting FO_ElementDef object. You can identify the element definition by using its FP_Name property. 158 FDK Programmer’s Guide 3 Frame Book Architecture .................................. ..... 3 This chapter describes books and discusses how the Frame API represents them. What the user sees A book maintains a collection of documents that are known as components. The book helps you organize and format these component documents. It also enables you to create generated files, such as tables of contents and indexes. A book does not contain the component document files. It contains references to the component document files, in an ordered list; such a reference is called a book component. Each component contains its own setup data such as pagination and numbering. For example, each component contains properties to determine whether its page and paragraph numbering continues from the previous document or restarts at 1, and whether the document starts on a left or right page. The component properties should not differ from the corresponding properties in the document file. However, by setting the values in one but not both, a client could set up a component with different numbering properties than the corresponding document file. Subsequent book updates will make the numbering properties match. For example, the paragraph numbering for a set of document in files might be set to restart at 1. When the user adds the documents to the book, then each component will have the same numbering properties. Your client could loop through a book and set the numbering for each component to continue from the previous file. In this case, when your client (or the user) updates the book, the FrameMaker product will change the numbering for the document files so they match the component numbering. For more information about how component and document numbering properties interact, see your Frame product user’s manual. FDK Programmer’s Guide 159 3 Frame Book Architecture How the API represents books .............................................................................. IMPORTANT: A book component can be a document saved in any file format. The FDK can only modify document objects in documents that were saved in FrameMaker binary (FASL) files, but you can use channels to open MIF or text files and modify them. .............................................................................. How the API represents books The API represents each book with an FO_Book object which can contain one or more FO_BookComponent objects. FO_Book objects have properties that provide the following information: Whether the book has been modified Display properties such as book window size and location, text to show for each component, and text in the book’s status line Whether or not the book is view-only, and view-only display properties Selection state; whether the book icon is selected, the first selected component, or the range of selected structure elements in the book Properties that determine how to print the book and save it as PDF For structured books, structure properties such as the element catalog for the book and the ID of the highest level element in the book An FO_BookComponent object represents an individual book component. It has properties that provide the following information: 160 The name of the document represented by the component The IDs of the next and previous component in the book and the next selected component in the book Whether the component is generated, and the type of generated file; in other words, whether the component is a specific type of list or index Whether to include the component in print, update, and import formats operations The list of paragraph format tags the product uses to generate a list from this component The ID of the parent book Numbering and pagination properties for the component; these properties may differ from the document’s specific set of numbering properties For structured books, the structural element representing the book component FDK Programmer’s Guide How the API represents books ... Frame Book Architecture Suppose you create the book in Figure 3-1. The book is named C:\MyDocs\book1.book, and has three documents; myDoc1.fm, myDoc2.fm, and myDoc3.fm. Figure 3-1 A book with three components The API represents mybook.book with one FO_Book object and three FO_BookComponent objects. The following table lists some of the FO_Book object’s properties. Property Type Value FP_Name StringT C:\MyDocs\book1.book FP_NextOpenBookInSession F_ObjHandleT 0 FP_FirstComponentInBook F_ObjHandleT ID of FO_BookComponent object for myDoc1.fm FP_FirstSelectedComponent InBook F_ObjHandleT ID of FO_BookComponent object for myDoc3.fm FP_StatusLine StringT Empty string (""); the status line currently displays no text FP_TypeOfDisplayText IntT FV_BK_FILENAME The following code shows how to get properties from the selected book component. First it gets the active book, and then the first selected component in the active book. For the book in Figure 3-1, the component would be for myDoc3.fm. For the selected component, the code prints out the method the component uses to compute footnote numbering. Then, if the footnote numbering uses custom characters for footnotes (daggers, etc.), the code prints out the custom numbering string. FDK Programmer’s Guide 161 3 Frame Book Architecture How the API represents books VoidT F_ApiCommand(command) IntT command; { F_ObjHandleT bookId, compId; StringT numString; bookId = F_ApiGetId(0,FV_SessionId, FP_ActiveBook); compId = F_ApiGetId(FV_SessionId, bookId, FP_FirstSelectedComponentInBook); F_Printf(NULL, "\n CompName is: %s", F_ApiGetString(bookId, compId, FP_Name)); switch(F_ApiGetInt(bookId, compId, FP_FnNumComputeMethod)) { case FV_NUM_RESTART: F_Printf(NULL, "\nFn Compute: FV_NUM_RESTART"); break; case FV_NUM_CONTINUE: F_Printf(NULL, "\nFn Compute: FV_NUM_CONTINUE"); break; case FV_NUM_PERPAGE: F_Printf(NULL, "\nFn Compute: FV_NUM_PERPAGE"); break; case FV_NUM_READ_FROM_FILE: F_Printf(NULL,"\nFN Compute: FV_NUM_READ_FROM_FILE"); break; default: F_Printf(NULL, "\nFn Num Compute Method: UNKNOWN"); break; } if(F_ApiGetInt(bookId, compId, FP_FnNumStyle) == FV_FN_NUM_CUSTOM) { F_Printf(NULL, "\nFn Num Style: FV_FN_NUM_CUSTOM"); numString = F_ApiGetString( bookId, compId, FP_FnCustNumString); F_Printf(NULL, "\n Cust Str: %s", numString); F_ApiDeallocateString(&numString); } } 162 FDK Programmer’s Guide How the API represents books ... Frame Book Architecture How the API organizes book components The API organizes the FO_BookComponent objects that represent a book’s components in a linked list. The FO_Book object’s FP_FirstComponentInBook property specifies the first FO_BookComponent object in the list. Each FO_BookComponent object has FP_PrevComponentInBook and FP_NextComponentInBook properties that specify the IDs of the previous and next FO_BookComponent objects in the list. The order of the list is the same as the order of the components in the book. Suppose you create the book shown in Figure 3-1 on page page 161. The API represents this book with the objects shown in Figure 3-2. FP_FirstComponent InBook FO_Book FO_Book Component myDoc1.fm FO_Book Component myDoc2.fm FP_NextComponentInBook FP_PrevComponentInBook FO_Book Component myDoc3.fm Figure 3-2 Objects that represent a book and its components How the API represents structured books If a book is a FrameMaker structured book, it has an FP_HighestLevelElement property, which specifies the ID of the FO_Element object that represents the root element. Each component in the book also has an FP_ComponentElement property, which specifies the FO_Element object ID for that component’s structure element. FDK Programmer’s Guide 163 3 Frame Book Architecture Creating new books and components Creating new books and components To create a new book, use F_ApiNewNamedObject(). If you pass an empty string for the object name, the FrameMaker product creates an untitled book. To insert a new book component in a book, use F_ApiNewSeriesObject(). This creates a new book component, but the component has no document file assigned to it. If the user tries to to open such a component’s file, the FrameMaker product will alert the user that no file exists to match the component name. When you insert a new book component, you should assign a document to it. For more information on F_ApiNewSeriesObject(), see “Creating series objects” on page 365. The following code creates an untitled book with one component that represents a newly created, custom document file. After the code successfully saves the new document, it creates a book component and assigns the document name to the new component. #define in ((MetricT) 65536*72) . . . VoidT F_ApiCommand(command) IntT command; { F_ObjHandleT bookId, docId, compId; StringT s; F_ApiBailOut(); bookId = F_ApiNewNamedObject(FV_SessionId, FO_Book, (StringT)""); /* First create an 8.5 x 11 custom document. */ docId = F_ApiCustomDoc(F_MetricFractMul(in,17,2), 11*in, 1, F_MetricFractMul(in,1,4), in, in, in, in, FF_Custom_SingleSided, True); /* Save the doc, prompting for filename */ F_ApiSimpleSave(docId, (StringT)"", True); /* If file has name, make a component */ s = F_ApiGetString(FV_SessionId, docId, FP_Name); if(F_StrLen(s)) { compId = F_ApiNewSeriesObject( bookId, FO_BookComponent, 0); F_ApiSetString(bookId, compId, FP_Name, s); F_ApiDeallocateString(&s); } } 164 FDK Programmer’s Guide Updating a book ... Frame Book Architecture Updating a book After making changes in the documents or components of a book, your client must update the book to ensure all references are valid. For example, if you change the page numbering properties, you must update the book to ensure cross-references indicate the correct numbering. You can update a book via the F_ApiUpdateBook() command or the F_ApiSimpleGenerate() command. With F_ApiUpdateBook(), you can specify aspects of the Update operation, such as whether to update books with view-only documents. You can specify all aspects of the operation, or you can specify some aspects and allow the user to decide others. For example, you can instruct the FrameMaker product to post an alert if the book contains a MIF file. To use F_ApiUpdateBook(), you should first understand property lists and how to manipulate them directly. For more information on this subject, see “Representing object characteristics with properties” on page 63 and “Manipulating property lists directly” on page 293. The syntax for F_ApiUpdateBook() is: ErrorT F_ApiUpdateBook(F_ObjHandleT bookId, F_PropValsT *updateParamsp, F_PropValsT **updateReturnParamspp); This argument Means docId The ID of the document or book to save. updateParamsp A property list that tells the FrameMaker product how to update the book and how to respond to errors and other conditions. Use F_ApiGetUpdateBookDefaultParams() or F_ApiAllocatePropVals() to create and allocate memory for this property list. To use the default list, specify NULL. updateReturn Paramspp A property list that returns information about how the FrameMaker product updated the book. .............................................................................. IMPORTANT: Always initialize the pointer to the property list that you specify for updateReturnParamspp to NULL before you call F_ApiUpdateBook(). .............................................................................. To call F_ApiUpdateBook(), do the following: 1 Initialize the pointer to the updateReturnParamspp property list to NULL. FDK Programmer’s Guide 165 3 Frame Book Architecture Updating a book 2 Create an updateParamsp property list. You can get a default list by calling F_ApiGetUpdateBookDefaultParams(), or you can create a list from scratch. 3 Call F_ApiUpdateBook(). 4 Check the Update status. Check the returned values in the updateReturnParamspp list for information about how the FrameMaker product updated the book. 5 Deallocate the updateParamsp and updateReturnParamspp property lists. Steps 2, 4, and 5 are discussed in the following sections. Creating an updateParamsp script with F_ApiGetUpdateBookDefaultParams() The API provides a function named F_ApiGetUpdateBookDefaultParams() that creates a default updateParamsp property list. If you are setting a number of properties, it is easiest to use this function get the default property list and then change individual properties as needed. The syntax for F_ApiGetUpdateBookDefaultParams() is: F_PropValsT F_ApiGetUpdateBookDefaultParams(); The following table lists some of the properties in the property list returned by F_ApiGetUpdateBookDefaultParams(). The first value listed for each property is the default value for the property. You can change any property in the list to use its other legal values. Property Meaning and possible values FS_AlertUserAboutFailure Specifies whether to notify the user if something unusual occurs during the update operation False: don’t notify user True: notify user FS_MakeVisible Make newly generated files (lists and indexes) visible True: make visible False: don’t make visible 166 FDK Programmer’s Guide Updating a book ... Frame Book Architecture Property Meaning and possible values FS_ShowBookErrorLog Specifies whether to use the book error log to display warnings. False: don’t display book error log; display warnings in the console True: display the book error log For the complete list returned by F_ApiGetUpdateBookDefaultParams(), see “F_ApiGetUpdateBookDefaultParams()” on page 271 of the FDK Programmer’s Reference. For example, to get a default updateParamsp property list and modify it so that it instructs F_ApiUpdate() to show the book error log, use the following code: . . . F_PropValsT params; ErrorT err; . . . /* Get the default parameter list. */ params = F_ApiGetUpdateBookDefaultParams(); /* Get the index for the error log property, */ /* then set the property to True. */ i = F_ApiGetPropIndex(¶ms, FS_ShowBookErrorLog); params.val[i].propVal.u.ival = True; . . . The API allocates memory for the property list created by F_ApiGetUpdateBookDefaultParams(). Use F_ApiDeallocatePropVals() to free the property list when you are done with it. Creating an updateParamsp script from scratch If you want to specify only a few properties when you call F_ApiUpdateBook(), it is most efficient to create a property list from scratch. To create the property list, you must allocate memory for it, and then set up the individual properties. Use the API convenience function, F_ApiAllocatePropVals(), to allocate memory for the property list. For example, the following code creates an FDK Programmer’s Guide 167 3 Frame Book Architecture Updating a book updateParamsp property list that will instruct F_ApiUpdateBook() to display the error log: #DEFINE ERR_LOG 0 . . . F_PropValsT params, *returnParamsp = NULL; . . . /* Allocate memory for the list. */ params = F_ApiAllocatePropVals(1); /* Set up FS_ShowBookErrorLog property and set it to True. */ params.val[ERR_LOG].propIdent.num = FS_ShowBookErrorLog; params.val[ERR_LOG].propVal.valType = FT_Integer; params.val[ERR_LOG].propVal.u.ival = True; . . . /* When you’re finished, free the F_PropValsT */ F_ApiDeallocatePropVals(¶ms) Checking update status F_ApiUpdateBook() stores a pointer to a property list in updateReturnParamspp; the list contains one property which contains flags to indicate the status. For a list of the possible flags, see “F_ApiUpdateBook()” on page 473 of the FDK Programmer’s Reference. To determine if a particular FS_UpdateBookStatus bit is set, use F_ApiCheckStatus(). For example, the following code determines if an Update operation was canceled because the current book contains duplicate files (components that refer to the same file): 168 FDK Programmer’s Guide Updating a book ... Frame Book Architecture . . . F_PropValsT params, *returnParamsp = NULL; F_ObjHandleT bookId; /* Get the ID of the active book. */ bookId = F_ApiGetId(0, FV_SessionId, FP_ActiveBook); params = F_ApiGetUpdateBookDefaultParams(); F_ApiUpdate(bookId, ¶ms, &returnParamsp); if (F_ApiCheckStatus(returnParamsp, FV_DuplicateFileInBook)) F_ApiAlert("Duplicate files in book.", FF_ALERT_CONTINUE_NOTE); /* Deallocate property lists. */ F_ApiDeallocatePropVals(¶ms); F_ApiDeallocatePropVals(returnParamsp); . . . The API provides a utility function named F_ApiPrintUpdateStatus(), which prints the save error values to the console platforms. For more information, see “F_ApiPrintUpdateBookStatus()” on page 369 of the FDK Programmer’s Reference. FDK Programmer’s Guide 169 3 Frame Book Architecture Using the book error log Example The following code updates the currently active book. The update operation will display the error log for any error conditions, will allow inconsistent numbering properties, and (since the code allows inconsistent numbering) will not update the numbering in the book. It then prints out the update status. Finally, the code deallocates the property lists that it used to update the book. . . . #include "futils.h" IntT i; UCharT msg[1024]; F_PropValsT params, *returnParamsp = NULL; F_ObjHandleT bookId; params = F_ApiGetUpdateBookDefaultParams(); i = F_ApiGetPropIndex(¶ms, FS_ShowBookErrorLog); params.val[i].propVal.u.ival = True; i = F_ApiGetPropIndex(¶ms, FS_AllowInconsistentNumProps); params.val[i].propVal.u.ival = FV_DoOk; i = F_ApiGetPropIndex(¶ms, FS_UpdateBookNumbering); params.val[i].propVal.u.ival = False; err = F_ApiUpdateBook(bookId, ¶ms, &returnp); F_ApiPrintUpdateBookStatus(returnp); F_ApiDeallocatePropVals(¶ms); F_ApiDeallocatePropVals(returnp); . . . Using the book error log When updating a book, the FrameMaker product posts errors to a book error log. The error log is a FrameMaker document that lists error conditions and includes hypertext links to offending locations in the book’s document files. By default, FDK clients post book errors to the console. However, your clients can post errors to the log, and can include hypertext links in those messages. 170 FDK Programmer’s Guide Using the book error log ... Frame Book Architecture Displaying the error log for book updates By default, the FrameMaker product displays update errors in the console. You direct the FrameMaker product to display the error log via the property list you pass to F_ApiUpdateBook(). In that list, set the FS_ShowBookErrorLog flag to True. For more information about the update book properties, see “Creating an updateParamsp script with F_ApiGetUpdateBookDefaultParams()” on page 166. Writing messages to the error log The FrameMaker product includes an API client that writes messages to the error log. To write a message to the error log, you must use F_ApiCallClient(). The syntax for the client call is: F_ApiCallClient("BookErrorLog", "log -b=[bookId] -d=[docId] -o=[objId] --[text]"); where: BookErrorLog is the name of the client to call. log identifies this as a log message. -b is either the book ID or a document ID; typically the active book. -d is either a document ID or an object ID; typically a document associated with a book component. -o is an object in the document represented by the -d argument. If you pass both a document ID and an object ID, the call adds a hypertext link, from the error message to the object you specified. -- is the text of the message to appear in the log. To post a time stamp in the message, pass the FM_PRINT_DATESTAMP token as the message string. The call creates a unique log for each book or document ID you pass in the -b argument; if you pass 0 for a book ID, you will create a log that is not associated with any book; all calls with the 0 book ID will go to that log file. When you pass a document ID for the -d argument, the call creates an entry with the document’s pathname. It then indents all contiguous entries with the same document ID under that document’s pathname. This continues until you pass a different document ID. If you pass 0 for the -d argument, the call will not indent the errors. If you don’t have the document ID, you can specify log entry indenting under a filename via the text you pass for the log message. To do this, you precede the log message with a filename, followed by a carriage return. This method creates an indented section each time you pass a filename and carraige return, even if you pass the same filename in a series of log entries. FDK Programmer’s Guide 171 3 Frame Book Architecture Using the book error log For example, if you passed the following to the BookErrorLog client in two consecutive calls: "filename.fm\012Here is my first Log Message" "filename.fm\012Here is my second Log Message" The BookErrorLog client would create the following messages: filename.fm Here is my first Log Message filename.fm Here is my second Log Message Example The following code shows a function that posts messages to a log, with or without a time stamp; if you pass valid ID’s for all the ID arguments, the log message will include a hypertext link to the specified object in the specified document: VoidT ReportError(F_ObjHandleT docId, F_ObjHandleT objId, ConStringT errmsg, BoolT dateStamp) { F_ObjHandleT bookId; StringT log_msg = F_StrNew((UIntT)256); bookId = F_ApiGetId(0, FV_SessionId, FP_ActiveBook); if(dateStamp) { F_Sprintf(log_msg, "log -b=%d -d=%d -o=%d --%s", bookId, docId, objId, (StringT)"FM_PRINT_DATESTAMP"); } else { F_Sprintf(log_msg, "log -b=%d -d=%d -o=%d --%s", bookId, docId, objId, errmsg); } F_ApiCallClient("BookErrorLog", log_msg); F_ApiDeallocateString(&log_msg); } 172 FDK Programmer’s Guide PART III .......................................... Frame Application Program Interface 4 Introduction to the Frame API .................................. ..... 1 This chapter provides an overview of how the API works and how to create an FDK client. It also provides a simple example—a client that you can create and run right away. The API enables you to create a client that takes control of a FrameMaker product session. With the API, a client can do almost anything an interactive user can do. It can create, save, and print documents; add and delete text and graphics; and perform many other formatting and document-management tasks. It can also interact with the user by responding to user actions, displaying dialog boxes, and creating menus. How the API works The API represents everything in a FrameMaker product session as an object.1 Each object has a type, a constant that indicates the type of thing it represents. For example, an object’s type can be FO_Doc (if it represents a document), FO_Rectangle (if it represents a graphic rectangle), or FO_Pgf (if it represents a paragraph). FrameMaker products assign an identifier (ID) to each object in a session. You use this ID to identify an object when you call API functions. An object’s characteristics are called properties. Each type of object has a particular set of properties or a property list. For example, an FO_Rectangle object’s property list includes properties named FP_Width and FP_Height, which represent its height and width. An FO_Pgf object’s property list includes properties named FP_LeftIndent and FP_Leading, which represent its left indent and its leading. Each property has a predetermined data type, such as IntT (integer, Boolean, or ordinal), StringT (string), or F_ObjHandleT (object ID). Each of an individual object’s properties has a value. This value describes the property for that particular object. For example, suppose a document contains a smoothed ................................. 1. Frame API objects should not be confused with the graphic objects that you create with the Tools palette, object elements in structured documents, or the objects of object-oriented programming languages. FDK Programmer’s Guide 175 4 Introduction to the Frame API How the API works rectangle that is 20 points wide and 10 points high. The Frame API represents the rectangle as an FO_Rectangle object with the following properties and values. Property Data Type Value FP_Width MetricT 20 * 65536a FP_Height MetricT 10 * 65536 FP_RectangleIsSmoothed IntT True FP_FrameParent F_ObjHandleT ID of the frame containing the rectangle a. MetricT values are 32-bit integers that represent measurements in points. The 16 most significant bits represent the digits before the decimal. The 16 least significant bits represent the digits after the decimal. A point is 65536 (1 << 16) in MetricT units. For more information on MetricT, see “MetricT values” on page 950 of the FDK Programmer’s Reference. FO_Rectangle objects actually have many more properties than are shown in the table above. For a complete list of Frame API objects and properties, see Chapter 3, “Object Reference,” of the FDK Programmer’s Reference. How clients can change FrameMaker product documents, books, and sessions A client can change FrameMaker documents, books, and sessions by: Creating and destroying objects The API provides functions to create and destroy objects. Changing object properties The API provides functions to get and set object properties. 176 FDK Programmer’s Guide Programmatically executing FrameMaker product commands, such as Open, Print, Save, and Clear All Change Bars Special types of clients ... Introduction to the Frame API How clients communicate with the user A client can communicate with the user by: Creating menus and menu items Displaying dialog boxes The API allows a client to respond to user actions by: Notifying the client when the user initiates certain events, such as Open, Save, or Quit Passing a message to the client when the user clicks a hypertext marker that contains a message apiclient hypertext command How clients work with FrameMaker Clients are dynamic link libraries (DLLs), or they can be executable programs that use COM to communicate with a FrameMaker session.. A client does not need to be aware of the low-level details of integrating with FrameMaker, because the API provides high-level functions that are the same on all platforms. When the user starts FrameMaker, it sends an initialization call to each registered client. Clients can take control immediately, or they can request FrameMaker to notify them of specific events and wait for those events to occur. Special types of clients In addition to conventional clients that take control of a FrameMaker product session in response to user actions, the API allows you to create three special types of clients: document reports, filters, and take-control clients. Document reports A document report is a client that provides detailed information about a document. The user can start a document report by choosing Utilities>Document Reports from the File menu, and then choosing the report from the Document Reports dialog box. The FDK includes a sample document report, named wordcnt, which counts the number of words in a document. Filters A filter is a client that converts FrameMaker product files to or from other file formats. An import filter is a filter that the FrameMaker product calls when the user attempts to open a non-Frame file and chooses a filter in the Unknown File Type dialog box. The FDK Programmer’s Guide 177 4 Introduction to the Frame API Special types of clients import filter reads the file and converts it to a FrameMaker product document or book. The FDK includes a sample import filter, named mmlimport, that converts MML files to FrameMaker product documents. An export filter is a filter that the FrameMaker product calls when the user attempts to save a FrameMaker product document or book in a particular format by choosing the format in the Save dialog box or by specifying a filename with a particular extension. The export filter writes information in the document or book to a file with a different format. A file-to-file filter is a filter that the FrameMaker product can call to both import or export files of different formats. A single file-to-file filter client can actually consist of more than one filter. For example, the same client could filter CGM to FrameVector and FrameVector to CGM. The way you register the client’s different filters determines which filter to invoke for import and export. Another advanage of these filters is they can filter from an external file to an external file. For example, you could filter from CGM to TIFF, and the TIFF file can remain an external file that is imported into the document by reference. Take-control clients A take-control client is a client that takes control of a FrameMaker product session immediately after the FrameMaker product starts. Take-control clients are useful for conducting batch operations in which little or no user interaction is needed. Portability The API’s design makes it easy to create portable clients. In most cases, you only need to recompile your client to run it on a different platform. To ensure that your client is completely portable, use the FDE with the API. You should replace platform-specific I/O, string, and memory functions in your client with the alternatives the FDE provides. For more information on the FDE, see Part III, “Frame Development Environment (FDE).” The FDE and the API provide alternatives to the C language’s fundamental data types. For example, the FDE and the API substitute IntT for a 32-bit int and UCharT for unsigned char. The API uses other types for specific purposes. For example, it uses F_ObjHandleT for object IDs. For a list of API data types, see Chapter 4, “Data Types and Structures Reference,” of the FDK Programmer’s Reference. 178 FDK Programmer’s Guide Running clients with different FrameMaker product interfaces ... Introduction to the Frame API Running clients with different FrameMaker product interfaces FrameMaker ships with two product interfaces, Structured FrameMaker and FrameMaker. A client can only use functionality that is available in the product interface that is active for the currently running FrameMaker process. For example, if a client is running on the unstructured FrameMaker product interface, it can’t create or manipulate structural elements (FO_Element objects). On the other hand, all functions in the FDK are available to a client running on the Structured FrameMaker product interface. To determine if a function is available in a particular product interface, see Chapter 2, “FDK Function Reference,” of the FDK Programmer’s Reference. For an example of how to programmatically determine which product interface is running, see “F_ApiGetString()” on page 234 of the FDK Programmer’s Reference. Creating and running a client To create and run a client, follow these general steps: 1 Write an initialization function. Most clients need to define an F_ApiInitialize() callback function. When the FrameMaker product starts, it calls your client’s F_ApiInitialize() function. Normally, you will want to include code in F_ApiInitialize() to set up your client’s menus and request notification for particular events. For more information on creating an F_ApiInitialize() callback, see Chapter 2, “API Client Initialization.” 2 Set up the client’s user interface. Your client probably needs to interact with the user. To respond to user actions, you can define the following callback functions in your client: F_ApiNotify() to respond to the user initiating FrameMaker product operations, such as Open and Save F_ApiCommand() to respond to the user choosing menu items created by your client F_ApiMessage() to respond to the user clicking hypertext markers that contain the message apiclient command F_ApiDialogEvent() to respond to the user manipulating items in a dialog box created by your client You can also display notices and prompt the user for input by using API dialog box functions, such as F_ApiAlert() and F_ApiPromptString(). FDK Programmer’s Guide 179 4 Introduction to the Frame API Creating and running a client For more information on setting up your client’s user interface, see Chapter 3, “Creating Your Client’s User Interface.” 3 Add code to programmatically execute FrameMaker product commands. Your client probably needs to execute some FrameMaker product commands, such as Open, Print, or Close. To execute these commands programmatically, use API functions, such as F_ApiSimpleOpen(), F_ApiSilentPrintDoc(), or F_ApiClose(). For more information on using API functions to execute FrameMaker product commands, see Chapter 4, “Executing Commands with API Functions.” 4 Add code to get and set object properties. To get or set an object property, use the F_ApiGetPropertyType() or F_ApiSetPropertyType() function that corresponds to the type of property you want to get or set. For example, to get or set an IntT property, use F_ApiGetInt() or F_ApiSetInt(). To get or set a StringT property, use F_ApiGetString() or F_ApiSetString(). For more information on changing object properties, see Chapter 5, “Getting and Setting Properties.” 5 Add code to create objects. To create objects, use the F_ApiNewObjectType() function that corresponds to the kind of object that you want to create. For example, to create a new anchored frame, use F_ApiNewAnchoredObject(). For more information on creating objects, see Chapter 8, “Creating and Deleting API Objects.” 6 Compile your client. The API function declarations are contained in the fapi.h header. Be sure to include this header in your client code. Include C library header files before the fapi.h header. The FDK comes with sample makefiles or project files for each supported platform. To compile your client, use your platform’s make or build utility. For more information on using FDK makefiles or project files on a specific platform, see the FDK Platform Guide for that platform. 7 Register your client with the FrameMaker product. The FrameMaker product needs to know about your client to initialize it. To let the FrameMaker product know about your client, you must make some changes to the environment under which the client runs. Add the following lines to the [APIClients] section of the maker.ini file: ClientName=ClientType, description, path, mode ClientName is the name that the FrameMaker product and other clients use to reference your client. ClientType specifies your client type: for example, 180 FDK Programmer’s Guide A simple example ... Introduction to the Frame API Standard, DocReport, or TextImport. description is a string describing your client. path is the pathname of your client’s DLL. mode determines what product interfaces your client supports—can be one of all, maker, or structured. You can also register a Windows client by setting values in the DLL’s VERSIONINFO resource, then copying or moving the DLL in the PrameMaker product’s Plugins folder.. A simple example The following client adds a menu with three items to the FrameMaker product menu bar when the FrameMaker product starts. The first menu item closes the active document; the second item sets the fill pattern of a selected graphic object; the third item adds a body page to the active document. Following the code is a line-by-line description of how it works. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 #include "fapi.h" #define CloseDoc 1 #define SetFill 2 #define AddPage 3 VoidT F_ApiInitialize(initialization) IntT initialization; /* Code for initialization type */ { F_ObjHandleT menuBarId, menuId; /* Get ID of the FrameMaker product menu bar. */ menuBarId = F_ApiGetNamedObject(FV_SessionId, FO_Menu, "!MakerMainMenu"); /* Add menu named "API" to the FrameMaker product menu bar. */ menuId = F_ApiDefineAndAddMenu(menuBarId, "APIMenu", "API"); /* Add items to API menu. */ F_ApiDefineAndAddCommand(CloseDoc, menuId,"CloseDocCmd", "Close","\\!CD"); F_ApiDefineAndAddCommand(SetFill, menuId,"SetFillCmd", "Set Fill","\\!SF"); F_ApiDefineAndAddCommand(AddPage, menuId,"AddPageCmd", "Add Page","\\!AP"); } VoidT F_ApiCommand(command) IntT command; { F_ObjHandleT pgId, objId, docId; FDK Programmer’s Guide 181 Introduction to the Frame API 4 A simple example 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 /* Get the ID of the active document. */ docId = F_ApiGetId(0, FV_SessionId, FP_ActiveDoc); if(!docId) return; /* Return if there is no active document. */ switch (command) { case CloseDoc: /* Close document even if it’s changed. */ F_ApiClose(docId, FF_CLOSE_MODIFIED); break; case SetFill: /* Set fill pattern to black. */ /* Get ID of selected object. */ objId = F_ApiGetId(FV_SessionId, docId, FP_FirstSelectedGraphicInDoc); /* If an object is selected, set its fill. */ if (!objId) F_ApiAlert("Select an object first.", FF_ALERT_CONTINUE_WARN); else F_ApiSetInt(docId, objId, FP_Fill, FV_FILL_BLACK); break; case AddPage: /* Add a new page. */ pgId = F_ApiNewSeriesObject(docId, FO_BodyPage, 0); break; } } Lines 1–5 These lines include header files and define the constants for the client’s menu items. All clients must include the fapi.h header. To ensure your client is portable, include fapi.h before any other header files. Lines 6–25 These lines define the F_ApiInitialize() callback function. When the user starts the FrameMaker product, it calls F_ApiInitialize(). The call to F_ApiGetNamedObject() gets the ID of the FrameMaker product menu bar (!MakerMainMenu). The call to F_ApiDefineAndAddMenu() creates a menu named API on the menu bar. The calls to F_ApiDefineAndAddCommand() add menu items to the API menu and define keyboard shortcuts for the items. Lines 26–56 These lines define the F_ApiCommand() callback function. When the user chooses a menu item, the FrameMaker product calls this callback with command set to the menu item number (in this example, CloseDoc, SetFill, or AddPage). 182 FDK Programmer’s Guide A simple example ... Introduction to the Frame API Lines 31–34 These lines get the ID of the document to change. To use most API functions, you need to specify an ID. This example gets the ID of the document that has input focus, that is, the active document. In each FrameMaker product session there is only one active document at a time. The session object (FO_Session) has a property named FP_ActiveDoc that specifies its ID. To retrieve the active document’s ID from the FO_Session object, you use F_ApiGetId() to query the FO_Session object’s FP_ActiveDoc property. The syntax for F_ApiGetId() is: F_ObjHandleT F_ApiGetId(parentId, /* Object’s parent */ objId, /* Object whose property you want to query */ property);/* Constant specifying property to query */ The parentId parameter specifies the ID of the object’s parent—the session, book, or document that contains the object. No other object contains the FO_Session object, so parentId is set to 0. The ID of the FO_Session object (there can only be one) is always FV_SessionId, so objId is set to FV_SessionId. Lines 37–40 These lines close the active document when the user chooses Close Doc from the API menu. The FF_CLOSE_MODIFIED flag instructs the API to close the document without warning the user, even if the document has unsaved changes. Lines 41–51 These lines set the fill pattern of a selected object to black when the user chooses Set Fill from the API menu. To set the selected object’s fill pattern, the client needs the object’s ID. To get the ID, the client uses F_ApiGetId() to query the document property, FP_FirstSelectedGraphicInDoc. If no object is selected, F_ApiGetId() returns 0. The F_ApiAlert() call displays an alert that tells the user to select an object. The constant, FF_ALERT_CONTINUE_WARN, specifies the type of alert—an alert with a Continue button. FDK Programmer’s Guide 183 4 Introduction to the Frame API A simple example To set the object’s fill pattern, the client must set its FP_Fill property. FP_Fill is an IntT property, so the client must use F_ApiSetInt() to set it. The syntax for F_ApiSetInt() is: VoidT F_ApiSetInt(parentId,/* Object’s parent */ objId, /* Object whose property you want to set */ property, /* Constant specifying property to set */ value);/* Value to which to set the property */ FP_Fill can have any value between 0 and 15. The API-defined constant, FV_FILL_BLACK, specifies 0 (black). Lines 52–54 These lines add a body page to the document when the user chooses Add a Page from the API menu. A body page object is a series object. To create a series object, you use F_ApiNewSeriesObject(). The syntax for F_ApiNewSeriesObject() is: F_ObjHandleT F_ApiNewSeriesObject(parentId,/* Object’s Parent */ objectType, /* Constant specifying new object type */ prevObjectId); /* Object for new object to follow */ The parentId parameter specifies the ID of the object that is to contain the new object. The new page should appear in the active document, so parentId is set to docId. The API uses FO_BodyPage objects to represent body pages, so objectType is set to FO_BodyPage. Specifying 0 for prevObjectId puts the new page at the beginning of the document. For more information on creating different types of objects, see “Creating objects” on page 357. 184 FDK Programmer’s Guide Using old clients with FDK 12 ... Introduction to the Frame API Compiling and running the example client The source code for the example client and a makefile or project file are provided in provided in the samples/myapi directory of your FDK installation. To compile the client, use your platform’s make or build utility. To run the example client, you must first register it. Assuming you have compiled your client into a DLL named myapi.dll and copied or moved it to the FrameMaker fminit directory, add the following line to the maker.ini file: myapi = Standard,Ch. 1 Sample,fminit\myapi.dll After you have registered the example client, start FrameMaker and open a document. The API menu should appear to the right of the FrameMaker menus. Using old clients with FDK 12 For legacy clients compiled with FDK 10 to run successfully with FDK 12, they should be recompiled with Microsoft Visual Studio 2010. FDK Programmer’s Guide 185 4 186 Introduction to the Frame API Using old clients with FDK 12 FDK Programmer’s Guide 5 API Client Initialization .................................. ..... 2 This chapter describes how to start interaction between your client and FrameMaker. Responding to the FrameMaker product’s initialization call When the FrameMaker product starts, it attempts to start all the clients registered with it,1 except document reports and filters. The FrameMaker product attempts to start each client by calling its F_ApiInitialize() callback function. Your client should define F_ApiInitialize() as follows: VoidT F_ApiInitialize(initialization) IntT initialization; { /* Your client code goes here */ } This argument Means initialization A flag that indicates the type of initialization (see “Initialization types”) Usually, you want your client to do something immediately after the user starts the FrameMaker product. For example, you may want to add menus to the menu bar or request notification for certain events. To do this, you call API functions from the F_ApiInitialize() function. For information on creating menus and requesting notification, see Chapter 3, “Creating Your Client’s User Interface.” ................................. 1. For information on registering your client with a FrameMaker product, see the FDK Platform Guide for your platform. FDK Programmer’s Guide 187 5 API Client Initialization Initialization types Suppose you want your client to display a dialog box after the FrameMaker product is started. To do this, you could use the following F_ApiInitialize() function: . . . VoidT F_ApiInitialize(initialization) IntT initialization; { F_ApiAlert("Client has started.", FF_ALERT_CONTINUE_NOTE); } . . . Initialization types The following table summarizes the different types of initializations and the initialization constants FrameMaker products can pass to your client’s F_ApiInitialize() callback. When F_ApiInitialize is called Initialization constant FrameMaker product starts with no special options After starting FA_Init_First All except document reports and filters FrameMaker product starts with take-control client After starting FA_Init_First All except document reports and filters After all clients have finished processing the FA_Init_First initialization FA_Init_TakeControl All clients set up as take-control clients Document report chosen from Document Reports dialog box After report is chosen FA_Init_DocReport The chosen document report Notification, menu choice, or hypertext command for a client that has bailed out When the menu item is chosen, the hypertext command is clicked, or the notification should be issued FA_Init_Subsequent Clients that have bailed out and are waiting for an event, menu choice, or hypertext command to occur Type of initialization 188 FDK Programmer’s Guide Clients that receive initialization Initialization types ... API Client Initialization First initialization When the user starts a FrameMaker product, the FrameMaker product calls the F_ApiInitialize() function of each registered client (unless it’s a document report or filter) with initialization set to FA_Init_First. Take-control initialization The FDK allows you to set up clients to receive a special initialization called a takecontrol or FA_Init_TakeControl initialization. The FrameMaker product issues the FA_Init_TakeControl initialization after it has issued the FA_Init_First initialization and all clients have returned control. This initialization is useful if you want your client to conduct some batch processing after other clients have initialized, but before the interactive user has control. The FrameMaker product can issue the FA_Init_TakeControl initialization to several clients. To set up a client to receive FA_Init_TakeControl initializations, set the client’s type to TakeControl in the FrameMaker product .ini file. Document report initialization When a FrameMaker product is started, it does not attempt to initialize API clients that are registered as document reports. It initializes a document report only when the user chooses the document report from the Document Reports dialog box. When this occurs, the FrameMaker product calls the document report’s F_ApiInitialize() callback with initialization set to FA_Init_DocReport. To appear in the Document Reports dialog box, a document report must be registered with the FrameMaker product as a document report. For information on registering document reports, see the FDK Platform Guide for your platform. Filter initialization If your client is registered as a filter, you should not define an F_ApiInitialize() function for it. When the user opens or saves a file and selects your filter, the FrameMaker product notifies your client by calling your client’s F_ApiNotify() callback. For more information on F_ApiNotify() and notification, see “Responding to user-initiated events or FrameMaker product operations” on page 217. To receive notification, your filter must be registered as a filter. For information on registering filters, see the FDK Platform Guide for your platform. FDK Programmer’s Guide 189 5 API Client Initialization Disabling the API Initialization after a client has bailed out If your API client is waiting for an event and not performing any other processing, it can call F_ApiBailOut(). This exits your client’s process and frees all the system resources that it uses. If an event that your client is waiting for occurs, the FrameMaker product restarts your client by calling its F_ApiInitialize() function with initialization set to FA_Init_Subsequent. A document report should always bail out after it completes processing, because the API initializes it each time the user chooses it from the Document Reports dialog box. A filter should always bail out after it filters a file, because the API initializes it each time a filterable file is opened, imported, or saved. For more information on F_ApiBailOut(), see “F_ApiBailOut()” on page 84 of the FDK Programmer’s Reference. Disabling the API The user can disable all API clients before starting theFrameMaker product by changing the API=On setting in the FrameMaker product .ini file to API=Off. .............................................................................. IMPORTANT: Many FrameMaker features are implemented via API clients. If you disable the API then you also disable these features. Such features include XML and SGML import and export, Save As HTML, and Word Count. .............................................................................. FrameMaker Product Activation by Asynchronous Clients Asynchronous clients on Windows that launch a FrameMaker process and wait for it to become idle (by calling WaitForInputIdle) before attempting to connect using F_ApiWinConnectSession need to make provision for the connection time required during activation as explained below. If FrameMaker has not been activated (relevant only for the FrameMaker Point Product on Windows XP and Windows Vista®), an activation screen prompts the user for input. The WaitForInputIdle call returns at this point while FrameMaker isn’t actually ready for communication. Therefore, the client must give the user enough time to activate or skip activation before attempting to connect to FrameMaker using F_ApiWinConnectSession. Otherwise, the client can require the user to activate the product before using it. Despite activation, WaitForInputIdle returns too early before FrameMaker is actually ready to establish a connection. The issue can be resolved by modifying the code and introducing a 5-10 second sleep before attempting to connect to the FrameMaker session. 190 FDK Programmer’s Guide FrameMaker Product Activation by Asynchronous Clients ... API Client Initialization Another solution is to attempt to connect a multiple or indefinite number of times with short sleeps in between. Asynchronous clients running the FrameMaker Point Product on Windows 2000 or running the FrameMaker Server on Windows 2000, XP, or VISTA won’t encounter any such problems. FDK Programmer’s Guide 191 5 192 API Client Initialization FrameMaker Product Activation by Asynchronous Clients FDK Programmer’s Guide 6 Creating Your Client’s User Interface .................................. ..... 3 This chapter describes how to use the Frame API to create a user interface for your FDK client. Your client can interact with the user in the following ways: By displaying its own dialog boxes By implementing its own menus, menu items, and keyboard shortcuts By responding to the message apiclient hypertext command By responding to user-initiated events or FrameMaker product operations By implementing quick-key commands The following sections discuss these ways of interacting with the user in greater detail. Using API dialog boxes to prompt the user for input The Frame API provides a variety of premade dialog boxes. All of these dialog boxes are modal—the user must dismiss them before continuing. The following sections discuss how to use these dialog boxes. The API also allows you to create and use custom modal and modeless dialog boxes. For more information, see Chapter 10, “Creating Custom Dialog Boxes for Your Client” and Chapter 11, “Handling Custom Dialog Box Events.” FDK Programmer’s Guide 193 7 C r e a t i n g Yo u r C l i e n t ’ s U s e r I n t e r f a c e Using API dialog boxes to prompt the user for input Using alert boxes To display a dialog box with a short message, use F_ApiAlert(). The syntax for F_ApiAlert() is: IntT F_ApiAlert(StringT message, IntT type); This argument Means message The message that appears in the alert box type The type of alert box Specify one of the following values for the type argument. type constant Type of dialog box displayed FF_ALERT_OK_DEFAULT Displays OK and Cancel buttons; OK is the default FF_ALERT_CANCEL_DEFAULT Displays OK and Cancel buttons; Cancel is the default FF_ALERT_CONTINUE_NOTE Displays Continue button FF_ALERT_CONTINUE_WARN Displays Continue button with a warning indication FF_ALERT_YES_DEFAULT Displays Yes and No buttons; Yes is the default FF_ALERT_NO_DEFAULT Displays Yes and No buttons; No is the default F_ApiAlert() returns 0 if the user clicks OK, Continue, or Yes; otherwise, it returns a nonzero value. 194 FDK Programmer’s Guide Using API dialog boxes to prompt the user for input ... C r e a t i n g Yo u r C l i e n t ’ s U s e r I n t e r f a c e Example The following code displays the alert box shown in Figure 3-1: . . . IntT err; err = F_ApiAlert((StringT)"This alert is an OK_DEFAULT.", FF_ALERT_OK_DEFAULT); . . . Figure 3-1 FF_ALERT_OK_DEFAULT alert box Using string, integer, and metric input dialog boxes To prompt the user for a single string, integer, or metric value, use F_ApiPromptString(), F_ApiPromptInt(), or F_ApiPromptMetric(). These functions all allow you to provide a default value for the entry field. Their syntax is: IntT F_ApiPromptString(StringT *stringp, StringT message, StringT stuffVal); IntT F_ApiPromptInt(IntT *intp, StringT message, StringT stuffVal); IntT F_ApiPromptMetric(MetricT *metricp, StringT message, StringT stuffVal, MetricT defaultunit); This argument Means stringp, intp, or metricp A pointer to the user variable that gets the return value from the input field when the user clicks OK. message The message that appears in the dialog box. FDK Programmer’s Guide 195 7 C r e a t i n g Yo u r C l i e n t ’ s U s e r I n t e r f a c e Using API dialog boxes to prompt the user for input This argument Means stuffVal The default value that appears in the input field when the dialog box is first displayed. It must be a string for integer and metric prompts, as well as string prompts. defaultunit The metric unit to use if the user doesn’t specify one. For example, to use inches as the default unit, specify 4718592. For more information on metric values, see “MetricT values” on page 950 of the FDK Programmer’s Reference. These functions all return 0 if the user clicks OK. Otherwise, they return a nonzero error value. If the user clicks Cancel, the API does not assign a value to *stringp, *intp, or *metricp. If the user types alphabetic text after a number in an F_ApiPromptInt() dialog box, the API ignores the text and just returns the number. For example, if the user types 10 cookies, the returned value is 10. F_ApiPromptMetric() dialog boxes behave like metric dialog boxes in the user interface. If the user types a number followed by a string that represents a unit, the API converts the value into the equivalent number of metric units. For example, if the user types 5in or 5", the API returns 5*(4718592). If the user doesn’t specify a unit, the API uses the unit specified by defaultunit. .............................................................................. IMPORTANT: F_ApiPromptString() allocates memory for the string referenced by *stringp. Use the FDK function F_ApiDeallocateString() to free the string when you are done with it. .............................................................................. 196 FDK Programmer’s Guide Using API dialog boxes to prompt the user for input ... C r e a t i n g Yo u r C l i e n t ’ s U s e r I n t e r f a c e Examples The following code displays the dialog box shown in Figure 3-2: . . . #include "fmemory.h" IntT err; StringT sres; err = F_ApiPromptString(&sres, (StringT)"String?", (StringT)"Default text"); if (err) return; /* Some code to use the string goes here. */ F_ApiDeallocateString(&sres); . . . Figure 3-2 String prompt dialog box The following code displays the dialog box shown in Figure 3-3: . . . #include "futils.h" /* Provides declaration for F_Sprintf(). */ IntT err, ires; UCharT msg[256]; err = F_ApiPromptInt(&ires, (StringT)"Integer?", "1234"); if (err) F_Sprintf(msg,(StringT)"Cancelled, ires has no value"); else F_Sprintf(msg,(StringT)"The value of ires is %d.",ires); F_ApiAlert(msg, FF_ALERT_CONTINUE_NOTE); . . . Figure 3-3 Integer prompt dialog box FDK Programmer’s Guide 197 7 C r e a t i n g Yo u r C l i e n t ’ s U s e r I n t e r f a c e Using API dialog boxes to prompt the user for input The following code displays the dialog box shown in Figure 3-4: . . . #define IN (MetricT) 65536*72 /* Default unit (inches) */ IntT err; MetricT mres; err = F_ApiPromptMetric(&mres, (StringT)"Metric?", "12.34in", IN); . . . Figure 3-4 Metric prompt dialog box Using file selection dialog boxes To display dialog boxes similar to theFrameMaker product’s Open and Save dialog boxes, use F_ApiChooseFile(). F_ApiChooseFile() displays files and directories in a scrolling list and allows the user to choose a file or directory. The syntax for F_ApiChooseFile() is: IntT F_ApiChooseFile(StringT *choice, StringT title, StringT directory, StringT stuffVal, IntT mode, StringT helpLink); 198 FDK Programmer’s Guide Using API dialog boxes to prompt the user for input ... C r e a t i n g Yo u r C l i e n t ’ s U s e r I n t e r f a c e This argument Means choice The selected pathname when the user clicks OK. title The message that appears in the dialog box. directory The default directory when the dialog box is first displayed. If you specify an empty string, the last directory used by your client is used. If your client hasn’t used any directories, the directory specified by the session property, FP_OpenDir, is used. stuffVal The default value that appears in the input field when the dialog box first appears. If the dialog box type specified by mode doesn’t have an input field, this string is ignored. mode A constant specifying the type of dialog box. For a list of dialog box types, see “F_ApiChooseFile()” on page 89 of the FDK Programmer’s Reference. helpLink Obsolete in versions 6.0 and later; pass an empty string. The name of a document containing help information for the dialog box and an optional hypertext link. .............................................................................. IMPORTANT: F_ApiChooseFile() allocates memory for the string referenced by *choice. Use F_ApiDeallocateString() to free the string when you are done with it. .............................................................................. FDK Programmer’s Guide 199 7 C r e a t i n g Yo u r C l i e n t ’ s U s e r I n t e r f a c e Using API dialog boxes to prompt the user for input Example To create the dialog box shown in Figure 3-5, add the following code to your client: . . . #include "futils.h" #include "fmemory.h" IntT err; StringT sres; UCharT msg[256]; err = F_ApiChooseFile(&sres, (StringT)"Choose a file", (StringT)"/tmp", (StringT)"", FV_ChooseSelect, (StringT)""); if (err) F_Sprintf(msg,(StringT)"Cancelled, sres is not defined."); else F_Sprintf(msg,(StringT)"The value of sres is %s.",sres); F_ApiAlert(msg, FF_ALERT_CONTINUE_NOTE); if (!err) F_ApiDeallocateString(&sres); . . . Figure 3-5 File selection dialog box 200 FDK Programmer’s Guide Using API dialog boxes to prompt the user for input ... C r e a t i n g Yo u r C l i e n t ’ s U s e r I n t e r f a c e Using scroll list dialog boxes To display a scroll list dialog box, use F_ApiScrollBox(). F_ApiScrollBox() displays an array of items that you provide and allows the user to choose one. The syntax for F_ApiScrollBox() is: IntT F_ApiScrollBox(IntT *selected_item, StringT title, F_StringsT *stringslist, IntT default); This argument Means selected_item The index of the selected item when the user clicks OK (or double-clicks an item). The index of the first item is 0. title The title that appears on the dialog box. stringslist The list of items that appears in the scroll list. default The index of the item that is selected when the dialog box first appears. For no default, specify -1. F_StringsT is defined as: typedef struct { UIntT len; /* Number of strings */ StringT *val; /* Array of strings */ } F_StringsT; The F_ApiScrollBox() function returns a nonzero value if the user clicks Cancel or an error occurs, or 0 if the user clicks OK. FDK Programmer’s Guide 201 7 C r e a t i n g Yo u r C l i e n t ’ s U s e r I n t e r f a c e Using API dialog boxes to prompt the user for input Example To create the dialog box shown in Figure 3-6, add the following code to your client: . . . #include "futils.h" IntT err, choice, listLen = 3; UCharT msg[256]; F_StringsT colors; colors.val = (StringT *) F_Alloc(listLen*sizeof(StringT), NO_DSE); if (colors.val) { colors.len = (UIntT)listLen; colors.val[0] = F_StrCopyString("red"); colors.val[1] = F_StrCopyString("green"); colors.val[2] = F_StrCopyString("blue"); err = F_ApiScrollBox(&choice, "Choose a color.", &colors, 0); if (!err) F_Sprintf(msg, "The choice is %s.", colors.val[choice]); else F_Sprintf(msg, "Cancel was pressed"); F_ApiAlert(msg, FF_ALERT_CONTINUE_NOTE); F_ApiDeallocateStrings(&colors); } . . . Figure 3-6 Scroll list dialog box 202 FDK Programmer’s Guide Using commands, menu items, and menus in your client ... C r e a t i n g Yo u r C l i e n t ’ s U s e r I n t e r f a c e Using commands, menu items, and menus in your client The API allows you to use commands, menu items, and menus in your client’s user interface. A command is a part of FrameMaker product or FDK client functionality that a user can invoke by typing a shortcut. A menu item is an instance of a command that appears on a menu. There can be several menu items for each command. A menu is a list of menu items or other menus. A menu bar is a list of menus that appears at the top of the FrameMaker window on Windows platforms. To use commands and menus in your client’s user interface, follow these general steps: 1. Get the IDs of the FrameMaker product menu bars and menus that you want to add your client’s menus and commands to. 2. Define your client’s commands and add them to menus. 3. Define your client’s menus and add them to FrameMaker product menus or menu bars. 4. Write an F_ApiCommand() callback to respond to the user invoking your client’s commands. These steps are discussed in greater detail in the following sections. Getting the IDs of FrameMaker product menus and menu bars To get the IDs of commands, menus, or menu bars, use F_ApiGetNamedObject(). The syntax for F_ApiGetNamedObject() is: F_ObjHandleT F_ApiGetNamedObject(F_ObjHandleT parentId, IntT objType, StringT objName); This argument Means parentId The ID of the document, book, or session containing the object for which you want to get an ID. For commands and menus, it is always FV_SessionId. objType The object type. To get the ID of a command, specify FO_Command. To get the ID of a menu or menu bar, specify FO_Menu. objName The name of the command, menu, or menu bar. This name may not be the same as the label or title that appears on a menu. The menu and command names you can specify for objName depend on how the user has customized the menus. The [Files] section of the maker.ini file FDK Programmer’s Guide 203 7 C r e a t i n g Yo u r C l i e n t ’ s U s e r I n t e r f a c e Using commands, menu items, and menus in your client specifies the location of the menu and command configuration files that list FrameMaker’s menus and commands. The following table lists some FrameMaker product menus and the names you use to specify them: Menu title Name Edit EditMenu Element ElementMenu File FileMenu Format FormatMenu Graphics GraphicsMenu Special SpecialMenu Table TableMenu View ViewMenu Help !HelpMenu The following table lists the names of some FrameMaker product menu bars. Menu bar names starting with an exclamation point (!) can’t be removed by the user. 204 FrameMaker product menu bar Name Menu bar for documents (complete menus) !MakerMainMenu Menu bar for documents (quick menus) !QuickMakerMainMenu Menu bar for books (complete menus) !BookMainMenu Menu bar for books (quick menus) !QuickBookMainMenu View-only menu bar !ViewOnlyMainMenu FDK Programmer’s Guide Using commands, menu items, and menus in your client ... C r e a t i n g Yo u r C l i e n t ’ s U s e r I n t e r f a c e Example The following code gets the ID of the Edit menu and the view-only menu bar: . . . F_ObjHandleT editMenuId, viewOnlyMenuBarId; editMenuId = F_ApiGetNamedObject(FV_SessionId, FO_Menu, "EditMenu"); viewOnlyMenuBarId = F_ApiGetNamedObject(FV_SessionId, FO_Menu, "!ViewOnlyMainMenu"); . . . Defining commands and adding them to menus To define a command and add it to a menu, use F_ApiDefineAndAddCommand(). The syntax for F_ApiDefineAndAddCommand() is: F_ObjHandleT F_ApiDefineAndAddCommand(IntT cmd, F_ObjHandleT toMenuId, StringT name, StringT label, StringT shortcut); This argument Means cmd The integer that the FrameMaker product passes to your client’s F_ApiCommand() function when the user chooses the menu item or types the keyboard shortcut for the command. toMenuId The ID of the menu to which to add the command. name A unique name to identify the command. label The title of the command as it appears on the menu. shortcut The keyboard shortcut sequence. Many FrameMaker product commands use shortcuts beginning with Esc (\!). To specify Esc when you create a command, use \\! in the string you pass to shortcut. F_ApiDefineAndAddCommand() returns the ID of the command it creates. FDK Programmer’s Guide 205 7 C r e a t i n g Yo u r C l i e n t ’ s U s e r I n t e r f a c e Using commands, menu items, and menus in your client Example The following code defines a command with the shortcut Esc N L and adds it to the Utilities menu: . . . #define NUMBER_LINES 1 F_ObjHandleT utilsMenuId, cmdId; utilsMenuId = F_ApiGetNamedObject(FV_SessionId, FO_Menu, "UtilitiesMenu"); cmdId = F_ApiDefineAndAddCommand(NUMBER_LINES, utilsMenuId, "NumberLines","Number lines", "\\!NL"); . . . Figure 3-7 Utilities menu with client-defined menu item Defining and adding menus To define a menu and add it to a menu bar or another menu, use F_ApiDefineAndAddMenu(). The syntax for F_ApiDefineAndAddMenu() is: F_ObjHandleT F_ApiDefineAndAddMenu(F_ObjHandleT toMenuId, StringT name, StringT label); This argument Means toMenuId The ID of the menu or menu bar to which to add the new menu name A unique name that identifies the new menu label The title of the new menu as it appears on the menu or menu bar F_ApiDefineAndAddMenu() returns the ID of the menu it creates. If you specify a menu bar ID for toMenuId, the FrameMaker product implements the new menu as a pull-down menu. If you specify a pull-down or a pop-up menu ID for toMenuId, the FrameMaker product implements the new menu as a pull-right menu. 206 FDK Programmer’s Guide Using commands, menu items, and menus in your client ... C r e a t i n g Yo u r C l i e n t ’ s U s e r I n t e r f a c e .............................................................................. IMPORTANT: Your menu appears only on the menu bar you specify. For example, if you add a menu only to the !MakerMainMenu menu bar, the menu will not appear if the user switches to quick menus. For your menu to appear after the user has switched to quick menus, you must also add it to the !QuickMakerMainMenu menu bar. .............................................................................. Adding commands to a menu that you have created To add a command to a menu that you have created, call F_ApiDefineAndAddCommand() with toMenuId set to the ID returned by the F_ApiDefineAndAddMenu() call that created the menu. For example, the following code defines a menu and adds it to the FrameMaker document menu bar. Then it adds some commands to the menu. . . . #define CHECK 1 #define PRINT 2 F_ObjHandleT menubarId, menuId, cmd1Id, cmd2Id; /* Get the ID of the FrameMaker main menu bar. */ menubarId = F_ApiGetNamedObject(FV_SessionId, FO_Menu, "!MakerMainMenu"); /* Define and add the menu to the main menu. */ menuId = F_ApiDefineAndAddMenu(menubarId, "GrammarMenu", "Grammar"); /* Define some commands and add them to the menu. */ cmd1Id = F_ApiDefineAndAddCommand(CHECK, menuId, "CheckGrammar","Check Grammar", "\\!CG"); cmd2Id = F_ApiDefineAndAddCommand(PRINT, menuId, "PrintErrors","Print Errors", "\\!PE"); . . . Figure 3-8 FrameMaker main menu bar and a client-defined menu FDK Programmer’s Guide 207 7 C r e a t i n g Yo u r C l i e n t ’ s U s e r I n t e r f a c e Using commands, menu items, and menus in your client Example The following code defines a menu and adds it to the Edit menu: . . . #define CHECK 1 #define PRINT 2 F_ObjHandleT editMenuId, menuId, cmd1Id, cmd2Id; /* Get the ID of the edit menu. */ editMenuId = F_ApiGetNamedObject(FV_SessionId, FO_Menu, "EditMenu"); /* Define the menu and add it to the Edit menu. */ menuId = F_ApiDefineAndAddMenu(editMenuId, "GrammarMenu", "Grammar"); /* Define some commands and add them to the menu. */ cmd1Id = F_ApiDefineAndAddCommand(CHECK, menuId, "CheckGrammar","Check Grammar", "\\!CG"); cmd2Id = F_ApiDefineAndAddCommand(PRINT, menuId, "PrintErrors","Print Errors", "\\!PE"); . . . Figure 3-9 Edit menu with a client-defined pull-right menu 208 FDK Programmer’s Guide Using commands, menu items, and menus in your client ... C r e a t i n g Yo u r C l i e n t ’ s U s e r I n t e r f a c e Responding to the user choosing a command Whenever the user chooses a menu item or types a keyboard shortcut for a command created by your client, the FrameMaker product attempts to call your client’s F_ApiCommand() function. Your client should define this function as follows: VoidT F_ApiCommand(command) IntT command; { /* Code to respond to command choices goes here. */ } This argument Means command The value of the cmd parameter in the F_ApiDefineAndAddCommand() call that created the command that the user chose FDK Programmer’s Guide 209 7 C r e a t i n g Yo u r C l i e n t ’ s U s e r I n t e r f a c e Using commands, menu items, and menus in your client Example The following client defines some commands and adds them to the Special menu. It provides an F_ApiCommand() function to respond to the user choosing the commands. #include "fapi.h" #define LOAD 1 #define QUERY 2 VoidT F_ApiInitialize(initialization) IntT initialization; { F_ObjHandleT specialMenuId; /* Get the ID of the special menu. */ specialMenuId = F_ApiGetNamedObject(FV_SessionId, FO_Menu, "SpecialMenu"); /* Define the commands and add them to the Special menu. */ F_ApiDefineAndAddCommand(LOAD, specialMenuId, "LoadDatabase", "Load Database",""); F_ApiDefineAndAddCommand(QUERY, specialMenuId, "QueryDatabase", "Query Database", ""); } VoidT F_ApiCommand(command) IntT command; { switch(command) { case LOAD: /* Code to load database goes here. */ break; case QUERY: /* Code to query database goes here. */ break; } } 210 FDK Programmer’s Guide Replacing FrameMaker product menus and commands ... C r e a t i n g Yo u r C l i e n t ’ s U s e r I n t e r f a c e Replacing FrameMaker product menus and commands You can replace FrameMaker product menus and commands with your own menus and commands by calling F_ApiDefineAndAddCommand() and F_ApiDefineAndAddMenu() with the name parameter set to the name of a FrameMaker product menu or command. For example, the following code replaces the FrameMaker product Print command: . . . #define PRINT_CMD 223 F_ObjHandleT fileMenuId, printCmdId; fileMenuId = F_ApiGetNamedObject(FV_SessionId, FO_Menu, "FileMenu"); printCmdId = F_ApiDefineAndAddCommand(PRINT_CMD, fileMenuId, "Print", "Print...", "\\!fp"); . . . If you use this code, the Print command appears on the File menu exactly as it normally would. However, when the user chooses it, the FrameMaker product never executes the Print operation. Instead, it calls your client’s F_ApiCommand() callback with command set to PRINT_CMD. The F_ApiCommand() callback can execute your own version of the Print operation. For example, it can set the default number of copies to 1 and then call F_ApiSilentPrintDoc() to print the document. This prevents the user from printing more than one copy of a document at a time. Allowing users to configure your client’s interface When you call F_ApiDefineAndAddCommand() and specify the name of a command that is already defined in the user’s menu configuration files, the FrameMaker product gives precedence to the definition in the configuration files. If the configuration files assign a label or a shortcut to the command, the FrameMaker product uses it instead of the one you specify. If the command is already a menu item, the FrameMaker product ignores the menu that you specify and leaves the menu item where it is. FDK Programmer’s Guide 211 7 C r e a t i n g Yo u r C l i e n t ’ s U s e r I n t e r f a c e Allowing users to configure your client’s interface For example, if the Print command is already defined and appears on the File menu, the following code has the same effect as the sample code in the previous section: . . . #define PRINT_CMD 223 F_ObjHandleT printCmdId, bogusMenuId = 12345; printCmdId = F_ApiDefineAndAddCommand(PRINT_CMD, bogusMenuId, "Print", "This is ignored", "This too"); . . . If you use this code, the Print command appears on the File menu exactly as it normally does. Because FrameMaker products give precedence to the labels, shortcuts, and menu item locations specified by the menu configuration files, users can configure your client’s interface. If users know the names of your client’s commands, they can assign labels and shortcuts to the commands and specify where the commands appear on the menus by editing their menu configuration files. For example, if your client defines a command with the following code: . . . F_ObjHandleT editMenuId; editMenuId = F_ApiGetNamedObject(FV_SessionId, FO_Menu, "EditMenu"); F_ApiDefineAndAddCommand(1, editMenuId, "NumberLines","Number Lines", "\\!NL"); . . . users can make the command appear on the Special menu instead of the Edit menu by adding the following line to their menu configuration files: > If users add this line to their menu configuration files and your client does not define the NumberLines command or is not running, the NumberLines menu item appears dimmed. .............................................................................. IMPORTANT: Adobe Systems recommends that you document the names of your client’s menus and commands so that users can customize them. .............................................................................. 212 FDK Programmer’s Guide Using hypertext commands in your client’s user interface ... C r e a t i n g Yo u r C l i e n t ’ s U s e r I n t e r f a c e For more information on using menu configuration files, see the online manual, Customizing FrameMaker Products. For more information on changing commands, menu items, and menus, see Chapter 9, “Manipulating Commands and Menus with the API.” Using hypertext commands in your client’s user interface You can embed hypertext commands in markers within FrameMaker product documents. A FrameMaker product’s basic set of hypertext commands allows you to establish links within and between documents and to jump from link to link. You can lock a FrameMaker product document that contains hypertext commands so that it behaves like a command palette. For information on locking documents, see your FrameMaker product user documentation. Documents have a set of properties that specify their characteristics when they are locked. By setting these properties, you can change how a locked document window appears. For example, you can hide the scroll bars and the window control buttons. For a list of locked document properties, see “Document View Only properties” on page 821 of the FDK Programmer’s Reference. FrameMaker products provide a special hypertext command, message apiclient, that can send messages to your client. With this command, you can create an extremely flexible user interface. Your client only needs to define responses for the hypertext messages that are sent to it. Users and hypertext document designers can set up the interface that sends the messages. The message apiclient hypertext command is especially useful for setting up command palettes for your client. To use the message apiclient hypertext command in your client’s interface, follow the general steps below: 1 Set up the hypertext commands. 2 Create a function named F_ApiMessage() in your client to respond to the user clicking a hypertext marker that contains a message apiclient command. These steps are discussed in greater detail in the following sections. FDK Programmer’s Guide 213 7 C r e a t i n g Yo u r C l i e n t ’ s U s e r I n t e r f a c e Using hypertext commands in your client’s user interface Setting up hypertext commands The syntax for message apiclient is: message apiclient yourmessage This argument Means apiclient The name under which the client is registered with the FrameMaker product. It is the ClientName specified in the [APIClients] section of the maker.ini file. yourmessage The string that the FrameMaker product passes to the API client. When the user clicks a hypertext command, the FrameMaker product calls the F_ApiMessage() function of the client specified by apiclient and passes the string specified by yourmessage to the client. Responding to message apiclient commands To respond to the message apiclient hypertext command, your client must define F_ApiMessage() as follows: VoidT F_ApiMessage(message, docId, objId) StringT message; F_ObjHandleT docId; F_ObjHandleT objId; { /* Code to respond to hypertext message goes here. */ } 214 This argument Means message The string from the hypertext command message docId The ID of the document containing the hypertext marker objId The ID of the hypertext marker the user clicked FDK Programmer’s Guide Using hypertext commands in your client’s user interface ... C r e a t i n g Yo u r C l i e n t ’ s U s e r I n t e r f a c e Example Suppose you want to create a command palette with two arrows in it. When the user clicks an arrow, it changes the fill pattern of a selected graphic object in the active document. To make this command palette, create a document with the graphics shown in Figure 3-10. Figure 3-10 Example hypertext markers Assuming your client is registered with the FrameMaker product as myapi, insert the following hypertext markers into the document: In the text column around the up arrow: message myapi 1 In the text column around the down arrow: message myapi 2 Save the document in View Only format. FDK Programmer’s Guide 215 7 C r e a t i n g Yo u r C l i e n t ’ s U s e r I n t e r f a c e Using hypertext commands in your client’s user interface To respond to the user clicking one of the arrows, add the following code to your client: . . . #define UPARROW 1 #define DOWNARROW 2 VoidT F_ApiMessage(message, docId, objId) StringT message; F_ObjHandleT docId; F_ObjHandleT objId; { F_ObjHandleT targetDocId, targetGraphicId; IntT fillpatt; /* Get ID of active document. Note that View Only documents * are not considered active. */ targetDocId = F_ApiGetId(0, FV_SessionId, FP_ActiveDoc); /* Get ID of selected object in active document. */ targetGraphicId = F_ApiGetId(targetDocId, targetDocId, FP_FirstSelectedGraphicInDoc); if(!targetGraphicId) return; /* Get selected object’s current fill pattern. */ fillpatt = F_ApiGetInt(targetDocId, targetGraphicId, FP_Fill); switch(atoi(message)) { case UPARROW: /* Only 16 patterns available, so reset at 16. */ if (++fillpatt == 16) fillpatt = 0; break; case DOWNARROW: if (--fillpatt == 0) fillpatt = 15; break; } /* Set the fill pattern of the selected graphic. */ F_ApiSetInt(targetDocId, targetGraphicId, FP_Fill, fillpatt); } . . . For this example client to work, you should have the View Only document and one normal document open. Select a graphic in the normal document, then click one of the hypertext markers in the View Only document. 216 FDK Programmer’s Guide Responding to user-initiated events or FrameMaker product operations ... C r e a t i n g Yo u r C l i e n t ’ s U s e r I n t e r f a c e Responding to user-initiated events or FrameMaker product operations Your client can respond when the user initiates certain events or FrameMaker product operations. For example, you may want your client to archive an extra copy of a document each time the user saves it, or to display a special dialog box when the user exits a document. To make your client respond to events, follow these general steps: 1 Request notification for the events. 2 Create a callback function named F_ApiNotify() to respond to the events. These steps are discussed in greater detail in the following sections. Requesting notification for events To receive notification for a particular event, your client must request it by calling F_ApiNotification(). The syntax for F_ApiNotification() is: IntT F_ApiNotification(IntT notification, IntT state); This argument Means notification A constant that specifies the notification point. See the table below for a list of the constants. state Specifies whether to turn notification for the notification point on or off. Specify True to request notification or False to turn notification off. FDK Programmer’s Guide 217 7 C r e a t i n g Yo u r C l i e n t ’ s U s e r I n t e r f a c e Responding to user-initiated events or FrameMaker product operations For most events, there are several notification points, or stages in the event when the FrameMaker product can notify your client. For example, when the FrameMaker product saves a file, there are two notification points: one immediately before and one immediately after it saves the file. The following table lists the notification points and constants the FrameMaker product passes to F_ApiNotify() for some events. Event or operation Notification points Notification constants Frame binary document opened Before checking the type of the file to be opened FA_Note_PreFileType After checking the type of the file to be opened FA_Note_PostFileType Before opening the file FA_Note_PreOpenDoc After opening the file FA_Note_PostOpenDoc Filterable document opened Before checking the type of the file to be opened FA_Note_FilterIn Document saved in Frame binary format Before saving the document FA_Note_PreSaveDoc After saving the document FA_Note_PostSaveDoc Document saved as filterable type Before saving the document FA_Note_FilterOut Document exited Before exiting the document FA_Note_PreQuitDoc After exiting the document FA_Note_PostQuitDoc For a complete list of events and notification points, see “F_ApiNotification()” on page 333 of the FDK Programmer’s Reference. You can request notification in your client’s F_ApiInitialize() callback or anywhere you want in your client. 218 FDK Programmer’s Guide Responding to user-initiated events or FrameMaker product operations ... C r e a t i n g Yo u r C l i e n t ’ s U s e r I n t e r f a c e Example Suppose you want a FrameMaker product to notify your client whenever the user exits a document. To request this notification when your client is first started, write the F_ApiInitialize() callback as follows: . . . VoidT F_ApiInitialize(initialization) IntT initialization; { /* Request notification for exit. */ if (initialization == FA_Init_First) F_ApiNotification(FA_Note_PreQuitDoc, True); } . . . Requesting notification for API filters API client filters do not need to request notification. To receive filter notifications, filters only need to be registered with the FrameMaker product. If they are correctly registered, filters receive the following notifications: This type of filter Receives this notification Import FA_Note_FilterIn Export FA_Note_FilterOut For more information on writing client filters, see “Writing filter clients” on page 472 of the FDK Programmer’s Guide. For more information on registering filters, see the FDK Platform Guide for your platform. FDK Programmer’s Guide 219 7 C r e a t i n g Yo u r C l i e n t ’ s U s e r I n t e r f a c e Responding to user-initiated events or FrameMaker product operations Adding the F_ApiNotify() callback The FrameMaker product notifies your client of events for which it has requested notification by calling its F_ApiNotify() function. Your client should define F_ApiNotify() as follows: VoidT F_ApiNotify(notification, docId, sparm, iparm) IntT notification; F_ObjHandleT docId; StringT sparm; IntT iparm; { /* Code that responds to notifications goes here. */ } This argument Means notification A constant that indicates the event and the notification point (see the table on page 218 for a list of the constants). docId The ID of the active document when the event occurs. For filters, the document into which the filter should import its data; if this is zero, the filter must create a new document. sparm The string, if any, associated with the notification. For example, if the notification is for an Open or Save, sparm specifies the pathname of the affected file. If the notification is for text entry, sparm specifies the text the user typed. Depending on how fast the user is typing, sparm may specify one or several characters at a time. iparm The integer associated with the notification. For example, if notification is FA_NotePreFunction or FA_NotePostFunction, iparm specifies the f-code for the command. F_ApiNotify() can call API functions to get or set object properties or to initiate FrameMaker product operations. The FrameMaker product calls F_ApiNotify() only at the notification points for which your client has requested notification. 220 FDK Programmer’s Guide Responding to user-initiated events or FrameMaker product operations ... C r e a t i n g Yo u r C l i e n t ’ s U s e r I n t e r f a c e For example, the following code prints the name of each document the user opens to the console: . . . VoidT F_ApiInitialize(initialization) IntT initialization; { if (initialization == FA_InitFirst) F_ApiNotification(FA_Note_PostOpenDoc, True); } VoidT F_ApiNotify(notification, docId, sparm, iparm) IntT notification; F_ObjHandleT docId; StringT sparm; IntT iparm; { if (notification == FA_Note_PostOpenDoc) F_Printf(NULL, "The user opened: %s\n", sparm); } . . . Canceling commands Your client can cancel any command or action for which it receives a FA_Note_PreNotificationPoint notification. For example, if it receives the FA_Note_PreQuitDoc notification, it can cancel the Close command and prevent the user from closing a document. FDK Programmer’s Guide 221 7 C r e a t i n g Yo u r C l i e n t ’ s U s e r I n t e r f a c e Responding to user-initiated events or FrameMaker product operations To abort a command, call F_ApiReturnValue(), with the parameter set to FR_CancelOperation, when your client receives notification for the command. For example, the following code cancels the Exit command, preventing the user from closing any documents: . . . F_ApiNotification(FA_Note_PreQuitDoc, True); . . . VoidT F_ApiNotify(notification, docId, sparm, iparm) IntT notification; F_ObjHandleT docId; StringT sparm; IntT iparm; { /* If user is trying to close document, cancel command. */ if (notification == FA_Note_PreQuitDoc) F_ApiReturnValue(FR_CancelOperation); } . . . Responding to text entry and actions that have no specific notifications The API doesn’t provide specific notifications for most user actions. Instead, it provides the following general notifications, which it issues for nearly every user action. 222 Event or operation Notification points Notification constants Any user action that the FrameMaker product processes After the FrameMaker product finishes processing the action FA_Note_BackToUser FrameMaker product command invoked or text entered in a document Before the FrameMaker product executes the command or adds text to the document FA_Note_PreFunction After the FrameMaker product executes the command or adds text to the document FA_Note_PostFunction FDK Programmer’s Guide Responding to user-initiated events or FrameMaker product operations ... C r e a t i n g Yo u r C l i e n t ’ s U s e r I n t e r f a c e The API issues the FA_NoteBackToUser notification after any user action the FrameMaker product processes, including insertion point changes, selection changes, and text entry. This notification is useful if you need to update a modeless dialog box containing settings that are dependent on the insertion point. When the API issues the FA_NoteBackToUser notification, it indicates only that an action occurred; it does not specify which action. If you want to respond to specific actions, use the FA_Note_PreFunction or the FA_Note_PostFunction notification instead of FA_NoteBackToUser. .............................................................................. IMPORTANT: When the FrameMaker product performs a book-wide command (a command that process all documents in a book), it posts an FA_NotePreFunction and FA_NotePostFinction notification for the book file, and for each document in the book. When trapping book-wide frunctions, you should check the value of docId to determine whether it indicates a document or the active book. For example, if you search a book with two documents in it, the FrameMaker product posts the following funtion notifications: FA_Note_PreFunction (start searching book) FA_Note_PreFunction (start searching first document) FA_Note_PostFunction (stop searching first document) FA_Note_PreFunction (start searching second document) FA_Note_PostFunction (stop searching second document) FA_Note_PostFunction (stop searching book) .............................................................................. When the API issues an FA_Note_PreFunction or FA_Note_PostFunction notification, it specifies the user action by setting iparm to a function code (f-code). An f-code is a hexadecimal code that specifies a command or other user action. The following table shows some common f-codes and the commands or user actions they specify. F-code Command or user action PGF_APPLY_TAG The user applied a paragraph format CHAR_APPLY_TAG The user applied a character format TXT_10 The user set the text size to 10 points KBD_OPEN The user chose Open KBD_INPUT The user typed some text KBD_ALIGN The user chose Align FDK Programmer’s Guide 223 7 C r e a t i n g Yo u r C l i e n t ’ s U s e r I n t e r f a c e Responding to user-initiated events or FrameMaker product operations For a complete list of f-codes, see the fcodes.h file shipped with the FDK. If a user action is associated with a text string, the API passes the string to the sparm parameter of your client’s F_ApiNotify() function. For example, when the user types text, the API sets sparm to the text the user typed. 224 FDK Programmer’s Guide Responding to user-initiated events or FrameMaker product operations ... C r e a t i n g Yo u r C l i e n t ’ s U s e r I n t e r f a c e The following table lists some f-codes and the strings that are associated with them. F-code Associated string that the API passes to sparm PGF_APPLY_TAG The name of the paragraph format the user applied. CHAR_APPLY_TAG The name of the character format the user applied. KBD_INPUT The text the user typed. It can be one or more characters depending on how fast the user types. TXT_FAMILY_AND _VARIATION The name of the font family the user chose. Your client can cancel any action for which it receives the FA_Note_PreFunction notification by calling F_ApiReturnValue() with retVal set to FR_CancelOperation. Your client can even cancel text entry. For example, the following code intercepts any text the user attempts to type in a document and prints it to the console: . . . #include "fcodes.h" /* Turn on notification. */ F_ApiNotification(FA_Note_PreFunction, True); . . . VoidT F_ApiNotify(notification, docId, sparm, iparm) IntT notification; F_ObjHandleT docId; StringT sparm; IntT iparm; { if (notification == FA_Note_PreFunction && iparm == KBD_INPUT) { F_Printf(NULL,"The user typed: %s\n", sparm); /* Prevent text from being added to document. */ F_ApiReturnValue(FR_CancelOperation); } } . . . Responding to events initiated by API clients A FrameMaker product notifies your client of any event that it has requested notification for. The event can be initiated directly by the user or by another client. FDK Programmer’s Guide 225 7 C r e a t i n g Yo u r C l i e n t ’ s U s e r I n t e r f a c e Responding to user-initiated events or FrameMaker product operations The Frame API provides a set of functions that allow API clients to programmatically execute Open, Save, and several other FrameMaker product operations. For more information on these functions, see Chapter 4, “Executing Commands with API Functions.” When a client executes an operation with one of these functions, the FrameMaker product notifies all the other API clients that have requested notification for that event1. It does not, however, notify the client that executed the operation. For example, to have your client automatically make an additional copy of a document when the user saves it, use the following code: . . . /* Turn on notification. */ F_ApiNotification(FA_Note_PostSaveDoc, True); . . . VoidT F_ApiNotify(notification, docId, sparm, iparm) IntT notification; F_ObjHandleT docId; StringT sparm; IntT iparm; { /* After the document has been saved, save another copy. */ if (notification == FA_Note_PostSaveDoc) F_ApiSimpleSave(docId, "mybackup.doc", False); } . . . In the example above, F_ApiNotify(), which responds to a Save notification, uses F_ApiSimpleSave() to execute a Save operation itself. This does not result in infinite recursion because the FrameMaker product does not notify the client of the Save operation that it executes itself. ................................. 1. An API client can explicitly instruct a FrameMaker product to suppress notifications to other API clients when it opens or saves a file by setting the FS_DontNotifyAPIClients property of the Open or Save script to True. For more information on properties in the Open and Save scripts, see “F_ApiGetOpenDefaultParams()” on page 212 and “F_ApiGetSaveDefaultParams()” on page 227 of the FDK Programmer’s Reference. 226 FDK Programmer’s Guide Responding to user-initiated events or FrameMaker product operations ... C r e a t i n g Yo u r C l i e n t ’ s U s e r I n t e r f a c e Handling notification for Open operations The Open operation is more complex than most other operations. A FrameMaker product does the following when it opens a file: 1 Determines whether the file is filterable. If the file is filterable, the FrameMaker product issues the FA_Note_FilterIn notification to the appropriate filter and abandons the Open operation. It is up to the filter to finish opening the file. No other client receives any notification. If the file is not filterable, the FrameMaker product continues with the Open operation. 2 Issues an FA_Note_PreFileType notification to all clients that have requested it. This allows clients to uncompress a file if it is compressed, check it out if it is under version control, or perform other operations that may change its type. 3 Checks the file’s type. If the file is a type that the FrameMaker product can’t open, the FrameMaker product displays a warning and cancels the Open operation. If the file is from a previous version of a FrameMaker product, it prompts the user to convert the file or cancel the Open operation. 4 Issues an FA_Note_PostFileType notification to all clients that have requested it. 5 Determines whether the file is a document or a book, and whether its format is Frame binary or MIF. 6 Issues an FA_Note_PreOpenDoc, FA_Note_PreOpenBook, FA_Note_PreOpenMIF, or FA_Note_PreOpenBookMIF notification. 7 Opens the document or book. If the document or book is MIF, the FrameMaker product converts it. 8 Issues an FA_Note_PostOpenDoc, FA_Note_PostOpenMIF, FA_Note_PostOpenBook, or FA_Note_PostOpenBookMIF notification. Normally, you don’t request the FA_Note_PreFileType and FA_Note_PostFileType notifications, because you don’t want to do anything with a file before the FrameMaker product has checked its type. However, if you want to change a file’s contents after the user has selected it but before the FrameMaker product has checked its type, you should request notification for the FA_Note_PreFileType notification point. FDK Programmer’s Guide 227 7 C r e a t i n g Yo u r C l i e n t ’ s U s e r I n t e r f a c e Implementing quick keys For example, suppose you want to uncompress a compressed document file when the user opens it. Normally, when a user attempts to open a compressed file, the FrameMaker product displays an “Unrecognized type” alert and cancels the Open operation when it checks the file’s type. You must uncompress the file after the user has chosen it, but before the FrameMaker product checks its type. To do this, you could use the following code: . . . F_ApiNotification(FA_Note_PreFileType, True); . . . VoidT F_ApiNotify(notification, docId, sparm, iparm) IntT notification; F_ObjHandleT docId; StringT sparm; IntT iparm { if (notification == FA_Note_PreFileType) { /* Code to test if file is compressed goes here. */ F_ApiAlert("Uncompressing file.", FF_ALERT_CONTINUE_NOTE); /* Code to uncompress file goes here. */ } } . . . Implementing quick keys FrameMaker products provide a quick-key interface, which allows the user to choose commands in the document Tag area. In FrameMaker, for example, the user can apply a character format by pressing Esc q c. FrameMaker displays an f: prompt in the Tag area. The user can then choose a character format by typing the first few letters of the format’s name and pressing Return when the format appears in the Tag area. 228 FDK Programmer’s Guide Implementing quick keys ... C r e a t i n g Yo u r C l i e n t ’ s U s e r I n t e r f a c e Your client can implement its own quick-key interface by calling F_ApiQuickSelect(). The syntax for F_ApiQuickSelect() is: IntT F_ApiQuickSelect(F_ObjHandleT docId, StringT prompt, F_StringsT *stringlist); This argument Means docId The ID of the document containing the Tag area in which to display the prompt prompt The prompt that appears in the Tag area stringlist The list of strings from which the user can choose F_ApiQuickSelect() returns the index of the string the user chose or -1 if the user canceled the command. For example, the following code implements the quick-key interface shown in Figure 3-11: . . . F_StringsT fruits; StringT strings[3]; IntT choice; F_ObjHandleT docId; docId = F_ApiGetId(0, FV_SessionId, FP_ActiveDoc); strings[0] = (StringT)"Kumquat"; strings[1] = (StringT)"Durian"; strings[2] = (StringT)"Rambutan"; fruits.len = 3; fruits.val = strings; choice = F_ApiQuickSelect(docId, (StringT)"Fruit:", &fruits); if (choice != -1) F_Printf(NULL, (StringT)"The user chose: %s.\n", strings[choice]); . . . Figure 3-11 Tag area with client-defined quick key FDK Programmer’s Guide 229 7 C r e a t i n g Yo u r C l i e n t ’ s U s e r I n t e r f a c e Freeing system resources by bailing out Freeing system resources by bailing out Instead of leaving your client idle when it’s not executing, you may want to free the system resources it uses. The API provides a function named F_ApiBailOut(), which allows you to do this. When you call F_ApiBailOut(), the FrameMaker product waits until your client returns from the current callback, then exits your client, freeing the system resources it uses. .............................................................................. IMPORTANT: Never call exit(), F_Exit(), or abort() from an API client. If you call one of these functions, the function exits the FrameMaker product and unpredictable results, including data loss, may occur. .............................................................................. After it exits your client, the FrameMaker product continues processing events that affect it. Your client’s menus remain on the menu bar and are still valid. If your client has requested notification for particular events, the FrameMaker product continues to monitor those events. The FrameMaker product also monitors message apiclient hypertext commands that specify your client. If the user chooses one of your client’s menu items or hypertext commands, or initiates an event for which your client requested notification, the FrameMaker product restarts your client, calling its F_ApiInitialize() function with initialization set to FA_Init_Subsequent. After F_ApiInitialize() has returned control, the FrameMaker product also calls the appropriate callback function for the menu choice, hypertext command, or event. .............................................................................. IMPORTANT: If your client bails out, it loses all its global variable settings. .............................................................................. 230 FDK Programmer’s Guide Freeing system resources by bailing out ... C r e a t i n g Yo u r C l i e n t ’ s U s e r I n t e r f a c e The following code requests notification for the FA_Note_PreQuitDoc notification point and then bails out after the user starts the FrameMaker product. If the user subsequently closes a document, it displays dialog boxes indicating when the FrameMaker product reinitializes the client and when it issues the FA_Note_PreQuitDoc notification. . . . VoidT F_ApiInitialize(initialization) IntT initialization; { switch (initialization){ case FA_Init_First: /* Request notification. */ F_ApiNotification(FA_Note_PreQuitDoc, True); /* Bail out and wait for the event. */ F_ApiBailOut(); break; case FA_Init_Subsequent: F_ApiAlert((StringT)"Client is reinitializing", FF_ALERT_CONTINUE_NOTE); break; } } VoidT F_ApiNotify(notification, docId, filename) IntT notification; F_ObjHandleT docId; StringT filename; { if (notification == FA_Note_PreQuitDoc) F_ApiAlert((StringT)"Client has reinitialized.", FF_ALERT_CONTINUE_NOTE); } FDK Programmer’s Guide 231 7 Executing Commands with API Functions .................................. ..... 4 This chapter discusses how to use Frame API functions to execute FrameMaker product commands programmatically. The API doesn’t provide a function to directly execute each of the commands available in the FrameMaker product user interface. This is because you can achieve the effect of some commands by setting object properties. For example, to set a graphic’s fill pattern, you set the object’s FP_Fill property. For more information on setting object properties, see Chapter 5, “Getting and Setting Properties.” Handling errors When an API function fails, it stores an error code in the global variable, FA_errno. FA_errno retains the error code until another function fails and sets it or until your code explicitly sets it. To determine whether a set of API function calls has failed, initialize FA_errno to FE_Success once before all the calls and check it once after all the calls. To find the error codes a function can generate, look up the function in Chapter 2, “FDK Function Reference,” in the FDK Programmer’s Reference. For a list of all API error codes and their meanings, see the fapidefs.h header file included with FDK or Chapter 5, “Error Codes,” in the FDK Programmer’s Reference. In the interest of brevity, the examples in this chapter do not include error-handling code. However, you should check FA_errno after calling functions that set it. Handling messages and warnings In the user interface, some commands such as Open and Save sometimes need to prompt the user with warnings or messages. The API provides two types of functions to execute these commands: Simple functions allow you to either suppress the messages and warnings entirely or to prompt the user with them. Scriptable functions allow you to specify a response for each possible message or warning. FDK Programmer’s Guide 233 7 Executing Commands with API Functions Handling messages and warnings Using simple functions Simple functions enable you to execute commands such as Save and Open without specifying numerous parameters. They execute these commands in either an interactive or a noninteractive mode. If you call a simple function and specify the interactive mode, the FrameMaker product behaves exactly as it would if the user had initiated the command. If a message or warning condition occurs, the FrameMaker product prompts the user. For example, if you call F_ApiSimpleOpen() in the interactive mode, the FrameMaker product displays the Open dialog box and prompts the user to choose a file to open. If the user chooses a text file, the FrameMaker product displays a Reading Text File dialog box. If you are sure that executing a command won’t do something undesirable, and you don’t want the FrameMaker product to display error and warning messages, call a simple function in noninteractive mode. Be careful when you do this, because you may inadvertently destroy data. For example, suppose you attempt to save a file by calling F_ApiSimpleSave() in the noninteractive mode. If the file already exists, the FrameMaker product overwrites it without warning your client or the user. Noninteractive mode is useful for clients that need to carry out tasks without a user present. Using scriptable functions To specify a response for each possible message or warning that the FrameMaker product may issue while executing a command, use a scriptable function to execute the command. When you call a scriptable function, you pass it a script or property list that contains properties corresponding to possible messages or warnings. For most messages and warnings, you either specify a Yes, No, or Cancel response, or you can instruct the FrameMaker product to prompt the user for the response. Scriptable functions return detailed information on how the FrameMaker product executes a command. For example, the scriptable Open function F_ApiOpen() returns information, such as whether the file was filtered and whether an Autosave file was used. The API provides a function named F_ApiAllocatePropVals(), which allocates a property list that you can use with scriptable functions. The API also provides functions that create default scripts for the different scriptable functions. You can use these functions to get a default script and then customize the script by changing individual properties. 234 FDK Programmer’s Guide Opening documents and books ... Executing Commands with API Functions Opening documents and books The API provides two functions to open a document or book: F_ApiSimpleOpen() is an easy-to-use function for opening a document or book. F_ApiOpen() allows you to script the process of opening a document or book. Opening a document or book with F_ApiSimpleOpen() The syntax for F_ApiSimpleOpen() is: F_ObjHandleT F_ApiSimpleOpen(StringT fileName, BoolT interactive); This argument Means fileName The absolute pathname of the file to open. For information on how filenames and paths on different platforms are expressed, see the FDK Platform Guide for your platform. interactive Specifies whether the FrameMaker product displays messages and warnings to the user. If F_ApiSimpleOpen() is successful, it returns the ID of the FO_Doc or FO_Book object that represents the document or book that it opened. If a condition (such as a nonexistent file) makes it impossible to open a file, F_ApiSimpleOpen() aborts the operation and returns 0. If you set interactive to True, the FrameMaker product displays the Open dialog box. It uses the path specified by the session property FP_OpenDir as the default path. The FrameMaker product also displays all the other messages and warnings it would normally display if the user chose the Open command. For example, if a document contains fonts that are not available in the current session, the FrameMaker product displays a “Fonts Unavailable. Open Anyway?” dialog box. If the user clicks Cancel, F_ApiSimpleOpen() aborts the operation and returns 0. If you set interactive to False, the FrameMaker product does not display the Open dialog box or other messages and warnings. If it is necessary to modify a file to continue opening it, F_ApiSimpleOpen() aborts the operation without notifying the user, and returns 0. For example, if a document contains fonts that are not available, F_ApiSimpleOpen() aborts the Open operation instead of converting the fonts. FDK Programmer’s Guide 235 7 Executing Commands with API Functions Opening documents and books Example The following code opens a document named /tmp/my.doc and displays its ID: . . . #include "futils.h" F_ObjHandleT docId; UCharT msg[256]; docId = F_ApiSimpleOpen((StringT)"/tmp/my.doc", False); if (!docId) F_ApiAlert((StringT)"Couldn’t open.",FF_ALERT_CONTINUE_NOTE); else { F_Sprintf(msg, (StringT)"my.doc’s ID is 0x%x.", docId); F_ApiAlert(msg, FF_ALERT_CONTINUE_NOTE); } . . . Opening a document or book with F_ApiOpen() To open a document or book and programmatically specify responses to warnings and messages that the FrameMaker product issues, use F_ApiOpen(). With F_ApiOpen(), you can specify aspects of the Open operation, such as whether to make a document visible and whether to use an Autosave file. You can specify all aspects of the operation, or you can specify some aspects and allow the user to decide others. For example, you can instruct the FrameMaker product to only open a MIF file but allow the user to choose the file. To use F_ApiOpen(), you should first understand property lists and how to manipulate them directly. For more information on this subject, see “Representing object characteristics with properties” on page 63 and “Manipulating property lists directly” on page 293. 236 FDK Programmer’s Guide Opening documents and books ... Executing Commands with API Functions The syntax for F_ApiOpen() is: F_ObjHandleT F_ApiOpen(StringT fileName, F_PropValsT *openParamsp, F_PropValsT **openReturnParamspp); This argument Means fileName The absolute pathname of the file to open. If you are using F_ApiOpen() to create a document, specify the template name. openParamsp A property list (script) that tells the FrameMaker product how to open the file and how to respond to errors and other conditions that arise. Use F_ApiGetOpenDefaultParams() or F_ApiAllocatePropVals() to create and allocate memory for this property list. To use the default list, specify NULL. openReturnParamspp A property list that returns the pathname and provides information on how the FrameMaker product opened the file. .............................................................................. Always initialize the pointer to the property list that you specify for openReturnParamspp to NULL before you call F_ApiOpen(). I M P O RTA NT: .............................................................................. If F_ApiOpen() is successful, it returns the ID of the opened document or book. Otherwise, it returns 0. To call F_ApiOpen(), do the following: 1 Initialize the pointer to the openReturnParamspp property list to NULL. 2 Create an openParamsp property list. You can get a default list by calling F_ApiGetOpenDefaultParams(), or you can create a list from scratch. 3 Call F_ApiOpen(). 4 Check the Open status. Check the returned values in the openReturnParamspp list for the name of the opened file and other information about how the FrameMaker product opened the file. FDK Programmer’s Guide 237 7 Executing Commands with API Functions Opening documents and books 5 Deallocate memory for the openParamsp and openReturnParamspp property lists. Use F_ApiDeallocatePropVals() to deallocate memory for the lists. Steps 2, 4, and 5 are discussed in the following sections. Creating an openParamsp script with F_ApiGetOpenDefaultParams() If you need to specify a number of properties in the openParamsp property list, it is easiest to get a default list with F_ApiGetOpenDefaultParams() and then modify individual properties in the list. The syntax for F_ApiGetOpenDefaultParams() is: F_PropValsT F_ApiGetOpenDefaultParams(); The following table lists some of the properties in the property list returned by F_ApiGetOpenDefaultParams(). The first value listed for each property is the default value used in the list. You can change the list to use the other listed values. For the complete list of properties in the property list, see “F_ApiGetOpenDefaultParams()” on page 212 in the FDK Programmer’s Reference. Property Instruction or situation and possible values FS_ShowBrowser Display Open dialog box. False: don’t display it. True: display it. FS_OpenDocViewOnly Open document as View Only. False: don’t open as View Only. True: open as View Only. FS_NameStripe String specifying the name that appears on the document title bar. NULL. FS_NewDoc Create a new document. False: open an existing document. True: create a new document. 238 FDK Programmer’s Guide Opening documents and books ... Executing Commands with API Functions For example, to get a default openParamsp property list and modify it so that it instructs F_ApiOpen() to show the Open dialog box, use the following code: . . . F_ObjHandleT docId; F_PropValsT params, *returnParamsp = NULL; IntT i; /* Get a default property list. */ params = F_ApiGetOpenDefaultParams(); /* If F_ApiGetOpenDefaultParams() fails, len will be 0. */ if(params.len == 0) return; /* Get index of FS_ShowBrowser property, then set it to True. */ i = F_ApiGetPropIndex(¶ms, FS_ShowBrowser); params.val[i].propVal.u.ival = True; /* Change default to /tmp when Open dialog box appears. */ F_ApiSetString(0, FV_SessionId, FP_OpenDir, "/tmp"); docId = F_ApiOpen("", ¶ms, &returnParamsp); F_ApiDeallocatePropVals(¶ms); F_ApiDeallocatePropVals(returnParamsp); . . . The API allocates memory for the property list created by F_ApiGetOpenDefaultParams(). Use F_ApiDeallocatePropVals() to free the property list when you are done with it. For another example of how to call F_ApiOpen() using a default property list created by F_ApiGetOpenDefaultParams(), see “F_ApiGetOpenDefaultParams()” on page 212 in the FDK Programmer’s Reference. Creating an openParamsp script from scratch If you only need to specify a few properties when you call F_ApiOpen(), it is most efficient to create a property list from scratch. To create the property list, you must allocate memory for it and then set up the individual properties. FDK Programmer’s Guide 239 7 Executing Commands with API Functions Opening documents and books To allocate memory for the property list, use the API convenience function, F_ApiAllocatePropVals(). The syntax for F_ApiAllocatePropVals() is: F_PropValsT F_ApiAllocatePropVals(IntT numProps); This argument Means numProps The number of properties for which to allocate memory For example, the following code creates an openParamsp property list that instructs F_ApiOpen() to show the Open dialog box: . . . F_ObjHandleT docId; F_PropValsT params, *returnParamsp = NULL; /* Allocate memory for the list. */ params = F_ApiAllocatePropVals(1); /* Set up the FS_ShowBrowser property and set it to True. */ params.val[0].propIdent.num = FS_ShowBrowser; params.val[0].propVal.valType = FT_Integer; params.val[0].propVal.u.ival = True; docId = F_ApiOpen("", ¶ms, &returnParamsp); F_ApiDeallocatePropVals(¶ms); F_ApiDeallocatePropVals(returnParamsp); . . . The API allocates memory for the property list created by F_ApiAllocatePropVals(). Use F_ApiDeallocatePropVals() to free the property list when you are done with it. 240 FDK Programmer’s Guide Opening documents and books ... Executing Commands with API Functions Checking the Open status F_ApiOpen() stores a pointer to a property list (F_PropValsT structure) in openReturnParamspp. To get the name of the file that F_ApiOpen() opened and other information about how F_ApiOpen() opened the file, check this property list. It includes the properties shown in the following table. Property Meaning and possible values FS_OpenedFileName A string that specifies the opened file’s pathname. If you scripted FS_ShowBrowser, or the file was filtered, or you didn’t specify the pathname, this pathname can be different from the one you specified in the Open script. FS_OpenNativeError The error condition. If the file is opened successfully, it is set to FE_Success. For a complete list of the other values it can be set to, see “F_ApiOpen()” on page 349 in the FDK Programmer’s Reference. FS_OpenStatus A bit field indicating what happened when the file was opened. For a complete list of the possible status flags, see “F_ApiOpen()” on page 349 in the FDK Programmer’s Reference. The FS_OpenNativeError property and the FA_errno global variable indicate the result of a call to F_ApiOpen(). The FS_OpenStatus flags indicate how or why this result occurred. For example, if you attempt to open a file with F_ApiOpen() and the Open operation is canceled, FS_OpenNativeError and FA_errno are set to FE_Canceled. If the operation was canceled because the user canceled it, the FV_UserCanceled bit of the FS_OpenStatus property list is set. The API provides a function named F_ApiCheckStatus(), which allows you to determine if a particular FS_OpenStatus bit is set. The syntax for F_ApiCheckStatus() is: IntT F_ApiCheckStatus(F_PropValsT *p, IntT statusBit); This argument Means p The openReturnParamspp property list returned by F_ApiOpen() statusBit The status bit you want to test FDK Programmer’s Guide 241 7 Executing Commands with API Functions Opening documents and books If the specified bit is set, F_ApiCheckStatus() returns True. For example, the following code determines if an Open operation was canceled because a document used unavailable fonts: . . . F_ObjHandleT docId; F_PropValsT params, *returnParamsp = NULL; /* Get default property list. */ params = F_ApiGetOpenDefaultParams(); docId = F_ApiOpen("/tmp/my.doc", ¶ms, &returnParamsp); if (F_ApiCheckStatus(returnParamsp, FV_CancelFontsMapped)) F_ApiAlert("Canceled because my.doc has unavailable fonts.", FF_ALERT_CONTINUE_NOTE); /* Deallocate property lists. */ F_ApiDeallocatePropVals(¶ms); F_ApiDeallocatePropVals(returnParamsp); . . . The API also provides a convenience function named F_ApiPrintOpenStatus(), which prints the Open status values to the Frame console. F_ApiPrintOpenStatus() is useful for debugging clients that use F_ApiOpen(). For more information, see “F_ApiPrintOpenStatus()” on page 364 in the FDK Programmer’s Reference. Deallocating Open script property lists After you are done with the Open script property lists, call the API convenience function, F_ApiDeallocatePropVals(), to free the memory they use. The syntax for F_ApiDeallocatePropVals() is: VoidT F_ApiDeallocatePropVals(F_PropValsT *pvp); 242 This argument Means pvp The property list FDK Programmer’s Guide Opening documents and books ... Executing Commands with API Functions Example The following code opens a document named /tmp/my.doc. It creates a property list that instructs F_ApiOpen() to open the document as View Only and to display the title, Doc, in the title bar. . . . #include "fstrings.h" F_PropValsT params, *returnParamsp = NULL; F_ObjHandleT docId; /* Allocate memory for Open script with two properties. */ params = F_ApiAllocatePropVals(2); if(params.len == 0) return; /* Force title displayed on title bar to be "Doc". */ params.val[0].propIdent.num = FS_NameStripe; params.val[0].propVal.valType = FT_String; params.val[0].propVal.u.sval = (StringT)F_StrCopyString("Doc"); /* Open the file as View Only. */ params.val[1].propIdent.num = FS_OpenDocViewOnly; params.val[1].propVal.valType = FT_Integer; params.val[1].propVal.u.ival = True; /* Open /tmp/my.doc. */ docId = F_ApiOpen("/tmp/my.doc", ¶ms, &returnParamsp); /* Free memory used by the Open scripts. */ F_ApiDeallocatePropVals(¶ms); F_ApiDeallocatePropVals(returnParamsp); . . . FDK Programmer’s Guide 243 7 Executing Commands with API Functions Creating documents Creating documents To create a new document, you can use the following functions: F_ApiSimpleNewDoc() is an easy-to-use function that allows you to specify a template and interactive or noninteractive modes. F_ApiCustomDoc() uses the FrameMaker product’s default new document template and some parameters that you specify to create the new document. F_ApiOpen() allows you to script the New operation. For information on creating books, see “Creating a book” on page 361. The following sections describe how to create a new document in greater detail. Creating a document with F_ApiSimpleNewDoc() To create a new document from a specific template, use F_ApiSimpleNewDoc(). The syntax for F_ApiSimpleNewDoc() is: F_ObjHandleT F_ApiSimpleNewDoc(StringT templateName, IntT interactive); This argument Means templateName The absolute pathname of the template to use. For information on how filenames and paths on different platforms are expressed, see the FDK Platform Guide for that platform. interactive Specifies whether the FrameMaker product displays messages and warnings to the user. If you set interactive to True, the FrameMaker product creates a document from the specified template and displays messages and warnings to the user. If you set interactive to False, the FrameMaker product does not display messages and warnings; if the FrameMaker product encounters a condition for which it normally displays a dialog box, F_ApiSimpleNewDoc() attempts to do what’s necessary to continue creating the file. If F_ApiSimpleNewDoc() is successful, it returns the ID of the document it created; otherwise, it returns 0. You don’t provide the name for the new document until you save it. .............................................................................. I M P O RTA NT: If you call F_ApiSimpleNewDoc() with interactive set to True and the user clicks Portrait, Custom, or Landscape in the New dialog box, F_ApiSimpleNewDoc() does not create a document. It returns 0 and sets 244 FDK Programmer’s Guide Creating documents ... Executing Commands with API Functions FA_errno to FE_WantsPortrait, FE_WantsCustom, or FE_WantsLandscape. It is up to your client to create a portrait, custom, or landscape document by calling F_ApiCustomDoc(). For more information on creating custom documents, see “Creating a custom document,” next. .............................................................................. Example The following code creates a document from the /templates/Reports/Report1 template and saves it as /tmp/mynew.doc. It then uses F_ApiSimpleSave() to save the the document. For more information on F_ApiSimpleSave(), see “Saving documents and books” on page 251 . . . F_ObjHandleT docId; docId = F_ApiSimpleNewDoc("/templates/Reports/Report1", False); if (!docId) F_ApiAlert("Can’t create document.", FF_ALERT_CONTINUE_NOTE); else F_ApiSimpleSave(docId, "/tmp/mynew.doc", False); . . . Creating a custom document To create a custom new document, use F_ApiCustomDoc(). This function uses the FrameMaker product’s default new-document template to create the custom document. For more information on the default new-document template, see “Documents” on page 73. The syntax for F_ApiCustomDoc() is: F_ObjHandleT F_ApiCustomDoc(MetricT width, MetricT height, IntT numCols, MetricT columnGap, MetricT topMargin, MetricT botMargin, MetricT leftinsideMargin, MetricT rightoutsideMargin, IntT sidedness, BoolT makeVisible); FDK Programmer’s Guide 245 7 Executing Commands with API Functions Creating documents This argument Means width Page width. The Frame API expresses linear measurements with MetricT values. For more information on MetricT values, see Chapter 4, “Data Types and Structures Reference,” in the FDK Programmer’s Reference. height Page height. numCols Default number of columns. columnGap Default column spacing. topMargin Page top margin. botMargin Page bottom margin. leftinsideMargin Left margin (for single-sided documents) or the inside margin (for double-sided documents). rightoutsideMargin Right margin (for single-sided documents) or the outside margin (for double-sided documents). sidedness Constant that specifies whether the document is single-sided or double-sided and on which side the document starts. See the following table for the list of constants. makeVisible Specifies whether to make the document visible. True makes it visible. The sidedness argument can have any of the values shown in the following table. sidedness constant New document page characteristics FF_Custom_SingleSided Single-sided FF_Custom_FirstPageRight Double-sided, starting with a right page FF_Custom_FirstPageLeft Double-sided, starting with a left page If successful, F_ApiCustomDoc() returns the ID of the document it created. Otherwise, it returns 0. 246 FDK Programmer’s Guide Creating documents ... Executing Commands with API Functions Example The following code creates a custom document with the characteristics specified in the dialog box in Figure 4-1: . . . #include "fmetrics.h" #define in (MetricT)(65536*72) /* A Frame metric inch */ F_ObjHandleT docId; docId = F_ApiCustomDoc(F_MetricFractMul(in,17,2), 11*in, 1, F_MetricFractMul(in,1,4), in, in, in, in, FF_Custom_SingleSided, True); . . . Figure 4-1 Specifications for custom document Creating a document with F_ApiOpen() To create a document with F_ApiOpen(), set the FS_NewDoc property in the openParamsp script to True. For the syntax of F_ApiOpen(), see “Opening a document or book with F_ApiOpen()” on page 236. When you use F_ApiOpen() to create a document, set fileName to the name of the template that you want to use. You don’t provide the name for the new document until you save it. FDK Programmer’s Guide 247 7 Executing Commands with API Functions Creating documents For example, the following code creates a document from a template named /tmp/template and saves it as /tmp/mynew.doc. . . . F_ObjHandleT docId; F_PropValsT params, *returnParamsp = NULL; params = F_ApiAllocatePropVals(1); if(params.len == 0) return; /* Set up the FS_NewDoc property and set it to True. */ params.val[0].propIdent.num = FS_NewDoc; params.val[0].propVal.valType = FT_Integer; params.val[0].propVal.u.ival = True; docId = F_ApiOpen("/tmp/template", ¶ms, &returnParamsp); /* See “Saving documents and books” on page 251 for syntax. */ F_ApiSimpleSave(docId, "/tmp/mynew.doc", False); /* Deallocate property lists. */ F_ApiDeallocatePropVals(¶ms); F_ApiDeallocatePropVals(returnParamsp); . . . .............................................................................. If you are creating a document with F_ApiOpen() and you display the New dialog box (by setting FS_ShowBrowser to True), the user may click Portrait, Custom, or Landscape. If this occurs, F_ApiOpen() does not create a new document. It returns 0 and sets FA_errno to FE_WantsPortrait, FE_WantsCustom, or FE_WantsLandscape. It is up to your client to create a portrait, custom, or landscape document by calling F_ApiCustomDoc(). I M P O RTA NT: .............................................................................. 248 FDK Programmer’s Guide Printing documents and books ... Executing Commands with API Functions Printing documents and books To print a document or book, use F_ApiSilentPrintDoc(). F_ApiSilentPrintDoc() uses the default print settings for a document. The default print settings are the settings that appear in the Print dialog box when the user attempts to print the document in the user interface. The syntax for F_ApiSilentPrintDoc() is: IntT F_ApiSilentPrintDoc(F_ObjHandleT docId); This argument Means docId The ID of the document or book to print When you call F_ApiSilentPrintDoc(), the FrameMaker product doesn’t notify the user about error or warning conditions that occur when it attempts to print. To determine whether an error occurred, check FA_errno. Changing the print settings for a document When you print a document in the user interface, you can change the print settings in the Print dialog box. FrameMaker products save most print settings with a document. For example, if you set the scale to 90 percent and print the document in the same session or save the document, the default setting for the scale will be 90 percent. Similarly, if an API client calls F_ApiSilentPrintDoc() to print the document, the scale will be 90 percent, if the client doesn’t change it. The API represents a document’s print settings with a set of document properties. For example, a document’s FP_PrintNumCopies property specifies the number of copies of the document to print. To change a print setting programmatically, you change the property that represents it. For more information on changing properties, see Chapter 5, “Getting and Setting Properties.” For a list of document print properties, see “Document print properties” on page 806 in the FDK Programmer’s Reference. Examples The following code opens a document named /tmp/my.doc and prints it using the default print settings: . . . F_ObjHandleT docId; docId = F_ApiSimpleOpen("/tmp/my.doc", False); F_ApiSilentPrintDoc(docId); . . . FDK Programmer’s Guide 249 7 Executing Commands with API Functions Printing documents and books The following code opens /tmp/my.doc and modifies its default print settings so that the FrameMaker product will print two copies of the document to a printer named ps2. It does this by setting the document properties that specify the number of copies (FP_PrintNumCopies) and the printer (FP_PrinterName) to 2 and ps2, respectively: . . . F_ObjHandleT docId; /* Open the document. */ docId = F_ApiSimpleOpen("/tmp/my.doc", False); /* Change my.doc’s print properties. */ F_ApiSetInt(FV_SessionId, docId, FP_PrintNumCopies, 2); F_ApiSetString(FV_SessionId, docId, FP_PrinterName, "ps2"); F_ApiSilentPrintDoc(docId); . . . If you save /tmp/my.doc or attempt to print it within the same session, the default printer will be ps2 and the default number of copies will be 2 unless your client or the user changes the values of FP_PrinterName and FP_PrintNumCopies. 250 FDK Programmer’s Guide Saving documents and books ... Executing Commands with API Functions Saving documents and books To save a document or book, use one of the following functions: F_ApiSimpleSave() is an easy-to-use function for saving a document or book. F_ApiSave() allows you to script the process for saving a document or book. Saving a document or book with F_ApiSimpleSave() The syntax for F_ApiSimpleSave() is: F_ObjHandleT F_ApiSimpleSave(F_ObjHandleT docId, StringT saveAsName, IntT interactive); This argument Means docId ID of the document or book to save. saveAsName Name of the pathname to save the document or book to. For information on how filenames and paths on different platforms are represented, see the FDK Platform Guide for that platform. interactive Specifies whether the FrameMaker product displays messages and warnings to the user (True to display messages and warnings). If you set interactive to False and you specify the document or book’s current name, the FrameMaker product saves the document or book under its current name. If you specify another filename for saveAsName, the FrameMaker product saves the document or book to that filename. If you set interactive to True, the FrameMaker product displays the Save dialog box and allows the user to choose a filename. The document or book’s current name appears as the default name. If F_ApiSimpleSave() is successful, it returns the ID of the document it saved. If you save the document under its current name, the returned ID is the same ID you specified in the docId parameter. If you specify another filename for saveAsName, the returned ID is the ID of the new document. If F_ApiSimpleSave() can’t save the file, it returns 0. FDK Programmer’s Guide 251 7 Executing Commands with API Functions Saving documents and books Example The following code opens and then saves a document named /tmp/my.doc. After it has saved the document as /tmp/my.doc, it saves a copy of it as mynew.doc: . . . #include "futils.h" F_ObjHandleT mydocId, mynewdocId; UCharT msg[256]; mydocId = F_ApiSimpleOpen("/tmp/my.doc", False); /* Save my.doc as itself. */ F_ApiSimpleSave(mydocId, "/tmp/my.doc", False); /* Save my.doc as mynew.doc. */ mynewdocId = F_ApiSimpleSave(mydocId, "/tmp/mynew.doc", False); /* If the Save As was successful, display ID of mynew.doc. */ if (!mynewdocId) F_ApiAlert("Couldn’t save as mynew.doc.", FF_ALERT_CONTINUE_NOTE); else { F_Sprintf(msg, "The ID of mynew.doc is 0x%x.", mynewdocId); F_ApiAlert(msg, FF_ALERT_CONTINUE_NOTE); } . . . Saving a document or book with F_ApiSave() To save a document or book and specify responses to warnings and messages that the FrameMaker product issues, use the scriptable save function, F_ApiSave(). With F_ApiSave(), you can specify aspects of the Save operation, such as the file format (for example, MIF or Text Only). You can specify all aspects, or you can specify some and allow the user to decide others. For example, you can specify that the FrameMaker product should save a document as Text Only, but allow the user to decide how to convert the document’s tables to text. 252 FDK Programmer’s Guide Saving documents and books ... Executing Commands with API Functions The syntax for F_ApiSave() is: F_ObjHandleT F_ApiSave(F_ObjHandleT docId, StringT saveAsName, F_PropValsT *saveParamsp, F_PropValsT **saveReturnParamspp); This argument Means docId The ID of the document or book to save. saveAsName The pathname to save the document or book to. saveParamsp A property list that tells the FrameMaker product how to save the file and how to respond to errors and other conditions. Use F_ApiGetSaveDefaultParams() or F_ApiAllocatePropVals() to create and allocate memory for this property list. To use the default list, specify NULL. saveReturnParamspp A property list that returns information about how the FrameMaker product saved the file. .............................................................................. Always initialize the pointer to the property list that you specify for saveReturnParamspp to NULL before you call F_ApiSave(). I M P O RTA NT: .............................................................................. If F_ApiSave() is successful, it returns the ID of the document or book it saved. If F_ApiSave() performs a Save operation, it returns the ID that you specified in the docId parameter. If F_ApiSave() performs a Save As operation, it returns the ID of the new document or book. If F_ApiSave() can’t save a file, it returns 0. To call F_ApiSave(), do the following: 1 Initialize the pointer to the saveReturnParamspp property list to NULL. 2 Create a saveParamsp property list. You can get a default list by calling F_ApiGetSaveDefaultParams(), or you can create a list from scratch. 3 Call F_ApiSave(). 4 Check the Save status. Check the returned values in the saveReturnParamspp list for the name of the saved file and other information about how the FrameMaker product saved the file. 5 Deallocate the saveParamsp and saveReturnParamspp property lists. Steps 2, 4, and 5 are discussed in the following sections. FDK Programmer’s Guide 253 7 Executing Commands with API Functions Saving documents and books Creating a saveParamsp script with F_ApiGetSaveDefaultParams() The API provides a function named F_ApiGetSaveDefaultParams() that creates a default saveParamsp property list. If you are setting a number of properties, it is easiest to use F_ApiGetSaveDefaultParams() to get a default property list and then change individual properties as needed. The syntax for F_ApiGetSaveDefaultParams() is: F_PropValsT F_ApiGetSaveDefaultParams(); The following table lists some of the properties in the property list returned by F_ApiGetSaveDefaultParams(). The first value listed for each property is the default value returned by F_ApiGetSaveDefaultParams(). You can change the list to use the other listed values. Property Meaning and possible values FS_FileType Specifies the type of file to save to FV_SaveFmtBinary: save in Frame binary format FV_SaveFmtInterchange: save as MIF FV_SaveFmtStationery: save in Stationery format FV_SaveFmtViewOnly: save as View Only FV_SaveFmtText: save as Text Only FV_SaveFmtSgml: save as SGML FV_SaveFmtPdf: save as PDF FS_AlertUserAboutFailure Specifies whether to notify the user if something unusual occurs while the file is being saved False: don’t notify user True: notify user FS_SaveMode Specifies whether to use Save or Save As mode FV_ModeSaveAs: use Save As mode FV_ModeSave: use Save mode For the complete property list returned by F_ApiGetSaveDefaultParams(), see “F_ApiGetSaveDefaultParams()” on page 227 in the FDK Programmer’s Reference. 254 FDK Programmer’s Guide Saving documents and books ... Executing Commands with API Functions For example, to get a default saveParamsp property list and modify it so that it instructs F_ApiSave() to save the active document as Text Only, use the following code: . . . F_PropValsT params, *returnParamsp = NULL; F_ObjHandleT mydocId; IntT i; /* Get the ID of the active document. */ mydocId = F_ApiGetId(0, FV_SessionId, FP_ActiveDoc); /* Get default property list. */ params = F_ApiGetSaveDefaultParams(); /* Get index of FS_FileType property and set it to Text Only. */ i = F_ApiGetPropIndex(¶ms, FS_FileType); params.val[i].propVal.u.ival = FV_SaveFmtText; /* Save to text only file named my.txt. */ F_ApiSave(mydocId, "/tmp/my.txt", ¶ms, &returnParamsp); /* Deallocate property lists. */ F_ApiDeallocatePropVals(¶ms); F_ApiDeallocatePropVals(returnParamsp); . . . The API allocates memory for the property list created by F_ApiGetSaveDefaultParams(). Use F_ApiDeallocatePropVals() to free the property list when you are done with it. Creating a saveParamsp script from scratch If you want to specify only a few properties when you call F_ApiSave(), it is most efficient to create a property list from scratch. To create the property list, you must allocate memory for it, and then set up the individual properties. FDK Programmer’s Guide 255 7 Executing Commands with API Functions Saving documents and books Use the API convenience function, F_ApiAllocatePropVals(), to allocate memory for the property list. For example, the following code creates a saveParamsp property list that instructs F_ApiSave() to save a file as text only: . . . F_PropValsT params, *returnParamsp = NULL; F_ObjHandleT mydocId; /* Get the ID of the active document. */ mydocId = F_ApiGetId(0, FV_SessionId, FP_ActiveDoc); /* Allocate memory for the list. */ params = F_ApiAllocatePropVals(1); /* Set up the FS_FileType property and set it to True. */ params.val[0].propIdent.num = FS_FileType; params.val[0].propVal.valType = FT_Integer; params.val[0].propVal.u.ival = FV_SaveFmtText; F_ApiSave(mydocId, "/tmp/my.txt", ¶ms, &returnParamsp); . . . Checking Save status F_ApiSave() stores a pointer to a property list in saveReturnParamspp. This property list provides information on how the FrameMaker product saved the file. It includes the properties shown in the following table. Property Meaning and Possible Values FS_SavedFileName A string that specifies the saved file’s pathname. FS_SaveNativeError The error condition. If the file is saved successfully, it is set to FE_Success. For a complete list of the other values it can be set to, see “F_ApiSave()” on page 393 in the FDK Programmer’s Reference. FS_SaveStatus A bit field indicating what happened when the file was saved. For a complete list of the possible status flags, see “F_ApiSave()” on page 393 in the FDK Programmer’s Reference. The FS_SaveNativeError property and the FA_errno value indicate the result of the call to F_ApiSave(). The FS_SaveStatus flags indicate how or why this result occurred. To determine if a particular FS_SaveStatus bit is set, use F_ApiCheckStatus(). 256 FDK Programmer’s Guide Saving documents and books ... Executing Commands with API Functions Example The following code opens /tmp/my.doc and saves it as a View Only document named /tmp/viewonly.doc. It gets the name of the saved file from the returned property list and displays it. . . . #include "futils.h" IntT i; UCharT msg[1024]; F_PropValsT params, *returnParamsp = NULL; F_ObjHandleT mydocId, viewonlydocId; params = F_ApiAllocatePropVals(1); mydocId = F_ApiSimpleOpen("/tmp/my.doc", False); if(!mydocId) return; /* Set file type to View Only. */ params.val[0].propIdent.num = FS_FileType; params.val[0].propVal.valType = FT_Integer; params.val[0].propVal.u.ival = FV_SaveFmtViewOnly; /* Save document as viewonly.doc. */ viewonlydocId = F_ApiSave(mydocId, "/tmp/viewonly.doc", ¶ms, &returnParamsp); /* Get index of property specifying filename and display it. */ i = F_ApiGetPropIndex(returnParamsp, FS_SavedFileName); F_Sprintf(msg, "Saved: %s", returnParamsp->val[i].propVal.u.sval); F_ApiAlert(msg, FF_ALERT_CONTINUE_NOTE); /* Deallocate Save scripts. */ F_ApiDeallocatePropVals(¶ms); F_ApiDeallocatePropVals(returnParamsp); . . . FDK Programmer’s Guide 257 7 Executing Commands with API Functions Closing documents and books Closing documents and books To close a document or book, use F_ApiClose(). The syntax for F_ApiClose() is: IntT F_ApiClose(F_ObjHandleT Id, IntT flags); This argument Means Id The ID of the document, book, or session to close. To close the session, specify FV_SessionId. flags Specifies whether to abort or to close open documents or books if they have unsaved changes. Set the FF_CLOSE_MODIFIED flag to close open documents and books regardless of their state. F_ApiClose() behaves somewhat differently than the Close command in the user interface. If there are unsaved changes in a file and you set FF_CLOSE_MODIFIED for the flags argument, F_ApiClose() abandons the changes and closes the file anyway. If you set flags to 0, F_ApiClose() aborts the Close operation and returns FE_DocModified. .............................................................................. If you are closing an individual document, make sure Id specifies a valid document ID and not 0. If Id is set to 0, F_ApiClose() quits the Frame session (because FV_SessionId is defined as 0). I M P O RTA NT: .............................................................................. 258 FDK Programmer’s Guide Closing documents and books ... Executing Commands with API Functions Examples The following code closes the active document. If the document has unsaved changes, the client prompts the user. . . . F_ObjHandleT docId; IntT resp = 0; /* Get the ID of active document. Return if there isn’t one. */ docId = F_ApiGetId(0, FV_SessionId, FP_ActiveDoc); if(!docId) return; /* See if document has been modified. */ if (F_ApiGetInt(FV_SessionId, docId, FP_DocIsModified)) resp = F_ApiAlert("Document was changed, close it anyway?", FF_ALERT_OK_DEFAULT); if (!resp) F_ApiClose(docId, FF_CLOSE_MODIFIED); . . . The following code closes the active document unless it has unsaved changes: . . . F_ObjHandleT docId; docId = F_ApiGetId(0, FV_SessionId, FP_ActiveDoc); if(!docId) return; if (F_ApiClose(docId, 0)) F_ApiAlert("Unsaved changes. Can’t close.", FF_ALERT_CONTINUE_WARN); . . . FDK Programmer’s Guide 259 7 Executing Commands with API Functions Quitting a Frame session Quitting a Frame session To quit a Frame session, call F_ApiClose(), with Id set to FV_SessionId. For the syntax of F_ApiClose(), see “Closing documents and books” on page 258. For example, to close all the open documents and books in the current Frame session, and quit the session, use the following code: . . . F_ApiClose(FV_SessionId, FF_CLOSE_MODIFIED); . . . Becaus of the flag set to FF_CLOSE_MODIFIED, if any books or documents have been changed, the FrameMaker product abandons the changes. Comparing documents and books To compare two versions of a document or book using a FrameMaker product’s built-in comparison feature, use F_ApiCompare(). The syntax for F_ApiCompare() is: F_CompareRetT F_ApiCompare(F_ObjHandleT olderId, F_ObjHandleT newerId, IntT flags, StringT insertCondTag, StringT deleteCondTag, StringT replaceText, IntT compareThreshold); 260 This argument Means olderId The ID of the older version of the document or book. newerId The ID of the newer version of the document or book. flags Bit flags that specify how to generate the summary and composite documents. insertCondTag The condition tag to apply to insertions shown in the composite document. For no insert condition tag, specify NULL. deleteCondTag The condition tag to apply to deletions shown in the composite document. For no delete condition tag, specify NULL. FDK Programmer’s Guide Comparing documents and books ... Executing Commands with API Functions This argument Means replaceText Text to appear in place of the deleted text. For no replacement text, specify NULL. compareThreshold Percentage of words that can change before paragraphs are considered not equal. If two paragraphs are equal, word differences between them are shown within a paragraph in the composite document. If a paragraph is not equal to another, it is marked inserted or deleted. To specify an 85% threshold, set compareThreshold to 85. The default value is 75. The F_CompareRetT structure is defined as: typedef struct { F_ObjHandleT sumId; /* ID of the summary document */ F_ObjHandleT compId; /* ID of the composite document */ } F_CompareRetT; The following values can be ORed into the flags argument. This value Means FF_CMP_SUMMARY_ONLY Generate summary document, but not composite document FF_CMP_CHANGE_BARS Turn on change bars in the composite document FF_CMP_HYPERLINKS Put hypertext links in the summary document FF_CMP_SUMKIT Open the summary document FF_CMP_COMPKIT Open the composite document If you specify the FF_CMP_SUMKIT or FF_CMP_COMPKIT flags, F_ApiCompare() opens the summary and comparison documents and returns their IDs in the F_CompareRetT structure. It does not make these documents visible to the user. If you want them to be visible, you must set each of the document’s FP_DocIsOnScreen properties to True. FDK Programmer’s Guide 261 7 Executing Commands with API Functions Comparing documents and books Example The following code opens two documents and compares them as specified in the dialog boxes shown in Figure 4-2. It makes the summary document visible. . . . F_ObjHandleT oldId, newId; IntT flags; F_CompareRetT cmp; oldId = F_ApiSimpleOpen("/tmp/1Chapter", False); newId = F_ApiSimpleOpen("/tmp/1Chapter.new", False); flags = FF_CMP_CHANGE_BARS | FF_CMP_COMPKIT | FF_CMP_SUMKIT; cmp = F_ApiCompare(oldId, newId, flags, "Comment", "", "Replaced Text", 75); if (FA_errno != FE_Success) F_ApiAlert("Couldn’t compare", FF_ALERT_CONTINUE_NOTE); . . . Figure 4-2 Specifications for Compare Documents 262 FDK Programmer’s Guide Updating and generating documents and books ... Executing Commands with API Functions Updating and generating documents and books The API provides a variety of functions that allow you to generate, update, and reformat documents and books. The following sections discuss these functions. Updating the files in a book To update the numbering, text insets, cross-references, etc. in all the files in a book, and to programmatically specify responses to warnings and messages that the FrameMaker product issues, use F_ApiUpdateBook(). You can specify all aspects of the operation, or you can specify some aspects and allow the user to decide others. For example, you can instruct the FrameMaker product to update view-only files, or to abort the update when it encounters a view-only file. To use F_ApiUpdateBook(), you should first understand property lists and how to manipulate them directly. For more information on this subject, see “Representing object characteristics with properties” on page 63 and “Manipulating property lists directly” on page 293. The syntax for F_ApiUpdateBook() is: ErrorT F_ApiOpen(F_ObjHandleT bookId, F_PropValsT *updateParamsp, F_PropValsT **updateReturnParamspp); This argument Means bookId The ID of the book you will update. updateParamsp A property list (script) that tells the FrameMaker product how to update the book and how to respond to errors and other conditions that arise. Use F_ApiGetUpdateBookDefaultParams() or F_ApiAllocatePropVals() to create and allocate memory for this property list. To use the default list, specify NULL. updateReturnParamspp A property list that provides information on how the FrameMaker product updated the book. .............................................................................. Always initialize the pointer to the property list that you specify for openReturnParamspp to NULL before you call F_ApiUpdateBook(). I M P O RTA NT: .............................................................................. If F_ApiUpdateBook() is successful, it returns FE_Success. Otherwise, it returns an error which has the same value as FA_errno. FDK Programmer’s Guide 263 7 Executing Commands with API Functions Updating and generating documents and books To call F_ApiUpdateBook(), do the following: 1 Initialize the pointer to the updateReturnParamspp property list to NULL. 2 Create an updateParamsp property list. You can get a default list by calling F_ApiGetUpdateBookDefaultParams(), or you can create a list from scratch. 3 Call F_ApiUpdateBook(). 4 Check the Update status. Check the returned values in the updateReturnParamspp list for the name of the opened file and other information about how the FrameMaker product opened the file. 5 Deallocate memory for the updateParamsp and updateReturnParamspp property lists. Use F_ApiDeallocatePropVals() to deallocate memory for the lists. Generating files for a book To generate and update files for a book, use F_ApiSimpleGenerate(). The book and its generated files must be set up before you call F_ApiSimpleGenerate(). The syntax for F_ApiSimpleGenerate() is: IntT F_ApiSimpleGenerate(F_ObjHandleT bookId, IntT interactive, IntT makeVisible); This argument Means bookId The ID of the book for which to generate files interactive Specifies whether to display warnings and messages to the user (True displays messages and warnings) makeVisible Specifies whether to display generated files (True displays the files) Importing formats To import formats from a document to all the documents in a book or from one document to another document, use F_ApiSimpleImportFormats(). 264 FDK Programmer’s Guide Updating and generating documents and books ... Executing Commands with API Functions The syntax for F_ApiSimpleImportFormats() is: IntT F_ApiSimpleImportFormats(F_ObjHandleT bookId, F_ObjHandleT fromDocId, IntT formatFlags); This argument Means bookId The ID of the book or document to which to import formats fromDocId The ID of the document from which to import formats formatFlags Bit field that specifies the formats to import You can OR the values in the following table into the formatFlags parameter to specify which formats to import. This value Means FF_UFF_COLOR Import colors FF_UFF_COMBINED_FONTS Import combined font definitions FF_UFF_COND Import conditional text settings FF_UFF_DOCUMENT_PROPS Import document properties FF_UFF_FONT Import Character Catalog formats FF_UFF_MATH Import equation settings FF_UFF_PAGE Import page layouts FF_UFF_PGF Import Paragraph Catalog formats FF_UFF_REFPAGE Import reference pages FF_UFF_TABLE Import Table Catalog formats FF_UFF_VAR Import variable formats FF_UFF_XREF Import cross-reference formats FF_UFF_REMOVE_EXCEPTIONS Remove exception formats from target documents FF_UFF_REMOVE_PAGE_BREAKS Remove all forced page breaks from target documents Executing other updating and formatting commands The API provides several functions that allow you to execute FrameMaker product commands that update and reformat entire documents. FDK Programmer’s Guide 265 7 Executing Commands with API Functions Updating and generating documents and books The syntax for the functions is: IntT IntT IntT IntT IntT IntT IntT F_ApiClearAllChangebars(F_ObjHandleT docId); F_ApiRehyphenate(F_ObjHandleT docId); F_ApiResetReferenceFrames(F_ObjHandleT docId); F_ApiResetEqnSettings(F_ObjHandleT docId); F_ApiRestartPgfNumbering(F_ObjHandleT docId); F_ApiUpdateVariables(F_ObjHandleT docId); F_ApiUpdateXRefs(F_ObjHandleT docId, IntT updateXRefFlags); This argument Means docId ID of the document to update or reformat These functions behave like the corresponding commands in the user interface. They are useful for clients that need to update and reformat multiple files. For more information on a particular function, look it up in Chapter 2, “FDK Function Reference,” in the FDK Programmer’s Reference. 266 FDK Programmer’s Guide Updating and generating documents and books ... Executing Commands with API Functions Example The following code opens a book and resets the change bars in each of its component documents: . . . #include "fmemory.h" F_ObjHandleT bookId, compId, docId; StringT compName; bookId = F_ApiSimpleOpen("/tmp/my.book", False); compId = F_ApiGetId(FV_SessionId, bookId, FP_FirstComponentInBook); /* Traverse book’s components, opening each one * and clearing its change bars. */ while(compId) { compName = F_ApiGetString(bookId, compId, FP_Name); docId = F_ApiSimpleOpen(compName, False); F_Free(compName); F_ApiClearAllChangebars(docId); compId = F_ApiGetId(bookId, compId, FP_NextComponentInBook); } . . . Controlling Undo/Redo in the FDK API Undo/Redo in FrameMaker is controlled by the following: Initialization Flag Session Properties API Functions Initialization Flag to explicitly enable or disable undo/redo The EnableUndoInFDK flag in the initialization file (maker.ini) allows you to explicitly enable or disable undo/redo functionality for API commands, and its associated overhead. It is false (off) by default, which means that the undo behavior is the same as in previous releases; that is, calls to API commands clear the undo and redo stacks in the selected document, and API commands cannot be undone. To enable the new undo behavior for API commands, set the flag to true. (This flag does not affect the FrameMaker user interface or interactive behavior.) FDK Programmer’s Guide 267 7 Executing Commands with API Functions Updating and generating documents and books When EnableUndoInFDK is true, all API commands that modify document contents can be undone (see “Undoable API Commands” on page 268). Commands that do not modify content, such as saving a document, copying text, or manipulating windows, cannot be undone and are not recorded in the command history (undo stack). Session Properties to Control Undo/Redo FP_UndoFDKRecording - This property, can override the default value specified in the initialization flag EnableUndoInFDK. Use F_ApiSetInt to set this property value, and F_ApiGetInt to retrieve it. Set the property to zero to disable FDK Undo recording for a session, or to a non-zero value to enable Undo recording. FP_StackWarningLevel - This property determines how warnings are displayed when history-clearing operations occur. It corresponds to an option set in the Preferences dialog, and to the preference-file flag hpWarning. Use F_ApiSetInt to set this property value, and F_ApiGetInt to retrieve it. Allowed values are: FvWarnNever: Disables warnings for history-clearing operations for the session. FvWarnOnce: Displays a warning when a particular history-clearing command is issued,but does not warn on subsequent uses of that command. FvWarnAlways: Displays warnings every time a history-clearing command is issued. API Functions to Control Undo/Redo The F_ApiUndoCancel command explicitly clears both the undo and redo stacks in a specified document. The other individual API commands do not clear the undo stack Many API commands call two or more other API functions. By default, each API call is recorded as a separate undo action in the undo stack of the selected document. To treat a series of API calls as one command, call F_ApiUndoStartCheckpoint before the first call and F_ApiUndoEndCheckpoint after the last call in the group. Undoable API Commands The following API commands are undoable 268 F_ApiAddCols F_ApiAddRows F_ApiAddText F_ApiApplyPageLayout F_ApiClear ApiClearAllChangebars F_ApiCut F_ApiDelete F_ApiDeleteCols F_ApiDeletePropByName F_ApiDeleteRows F_ApiDeleteText FDK Programmer’s Guide Updating and generating documents and books ... Executing Commands with API Functions F_ApiDeleteTextInsetContents F_ApiDeleteUndefinedAttributes F_ApiDemoteElement F_ApiImport F_ApiMergeIntoFirst F_ApiMergeIntoLast F_ApiNewAnchoredFormattedObject F_ApiNewAnchoredObject F_ApiNewBookComponentInHierarchy F_ApiNewElement F_ApiNewElementInHierarchy F_ApiNewGraphicObject F_ApiNewNamedObject F_ApiNewSeriesObject F_ApiNewSubObject F_ApiNewTable F_ApiPaste F_ApiPromoteElement F_ApiReformat F_ApiUnStraddleCells F_ApiResetEqnSettings F_ApiResetReferenceFrames F_ApiRestartPgfNumbering F_ApiSetAttributeDefs F_ApiSetAttributes F_ApiSetElementRange F_ApiSetId F_ApiSetInt F_ApiSetIntByName F_ApiSetInts F_ApiSetMetric F_ApiSetMetricByName F_ApiSetMetrics F_ApiSetPoints F_ApiSetProps F_ApiSetPropVal F_ApiSetString F_ApiSetStrings F_ApiSetTabs F_ApiSetTextLoc F_ApiSetTextProps F_ApiSetTextPropVal F_ApiSetTextRange F_ApiSetTextVal F_ApiSetUBytesByName F_ApiUnWrapElement F_ApiSimpleImportElementDefs F_ApiSimpleImportFormats F_ApiSplitElement F_ApiStraddleCells F_ApiUnWrapElement F_ApiUpdateTextInset F_ApiSave F_ApiSimpleSave FDK Programmer’s Guide 269 7 Executing Commands with API Functions Simulating user input Simulating user input To simulate user input, call the API function F_ApiFcodes(). F_ApiFcodes() sends an array of function codes (f-codes) to the FrameMaker product. F-codes are hexadecimal codes that specify individual user actions, such as cursor movement and text entry. They are especially useful for manipulating windows. For example, the f-code KBD_EXPOSEWIN brings the active document or book window to the front. When you use F_ApiFcodes() to send an array of f-codes to a FrameMaker product, it executes each f-code as if the user performed the action. .............................................................................. I M P O RTA NT: F_ApiFcodes() does not work with dialog boxes on Windows. .............................................................................. The syntax for F_ApiFcodes() is: IntT F_ApiFcodes(IntT len, IntT *vec); This argument Means len The length of the array of f-codes in bytes vec The array of f-codes to send to the FrameMaker product The following table lists some user actions and the f-codes that emulate them. User action F-code Move insertion point to first flow on the current page CSR_TOP Move insertion point to the start of the next word CSR_NEXT_BOW Move insertion point to the beginning of the next paragraph CSR_NEXT_BOP Center the current paragraph PGF_CENTER Left justify the current paragraph PGF_LEFT Make selected text bold TXT_BOLD For a complete list of f-codes, see the fcodes.h file shipped with the FDK. F_ApiFcodes() uses the current focus in a dialog box or a visible document. If you want to execute a set of f-codes in a particular dialog box or document, make sure that the dialog box or document is active. To make a dialog box active, use f-codes such as 270 FDK Programmer’s Guide Straddling table cells ... Executing Commands with API Functions FOCUS_INPUT_SEARCH and FOCUS_INPUT_PGFFMT. To make a document active, set the session property FP_ActiveDoc to the document’s ID. Many f-codes perform tasks that API functions also perform. Whenever possible, try to use the other API functions instead of F_ApiFcodes() to perform these tasks. F_ApiFcodes() does not provide error or status feedback for individual f-codes, whereas each API function stores an error code to FA_errno when it fails. It is also difficult to debug lengthy f-code sequences. The following code uses f-codes to enter the string HI!, select the text, and then make it bold: . . . static IntT fcodes[] = {CSR_TOP,'H','I','!',HIGH_WORD_PREV, TXT_BOLD}; F_ApiFcodes(sizeof(fcodes)/sizeof(IntT), fcodes); . . . Straddling table cells To straddle and unstraddle table cells, use F_ApiStraddleCells() and F_ApiUnStraddleCells(). The syntax for these functions is: IntT F_ApiStraddleCells(F_ObjHandleT docId, F_ObjHandleT cellId, IntT heightInRows, IntT widthInCols); IntT F_ApiUnStraddleCells(F_ObjHandleT docId, F_ObjHandleT cellId, IntT heightInRows, IntT widthInCols); This argument Means docId The ID of the document containing the table cellId The ID of the first (leftmost and uppermost) cell to straddle or unstraddle heightInRows The number of cells to straddle or unstraddle vertically widthInCols The number of cells to straddle or unstraddle horizontally Both heightInRows and widthInCols must be greater than 0. At least one of them must be greater than 1. The cells you straddle must all be from the same type of row. You can’t, for example, straddle a set of cells that are in both heading and body FDK Programmer’s Guide 271 7 Executing Commands with API Functions Executing FrameMaker commands rows. You also can’t straddle cells that are already straddled. If the cells you specify include cells that are already straddled, F_ApiStraddleCells() returns FE_BadOperation. When you or the user straddle table cells, the FrameMaker product does not delete any of the FO_Cell objects that represent the cells. It links the paragraphs from the straddled cells into a single list. The FP_FirstPgf and FP_LastPgf properties of each cell in the straddle specify the first and last paragraphs in this list. Example The following code straddles the first two cells in the first column of a table: . . . F_ObjHandleT docId, tableId, firstrowId, cellId; /* Get IDs of document, table, first row, and first cell. */ docId = F_ApiGetId(0, FV_SessionId, FP_ActiveDoc); tableId = F_ApiGetId(FV_SessionId, docId, FP_FirstTblInDoc); firstrowId = F_ApiGetId(docId, tableId, FP_FirstRowInTbl); cellId = F_ApiGetId(docId, firstrowId, FP_FirstCellInRow); /* If there are two cells in the row, straddle them. */ if (F_ApiGetInt(docId, tableId, FP_TblNumCols) < 2) F_ApiAlert("Not enough columns!", FF_ALERT_CONTINUE_NOTE); else F_ApiStraddleCells(docId, cellId, 1, 2); . . . Executing FrameMaker commands The following sections describe how to programmatically execute FrameMaker commands. Manipulating elements The API provides several functions that allow you to execute basic commands that manipulate elements. 272 FDK Programmer’s Guide Executing FrameMaker commands ... Executing Commands with API Functions The syntax for these functions is: VoidT VoidT VoidT VoidT VoidT VoidT VoidT F_ApiDemoteElement(F_ObjHandleT docId); F_ApiMergeIntoFirst(F_ObjHandleT docId); F_ApiMergeIntoLast(F_ObjHandleT docId); F_ApiPromoteElement(F_ObjHandleT docId); F_ApiSplitElement(F_ObjHandleT docId); F_ApiUnWrapElement(F_ObjHandleT docId); F_ApiWrapElement(F_ObjHandleT docId, F_ObjHandleT edefId); This argument Means docId ID of the document containing selected text and/or structure elements edefId ID of element definition for the new element These functions behave like the corresponding commands in the user interface. They all use the current text or element selection in the specified document to determine which text and elements to manipulate. You can allow the user to set the text or element selection, or you can do it programmatically. For information on setting the text selection programmatically, see “Getting and setting the insertion point or text selection” on page 321. For more information on setting the element selection programmatically, see “Getting and setting the structural element selection” on page 329 Importing element definitions into FrameMaker documents and books To import element definitions from a FrameMaker document or book to a FrameMaker document or book, use F_ApiSimpleImportElementDefs(). FDK Programmer’s Guide 273 7 Executing Commands with API Functions Executing FrameMaker commands The syntax for F_ApiSimpleImportElementDefs() is: IntT F_ApiSimpleImportElementDefs( F_ObjHandleT docOrBookId, F_ObjHandleT fromDocOrBookId, IntT importFlags); This argument Means docOrBookId The ID of the document or book to import element definitions to. fromDocOrBookId The ID of the document or book from which to import element definitions. importFlags See the following table for the flags that you can OR into this parameter. The following table lists flags that you can OR into the importFlags parameter: Flag Meaning FF_IED_REMOVE_OVERRIDES Clear format overrides. FF_IED_REMOVE_BOOK_INFO If docOrBookId specifies a document, clear formatting inherited from the parent book. FF_IED_DO_NOT_IMPORT_EDD If the document specified by fromDocOrBookId is an EDD, don’t treat it as an EDD; just import its element catalog. FF_IED_NO_NOTIFY Do not issue the FA_Note_PreImportElemDefs or FA_Note_PostImportElemDefs notifications. If you import element definitions to a book, F_ApiSimpleImportElementDefs() imports element definitions to each book component for which the FP_ImportFmtInclude property is set to True. Calling FrameMaker clients programmatically Much of the structured document functionality FrameMaker provides is implemented in FDK clients. To call this functionality programmatically, you must use F_ApiCallClient(). 274 FDK Programmer’s Guide Executing FrameMaker commands ... Executing Commands with API Functions F_ApiCallClient() requires you to specify a client’s registered name and a string, which it passes to the client. The following table lists FrameMaker functionality and the registered names of the clients you can call to invoke it programmatically. Functionality Registered client name Element catalog manager Element Catalog Manager Structure generator Structure Generator Reading and writing Structured documents and reading, writing, and updating DTD and EDD documents FmDispatcher The following table lists the strings you pass to the structure generator client to programmatically generate structure in a document or book. String Meaning INPUTDOCID objectID The ID of the input document or book. RULEDOCID objectID The ID of the rule table document. OUTPUTDOCNAME filename The full pathname of the output document or book. This string is optional. If you do not specify a pathname, the structure generator leaves the document unsaved and open. LOGNAME filename The full pathname of a log file. This string is optional. If you do not specify a pathname, the structure generator leaves the log file unsaved and open. StructureDoc Instructs the structure generator to generate structure, using the strings listed above. FDK Programmer’s Guide 275 7 Executing Commands with API Functions Executing FrameMaker commands To programmatically generate structure for a document or a book, you call F_ApiCallClient() multiple times, each time passing it one of the strings listed in the table above. For example, the following code generates structure for a document: . . . F_ObjHandleT inputDocId, ruleTblDocId; UCharT buf[64]; . . . F_Sprintf(buf, "INPUTDOCID %d", inputDocId); F_ApiCallClient("StructGen", buf); F_Sprintf(buf, "RULEDOCID %d", ruleTblDocId); F_ApiCallClient("StructGen", buf); F_ApiCallClient("StructGen", "OUTPUTDOCNAME /tmp/mystruct.doc"); F_ApiCallClient("StructGen", "LOGNAME /tmp/logfile.doc"); F_ApiCallClient("StructGen", "StructureDoc"); . . . Note that all of the documents you specify must be open before you call the structure generator. If you are generating structure for a large number of documents, you can greatly speed processing by opening the documents invisibly. To open a document invisibly, set the FS_MakeVisible property of the Open script to False. For a complete list of the strings you can pass to the structure generator and other FrameMaker clients, see “F_ApiCallClient()” on page 85 in the FDK Programmer’s Reference. 276 FDK Programmer’s Guide 8 Getting and Setting Properties .................................. ..... 5 This chapter describes how to make changes in a FrameMaker product session, book, or document by getting and setting property values. It discusses how to get and set individual properties and entire property lists. It also provides some tips for getting and setting the properties of specific types of objects. What you can do with object properties In the FrameMaker product user interface, the user can change an object in a variety of ways. For example, the user can change the size and fill pattern of a graphic object or the starting page number of a book component. Each API object has a property list, a set of properties describing its attributes. Your API client can do anything a user can do to an object by getting and setting the properties in the object’s property list. For example, your client can set properties to: Change a graphic object’s size, fill pattern, or position in the back-to-front order Make a document or book active Change a book component’s position in a book Change a paragraph’s format Your client can also change properties that the user doesn’t have access to. For example, your client can set properties to: Make a document or book visible or invisible Keep the FrameMaker product from reformatting a document every time a change is made The API ensures that your client doesn’t corrupt a document by setting properties to illegal values. When you change a property, the API also automatically changes other properties as needed to preserve the integrity of the document or book. There are a number of read-only properties that you can get but not set. For a complete list of object properties and their possible values, see Chapter 3, “Object Reference,” in the FDK Programmer’s Reference. FDK Programmer’s Guide 277 9 Getting and Setting Properties Getting the IDs of the objects you want to change To change a session, document, or book by setting object properties, follow these general steps: 1 Find out which objects represent the things you want to change. To change something in a session, book, or document, you need to know which objects the API uses to represent it. For a description of how the API uses objects to represent things in FrameMaker products, see Part II, “Frame Product Architecture.” 2 Get the IDs of the objects you want to change. To set an object’s properties, you must specify its ID. The API provides functions for retrieving object IDs. 3 Manipulate the objects’ properties. The API provides functions for getting and setting individual properties and entire property lists. For example, the API represents a FrameMaker product session with an FO_Session object. You don’t need to get a session’s ID, because there is only one session and its ID is always FV_SessionId. To find all the session characteristics you can change, look up “Session” on page 894 in Chapter 3, “Object Reference,” in the FDK Programmer’s Reference. You can, for example, change the session’s automatic save time. The API represents the automatic save time with an integer (IntT) property named FP_AutoSaveSeconds. To set it to 60 seconds, use the following code: F_ApiSetInt(0, FV_SessionId, FP_AutoSaveSeconds, 60); /* /* /* /* Sessions have no parent */ The session’s ID */ The property to set */ The value to set it to */ The following sections describe steps 2 and 3 in greater detail. Getting the IDs of the objects you want to change Every object in a session has an ID. To get or set the properties of a particular object, you must specify its ID. In Frame book and document architecture, objects are organized in linked lists: an object has properties that specify the IDs of other objects, which have properties that specify the IDs of other objects, and so on. To get the IDs of specific objects, you traverse the linked lists by querying these properties. For diagrams and descriptions of the linked lists in Frame architecture, see Part II, “Frame Product Architecture.” 278 FDK Programmer’s Guide Getting the IDs of the objects you want to change ... Getting and Setting Properties To query a property that specifies an object ID, use F_ApiGetId(), which is defined as: F_ObjHandleT F_ApiGetId(F_ObjHandleT docId, F_ObjHandleT objId, IntT propNum); This argument Means docId The ID of the document, book, or session containing the object whose property you want to query. objId The ID of the object whose property you want to query. propNum The property to query. Specify one of the API-defined constants, such as FP_ActiveDoc. F_ApiGetId() returns the ID specified by the property. If the property doesn’t specify an ID or an error occurs, F_ApiGetId() returns 0. To get an object’s ID, you start traversing at the object that represents the session (the FO_Session object), because it is the only object whose ID (FV_SessionId) you know from the start. From the FO_Session object, you can get the IDs of the active and open documents and books in the session. FO_Session objects have properties, named FP_ActiveDoc and FP_ActiveBook, that specify the IDs of the active document or book. A document or a book is active if it has input focus. FO_Session objects also have properties, named FP_FirstOpenDoc and FP_FirstOpenBook, that specify the first document and the first book in the linked lists of open documents and books in a session. FO_Doc objects have a property named FP_NextOpenDocInSession that specifies the ID of the next FO_Doc object in the list of open documents. FO_Book objects have a property named FP_NextOpenBookInSession that specifies the ID of the next FO_Book object in the list of open books. If an FO_Doc or an FO_Book object is the last object in the list, its FP_NextOpenDocInSession or FP_NextOpenBookInSession property is set to 0. For a diagram of how the API represents the documents and books in a session, see Figure 1-2 on page 69. FDK Programmer’s Guide 279 9 Getting and Setting Properties Getting the IDs of the objects you want to change Suppose you want to display the IDs of the active document and all the open documents in a session. You can use the following code to do this: . . . #include "futils.h" F_ObjHandleT docId; UCharT msg[256]; /* Get the ID of the active document and display it. */ docId = F_ApiGetId(0, FV_SessionId, FP_ActiveDoc); if (docId) { F_Sprintf(msg, "The active document’s ID is 0x%x.", docId); F_ApiAlert(msg, FF_ALERT_CONTINUE_NOTE); } /* Get ID of the first document in list of open documents. */ docId = F_ApiGetId(0, FV_SessionId, FP_FirstOpenDoc); /* Traverse list of open documents and display their IDs. */ while (docId) { F_Sprintf(msg, "The document’s ID is 0x%x.", docId); F_ApiAlert(msg, FF_ALERT_CONTINUE_NOTE); docId = F_ApiGetId(FV_SessionId, docId, FP_NextOpenDocInSession); } . . . This code displays the ID of the active document twice, because the active document is included in the list of open documents. The linked list of open documents in a session isn’t in any particular order. The first document in the list is not necessarily the active document or the first document that was opened. Another way to get a document ID is to use F_ApiSimpleOpen(), F_ApiOpen(), or F_ApiSimpleNewDoc() to open or create the document. These functions all return the IDs of the document they open or create. 280 FDK Programmer’s Guide Getting the IDs of the objects you want to change ... Getting and Setting Properties Traversing lists of objects in a document Once you have the ID of a document, you can query its properties to get to the lists of objects that it contains. The document has a number of properties that point to these lists. For example, the document’s FP_FirstGraphicInDoc property specifies the ID of the first graphic object in the list of its graphic objects and its FP_FirstBodyPageInDoc property specifies the first body page in the list of its body pages. Except for the lists of pages, the lists are completely unordered. For example, the first graphic object in the list of graphic objects is not necessarily the first graphic that appears in the document. Suppose you want to traverse the list of all the paragraphs in the active document. To do this, you can use the following code: . . . #include "futils.h" F_ObjHandleT docId, pgfId; UCharT msg[256]; /* Get the ID of the active document. */ docId = F_ApiGetId(0, FV_SessionId, FP_ActiveDoc); /* Get ID of the first paragraph in the list of paragraphs. */ pgfId = F_ApiGetId(FV_SessionId, docId, FP_FirstPgfInDoc); /* Traverse the list of paragraphs and display their IDs. ** Even empty documents have several paragraphs, because text ** columns on master pages contain paragraphs. */ while (pgfId) { F_Sprintf(msg, "The paragraph’s ID is 0x%x.", pgfId); F_ApiAlert(msg, FF_ALERT_CONTINUE_NOTE); pgfId = F_ApiGetId(docId, pgfId, FP_NextPgfInDoc); } . . . The paragraphs in the list are not ordered. FDK Programmer’s Guide 281 9 Getting and Setting Properties Getting the IDs of the objects you want to change Traversing lists of graphic objects The API does not maintain separate lists of the different types of graphic objects in a document. For example, a document’s text columns (FO_TextFrame objects), rectangles (FO_Rectangle objects), and anchored frames (FO_AFrame objects) are all in the same list. To determine objects’ types as you traverse them, use F_ApiGetObjectType(). The syntax for F_ApiGetObjectType() is: UIntT F_ApiGetObjectType(F_ObjHandleT docId, F_ObjHandleT objId); This argument Means docId The ID of the document, book, or session containing the object objId The ID of the object whose type you want to get For example, the following code counts the number of anchored frames in the active document: . . . #include "futils.h" IntT numFrames = 0; F_ObjHandleT docId, objId; UCharT msg[256]; docId = F_ApiGetId(0, FV_SessionId, FP_ActiveDoc); /* Get ID of first graphic in the list of graphics. */ objId = F_ApiGetId(FV_SessionId, docId, FP_FirstGraphicInDoc); /* Traverse list of graphics, counting anchored frames. */ while (objId) { if (F_ApiGetObjectType(docId,objId) == FO_AFrame) numFrames++; objId = F_ApiGetId(docId, objId, FP_NextGraphicInDoc); } F_Sprintf(msg, "The document has %d anchored frames.", numFrames); F_ApiAlert(msg, FF_ALERT_CONTINUE_NOTE); . . . 282 FDK Programmer’s Guide Getting the IDs of the objects you want to change ... Getting and Setting Properties Traversing ordered lists of objects Traversing the list of all the objects of a certain type in a document is useful if you want to get every object of that type and the order doesn’t matter to you. However, it isn’t very useful if you want the objects in some kind of order, such as the order in which they appear on a document’s pages. To get objects in order, you must traverse the ordered lists that the API maintains. There are ordered lists of the graphic objects in a frame, the text columns within a flow, and many other objects. These lists can be deeply nested, for example, when a frame contains a frame that contains some graphic objects. There are a variety of object properties you can query to get to ordered lists. For example, to get to the list of graphic objects in a frame, you can query the frame’s FP_FirstGraphicInFrame or FP_LastGraphicInFrame properties. If you already have one of the graphic object’s IDs, you can query its FP_PrevGraphicInFrame and FP_NextGraphicInFrame properties to get to the objects behind it and in front of it in the list. The order of the list corresponds to the back-to-front order of the graphics in the frame. For information on the linked lists that a particular object is included in, see the section that discusses that object in Chapter 2, “Frame Document Architecture.” Although there are ordered lists of the paragraphs within each of a document’s flows, there is no ordered list of flows. You can get the paragraphs only in the order in which they occur within an individual flow. FDK Programmer’s Guide 283 9 Getting and Setting Properties Getting the IDs of the objects you want to change To get the paragraphs within an individual flow in order, you navigate from the flow to the first text frame in the flow, to the first paragraph in that text frame. For example, to get the paragraphs in a document’s main flow in order, you can use the following code: . . . #include "futils.h" F_ObjHandleT docId, pgfId, flowId, textFrameId; UCharT msg[256]; docId = F_ApiGetId(0, FV_SessionId, FP_ActiveDoc); /* Get ID of main flow, then the first text column in the * flow, then the first paragraph in that text column. */ flowId = F_ApiGetId(FV_SessionId, docId, FP_MainFlowInDoc); textFrameId = F_ApiGetId(docId, flowId, FP_FirstTextFrameInFlow); pgfId = F_ApiGetId(docId, textFrameId, FP_FirstPgf); /* Traverse ordered list of paragraphs in the flow. */ while (pgfId) { F_Sprintf(msg, "The paragraph’s ID is 0x%x.", pgfId); F_ApiAlert(msg, FF_ALERT_CONTINUE_NOTE); pgfId = F_ApiGetId(docId, pgfId, FP_NextPgfInFlow); } . . . For a diagram of the links between flows, text frames, and paragraphs, see “The list of paragraphs in a flow” on page 104. Getting the IDs of selected objects Document objects have properties that allow you to get the IDs of the following types of selected objects: Graphic objects Tables and table rows To get the IDs of selected structural elements in FrameMaker documents, you must call a special function, F_ApiGetElementRange(). 284 FDK Programmer’s Guide Getting the IDs of the objects you want to change ... Getting and Setting Properties For background information on selection in Frame documents, see “How the API represents the selection in a document” on page 80. For information on getting selected text, see “Getting and setting the insertion point or text selection” on page 321. Getting the IDs of selected graphic objects The API maintains an unordered list of all the selected graphic objects in a document. To manipulate graphic objects the user has selected, you traverse this list. For example, the following code sets the fill pattern of all the selected graphic objects in the active document to black: . . . F_ObjHandleT docId, objId; docId = F_ApiGetId(0, FV_SessionId, FP_ActiveDoc); objId = F_ApiGetId(FV_SessionId, docId, FP_FirstSelectedGraphicInDoc); while (objId) { F_ApiSetInt(docId, objId, FP_Fill, FV_FILL_BLACK); objId = F_ApiGetId(docId, objId, FP_NextSelectedGraphicInDoc); } . . . Getting the IDs of selected tables and table rows If a table is selected, you can get its ID by querying the document property, FP_SelectedTbl. A table is considered selected if any of its cells are selected or the insertion point is in any of its cells. To get the IDs of the rows selected within a table, query the FO_Tbl object’s FP_TopRowSelection and FP_BottomRowSelection properties. FP_TopRowSelection specifies the ID of the row at the top of the selection; FP_BottomRowSelection specifies the ID of the row at the bottom of the selection. To determine which cells in a row are selected, query a table’s FP_LeftColNum and FP_RightColNum properties. FP_LeftColNum specifies the number (starting from 0) of the leftmost selected column; FP_RightColNum specifies the number of the rightmost selected column. If a range of text that includes several tables is selected, and you want to get the tables’ IDs, you must get the text selection and traverse all the table anchor text items in it. For more information on getting the text selection, see “Getting and setting the insertion point or text selection” on page 321. FDK Programmer’s Guide 285 9 Getting and Setting Properties Getting the IDs of the objects you want to change Getting the IDs of selected structural elements For information on getting the IDs of selected structural elements, see “Getting and setting the structural element selection” on page 329. Getting the IDs of formats and other named objects The following are some of the types of objects that are named (identified by a unique name). FO_CharFmt FO_Color FO_CombinedFontDfn FO_Command FO_CondFmt FO_ElementDef FO_Flow FO_FmtChangeList FO_MarkerType FO_MasterPage FO_Menu FO_PgfFmt FO_TblFmt FO_UnanchoredFrame (named frames on reference pages) FO_VarFmt FO_XRefFmt The API maintains all the named objects of a particular type in a linked list. To get the objects, you can query FO_Doc properties and traverse the list. For example, to get all the variable formats in a document, query the FO_Doc object’s FP_FirstVarFmtInDoc property, and then traverse the FP_NextVarFmtInDoc properties from one FO_VarFmt object to the next. 286 FDK Programmer’s Guide Getting the IDs of the objects you want to change ... Getting and Setting Properties If you only want the ID for a single named object, it is usually easier to use F_ApiGetNamedObject(). The syntax for F_ApiGetNamedObject() is: F_ObjHandleT F_ApiGetNamedObject(F_ObjHandleT docId, IntT objType, StringT name); This argument Means docId The ID of the document or book containing the object objType The type of object (for example, FO_VarFmt) name The name of the object for which to get the ID For example, the following code gets the ID of the Paragraph Catalog format named Body in the active document: . . . F_ObjHandleT docId, pgfFmtId; docId = F_ApiGetId(0, FV_SessionId, FP_ActiveDoc); pgfFmtId = F_ApiGetNamedObject(docId, FO_PgfFmt, "Body"); . . . Getting IDs for objects that have persistent identifiers FrameMaker products assign a persistent unique identifier (UID) to each object in a document that isn’t identified by a name. The UID, unlike the object’s ID, does not change from one session to another. No matter how many times you open and exit a document, an object’s UID remains the same. It is important to note that cut and paste functions will assign new UID’s to the text. For example conditionalizing text will change a paragraph’s UID. To get an object’s UID, you query its FP_Unique property with F_ApiGetInt(). If you already know an object’s UID, you can find its ID in the current session by calling F_ApiGetUniqueObject(). FDK Programmer’s Guide 287 9 Getting and Setting Properties Manipulating properties The syntax for F_ApiGetUniqueObject() is: F_ObjHandleT F_ApiGetUniqueObject(F_ObjHandleT docId, IntT objType IntT unique); This argument Means docId The ID of the document containing the object objType The object type (for example FO_Pgf) unique The object’s UID For an example of how you can use UIDs, see “F_ApiGetUniqueObject()” on page 268 of the FDK Programmer’s Reference. Manipulating properties The API allows you to get and set either an individual property or a property list for an object. It is generally easier to get and set properties individually. However, some tasks, such as applying a Paragraph Catalog format to a paragraph, are easier to perform by getting and setting property lists. 288 FDK Programmer’s Guide Manipulating properties ... Getting and Setting Properties Getting and setting individual properties To get or set an individual property, use the F_ApiGetPropertyType() or F_ApiSetPropertyType() function that corresponds to the property’s data type. For example, to get an integer, enum, or boolean (IntT data type) property, use F_ApiGetInt(). To set a property that represents a set of strings (F_StringsT data type), use F_ApiSetStrings(). The data types of API properties are listed in Chapter 3, “Object Reference,” in the FDK Programmer’s Reference. The following table lists the functions you use to set different types of properties. The API also provides special functions to get and set properties that are identified by names. These functions are used for getting and setting inset properties only. They are discussed in Chapter 12, “Using Imported Files and Insets.” Property’s data type Functions to get and set property F_AttributesT F_ApiGetAttributes() F_ApiSetAttributes() F_AttributeDefsT F_ApiGetAttributeDefs() F_ApiSetAttributeDefs() F_ElementCatalogEntriesT F_ApiGetElementCatalog() F_ElementFmtsT F_ApiGetElementFormats() F_ApiSetElementFormats() F_ElementRangeT F_ApiGetElementRange() F_ApiSetElementRange() F_ObjHandleT F_ApiGetId() F_ApiSetId() IntT (including boolean, enum, and ordinal) F_ApiGetInt() F_ApiSetInt() F_IntsT F_ApiGetInts() F_ApiSetInts() MetricT F_ApiGetMetric() F_ApiSetMetric() F_MetricsT F_ApiGetMetrics() F_ApiSetMetrics() F_PointsT F_ApiGetPoints() F_ApiSetPoints() StringT F_ApiGetString() F_ApiSetString() FDK Programmer’s Guide 289 9 Getting and Setting Properties Manipulating properties Property’s data type Functions to get and set property F_StringsT F_ApiGetStrings() F_ApiSetStrings() F_TabsT F_ApiGetTabs() F_ApiSetTabs() F_TextLocT F_ApiGetTextLoc() F_ApiSetTextLoc() F_TextRangeT F_ApiGetTextRange() F_ApiSetTextRange() The syntax for most F_ApiGetPropertyType() and F_ApiSetPropertyType() functions is similar. For example, the syntax for F_ApiGetInt() is: IntT F_ApiGetInt(F_ObjHandleT docId, F_ObjHandleT objId, IntT propNum); This argument Means docId The ID of the document, book, or session containing the object. If the object is a session, specify 0. objId The ID of the object whose property you want to query. propNum The property to query (for example, FP_FnNum). The syntax for F_ApiSetString() is: VoidT F_ApiSetString(F_ObjHandleT docId, F_ObjHandleT objId, IntT propNum, StringT setVal); 290 This argument Means docId The ID of the document, book, or session containing the object objId The ID of the object whose property you want to set propNum The property to set, for example, FP_PrintFileName setVal The string to which to set the property FDK Programmer’s Guide Manipulating properties ... Getting and Setting Properties You can look up the exact syntax of an F_ApiGetPropertyType() or F_ApiSetPropertyType() function in Chapter 2, “FDK Function Reference,” in the FDK Programmer’s Reference. Suppose you want your client to change some characteristics of the Heading1 paragraph format. To find out how the API represents paragraph formats, look up paragraph formats in Part II, “Frame Product Architecture.” For a complete list of paragraph format properties, see Chapter 3, “Object Reference,” in the FDK Programmer’s Reference. The following code demonstrates how to change different types of paragraph format properties: . . . #define in (MetricT) (72 * 65536) /* A Frame metric inch */ F_ObjHandleT docId, pgfFmtId; /* Get the ID of Heading1 format in active document. */ docId = F_ApiGetId(0, FV_SessionId, FP_ActiveDoc); pgfFmtId = F_ApiGetNamedObject(docId, FO_PgfFmt, "Heading1"); /* Set Next Pgf Tag to Heading2. */ F_ApiSetString(docId, pgfFmtId, FP_NextTag, "Heading2"); /* Turn on Keep With Next. */ F_ApiSetInt(docId, pgfFmtId, FP_KeepWithNext, True); /* Set the left indent to 1 inch. */ F_ApiSetMetric(docId, pgfFmtId, FP_LeftIndent, in); . . . This code changes only the Heading1 Paragraph Catalog format. It does not change the formats of paragraphs that have already been tagged with Heading1. Getting and setting property lists Because most objects have relatively long property lists, it is often easier to get and set individual properties. However, to perform the following types of tasks, you may need to get and set entire property lists: Getting and setting text properties Applying table, paragraph, and character formats Copying graphic object properties FDK Programmer’s Guide 291 9 Getting and Setting Properties Manipulating properties To get and set property lists, you need to understand how the API represents them. For more information, see “Property lists” on page 64. F_ApiGetProps() and F_ApiSetProps() make it easy to get and set property lists. The syntax for these functions is: F_PropValsT F_ApiGetProps(F_ObjHandleT docId, F_ObjHandleT objId); VoidT F_ApiSetProps(F_ObjHandleT docId, F_ObjHandleT objId, F_PropValsT *setVal); This argument Means docId The ID of the session, book, or document containing the object objId The ID of the object to get or set the property list for setVal The property list to apply to the object The F_PropValsT structure returned by F_ApiGetProps() references memory that is allocated by the API. Use F_ApiDeallocatePropVals() to free this memory when you are done with it. If F_ApiGetProps() fails, the API sets the len field of the returned structure to 0. 292 FDK Programmer’s Guide Manipulating properties ... Getting and Setting Properties Example The following code copies the properties from one selected graphic object to another: . . . F_PropValsT props; F_ObjHandleT obj1Id, obj2Id, docId; /* Get ID of active document and the two selected objects. */ docId = F_ApiGetId(0, FV_SessionId, FP_ActiveDoc); obj1Id = F_ApiGetId(FV_SessionId, docId, FP_FirstSelectedGraphicInDoc); obj2Id = F_ApiGetId(docId, obj1Id, FP_NextSelectedGraphicInDoc); /* Make sure two objects are selected, then copy properties. */ if (!(obj1Id && obj2Id)) F_ApiAlert("First select two objects.", FF_ALERT_CONTINUE_WARN); else { props = F_ApiGetProps(docId, obj1Id); if(props.len == 0) return; /* Get props failed. */ F_ApiSetProps(docId, obj2Id, &props); } . . . Because a graphic object’s x and y coordinates are included in its property list, this code moves the two graphic objects to the same location, with one object overlaying the other. After you have copied a property list to an object, you can customize the list by changing individual properties. Manipulating property lists directly If you are setting individual text properties or using scriptable functions, such as F_ApiOpen(), you need to manipulate property lists directly. The order of the properties in property lists is not guaranteed to remain the same in future versions of FrameMaker products and the Frame API. So, to get a particular property in a list, you must traverse the entire property list and check each property’s identifier until you find it. The API provides a convenience routine named F_ApiGetPropIndex() that does this for you. FDK Programmer’s Guide 293 9 Getting and Setting Properties Manipulating properties The syntax for F_ApiGetPropIndex() is: IntT F_ApiGetPropIndex(F_PropValsT *pvp, IntT propNum); This argument Means pvp The property list propNum The property whose index you want to get F_ApiGetPropIndex() returns the index of the F_PropValT structure that represents the property’s property-value pair. If you specify an invalid property for propNum, F_ApiGetPropIndex() returns FE_BadPropNum. Suppose you want to display the session property that provides the name of the current FrameMaker product. The easy way to do this would be to use the following code: . . . StringT productName; productName = F_ApiGetString(0, FV_SessionId, FP_ProductName); F_ApiAlert(productName, FF_ALERT_CONTINUE_NOTE); . . . To do the same thing by getting the property list for the session and accessing the property directly, use the following code: . . . IntT i; F_PropValsT props; props = F_ApiGetProps(0, FV_SessionId); i = F_ApiGetPropIndex(&props, FP_ProductName); F_ApiAlert(props.val[i].propVal.u.sval, FF_ALERT_CONTINUE_NOTE); . . . Allocating and deallocating memory for properties The F_ApiGetPropertyType() functions that return pointers to arrays make copies of the arrays, allocating memory for them. For example, F_ApiGetString() does not return a pointer to the actual string used by the FrameMaker product. Instead, it creates a copy of the string and returns a pointer to the copy. The API does not 294 FDK Programmer’s Guide Getting and setting session properties ... Getting and Setting Properties deallocate memory used by the copy of the string. When you are done with it, you must deallocate it. Similarly, when you call a F_ApiSetPropertyType() function such as F_ApiSetString(), the function does not set a pointer to the string you pass to it. Instead it copies the string. The API does not deallocate the string you pass. When you are done with it, you must deallocate it. For example, the following code queries and displays the FP_OpenDir property. It uses the FDE function, F_Free(), to free the returned string. . . . #include "fstrings.h" #include "fmemory.h" StringT openDir; openDir = F_ApiGetString(0, FV_SessionId, FP_OpenDir); F_ApiAlert(openDir, FF_ALERT_CONTINUE_NOTE); F_Free(openDir); . . . For more information on FDE functions, see Part III, “Frame Development Environment (FDE).” Some API functions return structures containing pointers to arrays. The API allocates memory for these arrays. When you are done with this memory, you must deallocate it. The API provides convenience functions, such as F_ApiDeallocatePropVals(), F_ApiDeallocateStrings(), and F_ApiDeallocateMetrics(), which you can use for this. For example, to get the property list for an object and then deallocate it, use code similar to the following: . . . F_PropValsT props; F_ObjHandleT objId, docId; props = F_ApiGetProps(docId, objId); . . . F_ApiDeallocatePropVals(&props); . . . Getting and setting session properties The following sections describe useful tasks you can perform by getting and setting session properties. FDK Programmer’s Guide 295 9 Getting and Setting Properties Getting and setting session properties Making a document or book active In addition to finding out which document is active by getting the session’s FP_ActiveDoc property, you can make a document active by setting this property. For example, the following code makes the document specified by docId active: . . . F_ObjHandleT docId; F_ApiSetId(0, FV_SessionId, FP_ActiveDoc, docId); . . . When you make a visible document active, its window gets input focus. On some platforms, the windowing system highlights a window’s title bar or brings it to the front. . . . Disabling redisplaying to avoid screen flicker If you change numerous properties at once, it may cause screen flicker, an effect that occurs when a FrameMaker product executes a long series of changes that aren’t userinitiated. By default, FrameMaker products reformat after each change. You can avoid screen flicker by batching changes. To batch changes, set the FO_Session property FP_Displaying to False. As long as FP_Displaying is set to False, the FrameMaker product does not refresh the documents in the current session when you or the user changes them. To refresh the documents, you must call F_ApiRedisplay() for each changed document. The syntax for F_ApiRedisplay() is: IntT F_ApiRedisplay(F_ObjHandleT docId); 296 FDK Programmer’s Guide Getting and setting session properties ... Getting and Setting Properties For example, to change a number of properties at once, use code similar to the following: . . . F_ObjHandleT docId; F_ApiSetInt(0, FV_SessionId, FP_Displaying, False); /* Change multiple properties here. */ F_ApiSetInt(0, FV_SessionId, FP_Displaying, True); F_ApiRedisplay(docId); /* Must be called for each document */ . . . While FP_Displaying is set to False, the FrameMaker product doesn’t update the display at all. In some cases, you may want the FrameMaker product to update the display but to delay reformatting documents while you change them. To do this, set the FO_Session property FP_Reformatting to False. After you have reset FP_Reformatting to True, refresh the documents that you have changed by calling F_ApiReformat() for each document. FDK Programmer’s Guide 297 9 Getting and Setting Properties Getting and setting document properties Getting and setting document properties The following sections describe useful tasks you can perform by getting and setting document properties. Getting a document’s pathname A document’s absolute pathname is specified by its FP_Name property. The following code displays the active document’s absolute pathname: . . . F_ObjHandleT docId; StringT docName; /* Get the document ID and name. */ docId = F_ApiGetId(0, FV_SessionId, FP_ActiveDoc); docName = F_ApiGetString(FV_SessionId, docId, FP_Name); F_ApiAlert(docName, FF_ALERT_CONTINUE_NOTE); F_Free(docName); . . . Manipulating document windows The API provides several properties that allow you to manipulate document and book windows. To change a document window’s size and screen location, set the document’s FP_ScreenX, FP_ScreenY, FP_ScreenWidth, and FP_ScreenHeight properties. To bring the window to the front, set the document’s FP_IsInFront property. Setting a document or book title bar The API allows you to set the title bars of both documents and books. By default, a document or book’s title bar displays its name. However, you can make it display another string by setting the document or book’s FP_Label property to the string. For example, the following code displays the string MyTitle in the title bar of the active document: . . . F_ObjHandleT docId; docId = F_ApiGetId(0, FV_SessionId, FP_ActiveDoc); F_ApiSetString(FV_SessionId, docId, FP_Label, "MyTitle"); . . . 298 FDK Programmer’s Guide Getting and setting document properties ... Getting and Setting Properties After you set a document’s title bar, it doesn’t change until you reset it or the user closes the document. Setting the title bar of a document or book doesn’t change the name of the document or book file itself. If you set the document or book title bar and the user closes and reopens the document or book, the document or book name appears in the title bar again. Setting a document or book status bar The API allows you to set the status bars of both documents and books. If your client conducts extensive processing, it can display status messages in the status bar to inform users of its progress. To set the status bar of a document or a book, set its FP_StatusLine property. The string you set FP_StatusLine to remains in the status bar only until a client or the FrameMaker product overwrites it. FrameMaker products overwrite the status bar frequently. For example, every time the user moves the insertion point to a different paragraph in a document, the FrameMaker product redisplays the paragraph format in the status bar. Enhancing performance by making documents invisible The API allows you to make a document invisible. Your client can still make changes to an invisible document. If your client needs to batch process multiple documents, using invisible documents can increase its performance considerably. To make a document invisible, you can use the following code: . . . F_ObjHandleT docId; F_ApiSetInt(FV_SessionId, docId, FP_IsOnScreen, False); . . . You can also open documents invisibly by setting the FP_MakeVisible property of the Open script to False. .............................................................................. IMPORTANT: Because an invisible document can’t get input focus, it can’t be the active document specified by the session property FP_ActiveDoc. You can’t send f-codes to an invisible document. .............................................................................. FDK Programmer’s Guide 299 9 Getting and Setting Properties Getting and setting document properties Displaying a particular page Document objects (FO_Doc) have a property named FP_CurrentPage that specifies the ID of the current page. The current page is the page that appears on the screen. If more than one page appears on the screen, it is the page that appears with a dark border around it. You can make a page current by making the document that contains it the active document and then setting the document’s FP_CurrentPage property to the page’s ID. For example, the following code displays the second body page and then the first reference page of the active document: . . . F_ObjHandleT docId, bPg1Id, bPg2Id, rPg1Id; docId = F_ApiGetId(0, FV_SessionId, FP_ActiveDoc); /* Get second body page ID. */ bPg1Id = F_ApiGetId(FV_SessionId, docId, FP_FirstBodyPageInDoc); bPg2Id = F_ApiGetId(docId, bPg1Id, FP_PageNext); if (bPg2Id) { F_ApiSetId(FV_SessionId, docId, FP_CurrentPage, bPg2Id); F_ApiAlert("Now at 2nd body page.", FF_ALERT_CONTINUE_NOTE); } /* Go to first reference page. */ rPg1Id = F_ApiGetId(FV_SessionId, docId, FP_FirstRefPageInDoc); if (rPg1Id) F_ApiSetId(FV_SessionId, docId, FP_CurrentPage, rPg1Id); . . . 300 FDK Programmer’s Guide Getting and setting graphic object properties ... Getting and Setting Properties Getting and setting graphic object properties The following sections describe useful tasks you can perform by getting and setting graphic object properties. Changing an object’s size and location within a frame Each graphic object has FP_Height and FP_Width properties, which specify its height (the distance between its highest and lowest points) and its width (the distance between its leftmost and rightmost points). To change an object’s size, use F_ApiSetMetric() to set these properties. For example, the following code increases a selected object’s width by 10 points: . . . #define pts (MetricT) 65536 /* Frame metric point */ F_ObjHandleT docId, objId; docId = F_ApiGetId(0, FV_SessionId, FP_ActiveDoc); /* Get ID of selected object. */ objId = F_ApiGetId(FV_SessionId, docId, FP_FirstSelectedGraphicInDoc); /* Get object’s current width and add 10 points to it. */ if (objId) F_ApiSetMetric(docId, objId, FP_Width, F_ApiGetMetric(docId, objId, FP_Width) + 10*pts); . . . If you set the FP_Height and FP_Width properties of a polyline or polygon, the API changes all the object’s vertices proportionally. If you want to change a polygon or polyline’s vertices independently, use F_ApiSetPoints() to set its FP_Points property. For an example of how to set the FP_Points property, see “F_ApiSetPoints()” on page 422 of the FDK Programmer’s Reference. All graphic objects have an FP_LocX property, which specifies the distance of the object’s leftmost point from the left side of the parent frame, and an FP_LocY property, which specifies the distance of the object’s uppermost point from the top of its parent frame. To change an object’s location within a frame, use F_ApiSetMetric() to set these properties. FDK Programmer’s Guide 301 9 Getting and Setting Properties Getting and setting graphic object properties Moving graphics forward or back in the draw order FrameMaker products maintain the graphic objects in each frame in a linked list. Each graphic object has FP_PrevGraphicInFrame and FP_NextGraphicInFrame properties that specify the graphic objects before and after it in the list. The order of this list corresponds to the back-to-front draw order. The first object in the list is the first object the FrameMaker product draws, and therefore appears in back of objects later in the list. To move a graphic object forward or back in the draw order, you change its FP_PrevGraphicInFrame or FP_NextGraphicInFrame property so that it specifies a different object. You need to change only one of these properties. The FrameMaker product automatically changes the other one for you. It also automatically changes the FP_PrevGraphicInFrame or FP_NextGraphicInFrame properties of the object’s siblings. To move an object all the way to the back of the objects in a frame, set its FP_PrevGraphicInFrame property to 0. To move an object all the way to the front, set its FP_NextGraphicInFrame property to 0. For example, the following code moves a selected graphic object forward one level: . . . F_ObjHandleT docId, objId, sibId; docId = F_ApiGetId(0, FV_SessionId, FP_ActiveDoc); /* Get ID of one (and only one) selected object. */ objId = F_ApiGetId(FV_SessionId, docId, FP_FirstSelectedGraphicInDoc); if (!objId || F_ApiGetId(docId, objId, FP_NextSelectedGraphicInDoc)) F_ApiAlert("Select a single object", FF_ALERT_CONTINUE_NOTE); else { /* Try to get ID of object in front of selected object. */ sibId = F_ApiGetId(docId, objId, FP_NextGraphicInFrame); /* If there is an object in front, put it behind. */ if(sibId) F_ApiSetId(docId, objId, FP_PrevGraphicInFrame, sibId); } . . . 302 FDK Programmer’s Guide Getting and setting graphic object properties ... Getting and Setting Properties Moving graphic objects to different frames or pages To move a graphic object to a different frame, set its FP_FrameParent property to the ID of that frame. The API automatically changes all the properties that need to be changed to maintain the lists of objects in the object’s old and new parent frames. To move a graphic object to a different page, set its FP_FrameParent property to the ID of a frame on that page. All pages have an invisible frame, called a page frame. To put a graphic object directly on a page, set its FP_FrameParent property to the ID of the page’s page frame. For more information on page frames, see “How the API represents pages” on page 86. For an example of how to move objects from a frame to a page frame, see “F_ApiSetId()” on page 408 of the FDK Programmer’s Reference. Grouping objects To group a set of objects, you first use F_ApiNewGraphicObject() to create a group (FO_Group) object. Then you add the objects to the group object by setting their FP_GroupParent properties to the ID of the group object. The objects must be in the same frame as the group object. For information on how to use F_ApiNewGraphicObject(), see “Creating graphic objects” on page 361. To remove an object from a group, set the object’s FP_GroupParent property to 0. Copying properties from one graphic object to another Each type of graphic object has a number of properties, such as FP_Fill and FP_BorderWidth, which are common to all graphic objects. Some of these properties don’t manifest themselves for all graphic objects. For example, rectangles have an FP_ArrowType property, although they don’t have arrowheads. For a list of properties common to all graphic objects, see “Common graphics properties” on page 840 of the FDK Programmer’s Reference. You can use F_ApiGetProps() and F_ApiSetProps() to copy common properties from one graphic object to another, as shown in the example in “Getting and setting property lists” on page 291. When you copy properties from one graphic object to another, the objects do not have to be the same type. For example, you can copy the properties from a line to a rectangle. The API copies only the common properties, leaving properties that are specific to the rectangle, such as FP_RectangleIsSmoothed, intact. FDK Programmer’s Guide 303 9 Getting and Setting Properties Getting and setting paragraph properties Getting and setting paragraph properties The following sections describe useful tasks you can perform by getting and setting paragraph properties. Applying paragraph and Paragraph Catalog formats Paragraph (FO_Pgf) objects and Paragraph Catalog format (FO_PgfFmt) objects have the same formatting properties. To apply the properties from a paragraph to a Paragraph Catalog format or from a Paragraph Catalog format to a paragraph, you can use F_ApiGetProps() and F_ApiSetProps(). For example, the following code applies the Paragraph Catalog format named Body to the paragraph containing the insertion point: . . . F_PropValsT props; F_TextRangeT tr; F_ObjHandleT docId, pgfId, bodyFmtId; StringT pgfName; docId = F_ApiGetId(0, FV_SessionId, FP_ActiveDoc); /* Get ID of the Body Paragraph Catalog format. */ bodyFmtId = F_ApiGetNamedObject(docId, FO_PgfFmt, "Body"); if (!bodyFmtId) return; /* Get text selection. For more information, see page 321. */ tr = F_ApiGetTextRange(FV_SessionId,docId, FP_TextSelection); if(tr.beg.objId == 0) return; /* Get properties from the Body Paragraph Catalog format. */ props = F_ApiGetProps(docId, bodyFmtId); if(props.len == 0) return; /* Apply Body properties to paragraph containing insertion * point (or the beginning of the text selection). */ F_ApiSetProps(docId, tr.beg.objId, &props); . . . 304 FDK Programmer’s Guide Getting and setting paragraph properties ... Getting and Setting Properties If you have changed the Body format, you may want to reapply it to all paragraphs that are tagged Body. To change these paragraphs, you must traverse every paragraph in the document, determine if it’s tagged Body, and set its properties if it is. You can do this by adding the following code to the code shown above:1 . . . pgfId = F_ApiGetId(FV_SessionId, docId, FP_FirstPgfInDoc); while (pgfId) { /* Get each paragraph’s tag and see if it’s Body. */ pgfName = F_ApiGetString(docId, pgfId, FP_Name); if (F_StrEqual((StringT)"Body", pgfName)) F_ApiSetProps(docId, pgfId, &props); F_Free(pgfName); pgfId = F_ApiGetId(docId, pgfId, FP_NextPgfInDoc); } . . . Adding tabs To get and set the tabs for a paragraph or Paragraph Catalog format, use F_ApiGetTabs() and F_ApiSetTabs(). The syntax for F_ApiGetTabs() and F_ApiSetTabs() is: F_TabsT F_ApiGetTabs(F_ObjHandleT docId, F_ObjHandleT objId, IntT propNum); VoidT F_ApiSetTabs(F_ObjHandleT docId, F_ObjHandleT objId, IntT propNum, F_TabsT *setVal); ................................. 1. Some examples in this chapter use FDE functions, such as F_StrEqual(), F_Alloc(), and F_Realloc(). For more information on using the FDE and these functions, see Part III, “Frame Development Environment (FDE).” FDK Programmer’s Guide 305 9 Getting and Setting Properties Getting and setting paragraph properties This argument Means docId The ID of the document containing the paragraph or paragraph format whose tabs you want to query or set. objId The ID of the paragraph or paragraph format whose tabs you want to query or set. propNum The property to query. Specify FP_Tabs. setVal The F_TabsT structure to which to set the property. The F_TabsT structure is defined as: typedef struct { UIntT len; /* The number of tabs in val */ F_TabT *val; /* Structures that describe the tabs */ } F_TabsT; The F_TabT structure is defined as: typedef struct { MetricT x; /* Offset from paragraph’s left margin */ UCharT type; /* Constant for tab type, e.g. FV_TAB_RIGHT */ StringT leader; /* Characters before tab, e.g. "." */ UCharT decimal; /* Character for decimal tab, e.g. "." */ } F_TabT; When you get the tabs for a paragraph or paragraph format, the API returns them in left-to-right order in the val array. However, when you insert a tab, you don’t have to insert it in this order. You just add it to the end of the val array. When you call 306 FDK Programmer’s Guide Getting and setting paragraph properties ... Getting and Setting Properties F_ApiSetTabs(), the API sorts the tabs for you. For example, the following code adds a 4-inch decimal tab to the Body paragraph format: . . . #include "fmemory.h" #define in (MetricT) (65536 * 72) F_ObjHandleT docId, pgfFmtId; F_TabsT tabs; /* Get the ID for the Body paragraph format. */ docId = F_ApiGetId(0, FV_SessionId, FP_ActiveDoc); pgfFmtId = F_ApiGetNamedObject(docId, FO_PgfFmt, "Body"); if (!pgfFmtId) return; /* Get the tabs and allocate space for new tab. */ tabs = F_ApiGetTabs(docId, pgfFmtId, FP_Tabs); if (tabs.len++) tabs.val=(F_TabT*)F_Realloc(tabs.val, tabs.len*sizeof(F_TabT), NO_DSE); else tabs.val = (F_TabT*) F_Alloc(sizeof(F_TabT),NO_DSE); /* Add the tab. */ tabs.val[tabs.len-1].type = FV_TAB_DECIMAL; tabs.val[tabs.len-1].x = 4*in; tabs.val[tabs.len-1].decimal = ’,’; tabs.val[tabs.len-1].leader = F_StrCopyString(" "); /* Set paragraph format’s tabs property to the array of tabs. */ F_ApiSetTabs(docId, pgfFmtId, FP_Tabs, &tabs); F_ApiDeallocateTabs(&tabs); . . . FDK Programmer’s Guide 307 9 Getting and Setting Properties Getting and setting book properties Getting and setting book properties To rearrange book components, you change their FP_PrevComponentInBook and FP_NextComponentInBook properties. For example, to move the first component in a book down one position, you can use the following code: . . . F_ObjHandleT bookId, firstC, nextC; bookId = F_ApiGetId(0, FV_SessionId, FP_ActiveBook); firstC = F_ApiGetId(FV_SessionId, bookId, FP_FirstComponentInBook); nextC = F_ApiGetId(bookId, firstC, FP_NextComponentInBook); if (nextC) F_ApiSetId(bookId, firstC, FP_PrevComponentInBook, nextC); else F_ApiAlert("Only one component.", FF_ALERT_CONTINUE_NOTE); . . . 308 FDK Programmer’s Guide Getting and setting FrameMaker properties ... Getting and Setting Properties Getting and setting FrameMaker properties There are some special issues involved in getting and setting properties in structured FrameMaker documents. The following sections discuss some of these issues. Traversing elements To traverse the elements in a structured document, you use slightly different code than you would use to traverse other objects, such as paragraphs. If you want to traverse all the elements in a document, you can’t query only FP_NextSiblingElement properties. You must also recursively traverse each element’s child elements. For example, the following function prints the IDs of all the elements in a specified element: . . . VoidT traverseElement(F_ObjHandleT docId, F_ObjHandleT elementId) { StringT name; if (elementId) { elementId = F_ApiGetId(docId, elementId, FP_FirstChildElement); while(elementId) { F_Printf(NULL, (StringT) "Element ID is 0x%x.\n", elementId); traverseElement(docId, elementId); elementId = F_ApiGetId(docId, elementId, FP_NextSiblingElement); } } } . . . Manipulating format change list properties Most object types in the FDK have a single list of properties that applies to all objects of that type. For example, if you call F_ApiGetProps() for any FO_Pgf object in a document, it will always return the same list of properties. The values of the properties may be different for each paragraph, but the list of properties will always be the same. This is not the case with FO_FmtChangeList objects. All FO_FmtChangeList objects have the following common properties: FDK Programmer’s Guide 309 9 Getting and Setting Properties Getting and setting FrameMaker properties FP_Name FP_NextFmtChangeListInDoc FP_PgfCatalogReference However, individual FO_FmtChangeList objects can have different sets of additional properties, depending on what formatting characteristics they set. An FO_FmtChangeList object can have all the properties listed under “Format change lists” on page 826 of the FDK Programmer’s Reference, or it may have just a small subset of these properties. For example, the format change list in Figure 5-1 has only the common properties listed above and the FP_FontFamily property. If you call F_ApiGetProps() for this format change list, the function returns only four properties: the three common properties listed above and the FP_FontFamily property. Format change list: Code Default font properties Family: Courier Figure 5-1 Format change list If you attempt to use an F_ApiGetPropertyType() function to get a property that a format change list doesn’t have, the function fails, setting FA_errno to FE_PropNotSet. 310 FDK Programmer’s Guide Getting and setting FrameMaker properties ... Getting and Setting Properties Adding properties to a format change list To add a property to a format change list, you just set the property on the FO_FmtChangeList object. You can do this by calling an F_ApiSetPropertyType() function or by creating a property list containing the property and calling F_ApiSetProps() to set the list on the object. For example, the following code uses these two methods to add properties to the Code format change list: . . . #define pts (MetricT) 65536 F_PropValsT props; F_ObjHandleT docId, changeListId; docId = F_ApiGetId(0, FV_SessionId, FP_ActiveDoc); /* Create the Code change list. */ changeListId = F_ApiNewNamedObject(docId, FO_FmtChangeList, "Code"); /* Add the FP_PairKern property to turn pair kerning off. */ F_ApiSetInt(docId, changeListId, FP_PairKern, False); /* Set up list with FP_FontSize property to set size to 10. */ props = F_ApiAllocatePropVals(1); props.val[0].propIdent.num = FP_FontSize; props.val[0].propVal.valType = FT_Metric; props.val[0].propVal.u.ival = 10*pts; F_ApiSetProps(docId, changeListId, &props); . . . Note that the F_ApiSetProps() call in the code above only adds the FP_FontSize property. It does not affect the other properties of the format change list. FDK Programmer’s Guide 311 9 Getting and Setting Properties Getting and setting FrameMaker properties Removing properties from a format change list To remove a property from a format change list, call F_ApiDeletePropByName(). For example, the following code removes the FP_PairKern property from the Code format change list: . . . F_ObjHandleT docId, changeListId; docId = F_ApiGetId(0, FV_SessionId, FP_ActiveDoc); changeListId = F_ApiGetNamedObject(docId, FO_FmtChangeList, "Code"); if (!changeListId) return; F_ApiDeletePropByName(docId, changeListId, "FP_PairKern"); . . . Setting format rule clause properties Format rule clauses (FO_FmtRuleClause objects) have several properties that are only indirectly settable. For example, you can’t set the FP_RuleClauseType property directly. You can only set it indirectly by setting one of the following properties: FP_FormatName FP_FmtChangeListTag FP_FmtChangeList FP_SubFmtRule For example, if you set FP_FmtChangeListTag to Code, FrameMaker automatically sets FP_RuleClauseType to FV_RC_CHANGELIST_TAG. You can also set FP_FmtChangeList and FP_SubFmtRule only indirectly—by calling F_ApiSubObject() to add a change list or subformat rule to the format rule clause or by calling F_ApiDelete() to delete a change list or subformat rule. For an example of how to use F_ApiSubObject(), see “Creating format rules, format rule clauses, and format change lists” on page 369. Setting element definition properties Element definitions have the following properties that are only indirectly settable: 312 FP_TextFmtRules FP_ObjectFmtRules FP_PrefixRules FDK Programmer’s Guide Getting and setting FrameMaker properties FP_SuffixRules FP_FirstPgfRules FP_LastPgfRules ... Getting and Setting Properties Each of these properties specifies a list of format rules. You can’t directly add a format rule to one of these lists. Instead, you must call F_ApiSubObject(). F_ApiSubObject() creates an FO_FmtRule object and adds it to the end of the specified list. You also can’t directly remove a format rule from a list. Instead, you must call F_ApiDelete() to delete the format rule. For example, the following code adds and deletes a text format rule: . . . F_ObjHandleT docId, paraEdefId, fmtRuleId; paraEdefId = F_ApiGetNamedObject(docId, FO_ElementDef, "Para"); /* Add a text format rule to the element definition. */ fmtRuleId = F_ApiSubObject(docId, paraEdefId, FP_TextFmtRules); /* Delete the text format rule. */ F_ApiDelete(docId, fmtRuleId); . . . Determining the formatting that applies to an element To determine the formatting that applies to an element, you first get the following properties: FP_MatchingTextClauses FP_MatchingObjectClauses FP_MatchingPrefixClauses FP_MatchingSuffixClauses FP_MatchingFirstPgfClauses FP_MatchingLastPgfClauses Each of these properties specifies a list of format rule clauses that applies to the element. Getting these properties only for the element itself is not sufficient to determine the element’s formatting. These properties specify only the format rule clauses that are in the element definition’s format rules (that is, the format rules specified by the element definition’s FP_TextFmtRules, FP_ObjectFmtRules, FP_PrefixRules, FDK Programmer’s Guide 313 9 Getting and Setting Properties Getting and setting FrameMaker properties FP_SuffixRules, FP_FirstPgfRules, and FP_LastPgfRules properties). In order to fully determine the element’s formatting, you must find any applicable format rule clauses that the element inherits from its ancestor elements. To determine whether an element inherits format rule clauses from ancestor elements, you must traverse up the structure tree and check the FP_MatchingClauses properties for each ancestor element. Determining which element contains an object Frequently, it is useful to determine which element contains an object, such as a crossreference, a marker, or a table. The following table lists the properties you query to get the ID of an object’s containing element. Object Property that returns ID of containing element FO_Marker FP_Element FO_Fn FO_XRef FO_Var FO_AFrame FO_Row FO_Cell FO_Tbla FP_TblElement FP_TblTitleElement FP_TblHeaderElement FP_TblBodyElement FP_TblFooterElement a. If a table has a title or different types of rows, it can comprise several elements. To determine the ID of the object an element contains, you query the element’s FP_Object property. 314 FDK Programmer’s Guide Getting and setting FrameMaker properties ... Getting and Setting Properties Specifying client data for an element The FO_Element property FP_UserString allows your client to store its own data with individual structural elements. The FP_UserString property is persistent between sessions; after a client sets it, it remains the same until a client resets it. If an element is cut and pasted, it retains its FP_UserString property. If an element is copied and pasted, both the original element and the pasted element retain the FP_UserString property. Improving performance in FrameMaker clients If you are using the API to create structured documents, you may need to add a large number of elements or element definitions at a time. By default, FrameMaker validates elements and applies format rules each time you add an element or element definition. This can decrease performance considerably. To keep FrameMaker from validating elements and applying format rules, set the FO_Session properties FP_Validating and FP_ApplyFmtRules to False. FDK Programmer’s Guide 315 9 316 Getting and Setting Properties Getting and setting FrameMaker properties FDK Programmer’s Guide 9 Manipulating Text .................................. ..... 6 This chapter describes how to use the API to manipulate text in Frame documents. Specifically, it discusses how to: Retrieve text from a document Get and set the location of the insertion point or current text selection Add and delete text Get and set text formatting Programmatically execute Clipboard operations To better understand the material in this chapter, you may want to learn more about how the API represents text. For information on this subject, see “Text” on page 112. Getting text Text in Frame documents is contained in objects, such as FO_Cell, FO_Element, FO_Fn, FO_Pgf, FO_TextLine, FO_Var, FO_SubCol, FO_TextFrame, and FO_Flow objects. To get text, you must get the ID of the object that contains it. For information on getting object IDs, see “Getting the IDs of the objects you want to change” on page 278. Once you have the ID of an object that contains text, you use F_ApiGetText() to retrieve the text. The syntax for F_ApiGetText() is: F_TextItemsT F_ApiGetText(F_ObjHandleT docId, F_ObjHandleT objId, IntT flags); This argument Means docId The ID of the document containing the object for which you want to get text. FDK Programmer’s Guide 317 10 M a n i p u l a t i n g Te x t Getting text This argument Means objId The ID of the object (FO_Flow, FO_Element, FO_Fn, FO_Pgf, FO_Cell, FO_SubCol, FO_TextFrame, FO_TextLine, or FO_Var) containing the text. flags Bit flags that specify the type of text items to retrieve. To get specific types of text items, OR the constants that represent them (for example, FTI_FlowBegin and FTI_String) into flags. To get all types of text items, specify -1. For a complete list of the constants that represent text item types, see “F_ApiGetText()” on page 242 in the FDK Programmer’s Reference. The F_TextItemsT structure contains an array of text items. Each string of characters with common character and condition properties, each anchor, and each line or column break in the text constitutes a separate text item. F_TextItemsT is defined as: typedef struct { UIntT len; /* The number of text items */ F_TextItemT *val; /* Array of text items */ } F_TextItemsT; The API represents each text item with an F_TextItemT structure. F_TextItemT is defined as: typedef struct { IntT offset; /* Characters from beginning */ IntT dataType; /* Text item type, e.g. FTI_String */ union { StringT sdata; /* String if the type is FTI_String */ F_ObjHandleT idata; /* ID if item is an anchor */ } u; } F_TextItemT; 318 FDK Programmer’s Guide Getting text ... M a n i p u l a t i n g Te x t If a text item represents a string of characters, F_TextItemT.dataType is set to FTI_String and F_TextItemT.u.sdata contains the string. If the text item represents an anchor, F_TextItemT.dataType is set to a constant indicating the anchor type (for example, FTI_TblAnchor) and F_TextItemT.u.idata contains the ID of the anchored object (for example, an FO_Tbl object). For more information on the F_TextItemsT structure, see “How the API represents text” on page 112. After you are finished with an F_TextItemsT structure, free the memory that it uses with F_ApiDeallocateTextItems(). The syntax for F_ApiDeallocateTextItems() is: VoidT F_ApiDeallocateTextItems(F_TextItemsT *itemsp); where itemsp is the F_TextItemsT structure that you want to free. If you call F_ApiGetText() for a structural element (FO_Element object), the returned information depends on the type of element, as shown in the following table: Element’s FP_ElementType value Information returned by F_ApiGetText() FV_FO_CONTAINER All the text items from the beginning to the end of the element. FV_FO_SYS_VAR All the text items from the beginning to the end of the variable. FV_FO_XREF All the text items from the beginning to the end of the cross-reference. FV_FO_FOOTNOTE All the text items from the beginning to the end of the footnote. FV_FO_TBL_TITLE All the text items from the beginning to the end of the table title. FV_FO_TBL_CELL All the text items from the beginning to the end of the cell. FDK Programmer’s Guide 319 10 M a n i p u l a t i n g Te x t Getting text Element’s FP_ElementType value Information returned by F_ApiGetText() FV_FO_TBL_HEADING Nothing. F_ApiGetText() fails. FV_FO_TBL_BODY FV_FO_TBL_FOOTING FV_FO_MARKER FV_FO_TBL FV_FO_GRAPHIC FV_FO_EQN FV_FO_TBL_ROW Example The following code retrieves and prints the text in the active document’s main flow to the console. It retrieves and prints only strings and line ends. . . . #include "futils.h" F_ObjHandleT docId, flowId; IntT i; F_TextItemsT tis; F_TextItemT *ip; /* Get IDs for active document and main flow. */ docId = F_ApiGetId(0, FV_SessionId, FP_ActiveDoc); flowId = F_ApiGetId(FV_SessionId, docId, FP_MainFlowInDoc); tis = F_ApiGetText(docId, flowId, FTI_String | FTI_LineEnd); /* Traverse text items and print strings and line ends. */ for (i=0; i dataType == FTI_String) F_Printf(NULL,"%s", ip->u.sdata); else F_Printf(NULL,"\n"); } F_ApiDeallocateTextItems(&tis); . . . 320 FDK Programmer’s Guide Getting and setting the insertion point or text selection ... M a n i p u l a t i n g Te x t Getting and setting the insertion point or text selection The Frame API uses the document property FP_TextSelection to specify the insertion point or text selection in a document. This property specifies a text range, or F_TextRangeT structure, which is defined as: typedef struct { F_TextLocT beg; /* Beginning of the text range */ F_TextLocT end; /* End of the text range */ } F_TextRangeT; The F_TextLocT structure, which specifies a text location (a particular point in text), is defined as: typedef struct{ F_ObjHandleT objId; /* Object that contains the text */ IntT offset; /* Characters from beginning */ } F_TextLocT; If a range of text is selected, FP_TextSelection specifies a selection; F_TextRangeT.beg and F_TextRangeT.end specify the beginning and end of the selection. If there is an insertion point, FP_TextSelection specifies an insertion point; F_TextRangeT.beg and F_TextRangeT.end are the same—both specify the location of the insertion point. If there is no text selection or insertion point, the objId and offset fields of both F_TextRangeT.beg and F_TextRangeT.end are set to 0. For example, suppose the first five characters of the first paragraph on the page shown in Figure 6-1 are selected. Subcolumns Text frame Figure 6-1 Page with text frame containing two subcolumns FDK Programmer’s Guide 321 10 M a n i p u l a t i n g Te x t Getting and setting the insertion point or text selection The fields of the F_TextRangeT structure specified by the document’s FP_TextSelection property have the following values: Field Value beg.objId ID of the first paragraph beg.offset 0 end.objId ID of the first paragraph end.offset 5 If no text is selected and the insertion point is at the very beginning of the paragraph, the fields of the F_TextRangeT structure have the following values: Field Value beg.objId ID of the first paragraph beg.offset 0 end.objId ID of the first paragraph end.offset 0 .............................................................................. IMPORTANT: A valid text range can span multiple paragraphs, subcolumns, or text frames. It can’t span multiple flows, footnotes, table cells, or text lines. .............................................................................. It is possible for a document to have no text selection or insertion point at all. This can occur in the following circumstances: One or more graphic objects in the document are selected One or more entire table cells in the document are selected There is no selection of any type in the document If a document has no text selection or insertion point at all, the fields of the F_TextRangeT structure have the following values: 322 Field Value beg.objId 0 beg.offset 0 FDK Programmer’s Guide Getting and setting the insertion point or text selection Field Value end.objId 0 end.offset 0 ... M a n i p u l a t i n g Te x t For more information on the different types of selection and the properties that represent it, see “How the API represents the selection in a document” on page 80. To get and set a document’s insertion point (or text selection), use F_ApiGetTextRange() and F_ApiSetTextRange() to get and set its FP_TextSelection property. The syntax for these functions is: F_TextRangeT F_ApiGetTextRange(F_ObjHandleT parentId, F_ObjHandleT objId, IntT propNum); VoidT F_ApiSetTextRange(F_ObjHandleT parentId, F_ObjHandleT objId, IntT propNum, F_TextRangeT *setVal); This argument Means parentId The ID of the object containing objId. If objId specifies a document ID, parentId should specify FV_SessionId. If objId specifies a flow, text frame, or table cell ID, parentId should specify the ID of the document that contains it. objId The ID of the object whose property you want to get or set. To get or set the insertion point or text selection in a document, specify the document’s ID. propNum The property to get or set. To get or set the insertion point or text selection in a document, set propNum to FP_TextSelection. setVal The text range to which to set the property. The beg.objId and end.objId fields of the F_TextRangeT structure returned by F_ApiGetTextRange() always specify paragraph or text line IDs. The beg.objId and end.objId fields of the F_TextRangeT structure that you pass to F_ApiSetTextRange() can specify paragraph or text line IDs, but they can also specify flow, footnote, subcolumn, table cell, or text frame IDs. FDK Programmer’s Guide 323 10 M a n i p u l a t i n g Te x t Getting and setting the insertion point or text selection For example, to set the insertion point at the beginning of the first paragraph on the page shown in Figure 6-1, you can use the following code: . . . F_ObjHandleT docId, pgfId; F_TextRangeT tr; . . . /* Get document and paragraph IDs here. */ . . . /* Create text range that specifies an insertion point. */ tr.beg.objId = tr.end.objId = pgfId; tr.beg.offset = tr.end.offset = 0; /* Set document’s insertion point. */ F_ApiSetTextRange(FV_SessionId, docId, FP_TextSelection, &tr); . . . Instead of setting tr.beg.objId and tr.end.objId to the ID of the first paragraph, you can set them to the ID of the A flow, the text frame, or the left subcolumn. For example, the following code also sets the insertion point at the beginning of the first paragraph on the page shown in Figure 6-1: . . . F_ObjHandleT docId, flowId; F_TextRangeT tr; . . . /* Get document and flow IDs here. */ . . . tr.beg.objId = tr.end.objId = flowId; tr.beg.offset = tr.end.offset = 0; /* Set document’s insertion point. */ F_ApiSetTextRange(FV_SessionId, docId, FP_TextSelection, &tr); . . . 324 FDK Programmer’s Guide Getting and setting the insertion point or text selection ... M a n i p u l a t i n g Te x t The beg.offset and end.offset fields of the F_TextRangeT structure returned by F_ApiGetTextRange() always specify offsets relative to the beginning of a paragraph or text line object. The beg.offset and end.offset fields of the F_TextRangeT structure that you pass to F_ApiSetTextRange() can specify offsets relative to the beginning of an object, but they can also use the special value FV_OBJ_END_OFFSET. FV_OBJ_END_OFFSET specifies the offset of the last character in the object containing the text range. To specify offsets near the end of an object, you can add or subtract integers from FV_OBJ_END_OFFSET. For example, the following code selects the last five characters in a paragraph and the end of paragraph symbol: . . . F_ObjHandleT docId, pgfId; F_TextRangeT tr; . . . /* Get document and paragraph IDs here. */ . . . tr.beg.objId = tr.end.objId = pgfId; tr.beg.offset = FV_OBJ_END_OFFSET - 6; tr.end.offset = FV_OBJ_END_OFFSET; F_ApiSetTextRange(FV_SessionId, docId, FP_TextSelection, &tr); . . . The following code selects all the text in a cell: . . . F_ObjHandleT docId, cellId; F_TextRangeT tr; . . . /* Get document and cell IDs here. */ . . . tr.beg.objId = tr.end.objId = cellId; tr.beg.offset = 0; tr.end.offset = FV_OBJ_END_OFFSET; F_ApiSetTextRange(FV_SessionId, docId, FP_TextSelection, &tr); . . . FDK Programmer’s Guide 325 10 M a n i p u l a t i n g Te x t Getting and setting the insertion point or text selection Getting the text in a text range To get the text in a specific text range, use F_ApiGetTextForRange(). The syntax for F_ApiGetTextForRange() is: F_TextItemsT F_ApiGetTextForRange(F_ObjHandleT docId, F_TextRangeT *tr, IntT flags); This argument Means docId The ID of the document containing the text range. tr The text range containing the text you want to get. flags Bit flags that specify the type of text items to retrieve. For a complete list of the constants that represent text item types, see “F_ApiGetText()” on page 242 in the FDK Programmer’s Reference. For example, the following code gets the selected text in the active document: . . . F_ObjHandleT docId; F_TextRangeT tr; F_TextItemsT tis; docId = F_ApiGetId(0, FV_SessionId, FP_ActiveDoc); tr = F_ApiGetTextRange(FV_SessionId, docId, FP_TextSelection); /* If there’s just an insertion point, no text is selected. */ if(tr.beg.objId == tr.end.objId && tr.beg.offset == tr.end.offset) return; tis = F_ApiGetTextForRange(docId, &tr, FTI_String); . . . 326 FDK Programmer’s Guide Getting and setting the insertion point or text selection ... M a n i p u l a t i n g Te x t Getting and setting table selections If a table contains cells that are selected, you can get the table’s ID by querying the document property, FP_SelectedTbl. For more information, see “Getting the IDs of selected tables and table rows” on page 285. If a range of text that includes several tables is selected, you can get the tables’ IDs by calling F_ApiGetText() and retrieving the FTI_TblAnchor text items for the selection. Each FTI_TblAnchor text item specifies the ID of a table. To make the selection in a document include several tables, set the text selection so that it includes the text that contains the tables’ anchors. To make the selection include specific rows and columns within a single table, call F_ApiMakeTblSelection(). For more information, see “F_ApiMakeTblSelection()” on page 290 in the FDK Programmer’s Reference. Element ranges in structured tables If the current element range is within a cell, or if it indicates a selected table part, you can get the table's ID by querying the document property, FP_SelectedTbl. However, it's possible for a client to set the current element range to a point between table part elements. In this case, the document property, FP_SelectedTbl is NULL. For this reason, you cannot always use FP_SelectedTbl to determine whether the current element range is in a table. FDK Programmer’s Guide 327 10 M a n i p u l a t i n g Te x t Getting and setting the insertion point or text selection If FP_SelectedTbl returns NULL, the following code determines whether the current element location is within a table, as well as the type of the parent element: . . . F_ObjHandleT docId; F_PropValT propVal; F_ElementRangeT er; . . . /* Get the ID of the active document. */ docId = F_ApiGetId(0, FV_SessionId, FP_ActiveDoc); if(!docId) return; er = F_ApiGetElementRange(FV_SessionId, docId, FP_ElementSelection); /* First check to see if there is a selected table. */ propVal = F_ApiGetPropVal(FV_SessionId, docId, FP_SelectedTbl); if (!propVal.propVal.u.ival) { /* Now determine whether the current element range is within a table. */ propVal = F_ApiGetPropVal(docId, er.beg.parentId, FP_ElementType); if(propVal.propVal.u.ival == FV_FO_TBL) { F_Printf(NULL,(StringT)"You are in a table\n"); } else if(propVal.propVal.u.ival == FV_FO_TBL_TITLE) { F_Printf(NULL,(StringT)"You are in a table title\n"); } else if(propVal.propVal.u.ival == FV_FO_TBL_HEADING) { F_Printf(NULL,(StringT)"You are in a table heading\n"); } else if(propVal.propVal.u.ival == FV_FO_TBL_BODY) { F_Printf(NULL,(StringT)"You are in a table body\n"); } else if(propVal.propVal.u.ival == FV_FO_TBL_FOOTING) { F_Printf(NULL,(StringT)"You are in a table footing\n"); } else if(propVal.propVal.u.ival == FV_FO_TBL_ROW) { F_Printf(NULL,(StringT)"You are in a table row\n"); } else { 328 FDK Programmer’s Guide Getting and setting the insertion point or text selection ... M a n i p u l a t i n g Te x t F_Printf(NULL,(StringT)"You are not in a table at all\n"); } } /* Be sure to deallocate memory for the property value. */ F_ApiDeallocatePropVal(&propVal); Getting and setting the structural element selection Although you can get and set selected structural elements in a FrameMaker document by getting and setting the text selection, it is usually easier to use the following functions: F_ApiGetElementRange() gets the structural element selection in a document or book. F_ApiSetElementRange() sets the structural element selection in a document or book. The syntax for these functions is: F_ElementRangeT F_ApiGetElementRange( F_ObjHandleT docId, F_ObjHandleT objId, IntT propNum); VoidT F_ApiSetElementRange( F_ObjHandleT docId, F_ObjHandleT objId, IntT propNum, F_ElementRangeT *setVal); This argument Means docId The object containing objId. To get or set the element selection in a document, specify FV_SessionId. objId The ID of the document or book in which you want to get or set the element selection. propNum The property to get or set. To get or set the element selection, specify FP_ElementSelection. setVal The element range to set the property to. FDK Programmer’s Guide 329 10 M a n i p u l a t i n g Te x t Getting and setting the insertion point or text selection The F_ElementRangeT structure is defined as: typedef struct { F_ElementLocT beg; /* Beginning of the element range. */ F_ElementLocT end; /* End of the element range. */ } F_ElementRangeT; The F_ElementLocT structure specifies a location within an element. It is defined as: typedef struct { F_ObjHandleT parentId; /* Parent element ID. */ F_ObjHandleT childId; /* Child element ID. */ IntT offset; /* Offset within child/parent element. */ } F_ElementLocT; For information on how FrameMaker sets the fields of the F_ElementRangeT structure specified by FP_ElementSelection to represent different types of selection, see “How the API represents the element selection in a structured FrameMaker document” on page 81. For examples of how to get and set element selections, see “F_ApiGetElementRange()” on page 175 and “F_ApiSetElementRange()” on page 405 in the FDK Programmer’s Reference. To traverse the selection returned by F_ApiGetElementRange(), traverse the child elements of the element specified by beg.childId. Then traverse its sibling elements and all of their child elements until you reach the element specified by end.childId. To traverse an element’s child elements, you query its FP_FirstChildElement property and then query each child element’s FP_NextSiblingElement property. To traverse an element’s siblings, you query its FP_NextSiblingElement property and then query each sibling element’s FP_NextSiblingElement property. 330 FDK Programmer’s Guide Adding and deleting text ... M a n i p u l a t i n g Te x t Adding and deleting text To add and delete text, use F_ApiAddText() and F_ApiDeleteText(). The syntax for these functions is: F_TextLocT F_ApiAddText(F_ObjHandleT docId, F_TextLocT *textLocp, StringT text); This argument Means docId The ID of the document to which you’ll add text textLocp The point in text (text location) at which you’ll add text text The text to add IntT F_ApiDeleteText(F_ObjHandleT docId, F_TextRangeT *textRangep); This argument Means docId The ID of the document to delete text from textRangep The text range to delete F_ApiAddText() returns the text location at the end of the text that was added. F_ApiDeleteText() deletes any objects, such as tables and markers, anchored in the text it deletes. To add text to, or delete text from, a text inset, you must first unlock it by setting its FP_TiLocked property to False. After you are done adding or deleting text, relock the inset by setting its FP_TiLocked property to True. To specify special characters, line breaks, or paragraph breaks when you add text, use octal codes within the text string. For example, to specify an em dash, use \321. For more information on special characters, see “How the API represents special characters” on page 118. For a list of the characters in the FrameMaker product character set and the corresponding codes, see “Character Sets” in your FrameMaker product user documentation. FDK Programmer’s Guide 331 10 M a n i p u l a t i n g Te x t Adding and deleting text Example The following code adds some text at the insertion point (or the beginning of the current text selection) and then deletes it. The text has a dagger (†) at the end of it. . . . F_TextLocT trm; F_TextRangeT tr; F_ObjHandleT docId; /* Get current text selection. */ docId = F_ApiGetId(0, FV_SessionId, FP_ActiveDoc); tr = F_ApiGetTextRange(FV_SessionId, docId, FP_TextSelection); /* Return if there is no selection or IP. */ if(!tr.beg.objId) return; /* Insert text at insertion point or beginning of selection. * Use the octal code 240 to display the dagger. */ trm = F_ApiAddText(docId, &tr.beg, "Here’s some text.\240"); F_ApiAlert("Now we’ll delete it.", FF_ALERT_CONTINUE_NOTE); /* Set tr to end at end of the added text. Then delete it. */ tr.end.offset = trm.offset; F_ApiDeleteText(docId, &tr); . . . 332 FDK Programmer’s Guide Adding and deleting text ... M a n i p u l a t i n g Te x t Adding text to table cells To add text to a table cell, you must first get the ID of the cell. To do this, you traverse from the table to the row containing the cell, and then to the cell. Once you have the ID of the cell that you want to add text to, you add text to it by calling F_ApiAddText(). The following code adds some text to the first cell in the first row of the selected table in the active document: . . . F_TextLocT ip; F_ObjHandleT docId, tblId, rowId, cellId; /* Get the document and selected table IDs. */ docId = F_ApiGetId(0, FV_SessionId, FP_ActiveDoc); tblId = F_ApiGetId(FV_SessionId, docId, FP_SelectedTbl); /* Get the ID of the first row and cell. */ rowId = F_ApiGetId(docId, tblId, FP_FirstRowInTbl); cellId = F_ApiGetId(docId, rowId, FP_FirstCellInRow); /* Set up text location at beginning of cell. */ ip.objId = cellId; ip.offset = 0; F_ApiAddText(docId, &ip, "This text appears in the cell."); . . . For an example of how to create a table and add text to its title, see “Creating tables” on page 372. FDK Programmer’s Guide 333 10 M a n i p u l a t i n g Te x t Getting and setting text formatting Getting and setting text formatting Although the API doesn’t represent text as objects, the characters in text have properties. Each character has a property list describing its font, color, condition tags, and other character formatting attributes. The API provides special functions to get and set the properties in this list. You can also get and set text formatting by getting and setting paragraph, paragraph format, and character format properties. For more information, see “Getting and setting paragraph properties” on page 304. Getting text properties To get an individual property for a character, use F_ApiGetTextPropVal(). To get the entire list of text properties for a character, use F_ApiGetTextProps(). The syntax for these functions is: F_PropValT F_ApiGetTextPropVal(F_ObjHandleT docId, F_TextLocT *textLocp, IntT propNum); F_PropValsT F_ApiGetTextProps(F_ObjHandleT docId, F_TextLocT *textLocp); This argument Means docId The ID of the document containing the character. textLocp The text location of the character that you want to get text properties for. The returned properties are the properties that apply to the character to the right of the specified location. propNum The text property, such as FP_FontFamily or FP_FontSize, that you want to get. The API allocates the returned properties. Use F_ApiDeallocatePropVal() or F_ApiDeallocatePropVals() to free the properties when you’re done with them. You can get the text properties for only one character at a time, because they can be different for each character. For more information on how the API represents characters and text properties, see “How the API represents text” on page 112. 334 FDK Programmer’s Guide Getting and setting text formatting ... M a n i p u l a t i n g Te x t Example The following code gets the name of the character tag for the character to the right of the insertion point: . . . F_TextRangeT tr; F_PropValT prop; F_ObjHandleT docId; /* Get the current insertion point. */ docId = F_ApiGetId(0, FV_SessionId, FP_ActiveDoc); tr = F_ApiGetTextRange(FV_SessionId, docId, FP_TextSelection); if(!tr.beg.objId) return; prop = F_ApiGetTextPropVal(docId, &tr.end, FP_CharTag); F_Printf(NULL,"The character tag is %s.\n", prop.propVal.u.sval); . . . Setting text properties To set the text properties for a text range, use F_ApiSetTextPropVal() or F_ApiSetTextProps(). The syntax for these functions is: VoidT F_ApiSetTextPropVal(F_ObjHandleT docId, F_TextRangeT *textRangep, F_PropValT *setVal); VoidT F_ApiSetTextProps(F_ObjHandleT docId, F_TextRangeT *textRangep, F_PropValsT *setVal); This argument Means docId The ID of the document containing the text textRangep The text range setVal The property or property list to apply to the text range FDK Programmer’s Guide 335 10 M a n i p u l a t i n g Te x t Getting and setting text formatting Applying a character format to text To apply a character format to a text range, copy the property list of the FO_CharFmt object that represents the character format to the text range. For example, to apply the character format named Emphasis to the current text selection, use the following code: . . . F_TextRangeT tr; F_PropValsT props; F_ObjHandleT docId, charFmtId; IntT i; docId = F_ApiGetId(0, FV_SessionId, FP_ActiveDoc); if (!docId) return; /* Get current text selection. Return if there isn’t one.*/ tr = F_ApiGetTextRange(FV_SessionId, docId,FP_ TextSelection); if (!tr.beg.objId) return; /* Get Emphasis properties. */ charFmtId = F_ApiGetNamedObject(docId, FO_CharFmt, "Emphasis"); props = F_ApiGetProps(docId, charFmtId); /* Apply properties to selection. */ F_ApiSetTextProps(docId, &tr, &props); . . . This code has the same effect as choosing Emphasis in the Character Catalog. If no text is selected, the code has no effect. 336 FDK Programmer’s Guide Getting and setting text formatting ... M a n i p u l a t i n g Te x t Changing individual text properties If you need to apply only an individual property to a text range, use F_ApiSetTextProp(). For example, the following code changes the font family of the selected text to AvantGarde: . . . #include "fstrings.h" F_TextRangeT tr; F_PropValT prop; F_ObjHandleT docId; UIntT i = 0; F_StringsT strings; docId = F_ApiGetId(0, FV_SessionId, FP_ActiveDoc); tr = F_ApiGetTextRange(FV_SessionId, docId,FP_ TextSelection); if (!tr.beg.objId) return; /* Get list of font families available in current session. */ strings = F_ApiGetStrings(0, FV_SessionId, FP_FontFamilyNames); /* Find index of AvantGarde in list of families in session. */ for (i=0; i . Text format rules 1. In all contexts. Text range. No additional formatting. Prefix rules 1. In all contexts Prefix: “ Text range. Figure 8-1 Quotation element definition To create a named format change list, use F_ApiNewNamedObject(). To add the format change list to a format rule clause, set the format rule clause object’s FP_FmtChangeListTag property to the name of the change list. For example, the 370 FDK Programmer’s Guide Creating objects ... Creating and Deleting API Objects following code creates the Code format change list shown in Figure 8-2 and adds it to the first format rule clause of the Para element definition’s first text format rule: . . . F_ObjHandleT docId, changeListId; F_ObjHandleT edefId; UIntT i; F_StringsT fonts; F_IntsT rules, clauses; docId = F_ApiGetId(0, FV_SessionId, FP_ActiveDoc); changeListId = F_ApiNewNamedObject(docId, FO_FmtChangeList, "Code"); /* ** Get the index of the Courier font family in the list of ** fonts available in the current session. */ fonts = F_ApiGetStrings(0, FV_SessionId, FP_FontFamilyNames); for (i=0; i > > Removing menus and menu items To remove a menu or menu item, call F_ApiDelete() with the first parameter set to the ID of the menu that contains the menu or menu item and the second parameter set to the ID of the menu or menu item. F_ApiDelete() deletes a menu or menu item from only the menu you specify. If a menu or menu item is on several menus, you must make a separate F_ApiDelete() call to remove it from each menu. For example, the following code removes the Copy command from the Edit menu: . . . F_ObjHandleT copyCmdId, editMenuId; editMenuId = F_ApiGetNamedObject(FV_SessionId, FO_Menu, "EditMenu"); copyCmdId = F_ApiGetNamedObject(FV_SessionId, FO_Command, "Copy"); F_ApiDelete(editMenuId, copyCmdId); . . . 390 FDK Programmer’s Guide Arranging menus and menu items ... Manipulating Commands and Menus with the API Reordering menus and menu items To change a menu or menu item’s position on a menu, set its FP_NextMenuItemInMenu or FP_PrevMenuItemInMenu properties to specify the IDs of other menus or menu items on the menu. You need to set only one of these properties. FrameMaker automatically sets the other one for you. For example, if the Cut and Copy commands are on the Edit menu, you can use the following code to make Copy appear above Cut: . . . F_ObjHandleT cutCmdId, copyCmdId, editMenuId; editMenuId = F_ApiGetNamedObject(FV_SessionId, FO_Menu, "EditMenu"); cutCmdId = F_ApiGetNamedObject(FV_SessionId, FO_Command, "Cut"); copyCmdId = F_ApiGetNamedObject(FV_SessionId, FO_Command, "Copy"); F_ApiSetId(editMenuId, copyCmdId, FP_NextMenuItemInMenu, cutCmdId); . . . The following F_ApiSetId() call has the same effect as the call in the code above: F_ApiSetId(editMenuId, cutCmdId, FP_PrevMenuItemInMenu, copyCmdId); To move a menu or menu item to the top of a menu, set its FP_PrevMenuItemInMenu property to 0. To move it to the bottom of a menu, set its FP_NextMenuItemInMenu property to 0. For example, the following code moves the Copy menu item to the top of the Edit menu: . . . F_ObjHandleT copyCmdId, editMenuId; editMenuId = F_ApiGetNamedObject(FV_SessionId, FO_Menu, "EditMenu"); copyCmdId = F_ApiGetNamedObject(FV_SessionId, FO_Command, "Copy"); F_ApiSetId(editMenuId, copyCmdId, FP_PrevMenuItemInMenu, 0); . . . FDK Programmer’s Guide 391 13 Manipulating Commands and Menus with the API Arranging menus and menu items If a menu is on a menu bar, setting its FP_PrevMenuItemInMenu property to 0 moves it to the leftmost position on the menu bar; setting its FP_NextMenuItemInMenu property to 0 moves it to the rightmost position. You can’t move a menu or menu item to another menu by setting its FP_NextMenuItemInMenu or FP_PrevMenuItemInMenu properties. Instead, you must delete it and then add it to the menu on which you want it to appear. For example, the following code moves the Font menu from the Format menu to the main menu bar: . . . F_ObjHandleT formatMenuId, fontMenuId, mainMenuBarId; . . . /* Delete instance of Font menu on the Format menu. */ F_ApiDelete(formatMenuId, fontMenuId); F_ApiAddMenuToMenu(mainMenuBarId, fontMenuId); . . . Changing the menu set The user can switch to a menu set by choosing the menu set from View>Menus. Your client can switch menu sets programmatically by setting the session’s FP_CurrentMenuSet property. For example, the following code switches to quick menus: . . . F_ApiSetInt(0, FV_SessionId, FP_CurrentMenuSet, FV_MENU_QUICK); . . . You can’t switch to custom menus unless you have already loaded a custom menu file. To load a custom menu file, call F_ApiLoadMenuCustomizationFile(). 392 FDK Programmer’s Guide Arranging menus and menu items ... Manipulating Commands and Menus with the API Manipulating menu item separators You can manipulate menu item separators (FO_MenuItemSeparator objects) the same way you manipulate menus and menu items, with the following limitations: If there is more than one separator on a menu, each separator must have a different name. A separator can’t be the first or the last item on a menu. Separators can’t appear next to each other. FrameMaker provides six predefined separators: !Separator, Separator1, Separator2, Separator3, Separator4, and Separator5. To get the ID of one of these separators, use F_ApiGetNamedObject() as follows: . . . F_ObjHandleT separatorId; separatorId = F_ApiGetNamedObject(FV_SessionId, FO_MenuItemSeparator, "Separator1"); . . . You can use any predefined separator name when you add a separator to a menu. For example, you could use the predefined separator name Separator5 for the first separator you add to a menu. However, you should try to use the predefined separator name that corresponds to a separator’s position among the separators on a menu. For example, the first separator on a menu should use the predefined separator name Separator1 and the second separator should use the predefined separator name Separator2. This makes it easier for other clients and users who modify menu configuration files to manipulate the separators. You can use the same separator on different menus. For example, if you create two menus that contain two separators, you can use Separator1 and Separator2 on each menu. FDK Programmer’s Guide 393 13 Manipulating Commands and Menus with the API Arranging menus and menu items Adding, moving, and deleting separators You can add, move, and delete separators the same way you add, move, and delete commands and menu items. For example, the following code removes the separator that appears after the Conditional Text menu item on the Special menu. It then adds a separator and moves it above the Conditional Text menu item. . . . F_ObjHandleT specialMenuId, separatorId, conditionCmdId; specialMenuId = F_ApiGetNamedObject(FV_SessionId, FO_Menu, "SpecialMenu"); separatorId = F_ApiGetNamedObject(FV_SessionId, FO_MenuItemSeparator, "Separator1"); conditionCmdId = F_ApiGetNamedObject(FV_SessionId, FO_Command, "ConditionalText"); /* Delete the separator. */ F_ApiDelete(specialMenuId, separatorId); /* Add it back and move it below the Conditional Text item. */ F_ApiAddCommandToMenu(specialMenuId, separatorId); F_ApiSetId(specialMenuId, separatorId, FP_NextMenuItemInMenu, conditionCmdId); . . . Creating separator objects Because separators appear the same and you can use the same separator on multiple menus, you will normally need only the predefined separators. If you need additional separators, you can create them with F_ApiNewNamedObject() as follows: . . . F_ObjHandleT separatorId; separatorId = F_ApiNewNamedObject(FV_SessionId, FO_MenuItemSeparator, "MySeparator"); . . . 394 FDK Programmer’s Guide Getting and setting menu item labels ... Manipulating Commands and Menus with the API Getting and setting menu item labels Most FrameMaker product menu items have only one label. For example, the label of the Cut command is always Cut. However, some menu items have different labels for different contexts. For example, the label of the TableConvert command is Convert to Table when paragraph text is selected, but Convert to Paragraphs when the insertion point is in a table or table cells are selected. The FP_Labels property specifies the labels a menu item can have in different contexts. If a menu item has one label for all contexts, its FP_Labels property specifies only that label. Otherwise, its FP_Labels property specifies pairs of strings with the following format: context, label, where context specifies a context and label specifies the menu item label that appears when that context is applicable. The following table lists some of the values context can have. Context value When the label is displayed Book When a book is active Document When a document is active Long When a menu item is on a pull-down menu or the document pop-up menu ToTable When text that is not a table or text line is selected ToText When the insertion point is in a table cell or one or more table cells are selected Short When a menu item is on a pull-right menu or one of the formatting bar menus For example, the strings specified by the FP_Labels property of the TableConvert command are: {"ToTable", "Convert to Table...", "ToText", "Convert to Paragraphs..."} FDK Programmer’s Guide 395 13 Manipulating Commands and Menus with the API Getting and setting menu item labels Setting the labels of FrameMaker product menu items You can change the labels of FrameMaker product menu items. If a FrameMaker product menu item has labels for different contexts, you can change only the strings that specify the labels. You can’t change the strings that specify the contexts in which the labels appear. For example, the following code changes the labels for the TableConvert command: . . . #include "fstrings.h" F_ObjHandleT cmdId; StringT labels[4]; F_StringsT myLabels; . . . labels[0] = (StringT) F_StrCopyString("ToTable"); labels[1] = (StringT) F_StrCopyString("Make table out of this"); labels[2] = (StringT) F_StrCopyString("ToText"); labels[3] = (StringT) F_StrCopyString("Convert to paragraphs"); myLabels.len = 4; myLabels.val = (StringT *)labels; F_ApiSetStrings(FV_SessionId, cmdId, FP_Labels, &myLabels); . . . Setting the labels of client-defined menu items A client-defined menu item can have only one label for all contexts. Its FP_Labels property should specify only one string. For example, the following code sets the label of a client-defined menu item to My Item: . . . F_StringsT myLabels; F_ObjHandleT cmdId; StringT labels[1]; labels[0] = (StringT)"My Item"; myLabels.len = 1; myLabels.val = (StringT *)labels; F_ApiSetStrings(FV_SessionId, cmdId, FP_Labels, &myLabels); . . . 396 FDK Programmer’s Guide Manipulating expandomatic menu items ... Manipulating Commands and Menus with the API Manipulating expandomatic menu items An expandomatic menu item is a dynamically determined set of menu items that FrameMaker products treat as a single menu item. For example, the list of paragraph formats that appears on the lower part of the Format>Paragraphs menu is an expandomatic menu item named !ShowParagraphTags. FrameMaker products currently use the following expandomatic menu items: Expandomatic menu item name Description !ShowCharacterTags The list of character formats available in the current document !ShowDocumentWindows The list of document windows in the current session !ShowFilesRecentlyVisited The list of the last five files opened !ShowFontChoices The list of font families available in the session !ShowImportFiles The list of open files that a user can import into the current document !ShowParagraphTags The list of paragraph formats available in the current document A FrameMaker product can change the contents of an expandomatic menu item during a session. For example, when the user sets the insertion point in a document, the FrameMaker product changes the !ShowParagraphTags menu item to list the paragraph formats available in the document. If the user adds or deletes a paragraph format, the FrameMaker product updates the list to reflect the change. You can manipulate an expandomatic menu item just as you manipulate any other menu item. However, you can’t manipulate the individual items that constitute the expandomatic item. For example, you can move or remove the entire !ShowParagraphTags item, but you can’t move or remove an individual item, such as Body, that appears on it. You can get the ID of an expandomatic item with the code similar to the following: . . . F_ObjHandleT itemId; itemId = F_ApiGetNamedObject(FV_SessionId, FO_Command, "!ShowParagraphTags"); . . . Individual items in an expandomatic item don’t have IDs. You can determine which items an expandomatic menu item contains by getting object properties. For example, FDK Programmer’s Guide 397 13 Manipulating Commands and Menus with the API Using check marks you can determine which items !ShowFontChoices contains by getting the session property FP_FontFamilyNames. Using check marks FrameMaker products display check marks next to some menu items to indicate the state of a setting or option. For example, when borders are visible in a document, a FrameMaker product displays a check mark next to the Borders menu item. Your client can also display check marks next to its menu items. Menu items have two properties that control check marks: FP_CanHaveCheckMark, which specifies whether an item can have a check mark FP_CheckMarkIsOn, which specifies whether a check mark appears next to an item To use a check mark with a menu item, set FP_CanHaveCheckMark to True. Then make the check mark visible by setting FP_CheckMarkIsOn to True, or invisible by setting it to False. .............................................................................. IMPORTANT: Once you set FP_CanHaveCheckMark to True, resetting it to False has no effect. Setting FP_CheckMarkIsOn has an effect only when FP_CanHaveCheckMark is set to True. .............................................................................. Using context-sensitive commands and menu items Many FrameMaker product commands and menu items change depending on the context. For example, the Group command is disabled when there are no objects selected. The API provides properties that allow you to make your client’s commands and menu items context sensitive like FrameMaker product commands. The following sections describe how to use these properties. 398 FDK Programmer’s Guide Using context-sensitive commands and menu items ... Manipulating Commands and Menus with the API Enabling commands for specific contexts The FP_EnabledWhen property specifies the contexts in which a command is enabled. The following table lists some of the values FP_EnabledWhen can have. FP_EnabledWhen value Context in which a menu item is active FV_ENABLE_ALWAYS_ENABLE All contexts. This is the default value. FV_ENABLE_ALWAYS_DISABLE No context. Setting FP_EnabledWhen to this value completely disables the menu item. FV_ENABLE_IS_TEXT_SEL Text is selected in a paragraph or a graphic text line. FV_ENABLE_IN_TEXT_LINE The insertion point or selection is in a graphic text line. For a complete list of the values FP_EnabledWhen can have, see “FO_Command” on page 756 of the FDK Programmer’s Reference. When you create a command, FP_EnabledWhen has the default value, FV_ENABLE_ALWAYS_ENABLE. To completely disable a command, set its FP_EnabledWhen property to FV_ENABLE_ALWAYS_DISABLE. To reenable a command, reset FP_EnabledWhen to FV_ENABLE_ALWAYS_ENABLE. To enable a command only in a specific context, set its FP_EnabledWhen property to one of the other listed values. For example, the following code creates a command that is enabled only when text is selected: . . . F_ObjHandleT cmdId; cmdId = F_ApiDefineCommand(1,"Transpose","Transpose Words", ""); F_ApiSetInt(FV_SessionId, cmdId, FP_EnabledWhen, FV_ENABLE_IS_TEXT_SEL); . . . If a command is a menu item, it appears dimmed when it is disabled. You can determine whether a menu item is disabled by getting its FP_MenuItemIsEnabled property. This is easier than getting its FP_EnabledWhen property and determining whether the specified context currently applies. You can’t set the FP_MenuItemIsEnabled property. FDK Programmer’s Guide 399 13 Manipulating Commands and Menus with the API Using context-sensitive commands and menu items Using shift menu items FrameMaker products provide several shift menu items, menu items that change when the user holds down the Shift key. For example, when the user holds down the Shift key and displays the File menu, the label of the Close menu is Close All Open Files instead of Close. If the user chooses the menu item, the FrameMaker product closes all open files. 400 FDK Programmer’s Guide Using context-sensitive commands and menu items ... Manipulating Commands and Menus with the API Shift menu items actually represent two separate commands, which are linked by their FP_HasShiftOrUnshiftCommand and FP_ShiftOrUnshiftCommand properties. For example, the Close menu item represents the commands Close and CloseAll. The following table shows the values of their FP_HasShiftOrUnshiftCommand and FP_ShiftOrUnshiftCommand properties: Command Property Value Close FP_HasShiftOrUnshiftCommand FV_ITEM_HAS_SHIFT_COMMAND FP_ShiftOrUnshiftCommand ID of CloseAll command FP_HasShiftOrUnshiftCommand FV_ITEM_HAS_UNSHIFT_COMMAND FP_ShiftOrUnshiftCommand ID of Close command CloseAll The API allows clients to create and use shift menu items. To combine two commands into a shift menu item, you have to set the FP_HasShiftOrUnshiftCommand and FP_ShiftOrUnshiftCommand properties for only one of the commands. The API automatically sets the properties of the other command for you. For example, the following code creates a shift menu item representing the clientdefined commands, Checkin and CheckinAll. If the user displays the Edit menu normally, the label Check in File appears on it. If the user holds down the Shift key and displays the Edit menu, the label Check in All Open Files appears on it. . . . #define CHECKIN_CMD 1 #define CHECKIN_ALL_CMD 2 F_ObjHandleT editMenuId, checkinCmdId, checkinAllCmdId; editMenuId = F_ApiGetNamedObject(FV_SessionId, FO_Menu, "EditMenu"); checkinCmdId = F_ApiDefineAndAddCommand(CHECKIN_CMD, editMenuId, "Checkin","Check in File", ""); checkinAllCmdId = F_ApiDefineCommand(CHECKIN_ALL_CMD, "CheckinAll","Check in All Open Files",""); F_ApiSetInt(editMenuId, checkinCmdId, FP_HasShiftOrUnshiftCommand, FV_ITEM_HAS_SHIFT_COMMAND); F_ApiSetId(editMenuId, checkinCmdId, FP_ShiftOrUnshiftCommand, checkinAllCmdId); . . . FDK Programmer’s Guide 401 13 402 Manipulating Commands and Menus with the API Using context-sensitive commands and menu items FDK Programmer’s Guide 13 Creating Custom Dialog Boxes for Your Client .................................. ..... 10 This chapter describes how to use FrameMaker products to create and modify custom dialog boxes that you can use in your client’s user interface. You can create a dialog box that contains the following items: Boxes Buttons Checkboxes Pop-up menus (with a standard appearance or drawn from bitmap images) Radio buttons Scroll bars Scroll lists Text boxes (with one or more lines) If your client’s user interface requires only simple modal dialog boxes, you may not need to create custom dialog boxes. The API provides several simple, ready-made modal dialog boxes. For information on using these dialog boxes, see “Using API dialog boxes to prompt the user for input” on page 193. Overview The process of including a custom dialog box in your client involves the following general steps: 1 Create the custom dialog box. Creating a dialog box involves designing its layout and items and saving this information in a file format that can be used to build your FDK client. Instructions for this step are presented in this chapter. 2 Write the code in your client to manipulate the dialog box. After you create a custom dialog box for your client, you need to add code to your client to manipulate it. For more information, see Chapter 11, “Handling Custom Dialog Box Events.” FDK Programmer’s Guide 403 14 C r e a t i n g C u s t o m D i a l o g B o x e s f o r Yo u r C l i e n t Overview 3 Compile the dialog box with your client in the build process. After you write the code for your client, you can compile the code with the files containing dialog box information. This overview section describes the fundamentals behind the first step of this process, creating dialog boxes for clients. The later sections of this chapter describe the specific procedures in this step of the process. The end of this chapter lists some helpful tips to keep in mind when editing dialog boxes. Designing a dialog box in a FrameMaker product You can use a FrameMaker product as a dialog editing application. FrameMaker products can represent dialog box information as special Frame graphic objects. You can then modify the dialog box and its items just as you would modify standard Frame graphic objects. Figure 10-1 shows a dialog box edited within a FrameMaker product. Figure 10-1 Using a FrameMaker product to design a dialog box To edit dialog box information through a FrameMaker product, you open a special type of file called a Frame dialog resource (DRE) file. As Figure 10-2 shows, when you open a DRE file in a FrameMaker product, the FrameMaker product translates the dialog box information into a graphic representation of the dialog box. 404 FDK Programmer’s Guide Overview ... C r e a t i n g C u s t o m D i a l o g B o x e s f o r Yo u r C l i e n t This is similar to opening a Frame binary document in a FrameMaker product. When you open a Frame binary document, the FrameMaker product translates the document information into a graphic representation of the document. FrameMaker Product Open Frame binary document VIEWS Save Frame binary document 1 Representation of the document Open Save Representation of the dialog box DRE file DRE file Figure 10-2 Comparison between opening a Frame binary file and a DRE file The rest of this section describes Frame DRE files and how FrameMaker products interpret these files. Frame DRE files A DRE file is a text file that uses special syntax to describe a dialog box and its items. The following lines from a DRE file illustrate how the DRE file syntax describes the OK button in a dialog box:
Source Exif Data:
File Type : PDF File Type Extension : pdf MIME Type : application/pdf PDF Version : 1.6 Linearized : Yes Author : Adobe Solution Network Create Date : 2015:01:16 15:28:53Z Keywords : API, FDK, C, Programming, Client, Plugin Modify Date : 2015:01:16 15:29:56+05:30 Subject : FDK Documentation Language : en XMP Toolkit : Adobe XMP Core 5.4-c005 78.150055, 2012/11/19-18:45:32 Format : application/pdf Title : FDK Programmer’s Guide Creator : Adobe Solution Network Description : FDK Documentation Creator Tool : FrameMaker 12.0.3 Metadata Date : 2015:01:16 15:29:56+05:30 Producer : Acrobat Distiller 11.0 (Windows) Document ID : uuid:ddde7987-969f-4420-be47-7c5549548360 Instance ID : uuid:638cba42-aa50-4d1d-8ef1-6a2da4f55932 Page Mode : UseOutlines Page Count : 560EXIF Metadata provided by EXIF.tools