Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

700 lines
18 KiB

  1. /************************************************************/
  2. /* Windows Write, Copyright 1985-1992 Microsoft Corporation */
  3. /************************************************************/
  4. /* running.c -- code to handle editing of running header and footer */
  5. #define NOGDICAPMASKS
  6. #define NOVIRTUALKEYCODES
  7. #define NOWINSTYLES
  8. #define NOSYSMETRICS
  9. #define NOICON
  10. #define NOKEYSTATE
  11. #define NOSYSCOMMANDS
  12. #define NOSHOWWINDOW
  13. //#define NOATOM
  14. //#define NOGDI
  15. #define NOFONT
  16. #define NOBRUSH
  17. #define NOCLIPBOARD
  18. #define NOCOLOR
  19. #define NOCREATESTRUCT
  20. #define NODRAWTEXT
  21. #define NOMB
  22. #define NOMETAFILE
  23. #define NOMINMAX
  24. #define NOOPENFILE
  25. #define NOPEN
  26. #define NOREGION
  27. #define NOSCROLL
  28. #define NOSOUND
  29. #define NOTEXTMETRIC
  30. #define NOWH
  31. #define NOWINOFFSETS
  32. #define NOWNDCLASS
  33. #define NOCOMM
  34. #include <windows.h>
  35. #include "mw.h"
  36. #include "machdefs.h"
  37. #define NOKCCODES
  38. #include "ch.h"
  39. #include "docdefs.h"
  40. #include "cmddefs.h"
  41. #include "editdefs.h"
  42. #include "propdefs.h"
  43. #include "prmdefs.h"
  44. #include "wwdefs.h"
  45. #include "dlgdefs.h"
  46. #include "menudefs.h"
  47. #include "str.h"
  48. #if defined(OLE)
  49. #include "obj.h"
  50. #endif
  51. #ifdef JAPAN //T-HIROYN Win3.1
  52. #include "kanji.h"
  53. #endif
  54. int NEAR EditHeaderFooter();
  55. /* Current allowable cp range for display/edit/scroll */
  56. extern typeCP cpMinCur;
  57. extern typeCP cpMacCur;
  58. extern struct DOD (**hpdocdod)[];
  59. extern struct WWD rgwwd[];
  60. extern int docCur;
  61. extern int docScrap;
  62. extern int vfSeeSel;
  63. extern struct SEL selCur;
  64. extern struct PAP vpapAbs;
  65. extern struct SEP vsepNormal;
  66. extern HANDLE vhWnd;
  67. extern HANDLE hMmwModInstance;
  68. extern HANDLE hParentWw;
  69. #ifdef INEFFLOCKDOWN
  70. extern FARPROC lpDialogRunningHead;
  71. #else
  72. BOOL far PASCAL DialogRunningHead(HWND, unsigned, WORD, LONG);
  73. FARPROC lpDialogRunningHead = NULL;
  74. #endif
  75. extern HANDLE vhDlgRunningHead;
  76. extern CHAR stBuf[255];
  77. extern int utCur;
  78. extern int ferror;
  79. extern int vccpFetch;
  80. extern int vcchFetch;
  81. extern CHAR *vpchFetch;
  82. extern struct CHP vchpFetch;
  83. extern typeCP vcpLimParaCache;
  84. extern HWND vhWndMsgBoxParent;
  85. /* Min, Max cp's for header, footer */
  86. typeCP cpMinHeader=cp0;
  87. typeCP cpMacHeader=cp0;
  88. typeCP cpMinFooter=cp0;
  89. typeCP cpMacFooter=cp0;
  90. /* Min cp for document less header, footer */
  91. /* Header & footer always appear at the beginning */
  92. typeCP cpMinDocument=cp0;
  93. /* The following variables are used in this module only */
  94. #define cchWinTextSave 80
  95. static CHAR (**hszWinTextSave)[]=NULL;
  96. static struct PAP *ppapDefault;
  97. /* cpFirst and selection are saved in these during header/footer edit */
  98. typeCP cpFirstDocSave;
  99. struct SEL selDocSave;
  100. HWND vhDlgRunning;
  101. fnEditRunning(imi)
  102. { /* Enter mode so that user is editing the current document's
  103. running header or footer in the same window as he was editing
  104. the document, with the header/footer info in the dialog box
  105. NOT currently in focus ..pault */
  106. #ifndef INEFFLOCKDOWN
  107. if (!lpDialogRunningHead)
  108. if (!(lpDialogRunningHead = MakeProcInstance(DialogRunningHead, hMmwModInstance)))
  109. {
  110. WinFailure();
  111. return;
  112. }
  113. #endif
  114. Assert(imi == imiHeader || imi == imiFooter);
  115. if (wwdCurrentDoc.fEditHeader || wwdCurrentDoc.fEditFooter)
  116. {
  117. SetFocus(vhDlgRunningHead);
  118. return;
  119. }
  120. if (imi == imiHeader)
  121. wwdCurrentDoc.fEditHeader = TRUE;
  122. else
  123. wwdCurrentDoc.fEditFooter = TRUE;
  124. EditHeaderFooter();
  125. if (ferror)
  126. { /* Not enough memory to stabilize the running head environs */
  127. if (wwdCurrentDoc.fEditHeader)
  128. wwdCurrentDoc.fEditHeader = FALSE;
  129. else
  130. wwdCurrentDoc.fEditFooter = FALSE;
  131. return;
  132. }
  133. vhDlgRunningHead = CreateDialog(hMmwModInstance,
  134. MAKEINTRESOURCE(wwdCurrentDoc.fEditHeader ?
  135. dlgRunningHead : dlgFooter),
  136. hParentWw, lpDialogRunningHead);
  137. if (vhDlgRunningHead)
  138. {
  139. SetFocus(wwdCurrentDoc.wwptr);
  140. }
  141. else
  142. { /* recover and bail out */
  143. fnEditDocument();
  144. #ifdef WIN30
  145. WinFailure();
  146. #else
  147. Error(IDPMTNoMemory);
  148. #endif
  149. }
  150. }
  151. int NEAR EditHeaderFooter()
  152. { /* Setup for edit of header or footer */
  153. extern HWND hParentWw;
  154. int fHeader=wwdCurrentDoc.fEditHeader;
  155. CHAR szWinTextSave[ cchWinTextSave ];
  156. typeCP cpFirst;
  157. typeCP cpLim;
  158. #ifdef DEBUG
  159. /* TEST Assumption: No changes take place in running head/foot cp range
  160. during an interval in which no head/foot edits take place */
  161. typeCP cpMinDocT=cpMinDocument;
  162. ValidateHeaderFooter( docCur );
  163. Assert( cpMinDocT == cpMinDocument );
  164. #endif
  165. if (fHeader)
  166. {
  167. cpFirst = cpMinHeader;
  168. cpLim = cpMacHeader;
  169. }
  170. else
  171. {
  172. cpFirst = cpMinFooter;
  173. cpLim = cpMacFooter;
  174. }
  175. Assert( wwdCurrentDoc.fEditHeader != wwdCurrentDoc.fEditFooter );
  176. /* Save the cpFirst of the document window so we get a clean
  177. transition back to where we were in the document*/
  178. cpFirstDocSave = wwdCurrentDoc.cpFirst;
  179. selDocSave = selCur;
  180. TrashCache();
  181. TrashWw( wwDocument );
  182. if (!FWriteOk( fwcNil ))
  183. goto DontEdit;
  184. if ( cpFirst == cpLim )
  185. {
  186. /* If we are editing the header/footer for the first time in this document,
  187. insert a para end mark to hold the running h/f properties */
  188. extern struct PAP *vppapNormal;
  189. struct PAP papT;
  190. blt( vppapNormal, &papT, cwPAP );
  191. papT.rhc = (wwdCurrentDoc.fEditHeader) ?
  192. rhcDefault : rhcDefault + RHC_fBottom;
  193. InsertEolPap( docCur, cpFirst, &papT );
  194. if (ferror)
  195. return;
  196. ValidateHeaderFooter( docCur );
  197. cpLim += ccpEol;
  198. }
  199. else
  200. {
  201. extern int vccpFetch;
  202. typeCP cp;
  203. /* Test for a special case: loading a WORD document which has been
  204. properly set up to have running head/foot under MEMO. We must
  205. force the para end mark at the end of the header/footer to be
  206. a fresh run. This is so we will see an end mark when editing one
  207. of these. FormatLine only checks for cpMacCur at the start of a run. */
  208. Assert( cpLim - cpFirst >= ccpEol );
  209. if ( (cp = cpLim - ccpEol) > cpFirst )
  210. {
  211. FetchCp( docCur, cp - 1, 0, fcmBoth );
  212. if ( vccpFetch > 1)
  213. { /* char run does not end with char before EOL */
  214. /* Insert a char, then delete it */
  215. extern struct CHP vchpNormal;
  216. CHAR ch='X';
  217. InsertRgch( docCur, cp, &ch, 1, &vchpNormal, NULL );
  218. if (ferror)
  219. return;
  220. Replace( docCur, cp, (typeCP) 1, fnNil, fc0, fc0 );
  221. if (ferror)
  222. return;
  223. }
  224. }
  225. }
  226. DontEdit:
  227. /* Save current window text; set string */
  228. GetWindowText( hParentWw, (LPSTR)szWinTextSave, cchWinTextSave );
  229. if (FNoHeap(hszWinTextSave=HszCreate( (PCH)szWinTextSave )))
  230. {
  231. hszWinTextSave = NULL;
  232. }
  233. else
  234. {
  235. extern CHAR szHeader[];
  236. extern CHAR szFooter[];
  237. SetWindowText( hParentWw, fHeader ? (LPSTR)szHeader:(LPSTR)szFooter );
  238. }
  239. /* Set editing limits to just the cp range of the header/footer,
  240. minus the "invisible" terminating EOL */
  241. wwdCurrentDoc.cpFirst = wwdCurrentDoc.cpMin = cpMinCur = cpFirst;
  242. wwdCurrentDoc.cpMac = cpMacCur = CpMax( cpMinCur, cpLim - ccpEol );
  243. /* Leave the cursor at the beginning of the header/footer regardless */
  244. Select( cpMinCur, cpMinCur );
  245. /* Show the display here instead of waiting for Idle() because it looks
  246. better to have the head/foot text come up right away instead of waiting
  247. for the dialog box to come up */
  248. UpdateDisplay( FALSE );
  249. vfSeeSel = TRUE; /* Tell Idle() to scroll the selection into view */
  250. NoUndo();
  251. ferror = FALSE; /* If we got this far, we want to go into running
  252. head mode regardless of errors */
  253. }
  254. fnEditDocument()
  255. { /* Return to editing document after editing header/footer */
  256. extern HWND hParentWw;
  257. Assert( wwdCurrentDoc.fEditFooter != wwdCurrentDoc.fEditHeader );
  258. /* Restore original window name */
  259. if (hszWinTextSave != NULL)
  260. {
  261. SetWindowText( hParentWw, (LPSTR) (**hszWinTextSave) );
  262. FreeH( hszWinTextSave );
  263. hszWinTextSave = NULL;
  264. }
  265. TrashCache();
  266. ValidateHeaderFooter( docCur ); /* This will update from the results of
  267. the header/footer edit */
  268. TrashCache();
  269. wwdCurrentDoc.cpMin = cpMinCur = cpMinDocument;
  270. wwdCurrentDoc.cpMac = cpMacCur = CpMacText( docCur );
  271. TrashWw( wwDocument );
  272. wwdCurrentDoc.fEditHeader = FALSE;
  273. wwdCurrentDoc.fEditFooter = FALSE;
  274. /* Restore saved selection, cpFirst for document */
  275. wwdCurrentDoc.cpFirst = cpFirstDocSave;
  276. Select( selDocSave.cpFirst, selDocSave.cpLim );
  277. Assert( wwdCurrentDoc.cpFirst >= cpMinCur &&
  278. wwdCurrentDoc.cpFirst <= cpMacCur );
  279. NoUndo();
  280. vhDlgRunningHead = (HANDLE)NULL;
  281. }
  282. BOOL far PASCAL DialogRunningHead( hDlg, message, wParam, lParam )
  283. HWND hDlg; /* Handle to the dialog box */
  284. unsigned message;
  285. WORD wParam;
  286. LONG lParam;
  287. {
  288. /* This routine handles input to the Header/Footer dialog box. */
  289. extern BOOL vfPrinterValid;
  290. RECT rc;
  291. CHAR *pch = &stBuf[0];
  292. struct SEP **hsep = (**hpdocdod)[docCur].hsep;
  293. struct SEP *psep;
  294. static int fChecked;
  295. typeCP dcp;
  296. switch (message)
  297. {
  298. case WM_INITDIALOG:
  299. vhDlgRunning = hDlg; /* Put dialog handle in a global for
  300. ESC key in document functionality */
  301. CachePara(docCur, selCur.cpFirst);
  302. ppapDefault = &vpapAbs;
  303. FreezeHp();
  304. /* Get a pointer to the section properties. */
  305. psep = (hsep == NULL) ? &vsepNormal : *hsep;
  306. CheckDlgButton(hDlg, idiRHFirst, (ppapDefault->rhc & RHC_fFirst));
  307. if (wwdCurrentDoc.fEditHeader)
  308. {
  309. CchExpZa(&pch, psep->yaRH1, utCur, cchMaxNum);
  310. }
  311. else /* footer dialog box */
  312. {
  313. #ifdef KOREA /* 91.3.17 want to guarantee Default >= MIN, Sangl */
  314. if (vfPrinterValid)
  315. { extern int dyaPrOffset;
  316. extern int dyaPrPage;
  317. CchExpZa(&pch, imax(psep->yaMac - psep->yaRH2,
  318. vsepNormal.yaMac - dyaPrOffset - dyaPrPage),utCur, cchMaxNum);
  319. }
  320. else
  321. CchExpZa(&pch, psep->yaMac - psep->yaRH2, utCur, cchMaxNum);
  322. #else
  323. CchExpZa( &pch, psep->yaMac - psep->yaRH2, utCur, cchMaxNum);
  324. #endif
  325. }
  326. SetDlgItemText(hDlg, idiRHDx, (LPSTR)stBuf);
  327. MeltHp();
  328. break;
  329. case WM_ACTIVATE:
  330. if (wParam)
  331. {
  332. vhWndMsgBoxParent = hDlg;
  333. }
  334. return(FALSE); /* so that we leave the activate message to
  335. the dialog manager to take care of setting the focus correctly */
  336. case WM_COMMAND:
  337. switch (wParam)
  338. {
  339. int dya;
  340. case idiRHFirst:
  341. CheckDlgButton( hDlg, idiRHFirst, !IsDlgButtonChecked(hDlg, idiRHFirst));
  342. (**hpdocdod) [docCur].fDirty = TRUE;
  343. break;
  344. case idiRHInsertPage:
  345. if (FWriteOk( fwcInsert ))
  346. { /* Insert page # at insertion pt */
  347. extern struct CHP vchpFetch, vchpSel;
  348. extern int vfSeeSel;
  349. CHAR ch=schPage;
  350. struct CHP chp;
  351. if (selCur.cpFirst == selCur.cpLim)
  352. { /* Sel is insertion point -- get props from
  353. the vchpSel kludge */
  354. blt( &vchpSel, &chp, cwCHP );
  355. }
  356. else
  357. {
  358. FetchCp( docCur, selCur.cpFirst, 0, fcmProps );
  359. blt( &vchpFetch, &chp, cwCHP );
  360. }
  361. chp.fSpecial = TRUE;
  362. #ifdef JAPAN //T-HIROYN Win3.1
  363. if(NATIVE_CHARSET != GetCharSetFromChp(&chp)) {
  364. SetFtcToPchp(&chp, GetKanjiFtc(&chp));
  365. }
  366. #endif
  367. SetUndo( uacInsert, docCur, selCur.cpFirst, (typeCP) 1,
  368. docNil, cpNil, cp0, 0 );
  369. InsertRgch( docCur, selCur.cpFirst, &ch, 1, &chp, NULL );
  370. vfSeeSel = TRUE;
  371. }
  372. break;
  373. case idiRHClear:
  374. /* Clear running head/foot */
  375. dcp = cpMacCur-cpMinCur;
  376. #if defined(OLE)
  377. {
  378. BOOL bIsOK;
  379. ObjPushParms(docCur);
  380. Select(cpMinCur,cpMacCur);
  381. bIsOK = ObjDeletionOK(OBJ_DELETING);
  382. ObjPopParms(TRUE);
  383. if (!bIsOK)
  384. break;
  385. }
  386. #endif
  387. if (dcp > 0 && FWriteOk( fwcDelete ))
  388. {
  389. NoUndo();
  390. SetUndo( uacDelNS, docCur, cpMinCur, dcp,
  391. docNil, cpNil, cp0, 0 );
  392. Replace( docCur, cpMinCur, dcp, fnNil, fc0, fc0 );
  393. }
  394. break;
  395. case idiOk: /* return to document */
  396. BackToDoc:
  397. if (!FPdxaPosIt(&dya, hDlg, idiRHDx))
  398. {
  399. break;
  400. }
  401. else if (vfPrinterValid)
  402. {
  403. extern struct SEP vsepNormal;
  404. extern int dxaPrOffset;
  405. extern int dyaPrOffset;
  406. extern int dxaPrPage;
  407. extern int dyaPrPage;
  408. extern struct WWD rgwwd[];
  409. int dyaPrBottom = imax(0, vsepNormal.yaMac - dyaPrOffset -
  410. dyaPrPage);
  411. if (FUserZaLessThanZa(dya, (wwdCurrentDoc.fEditHeader ?
  412. dyaPrOffset : dyaPrBottom)))
  413. {
  414. int dxaPrRight = imax(0, vsepNormal.xaMac - dxaPrOffset
  415. - dxaPrPage);
  416. EnableExcept(vhDlgRunningHead, FALSE);
  417. ErrorBadMargins(hDlg, dxaPrOffset, dxaPrRight,
  418. dyaPrOffset, dyaPrBottom);
  419. EnableExcept(vhDlgRunningHead, TRUE);
  420. SelectIdiText(hDlg, idiRHDx);
  421. SetFocus(GetDlgItem(hDlg, idiRHDx));
  422. break;
  423. }
  424. }
  425. DoFormatRHText( dya, IsDlgButtonChecked( hDlg, idiRHFirst ) );
  426. fnEditDocument();
  427. /* force repaint to the whole client area */
  428. GetClientRect(vhWnd, (LPRECT)&rc);
  429. InvalidateRect(vhWnd, (LPRECT)&rc, FALSE);
  430. vhWndMsgBoxParent = (HWND)NULL;
  431. DestroyWindow(hDlg);
  432. break;
  433. case idiCancel:
  434. goto BackToDoc;
  435. default:
  436. return(FALSE);
  437. }
  438. break;
  439. #if WINVER < 0x300
  440. /* Don't really need to process this */
  441. case WM_CLOSE:
  442. goto BackToDoc;
  443. #endif
  444. #ifndef INEFFLOCKDOWN
  445. case WM_NCDESTROY:
  446. FreeProcInstance(lpDialogRunningHead);
  447. lpDialogRunningHead = NULL;
  448. /* fall through to return false */
  449. #endif
  450. default:
  451. return(FALSE);
  452. }
  453. return(TRUE);
  454. }
  455. /* end of DialogRunningHead */
  456. DoFormatRHText( dya, fFirstPage)
  457. int dya;
  458. int fFirstPage;
  459. { /* Format cp range for running head/foot currently being edited
  460. to have the passed running head properties */
  461. extern typeCP vcpLimParaCache;
  462. CHAR rgb[4];
  463. int fHeader=wwdCurrentDoc.fEditHeader;
  464. /* Note that the Min value for the part we were editing has not changed
  465. as a result of the edit, so no ValidateHeaderFooter is required */
  466. typeCP cpMin=fHeader ? cpMinHeader : cpMinFooter;
  467. int rhc;
  468. struct SEP **hsep = (**hpdocdod)[docCur].hsep;
  469. struct SEP *psep;
  470. if (!FWriteOk( fwcNil ))
  471. return;
  472. /* Ensure that this document has a valid section property
  473. descriptor. */
  474. if (hsep == NULL)
  475. {
  476. if (FNoHeap(hsep = (struct SEP **)HAllocate(cwSEP)))
  477. {
  478. return;
  479. }
  480. blt(&vsepNormal, *hsep, cwSEP);
  481. (**hpdocdod)[docCur].hsep = hsep;
  482. }
  483. psep = *hsep;
  484. /* Set running head distance from top/bottom; this is a Section
  485. property. This assumes the MEMO model: one section */
  486. if (fHeader)
  487. psep->yaRH1 = dya;
  488. else
  489. psep->yaRH2 = psep->yaMac - dya;
  490. /* For MEMO, running heads appear on both odd and even pages;
  491. appearance on first page is optional */
  492. rhc = RHC_fOdd + RHC_fEven;
  493. if (fFirstPage)
  494. rhc += RHC_fFirst;
  495. if (!fHeader)
  496. rhc += RHC_fBottom;
  497. /* Set running head PARA properties by adding an appropriate sprm */
  498. /* Set CpMacCur to include the "hidden" Eol; this will prevent
  499. AddOneSprm from adding an extraneous EOL */
  500. CachePara( docCur, CpMax( cpMinCur, cpMacCur-1 ) );
  501. Assert( vpapAbs.rhc != 0 );
  502. cpMacCur = CpMax( cpMacCur, vcpLimParaCache );
  503. selCur.cpFirst = cpMinCur; /* Expand selection to entire area so sprm */
  504. selCur.cpLim = cpMacCur; /* applies to it all */
  505. rgb [0] = sprmPRhc;
  506. rgb [1] = rhc;
  507. AddOneSprm(rgb, FALSE);
  508. } /* end of DoFormatRHText */
  509. MakeRunningCps( doc, cp, dcp )
  510. int doc;
  511. typeCP cp;
  512. typeCP dcp;
  513. { /* Make the cp range suitable for inclusion in a runninng head or foot.
  514. This means: (1) Apply a Sprm to the whole thing so it is formatted
  515. as a running head/foot, (2) Remove any chSects, replacing them
  516. with Eol's */
  517. extern struct UAB vuab;
  518. CHAR rgb [4];
  519. int rhc;
  520. int fAdjCpMacCur;
  521. typeCP cpLimPara;
  522. typeCP cpT;
  523. struct SEL selSave;
  524. if (dcp==cp0 || !FWriteOk( fwcNil ))
  525. return;
  526. selSave = selCur;
  527. /* Scan the cp range, replacing chSects with Eols */
  528. for ( cpT = cp;
  529. CachePara( doc, cpT ), (cpLimPara=vcpLimParaCache) <= cp + dcp;
  530. cpT = cpLimPara )
  531. {
  532. typeCP cpLastPara=cpLimPara-1;
  533. Assert( cpLimPara > cpT ); /* Otherwise we are locked in the loop */
  534. FetchCp( doc, cpLastPara, 0, fcmChars );
  535. if (*vpchFetch == chSect)
  536. {
  537. struct PAP papT;
  538. CachePara( doc, cpT );
  539. papT = vpapAbs;
  540. Replace( doc, cpLastPara+ccpEol, (typeCP)1, fnNil, fc0, fc0 );
  541. InsertEolPap( doc, cpLastPara, &papT );
  542. if (ferror)
  543. {
  544. NoUndo();
  545. break;
  546. }
  547. /* Adjust Undo count to account for extra insertion */
  548. vuab.dcp += (typeCP)(ccpEol-1);
  549. CachePara( doc, cpT );
  550. cpLimPara = vcpLimParaCache;
  551. }
  552. }
  553. /* Apply a Sprm that makes everything a running head/foot */
  554. rhc = RHC_fOdd + RHC_fEven;
  555. if (wwdCurrentDoc.fEditFooter)
  556. rhc += RHC_fBottom;
  557. selCur.cpFirst = cp; /* OK to just assign to selCur */
  558. selCur.cpLim = cp + dcp; /* because AddOneSprm will handle */
  559. /* We must temporarily set cpMacCur so that it includes the Eol
  560. at the end of the header/footer range. Otherwise, AddOneSprm
  561. may decide it needs to insert a superfluous Eol */
  562. CachePara( docCur, selCur.cpLim-1 );
  563. if (fAdjCpMacCur = (vcpLimParaCache > cpMacCur))
  564. cpMacCur += ccpEol;
  565. rgb [0] = sprmPRhc;
  566. rgb [1] = rhc;
  567. AddOneSprm(rgb, FALSE); /* Do not set UNDO; we want to undo the paste,
  568. which will take care of undoing the sprm */
  569. if (fAdjCpMacCur)
  570. cpMacCur -= ccpEol;
  571. Select( selSave.cpFirst, selCur.cpLim );
  572. }
  573.