Use label for template title (#2477)

This commit is contained in:
Veronica Berglyd Olsen
2025-07-17 15:47:45 +02:00
committed by GitHub
9 changed files with 47 additions and 25 deletions
+3
View File
@@ -166,6 +166,9 @@ a character note template, you can add a **Templates** root folder to your proje
added to this root folder will show up in the **Add Item** menu in the project tree toolbar. When added to this root folder will show up in the **Add Item** menu in the project tree toolbar. When
selected, a new document is created with its content copied from the chosen template. selected, a new document is created with its content copied from the chosen template.
If the first line of the template file is a title line, the title text will be replaced with the
text of the document label when it is first created.
.. versionadded:: 2.3 .. versionadded:: 2.3
+9 -1
View File
@@ -224,7 +224,7 @@ class NWProject:
return True return True
def copyFileContent(self, tHandle: str, sHandle: str) -> bool: def copyFileContent(self, tHandle: str, sHandle: str, newTitle: str | None = None) -> bool:
"""Copy content to a new document after it is created. This """Copy content to a new document after it is created. This
will not run if the file exists and is not empty. will not run if the file exists and is not empty.
""" """
@@ -239,6 +239,14 @@ class NWProject:
logger.debug("Populating '%s' with text from '%s'", tHandle, sHandle) logger.debug("Populating '%s' with text from '%s'", tHandle, sHandle)
text = self._storage.getDocumentText(sHandle) text = self._storage.getDocumentText(sHandle)
if (
newTitle and (lines := text.split("\n")) and lines
and lines[0].startswith(("# ", "## ", "### ", "#### ", "#! ", "##! ", "###! "))
):
prefix, _, _ = lines[0].partition(" ")
lines[0] = f"{prefix} {newTitle}"
text = "\n".join(lines)
self._storage.getDocument(tHandle).writeDocument(text) self._storage.getDocument(tHandle).writeDocument(text)
sItem.setLayout(tItem.itemLayout) sItem.setLayout(tItem.itemLayout)
self._index.reIndexHandle(tHandle) self._index.reIndexHandle(tHandle)
+1 -1
View File
@@ -667,7 +667,7 @@ class GuiProjectTree(QTreeView):
if itemType == nwItemType.FILE: if itemType == nwItemType.FILE:
if tHandle := SHARED.project.newFile(newLabel, sHandle, sPos): if tHandle := SHARED.project.newFile(newLabel, sHandle, sPos):
if copyDoc: if copyDoc:
SHARED.project.copyFileContent(tHandle, copyDoc) SHARED.project.copyFileContent(tHandle, copyDoc, newLabel)
elif hLevel > 0: elif hLevel > 0:
SHARED.project.writeNewFile(tHandle, hLevel, not nNote) SHARED.project.writeNewFile(tHandle, hLevel, not nNote)
SHARED.project.index.reIndexHandle(tHandle) SHARED.project.index.reIndexHandle(tHandle)
+2 -2
View File
@@ -1,7 +1,7 @@
%%~name: Scene %%~name: Scene
%%~path: 09f22ae8369f7/5aec885635c85 %%~path: f4ed1ae756a1f/5aec885635c85
%%~kind: TEMPLATE/DOCUMENT %%~kind: TEMPLATE/DOCUMENT
%%~hash: 05c9750b00020f8cf9a7bc7362bf19681022cc03 %%~hash: 537fb0132a80101060b40b42ad8875ebbcb40a5b
%%~date: 2024-02-02 10:58:47/2024-02-02 10:59:32 %%~date: 2024-02-02 10:58:47/2024-02-02 10:59:32
### Scene ### Scene
+2 -2
View File
@@ -1,7 +1,7 @@
%%~name: Character Note %%~name: Character Note
%%~path: 09f22ae8369f7/5ee8aebcdebc9 %%~path: f4ed1ae756a1f/5ee8aebcdebc9
%%~kind: TEMPLATE/NOTE %%~kind: TEMPLATE/NOTE
%%~hash: 6230bb6f796e708a72f4c29dc79d63dc90a47ba5 %%~hash: 0d33e49259d13a6be92b493d2122dcacc677eb0b
%%~date: 2024-02-02 10:54:52/2024-02-02 10:56:05 %%~date: 2024-02-02 10:54:52/2024-02-02 10:56:05
# Character Name # Character Name
+15 -15
View File
@@ -1,6 +1,6 @@
<?xml version='1.0' encoding='utf-8'?> <?xml version='1.0' encoding='utf-8'?>
<novelWriterXML appVersion="2.8a2" hexVersion="0x020800a2" fileVersion="1.5" fileRevision="6" timeStamp="2025-07-16 16:35:53"> <novelWriterXML appVersion="2.8a2" hexVersion="0x020800a2" fileVersion="1.5" fileRevision="6" timeStamp="2025-07-17 15:43:44">
<project id="e2be99af-f9bf-4403-857a-c3d1ac25abea" saveCount="2283" autoCount="304" editTime="100296"> <project id="e2be99af-f9bf-4403-857a-c3d1ac25abea" saveCount="2284" autoCount="304" editTime="100347">
<name>Sample Project</name> <name>Sample Project</name>
<author>Jane Smith</author> <author>Jane Smith</author>
</project> </project>
@@ -42,19 +42,19 @@
<name status="sc24b8f" import="ia857f0">Novel</name> <name status="sc24b8f" import="ia857f0">Novel</name>
</item> </item>
<item handle="53b69b83cdafc" parent="7031beac91f75" root="7031beac91f75" order="0" type="FILE" class="NOVEL" layout="DOCUMENT"> <item handle="53b69b83cdafc" parent="7031beac91f75" root="7031beac91f75" order="0" type="FILE" class="NOVEL" layout="DOCUMENT">
<meta expanded="no" heading="H1" charCount="148" wordCount="29" paraCount="4" cursorPos="178" /> <meta expanded="no" heading="H1" charCount="148" wordCount="29" paraCount="4" cursorPos="80" />
<name status="sc24b8f" import="ia857f0" active="yes">Title Page</name> <name status="sc24b8f" import="ia857f0" active="yes">Title Page</name>
</item> </item>
<item handle="974e400180a99" parent="7031beac91f75" root="7031beac91f75" order="1" type="FILE" class="NOVEL" layout="DOCUMENT"> <item handle="974e400180a99" parent="7031beac91f75" root="7031beac91f75" order="1" type="FILE" class="NOVEL" layout="DOCUMENT">
<meta expanded="no" heading="H0" charCount="233" wordCount="47" paraCount="2" cursorPos="194" /> <meta expanded="no" heading="H0" charCount="233" wordCount="47" paraCount="2" cursorPos="21" />
<name status="sf12341" import="ia857f0" active="yes">Page</name> <name status="sf12341" import="ia857f0" active="yes">Page</name>
</item> </item>
<item handle="edca4be2fcaf8" parent="7031beac91f75" root="7031beac91f75" order="2" type="FILE" class="NOVEL" layout="DOCUMENT"> <item handle="edca4be2fcaf8" parent="7031beac91f75" root="7031beac91f75" order="2" type="FILE" class="NOVEL" layout="DOCUMENT">
<meta expanded="no" heading="H1" charCount="26" wordCount="6" paraCount="1" cursorPos="36" /> <meta expanded="no" heading="H1" charCount="26" wordCount="6" paraCount="1" cursorPos="11" />
<name status="s90e6c9" import="ia857f0" active="yes">Part One</name> <name status="s90e6c9" import="ia857f0" active="yes">Part One</name>
</item> </item>
<item handle="6a2d6d5f4f401" parent="7031beac91f75" root="7031beac91f75" order="3" type="FILE" class="NOVEL" layout="DOCUMENT"> <item handle="6a2d6d5f4f401" parent="7031beac91f75" root="7031beac91f75" order="3" type="FILE" class="NOVEL" layout="DOCUMENT">
<meta expanded="yes" heading="H2" charCount="95" wordCount="18" paraCount="1" cursorPos="47" /> <meta expanded="yes" heading="H2" charCount="95" wordCount="18" paraCount="1" cursorPos="16" />
<name status="sf24ce6" import="ia857f0" active="yes">Chapter One</name> <name status="sf24ce6" import="ia857f0" active="yes">Chapter One</name>
</item> </item>
<item handle="636b6aa9b697b" parent="6a2d6d5f4f401" root="7031beac91f75" order="0" type="FILE" class="NOVEL" layout="DOCUMENT"> <item handle="636b6aa9b697b" parent="6a2d6d5f4f401" root="7031beac91f75" order="0" type="FILE" class="NOVEL" layout="DOCUMENT">
@@ -62,19 +62,19 @@
<name status="s90e6c9" import="ia857f0" active="yes">Making a Scene</name> <name status="s90e6c9" import="ia857f0" active="yes">Making a Scene</name>
</item> </item>
<item handle="bc0cbd2a407f3" parent="6a2d6d5f4f401" root="7031beac91f75" order="1" type="FILE" class="NOVEL" layout="DOCUMENT"> <item handle="bc0cbd2a407f3" parent="6a2d6d5f4f401" root="7031beac91f75" order="1" type="FILE" class="NOVEL" layout="DOCUMENT">
<meta expanded="no" heading="H3" charCount="548" wordCount="108" paraCount="3" cursorPos="650" /> <meta expanded="no" heading="H3" charCount="548" wordCount="108" paraCount="3" cursorPos="18" />
<name status="s90e6c9" import="ia857f0" active="yes">Another Scene</name> <name status="s90e6c9" import="ia857f0" active="yes">Another Scene</name>
</item> </item>
<item handle="ba8a28a246524" parent="7031beac91f75" root="7031beac91f75" order="4" type="FILE" class="NOVEL" layout="DOCUMENT"> <item handle="ba8a28a246524" parent="7031beac91f75" root="7031beac91f75" order="4" type="FILE" class="NOVEL" layout="DOCUMENT">
<meta expanded="no" heading="H2" charCount="617" wordCount="101" paraCount="3" cursorPos="1182" /> <meta expanded="no" heading="H2" charCount="617" wordCount="101" paraCount="3" cursorPos="413" />
<name status="s78ea90" import="ia857f0" active="yes">Interlude</name> <name status="s78ea90" import="ia857f0" active="yes">Interlude</name>
</item> </item>
<item handle="96b68994dfa3d" parent="7031beac91f75" root="7031beac91f75" order="5" type="FILE" class="NOVEL" layout="NOTE"> <item handle="96b68994dfa3d" parent="7031beac91f75" root="7031beac91f75" order="5" type="FILE" class="NOVEL" layout="NOTE">
<meta expanded="no" heading="H1" charCount="1909" wordCount="346" paraCount="7" cursorPos="1940" /> <meta expanded="no" heading="H1" charCount="1909" wordCount="346" paraCount="7" cursorPos="22" />
<name status="sf24ce6" import="ia857f0" active="no">A Note on Structure</name> <name status="sf24ce6" import="ia857f0" active="no">A Note on Structure</name>
</item> </item>
<item handle="88706ddc78b1b" parent="7031beac91f75" root="7031beac91f75" order="6" type="FILE" class="NOVEL" layout="DOCUMENT"> <item handle="88706ddc78b1b" parent="7031beac91f75" root="7031beac91f75" order="6" type="FILE" class="NOVEL" layout="DOCUMENT">
<meta expanded="yes" heading="H2" charCount="139" wordCount="28" paraCount="1" cursorPos="356" /> <meta expanded="yes" heading="H2" charCount="139" wordCount="28" paraCount="1" cursorPos="238" />
<name status="s90e6c9" import="ia857f0" active="yes">Chapter Two</name> <name status="s90e6c9" import="ia857f0" active="yes">Chapter Two</name>
</item> </item>
<item handle="ae7339df26ded" parent="88706ddc78b1b" root="7031beac91f75" order="0" type="FILE" class="NOVEL" layout="DOCUMENT"> <item handle="ae7339df26ded" parent="88706ddc78b1b" root="7031beac91f75" order="0" type="FILE" class="NOVEL" layout="DOCUMENT">
@@ -86,11 +86,11 @@
<name status="sf12341" import="ia857f0">Sequel</name> <name status="sf12341" import="ia857f0">Sequel</name>
</item> </item>
<item handle="bacb7059e3083" parent="e5e47ebf63b1c" root="e5e47ebf63b1c" order="0" type="FILE" class="NOVEL" layout="DOCUMENT"> <item handle="bacb7059e3083" parent="e5e47ebf63b1c" root="e5e47ebf63b1c" order="0" type="FILE" class="NOVEL" layout="DOCUMENT">
<meta expanded="no" heading="H1" charCount="27" wordCount="5" paraCount="1" cursorPos="41" /> <meta expanded="no" heading="H1" charCount="27" wordCount="5" paraCount="1" cursorPos="99" />
<name status="sc24b8f" import="ia857f0" active="yes">Title Page</name> <name status="sc24b8f" import="ia857f0" active="yes">Title Page</name>
</item> </item>
<item handle="a520879ca0b45" parent="e5e47ebf63b1c" root="e5e47ebf63b1c" order="1" type="FILE" class="NOVEL" layout="DOCUMENT"> <item handle="a520879ca0b45" parent="e5e47ebf63b1c" root="e5e47ebf63b1c" order="1" type="FILE" class="NOVEL" layout="DOCUMENT">
<meta expanded="no" heading="H2" charCount="299" wordCount="55" paraCount="2" cursorPos="29" /> <meta expanded="no" heading="H2" charCount="299" wordCount="55" paraCount="2" cursorPos="385" />
<name status="s8ae72a" import="ia857f0" active="yes">Chapter One</name> <name status="s8ae72a" import="ia857f0" active="yes">Chapter One</name>
</item> </item>
<item handle="f6622b4617424" parent="None" root="f6622b4617424" order="2" type="ROOT" class="CHARACTER"> <item handle="f6622b4617424" parent="None" root="f6622b4617424" order="2" type="ROOT" class="CHARACTER">
@@ -102,11 +102,11 @@
<name status="sf12341" import="ia857f0">Main Characters</name> <name status="sf12341" import="ia857f0">Main Characters</name>
</item> </item>
<item handle="14298de4d9524" parent="f7e2d9f330615" root="f6622b4617424" order="0" type="FILE" class="CHARACTER" layout="NOTE"> <item handle="14298de4d9524" parent="f7e2d9f330615" root="f6622b4617424" order="0" type="FILE" class="CHARACTER" layout="NOTE">
<meta expanded="no" heading="H1" charCount="49" wordCount="9" paraCount="1" cursorPos="40" /> <meta expanded="no" heading="H1" charCount="49" wordCount="9" paraCount="1" cursorPos="101" />
<name status="sf12341" import="i2d7a54" active="yes">John Smith</name> <name status="sf12341" import="i2d7a54" active="yes">John Smith</name>
</item> </item>
<item handle="bb2c23b3c42cc" parent="f7e2d9f330615" root="f6622b4617424" order="1" type="FILE" class="CHARACTER" layout="NOTE"> <item handle="bb2c23b3c42cc" parent="f7e2d9f330615" root="f6622b4617424" order="1" type="FILE" class="CHARACTER" layout="NOTE">
<meta expanded="no" heading="H1" charCount="55" wordCount="9" paraCount="1" cursorPos="40" /> <meta expanded="no" heading="H1" charCount="55" wordCount="9" paraCount="1" cursorPos="106" />
<name status="sf12341" import="i56be10" active="yes">Jane Smith</name> <name status="sf12341" import="i56be10" active="yes">Jane Smith</name>
</item> </item>
<item handle="15c4492bd5107" parent="None" root="15c4492bd5107" order="3" type="ROOT" class="WORLD"> <item handle="15c4492bd5107" parent="None" root="15c4492bd5107" order="3" type="ROOT" class="WORLD">
@@ -118,7 +118,7 @@
<name status="sf12341" import="i2d7a54" active="yes">Earth</name> <name status="sf12341" import="i2d7a54" active="yes">Earth</name>
</item> </item>
<item handle="f1471bef9f2ae" parent="15c4492bd5107" root="15c4492bd5107" order="1" type="FILE" class="WORLD" layout="NOTE"> <item handle="f1471bef9f2ae" parent="15c4492bd5107" root="15c4492bd5107" order="1" type="FILE" class="WORLD" layout="NOTE">
<meta expanded="no" heading="H1" charCount="115" wordCount="24" paraCount="1" cursorPos="0" /> <meta expanded="no" heading="H1" charCount="115" wordCount="24" paraCount="1" cursorPos="133" />
<name status="sf12341" import="i4a1d39" active="yes">Space</name> <name status="sf12341" import="i4a1d39" active="yes">Space</name>
</item> </item>
<item handle="5eaea4e8cdee8" parent="15c4492bd5107" root="15c4492bd5107" order="2" type="FILE" class="WORLD" layout="NOTE"> <item handle="5eaea4e8cdee8" parent="15c4492bd5107" root="15c4492bd5107" order="2" type="FILE" class="WORLD" layout="NOTE">
@@ -1,5 +1,5 @@
<?xml version='1.0' encoding='utf-8'?> <?xml version='1.0' encoding='utf-8'?>
<novelWriterXML appVersion="2.8a0" hexVersion="0x020800a0" fileVersion="1.5" fileRevision="6" timeStamp="2025-06-12 18:02:57"> <novelWriterXML appVersion="2.8a2" hexVersion="0x020800a2" fileVersion="1.5" fileRevision="6" timeStamp="2025-07-17 15:27:23">
<project id="d0f3fe10-c6e6-4310-8bfd-181eb4224eed" saveCount="1" autoCount="1" editTime="0"> <project id="d0f3fe10-c6e6-4310-8bfd-181eb4224eed" saveCount="1" autoCount="1" editTime="0">
<name>New Project</name> <name>New Project</name>
<author>Jane Doe</author> <author>Jane Doe</author>
@@ -22,13 +22,13 @@
<entry key="s000003" count="0" color="green" shape="STAR">Finished</entry> <entry key="s000003" count="0" color="green" shape="STAR">Finished</entry>
</status> </status>
<importance> <importance>
<entry key="i000004" count="5" color="purple" shape="SQUARE">New</entry> <entry key="i000004" count="6" color="purple" shape="SQUARE">New</entry>
<entry key="i000005" count="0" color="purple" shape="BLOCK_2">Minor</entry> <entry key="i000005" count="0" color="purple" shape="BLOCK_2">Minor</entry>
<entry key="i000006" count="0" color="purple" shape="BLOCK_3">Major</entry> <entry key="i000006" count="0" color="purple" shape="BLOCK_3">Major</entry>
<entry key="i000007" count="0" color="purple" shape="BLOCK_4">Main</entry> <entry key="i000007" count="0" color="purple" shape="BLOCK_4">Main</entry>
</importance> </importance>
</settings> </settings>
<content items="12" novelWords="10" notesWords="6" novelChars="45" notesChars="22"> <content items="13" novelWords="10" notesWords="9" novelChars="45" notesChars="33">
<item handle="0000000000008" parent="None" root="0000000000008" order="0" type="ROOT" class="NOVEL"> <item handle="0000000000008" parent="None" root="0000000000008" order="0" type="ROOT" class="NOVEL">
<meta expanded="no" /> <meta expanded="no" />
<name status="s000000" import="i000004">Novel</name> <name status="s000000" import="i000004">Novel</name>
@@ -73,6 +73,10 @@
<meta expanded="no" heading="H1" charCount="11" wordCount="3" paraCount="1" cursorPos="0" /> <meta expanded="no" heading="H1" charCount="11" wordCount="3" paraCount="1" cursorPos="0" />
<name status="s000000" import="i000004" active="yes">John</name> <name status="s000000" import="i000004" active="yes">John</name>
</item> </item>
<item handle="0000000000014" parent="000000000000a" root="000000000000a" order="2" type="FILE" class="CHARACTER" layout="NOTE">
<meta expanded="no" heading="H1" charCount="11" wordCount="3" paraCount="1" cursorPos="0" />
<name status="s000000" import="i000004" active="yes">Mike</name>
</item>
<item handle="000000000000b" parent="None" root="000000000000b" order="3" type="ROOT" class="WORLD"> <item handle="000000000000b" parent="None" root="000000000000b" order="3" type="ROOT" class="WORLD">
<meta expanded="no" /> <meta expanded="no" />
<name status="s000000" import="i000004">Locations</name> <name status="s000000" import="i000004">Locations</name>
+7
View File
@@ -100,6 +100,7 @@ def testCoreProject_NewFileFolder(monkeypatch, fncPath, tstPaths, mockGUI, mockR
bHandle = "0000000000011" bHandle = "0000000000011"
cHandle = "0000000000012" cHandle = "0000000000012"
dHandle = "0000000000013" dHandle = "0000000000013"
eHandle = "0000000000014"
xHandle = "1234567890abc" xHandle = "1234567890abc"
# Invalid call # Invalid call
@@ -111,11 +112,13 @@ def testCoreProject_NewFileFolder(monkeypatch, fncPath, tstPaths, mockGUI, mockR
assert project.newFile("Hello", aHandle) == bHandle assert project.newFile("Hello", aHandle) == bHandle
assert project.newFile("Jane", C.hCharRoot) == cHandle assert project.newFile("Jane", C.hCharRoot) == cHandle
assert project.newFile("John", C.hCharRoot) == dHandle assert project.newFile("John", C.hCharRoot) == dHandle
assert project.newFile("Mike", C.hCharRoot) == eHandle
assert aHandle in project.tree assert aHandle in project.tree
assert bHandle in project.tree assert bHandle in project.tree
assert cHandle in project.tree assert cHandle in project.tree
assert dHandle in project.tree assert dHandle in project.tree
assert eHandle in project.tree
# Write to file, failed # Write to file, failed
assert project.writeNewFile("blabla", 1, True) is False # Not a handle assert project.writeNewFile("blabla", 1, True) is False # Not a handle
@@ -151,6 +154,10 @@ def testCoreProject_NewFileFolder(monkeypatch, fncPath, tstPaths, mockGUI, mockR
assert dText == cText assert dText == cText
# Copy file content, and update title
assert project.copyFileContent(eHandle, cHandle, "Lars") is True
assert project.storage.getDocument(eHandle).readDocument() == "# Lars\n\nHi Jane\n\n"
# Save, close and check # Save, close and check
assert project.projChanged is True assert project.projChanged is True
assert project.saveProject() is True assert project.saveProject() is True
+1 -1
View File
@@ -1454,7 +1454,7 @@ def testGuiProjTree_Templates(qtbot, monkeypatch, nwGUI, projPath, mockRnd):
nwNewCharacter = project.tree[hNewCharacter] nwNewCharacter = project.tree[hNewCharacter]
assert nwNewCharacter is not None assert nwNewCharacter is not None
assert nwNewCharacter.itemName == "Note" assert nwNewCharacter.itemName == "Note"
assert project.storage.getDocument(hNewCharacter).readDocument() == "# Jane\n\n@tag: Jane\n\n" assert project.storage.getDocument(hNewCharacter).readDocument() == "# Note\n\n@tag: Jane\n\n"
# Clearing the menu and rebuilding it should work # Clearing the menu and rebuilding it should work
projBar.mTemplates.clearMenu() projBar.mTemplates.clearMenu()