1 /* AbiWord 2 * Copyright (C) 1998 AbiSource, Inc. 3 * 4 * This program is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU General Public License 6 * as published by the Free Software Foundation; either version 2 7 * of the License, or (at your option) any later version. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program; if not, write to the Free Software 16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 17 * 02110-1301 USA. 18 */ 19 20 #ifndef DOCLAYOUT_H 21 #define DOCLAYOUT_H 22 23 #ifdef HAVE_CONFIG_H 24 #include "config.h" 25 #endif 26 27 #include <stdio.h> 28 #include "ut_types.h" 29 #include "ut_vector.h" 30 #include "ut_hash.h" 31 #include "pt_Types.h" 32 #include "fp_PageSize.h" 33 #include "fl_Layout.h" 34 #include "fl_PartOfBlock.h" 35 #include "ut_units.h" 36 #include "xav_Listener.h" 37 38 39 typedef enum _FootnoteType 40 { 41 FOOTNOTE_TYPE_NUMERIC = 0, 42 FOOTNOTE_TYPE_NUMERIC_SQUARE_BRACKETS, 43 FOOTNOTE_TYPE_NUMERIC_PAREN, 44 FOOTNOTE_TYPE_NUMERIC_OPEN_PAREN, 45 FOOTNOTE_TYPE_LOWER, 46 FOOTNOTE_TYPE_LOWER_PAREN, 47 FOOTNOTE_TYPE_LOWER_OPEN_PAREN, 48 FOOTNOTE_TYPE_UPPER, 49 FOOTNOTE_TYPE_UPPER_PAREN, 50 FOOTNOTE_TYPE_UPPER_OPEN_PAREN, 51 FOOTNOTE_TYPE_LOWER_ROMAN, 52 FOOTNOTE_TYPE_LOWER_ROMAN_PAREN, 53 FOOTNOTE_TYPE_UPPER_ROMAN, 54 FOOTNOTE_TYPE_UPPER_ROMAN_PAREN, 55 _FOOTNOTE_TYPE_INVALID = 10000 56 } FootnoteType; 57 58 /** describe a footnote. */ 59 typedef struct { 60 FootnoteType n; /**< numeric value */ 61 const char * label; /**< UI label */ 62 const char * prop; /**< property string */ 63 } FootnoteTypeDesc; 64 65 extern const FootnoteTypeDesc s_FootnoteTypeDesc[]; 66 67 class FV_View; 68 class fl_DocListener; 69 class fl_SectionLayout; 70 class fl_DocSectionLayout; 71 class fl_BlockLayout; 72 class fl_TOCLayout; 73 class fp_Page; 74 class PD_Document; 75 class PP_AttrProp; 76 class GR_Graphics; 77 class GR_Font; 78 class UT_Timer; 79 class UT_Worker; 80 class fl_AutoNum; 81 class PX_ChangeRecord_StruxChange; 82 class fl_FootnoteLayout; 83 class fl_AnnotationLayout; 84 class fl_EndnoteLayout; 85 class fp_EndnoteContainer; 86 class GR_EmbedManager; 87 class fl_FrameLayout; 88 class fp_FrameContainer; 89 class fp_Container; 90 91 // the following get used by view and layout code, 92 // since they're private to the formatter, we stick 'em here 93 #define fl_PAGEVIEW_PAGE_SEP m_pG->tlu(20) // must be <= MARGIN_Y 94 #define fl_PAGEVIEW_MARGIN_X m_pG->tlu(25) 95 #define fl_PAGEVIEW_MARGIN_Y m_pG->tlu(25) 96 97 // ---------------------------------------------------------------- 98 99 // Note: Here used to be an overview of the classes in this 100 // directory. That has been moved to README.TXT since a newcomer would 101 // not know which source file to look in for that 102 // information. README.TXT on the other hand stands clearly out from 103 // the rest of the files. jskov 2000.12.29 104 105 class ABI_EXPORT FL_DocLayout 106 { 107 friend class fl_DocListener; 108 friend class fl_BlockLayout; 109 public: 110 FL_DocLayout(PD_Document* doc, GR_Graphics* pG); 111 ~FL_DocLayout(); 112 113 void fillLayouts(void); 114 bool loadPendingObjects(void); 115 bool AnchoredObjectHelper(double x, double y, UT_sint32 iPage, UT_UTF8String & allProps, PT_DocPosition & pos, fp_Page *& pPage); 116 void setView(FV_View*); 117 getView(void)118 inline FV_View * getView(void) const { return m_pView; } getGraphics(void)119 inline GR_Graphics* getGraphics(void) const { return m_pG; } 120 void setGraphics(GR_Graphics * pG); getGraphicTick(void)121 UT_uint32 getGraphicTick(void) const { return m_iGraphicTick;} incrementGraphicTick(void)122 void incrementGraphicTick(void) { m_iGraphicTick++;} getDocument(void)123 inline PD_Document* getDocument(void) const { return m_pDoc; } 124 #ifdef ENABLE_SPELL getPendingBlockForSpell(void)125 inline const fl_BlockLayout* getPendingBlockForSpell(void) const { return m_pPendingBlockForSpell; }; getPendingWordForSpell(void)126 inline const fl_PartOfBlockPtr& getPendingWordForSpell(void) const { return m_pPendingWordForSpell; }; 127 #endif 128 129 // The smart quote stuff works by listening for insertions (typing 130 // and paste) and motion. It needs one character of type-ahead 131 // before working the algorithm, so a single quote character going 132 // by is remembered as "pending". After the type-ahead (or 133 // motion) occurs, the pending quote is considered for promotion. 134 // For an insertion of multiple characters (which probably just 135 // means a paste), all smart quote consideration can be done 136 // immediately except for a quote occuring in the very last 137 // character of the stuff being inserted. getPendingBlockForSmartQuote(void)138 inline fl_BlockLayout* getPendingBlockForSmartQuote(void) const { return m_pPendingBlockForSmartQuote; }; getOffsetForSmartQuote(void)139 inline UT_uint32 getOffsetForSmartQuote(void) const { return m_uOffsetForSmartQuote; }; 140 void setPendingSmartQuote(fl_BlockLayout *block, UT_uint32 offset); 141 void considerSmartQuoteCandidateAt(fl_BlockLayout *block, UT_uint32 offset); considerPendingSmartQuoteCandidate()142 inline void considerPendingSmartQuoteCandidate() {considerSmartQuoteCandidateAt(m_pPendingBlockForSmartQuote, m_uOffsetForSmartQuote); } 143 144 void notifyBlockIsBeingDeleted(fl_BlockLayout *pBlock); setSkipUpdates(UT_uint32 numSkips)145 void setSkipUpdates(UT_uint32 numSkips) {m_iSkipUpdates = numSkips;} getSkipUpdates(void)146 UT_uint32 getSkipUpdates(void) { return m_iSkipUpdates;} 147 void setNeedsRedraw(void); 148 UT_sint32 getHeight() const; 149 UT_sint32 getWidth() const; 150 void refreshRunProperties(void); 151 const GR_Font* findFont(const PP_AttrProp * pSpanAP, 152 const PP_AttrProp * pBlockAP, 153 const PP_AttrProp * pSectionAP, 154 bool isField = false 155 ) const; 156 157 const GR_Font* findFont(const PP_AttrProp * pSpanAP, 158 const PP_AttrProp * pBlockAP, 159 const PP_AttrProp * pSectionAP, 160 GR_Graphics * pG, 161 bool isField = false 162 ) const; 163 164 void changeDocSections(const PX_ChangeRecord_StruxChange * pcrx, fl_DocSectionLayout * pDSL); 165 fp_Page* addNewPage(fl_DocSectionLayout* pOwner, bool bNoUpdate=false); 166 fp_Page* getFirstPage() const; 167 fp_Page* getLastPage() const; 168 fp_Page* getNthPage(int n) const; 169 UT_sint32 countPages() const; 170 UT_sint32 findPage(fp_Page * pPage) const; // FIXME figure out how to pass a const fp_Page * 171 void setFramePageNumbers(UT_sint32 iStartPage); 172 fl_FrameLayout* relocateFrame(fl_FrameLayout * pFL, fl_BlockLayout * newBlock, 173 const gchar** attributes = NULL, const gchar **properties = NULL); 174 void clearAllCountWraps(void); 175 bool addFramesToBeInserted(fp_FrameContainer * pFrame); 176 bool removeFramesToBeInserted(fp_FrameContainer * pFrame); 177 fp_FrameContainer * findFramesToBeInserted(fp_Page * pPage); 178 getPercentFilled(void)179 UT_sint32 getPercentFilled(void) const 180 { return m_iFilled;} setPercentFilled(UT_sint32 iFill)181 void setPercentFilled(UT_sint32 iFill) 182 { m_iFilled = iFill;} setLayoutIsFilling(bool bisFill)183 void setLayoutIsFilling(bool bisFill) { m_bisLayoutFilling = bisFill;} isLayoutFilling(void)184 bool isLayoutFilling(void) const { return m_bisLayoutFilling;} 185 fl_BlockLayout* findBlockAtPosition(PT_DocPosition pos, bool bLookOnlyBefore = false) const; 186 fl_BlockLayout* findBlockAtPositionReverse(PT_DocPosition pos) const; 187 void deletePage(fp_Page* pPage, bool bDontNotify); 188 189 void formatAll(); 190 void updateLayout(); 191 void updateOnViewModeChange(); 192 void rebuildFromHere(fl_DocSectionLayout * pDSL); 193 void updateColor(); 194 195 #ifdef ENABLE_SPELL 196 bool isPendingWordForSpell(void) const; 197 bool touchesPendingWordForSpell(fl_BlockLayout *pBlock, 198 UT_sint32 iOffset, 199 UT_sint32 chg) const; 200 void setPendingWordForSpell(const fl_BlockLayout *pBlock, 201 const fl_PartOfBlockPtr& pWord); 202 bool checkPendingWordForSpell(void); 203 void dequeueAll(void); 204 void queueAll(UT_uint32 iReason); 205 void queueBlockForBackgroundCheck(UT_uint32 reason, fl_BlockLayout *pBlock, bool bHead=false); 206 bool dequeueBlockForBackgroundCheck(fl_BlockLayout *pBlock); 207 spellQueueHead(void)208 fl_BlockLayout *spellQueueHead(void) const 209 { 210 return m_toSpellCheckHead; 211 } setSpellQueueHead(fl_BlockLayout * h)212 void setSpellQueueHead(fl_BlockLayout *h) 213 { 214 m_toSpellCheckHead = h; 215 } spellQueueTail(void)216 fl_BlockLayout *spellQueueTail(void) const 217 { 218 return m_toSpellCheckTail; 219 } setSpellQueueTail(fl_BlockLayout * t)220 void setSpellQueueTail(fl_BlockLayout *t) 221 { 222 m_toSpellCheckTail = t; 223 } 224 #endif 225 void addSection(fl_DocSectionLayout*); 226 void removeSection(fl_DocSectionLayout*); 227 void insertSectionAfter(fl_DocSectionLayout* pAfter, fl_DocSectionLayout* pNewSL); 228 void addHdrFtrSection(fl_SectionLayout* pHdrFtrSL); 229 void removeHdrFtrSection(fl_SectionLayout* pHdrFtrSL); 230 getFirstSection(void)231 inline fl_DocSectionLayout* getFirstSection(void) const { return m_pFirstSection; } getLastSection(void)232 inline fl_DocSectionLayout* getLastSection(void) const { return m_pLastSection; } 233 234 fl_DocSectionLayout* findSectionForHdrFtr(const char* pszHdrFtrID) const; 235 void deleteEmptyColumnsAndPages(void); 236 void deleteEmptyPages( bool bDontNotify = false); 237 GR_EmbedManager * getEmbedManager(const char * szEmbedType); 238 // -------------------------------------------------------------------- 239 // Footnote Methods 240 // fl_DocLAyout stores this Vector of footnotes to speed things up and 241 // to provide convience routines for other classes and methods 242 // 243 UT_uint32 countFootnotes(void) const; 244 void addFootnote(fl_FootnoteLayout *); 245 void removeFootnote(fl_FootnoteLayout *); 246 fl_FootnoteLayout * getNthFootnote(UT_sint32 i) const; 247 UT_sint32 getFootnoteVal(UT_uint32 footpid) const; 248 fl_FootnoteLayout * findFootnoteLayout(UT_uint32 footpid) const; 249 FootnoteType getFootnoteType(void) const; 250 void getStringFromFootnoteVal(UT_String & sVal, UT_sint32 iVal, FootnoteType iFootType) const; 251 getInitialFootVal(void)252 UT_sint32 getInitialFootVal(void) const 253 { return m_iFootnoteVal;} getRestartFootOnSection(void)254 bool getRestartFootOnSection(void) const 255 { return m_bRestartFootSection;} getRestartFootOnPage(void)256 bool getRestartFootOnPage(void) const 257 { return m_bRestartFootPage;} 258 FootnoteType FootnoteTypeFromString( const gchar * pszStr); 259 // EndNotes 260 void insertEndnoteContainer(fp_EndnoteContainer * pECon); 261 void removeEndnoteContainer(fp_EndnoteContainer * pECon); 262 fl_DocSectionLayout * getDocSecForEndnote(fp_EndnoteContainer * pECon ) const; 263 UT_uint32 countEndnotes(void) const; 264 void addEndnote(fl_EndnoteLayout *); 265 void removeEndnote(fl_EndnoteLayout *); 266 fl_EndnoteLayout * getNthEndnote(UT_sint32 i) const; 267 UT_sint32 getEndnoteVal(UT_uint32 endpid) const; 268 fl_EndnoteLayout * findEndnoteLayout(UT_uint32 endpid) const; 269 getEndnoteType(void)270 FootnoteType getEndnoteType(void) const 271 { return m_EndnoteType; } getInitialEndVal(void)272 UT_sint32 getInitialEndVal(void) const 273 { return m_iEndnoteVal;} getRestartEndOnSection(void)274 bool getRestartEndOnSection(void) const 275 { return m_bRestartEndSection;} getPlaceEndAtDocEnd(void)276 bool getPlaceEndAtDocEnd(void) const 277 { return m_bPlaceAtDocEnd;} getPlaceEndAtSecEnd(void)278 bool getPlaceEndAtSecEnd(void) const 279 { return m_bPlaceAtSecEnd;} 280 // -------------------------------------------------------------------- 281 // Annotation Methods 282 // fl_DocLAyout stores this Vector of Anntations to speed things up and 283 // to provide convience routines for other classes and methods 284 // 285 UT_uint32 countAnnotations(void) const; 286 void addAnnotation(fl_AnnotationLayout * pAL); 287 void removeAnnotation(fl_AnnotationLayout * pAL); 288 fl_AnnotationLayout * getNthAnnotation(UT_sint32 i) const; 289 UT_sint32 getAnnotationVal(UT_uint32 footpid) const; 290 fl_AnnotationLayout * findAnnotationLayout(UT_uint32 footpid) const; 291 bool displayAnnotations(void) const; 292 void setDisplayAnnotations(bool bDisplayAnnotations); 293 bool collapseAnnotations(void); 294 295 // -------------------------------------------------------------------- 296 // RDF Anchor Methods 297 bool displayRDFAnchors(void) const; 298 void setDisplayRDFAnchors(bool v); 299 300 // --------------------------------------------------- 301 // Table of contents 302 //---------------------------------------------------- 303 UT_sint32 getNumTOCs(void) const; 304 fl_TOCLayout * getNthTOC(UT_sint32 i) const; 305 bool addOrRemoveBlockFromTOC(fl_BlockLayout * pBlock); 306 bool removeBlockFromTOC(fl_BlockLayout * pBlock); 307 bool isBlockInTOC(fl_BlockLayout * pBlock) const; 308 bool getMatchingBlocksFromTOCs(fl_BlockLayout * pBlock, UT_GenericVector<fl_BlockLayout*>* pVecBlock) const; 309 bool addTOC(fl_TOCLayout * pTOC); 310 bool removeTOC(fl_TOCLayout * pTOC); 311 void recalculateTOCFields(void); 312 bool updateTOCsOnBookmarkChange(const gchar * pBookmark); 313 // -------------------------------------------------------------------- 314 #ifdef ENABLE_SPELL getAutoSpellCheck(void)315 bool getAutoSpellCheck(void) const { return (hasBackgroundCheckReason(bgcrSpelling)); } getAutoGrammarCheck(void)316 bool getAutoGrammarCheck(void) const { return (hasBackgroundCheckReason(bgcrGrammar)); } getSpellCheckCaps(void)317 bool getSpellCheckCaps(void) const { return m_bSpellCheckCaps; } getSpellCheckNumbers(void)318 bool getSpellCheckNumbers(void) const { return m_bSpellCheckNumbers; } getSpellCheckInternet(void)319 bool getSpellCheckInternet(void) const { return m_bSpellCheckInternet; } 320 void recheckIgnoredWords(); 321 #endif 322 // -------------------------------------------------------------------- getSmartQuotes(void)323 bool getSmartQuotes(void) const { return (hasBackgroundCheckReason(bgcrSmartQuotes)); } 324 // -------------------------------------------------------------------- 325 addBackgroundCheckReason(UT_uint32 reason)326 inline void addBackgroundCheckReason(UT_uint32 reason) {m_uDocBackgroundCheckReasons |= reason;} removeBackgroundCheckReason(UT_uint32 reason)327 inline void removeBackgroundCheckReason(UT_uint32 reason) {m_uDocBackgroundCheckReasons &= ~reason;} hasBackgroundCheckReason(UT_uint32 reason)328 inline bool hasBackgroundCheckReason(UT_uint32 reason) const {return ((m_uDocBackgroundCheckReasons & reason) ? true : false);} getBackgroundCheckReasons()329 inline UT_uint32 getBackgroundCheckReasons() const {return (m_uDocBackgroundCheckReasons);} 330 331 #ifdef ENABLE_SPELL getPendingBlockForGrammar(void)332 fl_BlockLayout * getPendingBlockForGrammar(void) const 333 { 334 return m_PendingBlockForGrammar; 335 } 336 void setPendingBlockForGrammar(fl_BlockLayout * pBL); 337 #endif 338 void triggerPendingBlock(fl_BlockLayout * pBL); 339 340 // These are used as bit flags in a UT_uint32. The enum is here just 341 // to get the namespace protection. 342 enum backgroundCheckReason 343 { 344 bgcrNone = 0, 345 bgcrDebugFlash = (1 << 0), 346 bgcrSpelling = (1 << 1), 347 bgcrSmartQuotes = (1 << 2), // ha! we're not using background checks for this after all 348 bgcrGrammar = (1 << 3) 349 }; 350 351 // New List Guts 352 inline fl_AutoNum * getListByID(UT_uint32 id) const; 353 inline fl_AutoNum * getNthList(UT_uint32 i) const; // { return m_vecLists[i]; } 354 inline UT_uint32 getListsCount(void) const; // { return m_vecLists.getItemCount(); } 355 inline void addList(fl_AutoNum * pAutoNum); isLayoutDeleting(void)356 bool isLayoutDeleting(void) const {return m_bDeletingLayout;} getRedrawCount()357 UT_uint32 getRedrawCount() const {return m_iRedrawCount;} 358 359 360 void updatePropsNoRebuild(void); 361 void updatePropsRebuild(void); getDocSize(void)362 PT_DocPosition getDocSize(void) const 363 { return m_iDocSize;} getLID(void)364 UT_uint32 getLID(void) const 365 { return m_lid;} 366 void notifyListeners(AV_ChangeMask mask); 367 void setQuickPrint(GR_Graphics * pGraphics); 368 GR_Graphics * getQuickPrintGraphics(void) const; isQuickPrint(void)369 bool isQuickPrint(void) const 370 { return m_bIsQuickPrint;} 371 GR_EmbedManager * getQuickPrintEmbedManager(const char * szEmbedType); 372 fp_PageSize m_docViewPageSize; 373 bool setDocViewPageSize(const PP_AttrProp * pAP); 374 void setSaveContainerPointer( fp_Container * pContainer); 375 void setRebuiltBlock(fl_BlockLayout *pBlock); 376 fl_BlockLayout* getRebuiltBlock(void) const; 377 fp_Container * getSavedContainerPointer(void) const; 378 379 #ifdef FMT_TEST 380 //! Pointer to last instatiated FL_DocLayout. Used for debugging. 381 static FL_DocLayout* m_pDocLayout; 382 383 void __dump(FILE * fp) const; 384 #endif 385 386 protected: 387 static void _backgroundCheck(UT_Worker * pTimer); 388 #ifdef ENABLE_SPELL 389 void _toggleAutoSpell(bool bSpell); 390 void _toggleAutoGrammar(bool bGrammar); 391 #endif 392 void _toggleAutoSmartQuotes(bool bSQ); 393 394 static void _prefsListener(class XAP_Prefs *, 395 UT_StringPtrMap *, void *); 396 397 398 static void _redrawUpdate(UT_Worker * pTimer); 399 400 private: 401 void _lookupProperties(void); 402 GR_Graphics* m_pG; 403 PD_Document* m_pDoc; 404 FV_View* m_pView; 405 fl_DocListener* m_pDocListener; 406 PL_ListenerId m_lid; 407 408 UT_GenericVector<fp_Page *> m_vecPages; 409 fl_DocSectionLayout*m_pFirstSection; 410 fl_DocSectionLayout*m_pLastSection; 411 412 // spell check stuff 413 // UT_GenericVector<fl_BlockLayout *> m_vecUncheckedBlocks; 414 fl_BlockLayout *m_toSpellCheckHead; 415 fl_BlockLayout *m_toSpellCheckTail; 416 const fl_BlockLayout* m_pPendingBlockForSpell; // if NULL, then ignore m_pPendingWordForSpell 417 fl_PartOfBlockPtr m_pPendingWordForSpell; 418 bool m_bSpellCheckCaps; 419 bool m_bSpellCheckNumbers; 420 bool m_bSpellCheckInternet; 421 bool m_bAutoSpellCheck; 422 UT_uint32 m_uDocBackgroundCheckReasons; 423 bool m_bStopSpellChecking; // Handshaking 424 bool m_bImSpellCheckingNow; // Variables 425 // smart quote latent instance 426 fl_BlockLayout* m_pPendingBlockForSmartQuote; // if NULL, ignore m_uOffsetForSmartQuote 427 UT_uint32 m_uOffsetForSmartQuote; 428 char m_szCurrentTransparentColor[10]; 429 UT_Worker* m_pBackgroundCheckTimer; 430 431 XAP_Prefs * m_pPrefs; 432 433 UT_Timer* m_pRedrawUpdateTimer; 434 UT_uint32 m_iSkipUpdates; 435 bool m_bDeletingLayout; 436 bool m_bisLayoutFilling; 437 UT_uint32 m_iRedrawCount; 438 UT_GenericVector<fl_FootnoteLayout *> m_vecFootnotes; 439 UT_GenericVector<fl_AnnotationLayout *> m_vecAnnotations; 440 UT_GenericVector<fl_EndnoteLayout *> m_vecEndnotes; 441 FootnoteType m_FootnoteType; 442 UT_sint32 m_iFootnoteVal; 443 bool m_bRestartFootSection; 444 bool m_bRestartFootPage; 445 UT_sint32 m_iEndnoteVal; 446 FootnoteType m_EndnoteType; 447 bool m_bRestartEndSection; 448 bool m_bPlaceAtDocEnd; 449 bool m_bPlaceAtSecEnd; 450 UT_uint32 m_iGraphicTick; 451 UT_GenericVector<fl_TOCLayout *> m_vecTOC; 452 PT_DocPosition m_iDocSize; 453 UT_sint32 m_iFilled; 454 bool m_bSpellCheckInProgress; 455 std::map<std::string, GR_EmbedManager *> m_mapEmbedManager; 456 bool m_bAutoGrammarCheck; 457 fl_BlockLayout * m_PendingBlockForGrammar; 458 UT_sint32 m_iGrammarCount; 459 bool m_bFinishedInitialCheck; 460 PT_DocPosition m_iPrevPos; 461 std::map<std::string, GR_EmbedManager *> m_mapQuickPrintEmbedManager; 462 GR_Graphics * m_pQuickPrintGraphics; 463 bool m_bIsQuickPrint; 464 bool m_bDisplayAnnotations; 465 bool m_bDisplayRDFAnchors; 466 fp_Container * m_pSavedContainer; 467 fl_BlockLayout * m_pRebuiltBlockLayout; 468 UT_GenericVector<fp_FrameContainer *> m_vecFramesToBeInserted; 469 }; 470 471 #endif /* DOCLAYOUT_H */ 472 473 474