Add support for mentions references (#2064)
This commit is contained in:
@@ -118,6 +118,9 @@ The root folders are closely tied to the tags and reference system. Each folder
|
|||||||
the categories of tags that can be used to reference them. For more information about the tags
|
the categories of tags that can be used to reference them. For more information about the tags
|
||||||
listed, see :ref:`a_references_references`.
|
listed, see :ref:`a_references_references`.
|
||||||
|
|
||||||
|
There is also a ``@mention`` keyword that can be used to reference any tag.
|
||||||
|
See :ref:`a_references_references` for more details.
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
You can rename root folders to whatever you want. However, this doesn't change the reference
|
You can rename root folders to whatever you want. However, this doesn't change the reference
|
||||||
keyword or what they do.
|
keyword or what they do.
|
||||||
|
|||||||
@@ -162,6 +162,12 @@ reference keywords allow multiple values.
|
|||||||
Custom references in the current section. The target must be a note tag in a **Custom** type
|
Custom references in the current section. The target must be a note tag in a **Custom** type
|
||||||
root folder. The custom folder are for any other category of notes you may want to use.
|
root folder. The custom folder are for any other category of notes you may want to use.
|
||||||
|
|
||||||
|
``@mention``
|
||||||
|
Anything mentioned, but not present in the current section. It is intended for those cases where
|
||||||
|
you reveal details about a character or place in a scene without it being otherwise a part of
|
||||||
|
it. This can be useful when checking for consistency later. Any tag in any root note folder can
|
||||||
|
be listed under mentions.
|
||||||
|
|
||||||
The syntax highlighter will alert the user that the tags and references are used correctly, and
|
The syntax highlighter will alert the user that the tags and references are used correctly, and
|
||||||
that the tags referenced exist.
|
that the tags referenced exist.
|
||||||
|
|
||||||
|
|||||||
@@ -165,6 +165,7 @@ a key or key combination for the inserted content.
|
|||||||
":kbd:`Ctrl+K`, :kbd:`G`", "Insert a ``@tag`` keyword"
|
":kbd:`Ctrl+K`, :kbd:`G`", "Insert a ``@tag`` keyword"
|
||||||
":kbd:`Ctrl+K`, :kbd:`H`", "Insert a short description comment"
|
":kbd:`Ctrl+K`, :kbd:`H`", "Insert a short description comment"
|
||||||
":kbd:`Ctrl+K`, :kbd:`L`", "Insert a ``@location`` keyword"
|
":kbd:`Ctrl+K`, :kbd:`L`", "Insert a ``@location`` keyword"
|
||||||
|
":kbd:`Ctrl+K`, :kbd:`M`", "Insert a ``@mention`` keyword"
|
||||||
":kbd:`Ctrl+K`, :kbd:`O`", "Insert an ``@object`` keyword"
|
":kbd:`Ctrl+K`, :kbd:`O`", "Insert an ``@object`` keyword"
|
||||||
":kbd:`Ctrl+K`, :kbd:`P`", "Insert a ``@plot`` keyword"
|
":kbd:`Ctrl+K`, :kbd:`P`", "Insert a ``@plot`` keyword"
|
||||||
":kbd:`Ctrl+K`, :kbd:`S`", "Insert a synopsis comment"
|
":kbd:`Ctrl+K`, :kbd:`S`", "Insert a synopsis comment"
|
||||||
|
|||||||
+50
-47
@@ -145,34 +145,35 @@ class nwFiles:
|
|||||||
|
|
||||||
class nwKeyWords:
|
class nwKeyWords:
|
||||||
|
|
||||||
TAG_KEY = "@tag"
|
TAG_KEY = "@tag"
|
||||||
POV_KEY = "@pov"
|
POV_KEY = "@pov"
|
||||||
FOCUS_KEY = "@focus"
|
FOCUS_KEY = "@focus"
|
||||||
CHAR_KEY = "@char"
|
CHAR_KEY = "@char"
|
||||||
PLOT_KEY = "@plot"
|
PLOT_KEY = "@plot"
|
||||||
TIME_KEY = "@time"
|
TIME_KEY = "@time"
|
||||||
WORLD_KEY = "@location"
|
WORLD_KEY = "@location"
|
||||||
OBJECT_KEY = "@object"
|
OBJECT_KEY = "@object"
|
||||||
ENTITY_KEY = "@entity"
|
ENTITY_KEY = "@entity"
|
||||||
CUSTOM_KEY = "@custom"
|
CUSTOM_KEY = "@custom"
|
||||||
|
MENTION_KEY = "@mention"
|
||||||
|
|
||||||
# Set of Valid Keys
|
# Set of Valid Keys
|
||||||
VALID_KEYS = {
|
VALID_KEYS = {
|
||||||
TAG_KEY, POV_KEY, FOCUS_KEY, CHAR_KEY, PLOT_KEY, TIME_KEY,
|
TAG_KEY, POV_KEY, FOCUS_KEY, CHAR_KEY, PLOT_KEY, TIME_KEY,
|
||||||
WORLD_KEY, OBJECT_KEY, ENTITY_KEY, CUSTOM_KEY
|
WORLD_KEY, OBJECT_KEY, ENTITY_KEY, CUSTOM_KEY, MENTION_KEY
|
||||||
}
|
}
|
||||||
|
|
||||||
# Map from Keys to Item Class
|
# Map from Keys to Item Class
|
||||||
KEY_CLASS = {
|
KEY_CLASS = {
|
||||||
POV_KEY: nwItemClass.CHARACTER,
|
POV_KEY: nwItemClass.CHARACTER,
|
||||||
FOCUS_KEY: nwItemClass.CHARACTER,
|
FOCUS_KEY: nwItemClass.CHARACTER,
|
||||||
CHAR_KEY: nwItemClass.CHARACTER,
|
CHAR_KEY: nwItemClass.CHARACTER,
|
||||||
PLOT_KEY: nwItemClass.PLOT,
|
PLOT_KEY: nwItemClass.PLOT,
|
||||||
TIME_KEY: nwItemClass.TIMELINE,
|
TIME_KEY: nwItemClass.TIMELINE,
|
||||||
WORLD_KEY: nwItemClass.WORLD,
|
WORLD_KEY: nwItemClass.WORLD,
|
||||||
OBJECT_KEY: nwItemClass.OBJECT,
|
OBJECT_KEY: nwItemClass.OBJECT,
|
||||||
ENTITY_KEY: nwItemClass.ENTITY,
|
ENTITY_KEY: nwItemClass.ENTITY,
|
||||||
CUSTOM_KEY: nwItemClass.CUSTOM,
|
CUSTOM_KEY: nwItemClass.CUSTOM,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -236,35 +237,37 @@ class nwLabels:
|
|||||||
"note": QT_TRANSLATE_NOOP("Constant", "Project Note"),
|
"note": QT_TRANSLATE_NOOP("Constant", "Project Note"),
|
||||||
}
|
}
|
||||||
KEY_NAME = {
|
KEY_NAME = {
|
||||||
nwKeyWords.TAG_KEY: QT_TRANSLATE_NOOP("Constant", "Tag"),
|
nwKeyWords.TAG_KEY: QT_TRANSLATE_NOOP("Constant", "Tag"),
|
||||||
nwKeyWords.POV_KEY: QT_TRANSLATE_NOOP("Constant", "Point of View"),
|
nwKeyWords.POV_KEY: QT_TRANSLATE_NOOP("Constant", "Point of View"),
|
||||||
nwKeyWords.FOCUS_KEY: QT_TRANSLATE_NOOP("Constant", "Focus"),
|
nwKeyWords.FOCUS_KEY: QT_TRANSLATE_NOOP("Constant", "Focus"),
|
||||||
nwKeyWords.CHAR_KEY: QT_TRANSLATE_NOOP("Constant", "Characters"),
|
nwKeyWords.CHAR_KEY: QT_TRANSLATE_NOOP("Constant", "Characters"),
|
||||||
nwKeyWords.PLOT_KEY: QT_TRANSLATE_NOOP("Constant", "Plot"),
|
nwKeyWords.PLOT_KEY: QT_TRANSLATE_NOOP("Constant", "Plot"),
|
||||||
nwKeyWords.TIME_KEY: QT_TRANSLATE_NOOP("Constant", "Timeline"),
|
nwKeyWords.TIME_KEY: QT_TRANSLATE_NOOP("Constant", "Timeline"),
|
||||||
nwKeyWords.WORLD_KEY: QT_TRANSLATE_NOOP("Constant", "Locations"),
|
nwKeyWords.WORLD_KEY: QT_TRANSLATE_NOOP("Constant", "Locations"),
|
||||||
nwKeyWords.OBJECT_KEY: QT_TRANSLATE_NOOP("Constant", "Objects"),
|
nwKeyWords.OBJECT_KEY: QT_TRANSLATE_NOOP("Constant", "Objects"),
|
||||||
nwKeyWords.ENTITY_KEY: QT_TRANSLATE_NOOP("Constant", "Entities"),
|
nwKeyWords.ENTITY_KEY: QT_TRANSLATE_NOOP("Constant", "Entities"),
|
||||||
nwKeyWords.CUSTOM_KEY: QT_TRANSLATE_NOOP("Constant", "Custom"),
|
nwKeyWords.CUSTOM_KEY: QT_TRANSLATE_NOOP("Constant", "Custom"),
|
||||||
|
nwKeyWords.MENTION_KEY: QT_TRANSLATE_NOOP("Constant", "Mentions"),
|
||||||
}
|
}
|
||||||
OUTLINE_COLS = {
|
OUTLINE_COLS = {
|
||||||
nwOutline.TITLE: QT_TRANSLATE_NOOP("Constant", "Title"),
|
nwOutline.TITLE: QT_TRANSLATE_NOOP("Constant", "Title"),
|
||||||
nwOutline.LEVEL: QT_TRANSLATE_NOOP("Constant", "Level"),
|
nwOutline.LEVEL: QT_TRANSLATE_NOOP("Constant", "Level"),
|
||||||
nwOutline.LABEL: QT_TRANSLATE_NOOP("Constant", "Document"),
|
nwOutline.LABEL: QT_TRANSLATE_NOOP("Constant", "Document"),
|
||||||
nwOutline.LINE: QT_TRANSLATE_NOOP("Constant", "Line"),
|
nwOutline.LINE: QT_TRANSLATE_NOOP("Constant", "Line"),
|
||||||
nwOutline.CCOUNT: QT_TRANSLATE_NOOP("Constant", "Chars"),
|
nwOutline.CCOUNT: QT_TRANSLATE_NOOP("Constant", "Chars"),
|
||||||
nwOutline.WCOUNT: QT_TRANSLATE_NOOP("Constant", "Words"),
|
nwOutline.WCOUNT: QT_TRANSLATE_NOOP("Constant", "Words"),
|
||||||
nwOutline.PCOUNT: QT_TRANSLATE_NOOP("Constant", "Pars"),
|
nwOutline.PCOUNT: QT_TRANSLATE_NOOP("Constant", "Pars"),
|
||||||
nwOutline.POV: QT_TRANSLATE_NOOP("Constant", "POV"),
|
nwOutline.POV: QT_TRANSLATE_NOOP("Constant", "POV"),
|
||||||
nwOutline.FOCUS: QT_TRANSLATE_NOOP("Constant", "Focus"),
|
nwOutline.FOCUS: QT_TRANSLATE_NOOP("Constant", "Focus"),
|
||||||
nwOutline.CHAR: KEY_NAME[nwKeyWords.CHAR_KEY],
|
nwOutline.CHAR: KEY_NAME[nwKeyWords.CHAR_KEY],
|
||||||
nwOutline.PLOT: KEY_NAME[nwKeyWords.PLOT_KEY],
|
nwOutline.PLOT: KEY_NAME[nwKeyWords.PLOT_KEY],
|
||||||
nwOutline.WORLD: KEY_NAME[nwKeyWords.WORLD_KEY],
|
nwOutline.WORLD: KEY_NAME[nwKeyWords.WORLD_KEY],
|
||||||
nwOutline.TIME: KEY_NAME[nwKeyWords.TIME_KEY],
|
nwOutline.TIME: KEY_NAME[nwKeyWords.TIME_KEY],
|
||||||
nwOutline.OBJECT: KEY_NAME[nwKeyWords.OBJECT_KEY],
|
nwOutline.OBJECT: KEY_NAME[nwKeyWords.OBJECT_KEY],
|
||||||
nwOutline.ENTITY: KEY_NAME[nwKeyWords.ENTITY_KEY],
|
nwOutline.ENTITY: KEY_NAME[nwKeyWords.ENTITY_KEY],
|
||||||
nwOutline.CUSTOM: KEY_NAME[nwKeyWords.CUSTOM_KEY],
|
nwOutline.CUSTOM: KEY_NAME[nwKeyWords.CUSTOM_KEY],
|
||||||
nwOutline.SYNOP: QT_TRANSLATE_NOOP("Constant", "Synopsis"),
|
nwOutline.MENTION: KEY_NAME[nwKeyWords.MENTION_KEY],
|
||||||
|
nwOutline.SYNOP: QT_TRANSLATE_NOOP("Constant", "Synopsis"),
|
||||||
}
|
}
|
||||||
BUILD_FMT = {
|
BUILD_FMT = {
|
||||||
nwBuildFmt.ODT: QT_TRANSLATE_NOOP("Constant", "Open Document (.odt)"),
|
nwBuildFmt.ODT: QT_TRANSLATE_NOOP("Constant", "Open Document (.odt)"),
|
||||||
|
|||||||
+24
-13
@@ -487,13 +487,14 @@ class NWIndex:
|
|||||||
if nBits == 0:
|
if nBits == 0:
|
||||||
return []
|
return []
|
||||||
|
|
||||||
# Check that the key is valid
|
# Check that the keyword is valid
|
||||||
isGood[0] = tBits[0] in nwKeyWords.VALID_KEYS
|
kBit = tBits[0]
|
||||||
|
isGood[0] = kBit in nwKeyWords.VALID_KEYS
|
||||||
if not isGood[0] or nBits == 1:
|
if not isGood[0] or nBits == 1:
|
||||||
return isGood
|
return isGood
|
||||||
|
|
||||||
# For a tag, only the first value is accepted, the rest are ignored
|
# For a tag, only the first value is accepted, the rest are ignored
|
||||||
if tBits[0] == nwKeyWords.TAG_KEY and nBits > 1:
|
if kBit == nwKeyWords.TAG_KEY and nBits > 1:
|
||||||
check, _ = self.parseValue(tBits[1])
|
check, _ = self.parseValue(tBits[1])
|
||||||
if check in self._tagsIndex:
|
if check in self._tagsIndex:
|
||||||
isGood[1] = self._tagsIndex.tagHandle(check) == tHandle
|
isGood[1] = self._tagsIndex.tagHandle(check) == tHandle
|
||||||
@@ -501,12 +502,16 @@ class NWIndex:
|
|||||||
isGood[1] = True
|
isGood[1] = True
|
||||||
return isGood
|
return isGood
|
||||||
|
|
||||||
|
if kBit == nwKeyWords.MENTION_KEY and nBits > 1:
|
||||||
|
isGood[1:nBits] = [aBit in self._tagsIndex for aBit in tBits[1:nBits]]
|
||||||
|
return isGood
|
||||||
|
|
||||||
# If we're still here, we check that the references exist
|
# If we're still here, we check that the references exist
|
||||||
# Class references cannot have the | symbol in them
|
# Class references cannot have the | symbol in them
|
||||||
refKey = nwKeyWords.KEY_CLASS[tBits[0]].name
|
if rClass := nwKeyWords.KEY_CLASS.get(kBit):
|
||||||
for n in range(1, nBits):
|
for n in range(1, nBits):
|
||||||
if (aBit := tBits[n]) in self._tagsIndex:
|
if (aBit := tBits[n]) in self._tagsIndex:
|
||||||
isGood[n] = self._tagsIndex.tagClass(aBit) == refKey and "|" not in aBit
|
isGood[n] = self._tagsIndex.tagClass(aBit) == rClass.name and "|" not in aBit
|
||||||
|
|
||||||
return isGood
|
return isGood
|
||||||
|
|
||||||
@@ -681,9 +686,10 @@ class NWIndex:
|
|||||||
"""Return all tags used by a specific document."""
|
"""Return all tags used by a specific document."""
|
||||||
return self._itemIndex.allItemTags(tHandle) if tHandle else []
|
return self._itemIndex.allItemTags(tHandle) if tHandle else []
|
||||||
|
|
||||||
def getClassTags(self, itemClass: nwItemClass) -> list[str]:
|
def getClassTags(self, itemClass: nwItemClass | None) -> list[str]:
|
||||||
"""Return all tags based on itemClass."""
|
"""Return all tags based on itemClass."""
|
||||||
return self._tagsIndex.filterTagNames(itemClass.name)
|
name = None if itemClass is None else itemClass.name
|
||||||
|
return self._tagsIndex.filterTagNames(name)
|
||||||
|
|
||||||
def getTagsData(
|
def getTagsData(
|
||||||
self, activeOnly: bool = True
|
self, activeOnly: bool = True
|
||||||
@@ -780,11 +786,16 @@ class TagsIndex:
|
|||||||
"""Get the class of a given tag."""
|
"""Get the class of a given tag."""
|
||||||
return self._tags.get(tagKey.lower(), {}).get("class", None)
|
return self._tags.get(tagKey.lower(), {}).get("class", None)
|
||||||
|
|
||||||
def filterTagNames(self, className: str) -> list[str]:
|
def filterTagNames(self, className: str | None) -> list[str]:
|
||||||
"""Get a list of tag names for a given class."""
|
"""Get a list of tag names for a given class."""
|
||||||
return [
|
if className is None:
|
||||||
x.get("name", "") for x in self._tags.values() if x.get("class", "") == className
|
return [
|
||||||
]
|
x.get("name", "") for x in self._tags.values()
|
||||||
|
]
|
||||||
|
else:
|
||||||
|
return [
|
||||||
|
x.get("name", "") for x in self._tags.values() if x.get("class", "") == className
|
||||||
|
]
|
||||||
|
|
||||||
##
|
##
|
||||||
# Pack/Unpack
|
# Pack/Unpack
|
||||||
|
|||||||
+18
-17
@@ -158,23 +158,24 @@ class nwFocus(Enum):
|
|||||||
|
|
||||||
class nwOutline(Enum):
|
class nwOutline(Enum):
|
||||||
|
|
||||||
TITLE = 0
|
TITLE = 0
|
||||||
LEVEL = 1
|
LEVEL = 1
|
||||||
LABEL = 2
|
LABEL = 2
|
||||||
LINE = 3
|
LINE = 3
|
||||||
CCOUNT = 4
|
CCOUNT = 4
|
||||||
WCOUNT = 5
|
WCOUNT = 5
|
||||||
PCOUNT = 6
|
PCOUNT = 6
|
||||||
POV = 7
|
POV = 7
|
||||||
FOCUS = 8
|
FOCUS = 8
|
||||||
CHAR = 9
|
CHAR = 9
|
||||||
PLOT = 10
|
PLOT = 10
|
||||||
TIME = 11
|
TIME = 11
|
||||||
WORLD = 12
|
WORLD = 12
|
||||||
OBJECT = 13
|
OBJECT = 13
|
||||||
ENTITY = 14
|
ENTITY = 14
|
||||||
CUSTOM = 15
|
CUSTOM = 15
|
||||||
SYNOP = 16
|
MENTION = 16
|
||||||
|
SYNOP = 17
|
||||||
|
|
||||||
|
|
||||||
class nwBuildFmt(Enum):
|
class nwBuildFmt(Enum):
|
||||||
|
|||||||
@@ -2176,7 +2176,7 @@ class MetaCompleter(QMenu):
|
|||||||
suffix = ""
|
suffix = ""
|
||||||
options = list(filter(
|
options = list(filter(
|
||||||
lambda x: lookup in x.lower(), SHARED.project.index.getClassTags(
|
lambda x: lookup in x.lower(), SHARED.project.index.getClassTags(
|
||||||
nwKeyWords.KEY_CLASS.get(kw.strip(), nwItemClass.NO_CLASS)
|
nwKeyWords.KEY_CLASS.get(kw.strip())
|
||||||
)
|
)
|
||||||
))[:15]
|
))[:15]
|
||||||
|
|
||||||
|
|||||||
+11
-10
@@ -535,16 +535,17 @@ class GuiMainMenu(QMenuBar):
|
|||||||
# Insert > Tags and References
|
# Insert > Tags and References
|
||||||
self.mInsKeywords = self.insMenu.addMenu(self.tr("Tags and References"))
|
self.mInsKeywords = self.insMenu.addMenu(self.tr("Tags and References"))
|
||||||
self.mInsKWItems = {}
|
self.mInsKWItems = {}
|
||||||
self.mInsKWItems[nwKeyWords.TAG_KEY] = (QAction(self.mInsKeywords), "Ctrl+K, G")
|
self.mInsKWItems[nwKeyWords.TAG_KEY] = (QAction(self.mInsKeywords), "Ctrl+K, G")
|
||||||
self.mInsKWItems[nwKeyWords.POV_KEY] = (QAction(self.mInsKeywords), "Ctrl+K, V")
|
self.mInsKWItems[nwKeyWords.POV_KEY] = (QAction(self.mInsKeywords), "Ctrl+K, V")
|
||||||
self.mInsKWItems[nwKeyWords.FOCUS_KEY] = (QAction(self.mInsKeywords), "Ctrl+K, F")
|
self.mInsKWItems[nwKeyWords.FOCUS_KEY] = (QAction(self.mInsKeywords), "Ctrl+K, F")
|
||||||
self.mInsKWItems[nwKeyWords.CHAR_KEY] = (QAction(self.mInsKeywords), "Ctrl+K, C")
|
self.mInsKWItems[nwKeyWords.CHAR_KEY] = (QAction(self.mInsKeywords), "Ctrl+K, C")
|
||||||
self.mInsKWItems[nwKeyWords.PLOT_KEY] = (QAction(self.mInsKeywords), "Ctrl+K, P")
|
self.mInsKWItems[nwKeyWords.PLOT_KEY] = (QAction(self.mInsKeywords), "Ctrl+K, P")
|
||||||
self.mInsKWItems[nwKeyWords.TIME_KEY] = (QAction(self.mInsKeywords), "Ctrl+K, T")
|
self.mInsKWItems[nwKeyWords.TIME_KEY] = (QAction(self.mInsKeywords), "Ctrl+K, T")
|
||||||
self.mInsKWItems[nwKeyWords.WORLD_KEY] = (QAction(self.mInsKeywords), "Ctrl+K, L")
|
self.mInsKWItems[nwKeyWords.WORLD_KEY] = (QAction(self.mInsKeywords), "Ctrl+K, L")
|
||||||
self.mInsKWItems[nwKeyWords.OBJECT_KEY] = (QAction(self.mInsKeywords), "Ctrl+K, O")
|
self.mInsKWItems[nwKeyWords.OBJECT_KEY] = (QAction(self.mInsKeywords), "Ctrl+K, O")
|
||||||
self.mInsKWItems[nwKeyWords.ENTITY_KEY] = (QAction(self.mInsKeywords), "Ctrl+K, E")
|
self.mInsKWItems[nwKeyWords.ENTITY_KEY] = (QAction(self.mInsKeywords), "Ctrl+K, E")
|
||||||
self.mInsKWItems[nwKeyWords.CUSTOM_KEY] = (QAction(self.mInsKeywords), "Ctrl+K, X")
|
self.mInsKWItems[nwKeyWords.CUSTOM_KEY] = (QAction(self.mInsKeywords), "Ctrl+K, X")
|
||||||
|
self.mInsKWItems[nwKeyWords.MENTION_KEY] = (QAction(self.mInsKeywords), "Ctrl+K, M")
|
||||||
for n, keyWord in enumerate(self.mInsKWItems):
|
for n, keyWord in enumerate(self.mInsKWItems):
|
||||||
self.mInsKWItems[keyWord][0].setText(trConst(nwLabels.KEY_NAME[keyWord]))
|
self.mInsKWItems[keyWord][0].setText(trConst(nwLabels.KEY_NAME[keyWord]))
|
||||||
self.mInsKWItems[keyWord][0].setShortcut(self.mInsKWItems[keyWord][1])
|
self.mInsKWItems[keyWord][0].setShortcut(self.mInsKWItems[keyWord][1])
|
||||||
|
|||||||
+36
-34
@@ -312,43 +312,45 @@ class GuiOutlineToolBar(QToolBar):
|
|||||||
class GuiOutlineTree(QTreeWidget):
|
class GuiOutlineTree(QTreeWidget):
|
||||||
|
|
||||||
DEF_WIDTH = {
|
DEF_WIDTH = {
|
||||||
nwOutline.TITLE: 200,
|
nwOutline.TITLE: 200,
|
||||||
nwOutline.LEVEL: 40,
|
nwOutline.LEVEL: 40,
|
||||||
nwOutline.LABEL: 150,
|
nwOutline.LABEL: 150,
|
||||||
nwOutline.LINE: 40,
|
nwOutline.LINE: 40,
|
||||||
nwOutline.CCOUNT: 50,
|
nwOutline.CCOUNT: 50,
|
||||||
nwOutline.WCOUNT: 50,
|
nwOutline.WCOUNT: 50,
|
||||||
nwOutline.PCOUNT: 50,
|
nwOutline.PCOUNT: 50,
|
||||||
nwOutline.POV: 100,
|
nwOutline.POV: 100,
|
||||||
nwOutline.FOCUS: 100,
|
nwOutline.FOCUS: 100,
|
||||||
nwOutline.CHAR: 100,
|
nwOutline.CHAR: 100,
|
||||||
nwOutline.PLOT: 100,
|
nwOutline.PLOT: 100,
|
||||||
nwOutline.TIME: 100,
|
nwOutline.TIME: 100,
|
||||||
nwOutline.WORLD: 100,
|
nwOutline.WORLD: 100,
|
||||||
nwOutline.OBJECT: 100,
|
nwOutline.OBJECT: 100,
|
||||||
nwOutline.ENTITY: 100,
|
nwOutline.ENTITY: 100,
|
||||||
nwOutline.CUSTOM: 100,
|
nwOutline.CUSTOM: 100,
|
||||||
nwOutline.SYNOP: 200,
|
nwOutline.MENTION: 100,
|
||||||
|
nwOutline.SYNOP: 200,
|
||||||
}
|
}
|
||||||
|
|
||||||
DEF_HIDDEN = {
|
DEF_HIDDEN = {
|
||||||
nwOutline.TITLE: False,
|
nwOutline.TITLE: False,
|
||||||
nwOutline.LEVEL: True,
|
nwOutline.LEVEL: True,
|
||||||
nwOutline.LABEL: False,
|
nwOutline.LABEL: False,
|
||||||
nwOutline.LINE: True,
|
nwOutline.LINE: True,
|
||||||
nwOutline.CCOUNT: True,
|
nwOutline.CCOUNT: True,
|
||||||
nwOutline.WCOUNT: False,
|
nwOutline.WCOUNT: False,
|
||||||
nwOutline.PCOUNT: False,
|
nwOutline.PCOUNT: False,
|
||||||
nwOutline.POV: False,
|
nwOutline.POV: False,
|
||||||
nwOutline.FOCUS: True,
|
nwOutline.FOCUS: True,
|
||||||
nwOutline.CHAR: False,
|
nwOutline.CHAR: False,
|
||||||
nwOutline.PLOT: False,
|
nwOutline.PLOT: False,
|
||||||
nwOutline.TIME: True,
|
nwOutline.TIME: True,
|
||||||
nwOutline.WORLD: False,
|
nwOutline.WORLD: False,
|
||||||
nwOutline.OBJECT: True,
|
nwOutline.OBJECT: True,
|
||||||
nwOutline.ENTITY: True,
|
nwOutline.ENTITY: True,
|
||||||
nwOutline.CUSTOM: True,
|
nwOutline.CUSTOM: True,
|
||||||
nwOutline.SYNOP: False,
|
nwOutline.MENTION: True,
|
||||||
|
nwOutline.SYNOP: False,
|
||||||
}
|
}
|
||||||
|
|
||||||
D_HANDLE = QtUserRole
|
D_HANDLE = QtUserRole
|
||||||
|
|||||||
@@ -1,13 +1,14 @@
|
|||||||
%%~name: Making a Scene
|
%%~name: Making a Scene
|
||||||
%%~path: 6a2d6d5f4f401/636b6aa9b697b
|
%%~path: 6a2d6d5f4f401/636b6aa9b697b
|
||||||
%%~kind: NOVEL/DOCUMENT
|
%%~kind: NOVEL/DOCUMENT
|
||||||
%%~hash: c7e664867218b3a9aac5c12119ef0ec63da2e5cc
|
%%~hash: 349d9ce3d59ad241d63b01380c53a7fb26ce9f19
|
||||||
%%~date: Unknown/2024-04-18 17:56:30
|
%%~date: Unknown/2024-10-24 23:44:27
|
||||||
### Making a Scene
|
### Making a Scene
|
||||||
|
|
||||||
@pov: Jane
|
@pov: Jane
|
||||||
@char: John, Jane
|
@char: John, Jane
|
||||||
@location: Earth
|
@location: Earth
|
||||||
|
@mention: Bob, Space
|
||||||
|
|
||||||
A scene is defined by a level three heading, like the one at the top of this page. The scene will be assigned to the chapter preceding it in the project tree. The scene document can be sorted after the chapter document, or as a child of the chapter. Both result in the same output in the end, so it is a matter of preference.
|
A scene is defined by a level three heading, like the one at the top of this page. The scene will be assigned to the chapter preceding it in the project tree. The scene document can be sorted after the chapter document, or as a child of the chapter. Both result in the same output in the end, so it is a matter of preference.
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<?xml version='1.0' encoding='utf-8'?>
|
<?xml version='1.0' encoding='utf-8'?>
|
||||||
<novelWriterXML appVersion="2.6a2" hexVersion="0x020600a2" fileVersion="1.5" fileRevision="4" timeStamp="2024-10-24 16:26:12">
|
<novelWriterXML appVersion="2.6a2" hexVersion="0x020600a2" fileVersion="1.5" fileRevision="4" timeStamp="2024-10-24 23:58:23">
|
||||||
<project id="e2be99af-f9bf-4403-857a-c3d1ac25abea" saveCount="2077" autoCount="279" editTime="93511">
|
<project id="e2be99af-f9bf-4403-857a-c3d1ac25abea" saveCount="2088" autoCount="280" editTime="93793">
|
||||||
<name>Sample Project</name>
|
<name>Sample Project</name>
|
||||||
<author>Jane Smith</author>
|
<author>Jane Smith</author>
|
||||||
</project>
|
</project>
|
||||||
@@ -58,11 +58,11 @@
|
|||||||
<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">
|
||||||
<meta expanded="no" heading="H3" charCount="2937" wordCount="520" paraCount="15" cursorPos="4" />
|
<meta expanded="no" heading="H3" charCount="2937" wordCount="520" paraCount="15" cursorPos="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="563" wordCount="108" paraCount="3" cursorPos="691" />
|
<meta expanded="no" heading="H3" charCount="548" wordCount="108" paraCount="3" cursorPos="650" />
|
||||||
<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">
|
||||||
|
|||||||
@@ -224,13 +224,17 @@ def testCoreIndex_CheckThese(mockGUI, fncPath, mockRnd):
|
|||||||
|
|
||||||
nHandle = project.newFile("Hello", C.hNovelRoot)
|
nHandle = project.newFile("Hello", C.hNovelRoot)
|
||||||
cHandle = project.newFile("Jane", C.hCharRoot)
|
cHandle = project.newFile("Jane", C.hCharRoot)
|
||||||
|
wHandle = project.newFile("Earth", C.hWorldRoot)
|
||||||
assert isinstance(nHandle, str)
|
assert isinstance(nHandle, str)
|
||||||
assert isinstance(cHandle, str)
|
assert isinstance(cHandle, str)
|
||||||
|
assert isinstance(wHandle, str)
|
||||||
|
|
||||||
nItem = project.tree[nHandle]
|
nItem = project.tree[nHandle]
|
||||||
cItem = project.tree[cHandle]
|
cItem = project.tree[cHandle]
|
||||||
|
wItem = project.tree[wHandle]
|
||||||
assert isinstance(nItem, NWItem)
|
assert isinstance(nItem, NWItem)
|
||||||
assert isinstance(cItem, NWItem)
|
assert isinstance(cItem, NWItem)
|
||||||
|
assert isinstance(wItem, NWItem)
|
||||||
|
|
||||||
assert index.rootChangedSince(C.hNovelRoot, 0) is False
|
assert index.rootChangedSince(C.hNovelRoot, 0) is False
|
||||||
assert index.rootChangedSince(None, 0) is False
|
assert index.rootChangedSince(None, 0) is False
|
||||||
@@ -242,21 +246,31 @@ def testCoreIndex_CheckThese(mockGUI, fncPath, mockRnd):
|
|||||||
"@tag:\n"
|
"@tag:\n"
|
||||||
"@:\n"
|
"@:\n"
|
||||||
))
|
))
|
||||||
|
assert index.scanText(wHandle, (
|
||||||
|
"# Earth\n"
|
||||||
|
"@tag: Earth\n"
|
||||||
|
))
|
||||||
assert index.scanText(nHandle, (
|
assert index.scanText(nHandle, (
|
||||||
"# Hello World!\n"
|
"# Hello World!\n"
|
||||||
"@pov: Jane\n"
|
"@pov: Jane\n"
|
||||||
|
"@location: Earth\n"
|
||||||
"@invalid: John\n" # Checks for issue #688
|
"@invalid: John\n" # Checks for issue #688
|
||||||
))
|
))
|
||||||
|
assert index._tagsIndex.tagHandle("Earth") == wHandle
|
||||||
|
assert index._tagsIndex.tagHeading("Earth") == "T0001"
|
||||||
|
assert index._tagsIndex.tagClass("Earth") == "WORLD"
|
||||||
|
|
||||||
assert index._tagsIndex.tagHandle("Jane") == cHandle
|
assert index._tagsIndex.tagHandle("Jane") == cHandle
|
||||||
assert index._tagsIndex.tagHeading("Jane") == "T0001"
|
assert index._tagsIndex.tagHeading("Jane") == "T0001"
|
||||||
assert index._tagsIndex.tagClass("Jane") == "CHARACTER"
|
assert index._tagsIndex.tagClass("Jane") == "CHARACTER"
|
||||||
|
|
||||||
assert index.getItemHeading(nHandle, "T0001").title == "Hello World!" # type: ignore
|
assert index.getItemHeading(nHandle, "T0001").title == "Hello World!" # type: ignore
|
||||||
assert index.getReferences(nHandle, "T0001") == {
|
assert index.getReferences(nHandle, "T0001") == {
|
||||||
"@char": [],
|
"@char": [],
|
||||||
"@custom": [],
|
"@custom": [],
|
||||||
"@entity": [],
|
"@entity": [],
|
||||||
"@focus": [],
|
"@focus": [],
|
||||||
"@location": [],
|
"@location": ["Earth"],
|
||||||
"@object": [],
|
"@object": [],
|
||||||
"@plot": [],
|
"@plot": [],
|
||||||
"@pov": ["Jane"],
|
"@pov": ["Jane"],
|
||||||
@@ -283,13 +297,29 @@ def testCoreIndex_CheckThese(mockGUI, fncPath, mockRnd):
|
|||||||
assert index.checkThese(["@tag", "John"], nHandle) == [True, True]
|
assert index.checkThese(["@tag", "John"], nHandle) == [True, True]
|
||||||
assert index.checkThese(["@pov", "John"], nHandle) == [True, False]
|
assert index.checkThese(["@pov", "John"], nHandle) == [True, False]
|
||||||
assert index.checkThese(["@pov", "Jane"], nHandle) == [True, True]
|
assert index.checkThese(["@pov", "Jane"], nHandle) == [True, True]
|
||||||
|
assert index.checkThese(["@mention", "Jane"], nHandle) == [True, True]
|
||||||
assert index.checkThese(["@ pov", "Jane"], nHandle) == [False, False]
|
assert index.checkThese(["@ pov", "Jane"], nHandle) == [False, False]
|
||||||
assert index.checkThese(["@what", "Jane"], nHandle) == [False, False]
|
assert index.checkThese(["@what", "Jane"], nHandle) == [False, False]
|
||||||
|
|
||||||
|
# Two w/Class Check
|
||||||
|
assert index.checkThese(["@pov", "Earth"], nHandle) == [True, False]
|
||||||
|
assert index.checkThese(["@focus", "Earth"], nHandle) == [True, False]
|
||||||
|
assert index.checkThese(["@char", "Earth"], nHandle) == [True, False]
|
||||||
|
assert index.checkThese(["@plot", "Earth"], nHandle) == [True, False]
|
||||||
|
assert index.checkThese(["@time", "Earth"], nHandle) == [True, False]
|
||||||
|
assert index.checkThese(["@location", "Earth"], nHandle) == [True, True]
|
||||||
|
assert index.checkThese(["@object", "Earth"], nHandle) == [True, False]
|
||||||
|
assert index.checkThese(["@entity", "Earth"], nHandle) == [True, False]
|
||||||
|
assert index.checkThese(["@custom", "Earth"], nHandle) == [True, False]
|
||||||
|
assert index.checkThese(["@mention", "Earth"], nHandle) == [True, True]
|
||||||
|
|
||||||
# Three Items
|
# Three Items
|
||||||
assert index.checkThese(["@tag", "Jane", "John"], cHandle) == [True, True, False]
|
assert index.checkThese(["@tag", "Jane", "John"], cHandle) == [True, True, False]
|
||||||
assert index.checkThese(["@who", "Jane", "John"], cHandle) == [False, False, False]
|
assert index.checkThese(["@who", "Jane", "John"], cHandle) == [False, False, False]
|
||||||
assert index.checkThese(["@pov", "Jane", "John"], nHandle) == [True, True, False]
|
assert index.checkThese(["@pov", "Jane", "John"], nHandle) == [True, True, False]
|
||||||
|
assert index.checkThese(["@pov", "Jane", "Earth"], nHandle) == [True, True, False]
|
||||||
|
assert index.checkThese(["@mention", "Jane", "Earth"], nHandle) == [True, True, True]
|
||||||
|
assert index.checkThese(["@mention", "Jane", "Stuff"], nHandle) == [True, True, False]
|
||||||
|
|
||||||
# Parse a Checked Value
|
# Parse a Checked Value
|
||||||
assert index.parseValue("Jane | Jane Smith") == ("Jane", "Jane Smith")
|
assert index.parseValue("Jane | Jane Smith") == ("Jane", "Jane Smith")
|
||||||
|
|||||||
@@ -165,12 +165,12 @@ def testGuiOutline_Main(qtbot, monkeypatch, nwGUI, projPath):
|
|||||||
|
|
||||||
# Current Order
|
# Current Order
|
||||||
order = [outlineTree._colIdx[col] for col in outlineTree._treeOrder]
|
order = [outlineTree._colIdx[col] for col in outlineTree._treeOrder]
|
||||||
assert order == [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]
|
assert order == [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17]
|
||||||
|
|
||||||
# Move 3 to 0
|
# Move 3 to 0
|
||||||
outlineTree._columnMoved(0, 3, 0)
|
outlineTree._columnMoved(0, 3, 0)
|
||||||
order = [outlineTree._colIdx[col] for col in outlineTree._treeOrder]
|
order = [outlineTree._colIdx[col] for col in outlineTree._treeOrder]
|
||||||
assert order == [3, 0, 1, 2, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]
|
assert order == [3, 0, 1, 2, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17]
|
||||||
|
|
||||||
# qtbot.stop()
|
# qtbot.stop()
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user