Only add page break before first line of a heading in PDF and preview (#2415)

This commit is contained in:
Veronica Berglyd Olsen
2025-06-18 19:25:39 +02:00
parent 2ec943d118
commit 2176dd2020
3 changed files with 36 additions and 10 deletions
+7 -4
View File
@@ -40,8 +40,9 @@ from novelwriter.formats.shared import BlockFmt, BlockTyp, T_Formats, TextFmt, s
from novelwriter.formats.tokenizer import HEADINGS, Tokenizer from novelwriter.formats.tokenizer import HEADINGS, Tokenizer
from novelwriter.types import ( from novelwriter.types import (
QtAlignAbsolute, QtAlignCenter, QtAlignJustify, QtAlignLeft, QtAlignRight, QtAlignAbsolute, QtAlignCenter, QtAlignJustify, QtAlignLeft, QtAlignRight,
QtKeepAnchor, QtMoveAnchor, QtPageBreakAfter, QtPageBreakBefore, QtKeepAnchor, QtMoveAnchor, QtPageBreakAfter, QtPageBreakAuto,
QtPropLineHeight, QtTransparent, QtVAlignNormal, QtVAlignSub, QtVAlignSuper QtPageBreakBefore, QtPropLineHeight, QtTransparent, QtVAlignNormal,
QtVAlignSub, QtVAlignSuper
) )
if TYPE_CHECKING: if TYPE_CHECKING:
@@ -253,8 +254,10 @@ class ToQTextDocument(Tokenizer):
elif tType in HEADINGS: elif tType in HEADINGS:
bFmt, cFmt = self._genHeadStyle(tType, tMeta, bFmt) bFmt, cFmt = self._genHeadStyle(tType, tMeta, bFmt)
newBlock(cursor, bFmt) for tPart in tText.split("\n"):
cursor.insertText(tText, cFmt) newBlock(cursor, bFmt)
cursor.insertText(tPart, cFmt)
bFmt.setPageBreakPolicy(QtPageBreakAuto)
elif tType == BlockTyp.SEP: elif tType == BlockTyp.SEP:
newBlock(cursor, bFmt) newBlock(cursor, bFmt)
+1
View File
@@ -52,6 +52,7 @@ QtVAlignSuper = QTextCharFormat.VerticalAlignment.AlignSuperScript
QtPageBreakBefore = QTextFormat.PageBreakFlag.PageBreak_AlwaysBefore QtPageBreakBefore = QTextFormat.PageBreakFlag.PageBreak_AlwaysBefore
QtPageBreakAfter = QTextFormat.PageBreakFlag.PageBreak_AlwaysAfter QtPageBreakAfter = QTextFormat.PageBreakFlag.PageBreak_AlwaysAfter
QtPageBreakAuto = QTextFormat.PageBreakFlag.PageBreak_Auto
QtPropLineHeight = 1 # QTextBlockFormat.LineHeightTypes.ProportionalHeight QtPropLineHeight = 1 # QTextBlockFormat.LineHeightTypes.ProportionalHeight
+28 -6
View File
@@ -25,14 +25,15 @@ import pytest
from PyQt6.QtGui import QFont, QTextBlock, QTextCharFormat, QTextCursor from PyQt6.QtGui import QFont, QTextBlock, QTextCharFormat, QTextCursor
from novelwriter import CONFIG from novelwriter import CONFIG
from novelwriter.constants import nwUnicode from novelwriter.constants import nwHeadFmt, nwUnicode
from novelwriter.core.project import NWProject from novelwriter.core.project import NWProject
from novelwriter.enum import nwComment from novelwriter.enum import nwComment
from novelwriter.formats.shared import BlockFmt, BlockTyp, TextDocumentTheme from novelwriter.formats.shared import BlockFmt, BlockTyp, TextDocumentTheme
from novelwriter.formats.toqdoc import ToQTextDocument from novelwriter.formats.toqdoc import ToQTextDocument
from novelwriter.types import ( from novelwriter.types import (
QtAlignAbsolute, QtAlignCenter, QtAlignJustify, QtAlignLeft, QtAlignRight, QtAlignAbsolute, QtAlignCenter, QtAlignJustify, QtAlignLeft, QtAlignRight,
QtPageBreakAfter, QtTransparent, QtVAlignNormal, QtVAlignSub, QtVAlignSuper QtPageBreakAfter, QtPageBreakAuto, QtPageBreakBefore, QtTransparent,
QtVAlignNormal, QtVAlignSub, QtVAlignSuper
) )
THEME = TextDocumentTheme() THEME = TextDocumentTheme()
@@ -54,6 +55,11 @@ def testFmtToQTextDocument_ConvertHeaders(mockGUI):
doc._isNovel = True doc._isNovel = True
doc._isFirst = True doc._isFirst = True
# Add a line break in chapter header format, see #2415
doc.setChapterFormat(f"{nwHeadFmt.CH_NUM}{nwHeadFmt.BR}{nwHeadFmt.TITLE}")
# Populate
doc._text = ( doc._text = (
"#! Title\n" "#! Title\n"
"# Partition\n" "# Partition\n"
@@ -63,12 +69,13 @@ def testFmtToQTextDocument_ConvertHeaders(mockGUI):
) )
doc.tokenizeText() doc.tokenizeText()
doc.doConvert() doc.doConvert()
assert doc.document.blockCount() == 5 assert doc.document.blockCount() == 6
# Title # Title
block = doc.document.findBlockByNumber(0) block = doc.document.findBlockByNumber(0)
assert block.text() == "Title" assert block.text() == "Title"
bFmt = block.blockFormat() bFmt = block.blockFormat()
assert bFmt.pageBreakPolicy() == QtPageBreakAuto # Expected on first title
assert bFmt.topMargin() == doc._mHead[BlockTyp.TITLE][0] assert bFmt.topMargin() == doc._mHead[BlockTyp.TITLE][0]
assert bFmt.bottomMargin() == doc._mHead[BlockTyp.TITLE][1] assert bFmt.bottomMargin() == doc._mHead[BlockTyp.TITLE][1]
cFmt = charFmtInBlock(block, 1) cFmt = charFmtInBlock(block, 1)
@@ -87,10 +94,23 @@ def testFmtToQTextDocument_ConvertHeaders(mockGUI):
assert cFmt.fontPointSize() == doc._sHead[BlockTyp.PART] assert cFmt.fontPointSize() == doc._sHead[BlockTyp.PART]
assert cFmt.foreground().color() == THEME.head assert cFmt.foreground().color() == THEME.head
# Chapter # Chapter, Line 1
block = doc.document.findBlockByNumber(2) block = doc.document.findBlockByNumber(2)
assert block.text() == "1"
bFmt = block.blockFormat()
assert bFmt.pageBreakPolicy() == QtPageBreakBefore
assert bFmt.topMargin() == doc._mHead[BlockTyp.HEAD1][0]
assert bFmt.bottomMargin() == doc._mHead[BlockTyp.HEAD1][1]
cFmt = charFmtInBlock(block, 1)
assert cFmt.fontWeight() == QFont.Weight.Bold
assert cFmt.fontPointSize() == doc._sHead[BlockTyp.HEAD1]
assert cFmt.foreground().color() == THEME.head
# Chapter, Line 2
block = doc.document.findBlockByNumber(3)
assert block.text() == "Chapter" assert block.text() == "Chapter"
bFmt = block.blockFormat() bFmt = block.blockFormat()
assert bFmt.pageBreakPolicy() == QtPageBreakAuto # Important! See #2415
assert bFmt.topMargin() == doc._mHead[BlockTyp.HEAD1][0] assert bFmt.topMargin() == doc._mHead[BlockTyp.HEAD1][0]
assert bFmt.bottomMargin() == doc._mHead[BlockTyp.HEAD1][1] assert bFmt.bottomMargin() == doc._mHead[BlockTyp.HEAD1][1]
cFmt = charFmtInBlock(block, 1) cFmt = charFmtInBlock(block, 1)
@@ -99,9 +119,10 @@ def testFmtToQTextDocument_ConvertHeaders(mockGUI):
assert cFmt.foreground().color() == THEME.head assert cFmt.foreground().color() == THEME.head
# Scene # Scene
block = doc.document.findBlockByNumber(3) block = doc.document.findBlockByNumber(4)
assert block.text() == "Scene" assert block.text() == "Scene"
bFmt = block.blockFormat() bFmt = block.blockFormat()
assert bFmt.pageBreakPolicy() == QtPageBreakAuto
assert bFmt.topMargin() == doc._mHead[BlockTyp.HEAD2][0] assert bFmt.topMargin() == doc._mHead[BlockTyp.HEAD2][0]
assert bFmt.bottomMargin() == doc._mHead[BlockTyp.HEAD2][1] assert bFmt.bottomMargin() == doc._mHead[BlockTyp.HEAD2][1]
cFmt = charFmtInBlock(block, 1) cFmt = charFmtInBlock(block, 1)
@@ -110,9 +131,10 @@ def testFmtToQTextDocument_ConvertHeaders(mockGUI):
assert cFmt.foreground().color() == THEME.head assert cFmt.foreground().color() == THEME.head
# Section # Section
block = doc.document.findBlockByNumber(4) block = doc.document.findBlockByNumber(5)
assert block.text() == "Section" assert block.text() == "Section"
bFmt = block.blockFormat() bFmt = block.blockFormat()
assert bFmt.pageBreakPolicy() == QtPageBreakAuto
assert bFmt.topMargin() == doc._mHead[BlockTyp.HEAD3][0] assert bFmt.topMargin() == doc._mHead[BlockTyp.HEAD3][0]
assert bFmt.bottomMargin() == doc._mHead[BlockTyp.HEAD3][1] assert bFmt.bottomMargin() == doc._mHead[BlockTyp.HEAD3][1]
cFmt = charFmtInBlock(block, 1) cFmt = charFmtInBlock(block, 1)