Skip to content

Commit df7083b

Browse files
committed
Ability to define paragraph pagination: widow control, keep next, keep lines, and page break before.
1 parent d1f34fc commit df7083b

File tree

5 files changed

+289
-6
lines changed

5 files changed

+289
-6
lines changed

Classes/PHPWord/Style/Paragraph.php

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,34 @@ class PHPWord_Style_Paragraph
9494
*/
9595
private $_next;
9696

97+
/**
98+
* Allow first/last line to display on a separate page
99+
*
100+
* @var bool
101+
*/
102+
private $_widowControl;
103+
104+
/**
105+
* Keep paragraph with next paragraph
106+
*
107+
* @var bool
108+
*/
109+
private $_keepNext;
110+
111+
/**
112+
* Keep all lines on one page
113+
*
114+
* @var bool
115+
*/
116+
private $_keepLines;
117+
118+
/**
119+
* Start paragraph on next page
120+
*
121+
* @var bool
122+
*/
123+
private $_pageBreakBefore;
124+
97125
/**
98126
* New Paragraph Style
99127
*/
@@ -108,6 +136,10 @@ public function __construct()
108136
$this->_hanging = null;
109137
$this->_basedOn = 'Normal';
110138
$this->_next = null;
139+
$this->_widowControl = true;
140+
$this->_keepNext = false;
141+
$this->_keepLines = false;
142+
$this->_pageBreakBefore = false;
111143
}
112144

113145
/**
@@ -323,4 +355,104 @@ public function setNext($pValue = null)
323355
return $this;
324356
}
325357

358+
/**
359+
* Get allow first/last line to display on a separate page setting
360+
*
361+
* @return bool
362+
*/
363+
public function getWidowControl()
364+
{
365+
return $this->_widowControl;
366+
}
367+
368+
/**
369+
* Set keep paragraph with next paragraph setting
370+
*
371+
* @param bool $pValue
372+
* @return PHPWord_Style_Paragraph
373+
*/
374+
public function setWidowControl($pValue = true)
375+
{
376+
if (!is_bool($pValue)) {
377+
$pValue = false;
378+
}
379+
$this->_widowControl = $pValue;
380+
return $this;
381+
}
382+
383+
/**
384+
* Get keep paragraph with next paragraph setting
385+
*
386+
* @return bool
387+
*/
388+
public function getKeepNext()
389+
{
390+
return $this->_keepNext;
391+
}
392+
393+
/**
394+
* Set keep paragraph with next paragraph setting
395+
*
396+
* @param bool $pValue
397+
* @return PHPWord_Style_Paragraph
398+
*/
399+
public function setKeepNext($pValue = true)
400+
{
401+
if (!is_bool($pValue)) {
402+
$pValue = false;
403+
}
404+
$this->_keepNext = $pValue;
405+
return $this;
406+
}
407+
408+
/**
409+
* Get keep all lines on one page setting
410+
*
411+
* @return bool
412+
*/
413+
public function getKeepLines()
414+
{
415+
return $this->_keepLines;
416+
}
417+
418+
/**
419+
* Set keep all lines on one page setting
420+
*
421+
* @param bool $pValue
422+
* @return PHPWord_Style_Paragraph
423+
*/
424+
public function setKeepLines($pValue = true)
425+
{
426+
if (!is_bool($pValue)) {
427+
$pValue = false;
428+
}
429+
$this->_keepLines = $pValue;
430+
return $this;
431+
}
432+
433+
/**
434+
* Get start paragraph on next page setting
435+
*
436+
* @return bool
437+
*/
438+
public function getPageBreakBefore()
439+
{
440+
return $this->_pageBreakBefore;
441+
}
442+
443+
/**
444+
* Set start paragraph on next page setting
445+
*
446+
* @param bool $pValue
447+
* @return PHPWord_Style_Paragraph
448+
*/
449+
public function setPageBreakBefore($pValue = true)
450+
{
451+
if (!is_bool($pValue)) {
452+
$pValue = false;
453+
}
454+
$this->_pageBreakBefore = $pValue;
455+
return $this;
456+
}
457+
326458
}

Classes/PHPWord/Writer/Word2007/Base.php

Lines changed: 50 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -117,27 +117,47 @@ protected function _writeTextRun(PHPWord_Shared_XMLWriter $objWriter = null, PHP
117117
$objWriter->endElement();
118118
}
119119

120-
protected function _writeParagraphStyle(PHPWord_Shared_XMLWriter $objWriter = null, PHPWord_Style_Paragraph $style, $withoutPPR = false)
120+
/**
121+
* Write paragraph style
122+
*
123+
* @param PHPWord_Shared_XMLWriter $objWriter
124+
* @param PHPWord_Style_Paragraph $style
125+
* @param bool $withoutPPR
126+
* @return void
127+
*/
128+
protected function _writeParagraphStyle(
129+
PHPWord_Shared_XMLWriter $objWriter = null,
130+
PHPWord_Style_Paragraph $style,
131+
$withoutPPR = false)
121132
{
122133
$align = $style->getAlign();
134+
$spacing = $style->getSpacing();
123135
$spaceBefore = $style->getSpaceBefore();
124136
$spaceAfter = $style->getSpaceAfter();
125-
$spacing = $style->getSpacing();
126137
$indent = $style->getIndent();
127138
$hanging = $style->getHanging();
128139
$tabs = $style->getTabs();
129-
130-
if (!is_null($align) || !is_null($spacing) || !is_null($spaceBefore) || !is_null($spaceAfter) || !is_null($indent) || !is_null($tabs)) {
140+
$widowControl = $style->getWidowControl();
141+
$keepNext = $style->getKeepNext();
142+
$keepLines = $style->getKeepLines();
143+
$pageBreakBefore = $style->getPageBreakBefore();
144+
145+
if (!is_null($align) || !is_null($spacing) || !is_null($spaceBefore) ||
146+
!is_null($spaceAfter) || !is_null($indent) || !is_null($hanging) ||
147+
!is_null($tabs) || !is_null($widowControl) || !is_null($keepNext) ||
148+
!is_null($keepLines) || !is_null($pageBreakBefore)) {
131149
if (!$withoutPPR) {
132150
$objWriter->startElement('w:pPr');
133151
}
134152

153+
// Alignment
135154
if (!is_null($align)) {
136155
$objWriter->startElement('w:jc');
137156
$objWriter->writeAttribute('w:val', $align);
138157
$objWriter->endElement();
139158
}
140159

160+
// Indentation
141161
if (!is_null($indent) || !is_null($hanging)) {
142162
$objWriter->startElement('w:ind');
143163
$objWriter->writeAttribute('w:firstLine', 0);
@@ -150,7 +170,9 @@ protected function _writeParagraphStyle(PHPWord_Shared_XMLWriter $objWriter = nu
150170
$objWriter->endElement();
151171
}
152172

153-
if (!is_null($spaceBefore) || !is_null($spaceAfter) || !is_null($spacing)) {
173+
// Spacing
174+
if (!is_null($spaceBefore) || !is_null($spaceAfter) ||
175+
!is_null($spacing)) {
154176
$objWriter->startElement('w:spacing');
155177
if (!is_null($spaceBefore)) {
156178
$objWriter->writeAttribute('w:before', $spaceBefore);
@@ -165,6 +187,29 @@ protected function _writeParagraphStyle(PHPWord_Shared_XMLWriter $objWriter = nu
165187
$objWriter->endElement();
166188
}
167189

190+
// Pagination
191+
if (!$widowControl) {
192+
$objWriter->startElement('w:widowControl');
193+
$objWriter->writeAttribute('w:val', '0');
194+
$objWriter->endElement();
195+
}
196+
if ($keepNext) {
197+
$objWriter->startElement('w:keepNext');
198+
$objWriter->writeAttribute('w:val', '1');
199+
$objWriter->endElement();
200+
}
201+
if ($keepLines) {
202+
$objWriter->startElement('w:keepLines');
203+
$objWriter->writeAttribute('w:val', '1');
204+
$objWriter->endElement();
205+
}
206+
if ($pageBreakBefore) {
207+
$objWriter->startElement('w:pageBreakBefore');
208+
$objWriter->writeAttribute('w:val', '1');
209+
$objWriter->endElement();
210+
}
211+
212+
// Tabs
168213
if (!is_null($tabs)) {
169214
$tabs->toXml($objWriter);
170215
}

Tests/PHPWord/Writer/Word2007/BaseTest.php

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,35 @@ public function testWriteCellStyle_CellGridSpan()
7777
$element = $doc->getElement('/w:document/w:body/w:tbl/w:tr/w:tc/w:tcPr/w:gridSpan');
7878

7979
$this->assertEquals(5, $element->getAttribute('w:val'));
80+
}
81+
82+
/**
83+
* Test write paragraph pagination
84+
*/
85+
public function testWriteParagraphStyle_Pagination()
86+
{
87+
// Create the doc
88+
$PHPWord = new PHPWord();
89+
$section = $PHPWord->createSection();
90+
$attributes = array(
91+
'widowControl' => 0,
92+
'keepNext' => 1,
93+
'keepLines' => 1,
94+
'pageBreakBefore' => 1,
95+
);
96+
foreach ($attributes as $attribute => $value) {
97+
$section->addText('Test', null, array($attribute => $value));
98+
}
99+
$doc = TestHelperDOCX::getDocument($PHPWord);
100+
101+
// Test the attributes
102+
$i = 0;
103+
foreach ($attributes as $attribute => $value) {
104+
$i++;
105+
$path = "/w:document/w:body/w:p[{$i}]/w:pPr/w:{$attribute}";
106+
$element = $doc->getElement($path);
107+
$this->assertEquals($value, $element->getAttribute('w:val'));
108+
}
80109
}
110+
81111
}
82-

changelog.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ Changes in branch for release 0.7.1 :
4444
- Feature: (ivanlanin) GH-87 - Paragraph: Ability to define parent style (basedOn) and style for following paragraph (next)
4545
- Feature: (jeroenmoors) GH-44 GH-88 - Clone table rows on the fly when using a template document
4646
- Feature: (deds) GH-16 - Initial addition of basic footnote support
47+
- Feature: (ivanlanin) GH-16 - Paragraph: Ability to define paragraph pagination: widow control, keep next, keep lines, and page break before
4748
- QA: (Progi1984) - UnitTests
4849

4950
Changes in branch for release 0.7.0 :
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
<?php
2+
3+
error_reporting(E_ALL);
4+
5+
if(php_sapi_name() == 'cli' && empty($_SERVER['REMOTE_ADDR'])) {
6+
define('EOL', PHP_EOL);
7+
}
8+
else {
9+
define('EOL', '<br />');
10+
}
11+
12+
require_once '../Classes/PHPWord.php';
13+
14+
// New Word document
15+
echo date('H:i:s') , " Create new PHPWord object" , EOL;
16+
$PHPWord = new PHPWord();
17+
$PHPWord->setDefaultParagraphStyle(array(
18+
'align' => 'both',
19+
'spaceAfter' => PHPWord_Shared_Font::pointSizeToTwips(12),
20+
'spacing' => 120,
21+
));
22+
23+
// Sample
24+
$section = $PHPWord->createSection();
25+
26+
$section->addText('Below are the samples on how to control your paragraph ' .
27+
'pagination. See "Line and Page Break" tab on paragraph properties ' .
28+
'window to see the attribute set by these controls.',
29+
array('bold' => true), null);
30+
31+
$section->addText('Paragraph with widowControl = false (default: true). ' .
32+
'A "widow" is the last line of a paragraph printed by itself at the top ' .
33+
'of a page. An "orphan" is the first line of a paragraph printed by ' .
34+
'itself at the bottom of a page. Set this option to "false" if you want ' .
35+
'to disable this automatic control.',
36+
null, array('widowControl' => false));
37+
38+
$section->addText('Paragraph with keepNext = true (default: false). ' .
39+
'"Keep with next" is used to prevent Word from inserting automatic page ' .
40+
'breaks between paragraphs. Set this option to "true" if you do not want ' .
41+
'your paragraph to be separated with the next paragraph.',
42+
null, array('keepNext' => true));
43+
44+
$section->addText('Paragraph with keepLines = true (default: false). ' .
45+
'"Keep lines together" will prevent Word from inserting an automatic page ' .
46+
'break within a paragraph. Set this option to "true" if you do not want ' .
47+
'all lines of your paragraph to be in the same page.',
48+
null, array('keepLines' => true));
49+
50+
$section->addText('Keep scrolling. More below.');
51+
52+
$section->addText('Paragraph with pageBreakBefore = true (default: false). ' .
53+
'Different with all other control above, "page break before" separates ' .
54+
'your paragraph into the next page. This option is most useful for ' .
55+
'heading styles.',
56+
null, array('pageBreakBefore' => true));
57+
58+
// Save File
59+
echo date('H:i:s') , " Write to Word2007 format" , EOL;
60+
$objWriter = PHPWord_IOFactory::createWriter($PHPWord, 'Word2007');
61+
$objWriter->save(str_replace('.php', '.docx', __FILE__));
62+
63+
// echo date('H:i:s') , " Write to OpenDocumentText format" , EOL;
64+
// $objWriter = PHPWord_IOFactory::createWriter($PHPWord, 'ODText');
65+
// $objWriter->save(str_replace('.php', '.odt', __FILE__));
66+
67+
// echo date('H:i:s') , " Write to RTF format" , EOL;
68+
// $objWriter = PHPWord_IOFactory::createWriter($PHPWord, 'RTF');
69+
// $objWriter->save(str_replace('.php', '.rtf', __FILE__));
70+
71+
72+
// Echo memory peak usage
73+
echo date('H:i:s') , " Peak memory usage: " , (memory_get_peak_usage(true) / 1024 / 1024) , " MB" , EOL;
74+
75+
// Echo done
76+
echo date('H:i:s') , " Done writing file" , EOL;

0 commit comments

Comments
 (0)