Stop showing index rebuild dialog on upgrades (#2537)
This commit is contained in:
@@ -560,6 +560,12 @@ def jsonEncode(data: dict | list | tuple, n: int = 0, nmax: int = 0) -> str:
|
||||
return "".join(buffer)
|
||||
|
||||
|
||||
def jsonCombine(data: dict[str, str]) -> str:
|
||||
"""Combine multiple already packed JSON strings."""
|
||||
payload = ",\n".join(f' "{k}": {v}' for k, v in data.items())
|
||||
return f"{{\n{payload}\n}}\n"
|
||||
|
||||
|
||||
##
|
||||
# XML Helpers
|
||||
##
|
||||
|
||||
+24
-11
@@ -33,8 +33,10 @@ from pathlib import Path
|
||||
from time import time
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from novelwriter import SHARED
|
||||
from novelwriter.common import isHandle, isItemClass, isTitleTag, jsonEncode
|
||||
from novelwriter import SHARED, __hexversion__
|
||||
from novelwriter.common import (
|
||||
formatTimeStamp, isHandle, isItemClass, isTitleTag, jsonCombine, jsonEncode
|
||||
)
|
||||
from novelwriter.constants import nwFiles, nwKeyWords, nwStyles
|
||||
from novelwriter.core.indexdata import NOTE_TYPES, TT_NONE, IndexHeading, IndexNode, T_NoteTypes
|
||||
from novelwriter.core.novelmodel import NovelModel
|
||||
@@ -82,6 +84,11 @@ class Index:
|
||||
a rebuild of the index data.
|
||||
"""
|
||||
|
||||
__slots__ = (
|
||||
"_indexBroken", "_indexChange", "_indexUpgrade", "_itemIndex", "_novelExtra",
|
||||
"_novelModels", "_project", "_rootChange", "_tagsIndex",
|
||||
)
|
||||
|
||||
def __init__(self, project: NWProject) -> None:
|
||||
|
||||
self._project = project
|
||||
@@ -90,6 +97,7 @@ class Index:
|
||||
self._tagsIndex = TagsIndex()
|
||||
self._itemIndex = ItemIndex(project, self._tagsIndex)
|
||||
self._indexBroken = False
|
||||
self._indexUpgrade = False
|
||||
|
||||
# Models
|
||||
self._novelModels: dict[str, NovelModel] = {}
|
||||
@@ -110,6 +118,10 @@ class Index:
|
||||
def indexBroken(self) -> bool:
|
||||
return self._indexBroken
|
||||
|
||||
@property
|
||||
def indexUpgrade(self) -> bool:
|
||||
return self._indexUpgrade
|
||||
|
||||
##
|
||||
# Getters
|
||||
##
|
||||
@@ -241,6 +253,8 @@ class Index:
|
||||
return False
|
||||
|
||||
try:
|
||||
meta = data.get("novelWriter.meta", {})
|
||||
self._indexUpgrade = meta.get("version") != __hexversion__
|
||||
self._tagsIndex.unpackData(data["novelWriter.tagsIndex"])
|
||||
self._itemIndex.unpackData(data["novelWriter.itemIndex"])
|
||||
except Exception:
|
||||
@@ -273,23 +287,22 @@ class Index:
|
||||
return False
|
||||
|
||||
logger.debug("Saving index file")
|
||||
tStart = time()
|
||||
start = time()
|
||||
|
||||
try:
|
||||
tagsIndex = jsonEncode(self._tagsIndex.packData(), n=1, nmax=2)
|
||||
itemIndex = jsonEncode(self._itemIndex.packData(), n=1, nmax=4)
|
||||
meta = {"version": __hexversion__, "timestamp": formatTimeStamp(start)}
|
||||
with open(indexFile, mode="w+", encoding="utf-8") as outFile:
|
||||
outFile.write("{\n")
|
||||
outFile.write(f' "novelWriter.tagsIndex": {tagsIndex},\n')
|
||||
outFile.write(f' "novelWriter.itemIndex": {itemIndex}\n')
|
||||
outFile.write("}\n")
|
||||
|
||||
outFile.write(jsonCombine({
|
||||
"novelWriter.meta": jsonEncode(meta, n=1),
|
||||
"novelWriter.tagsIndex": jsonEncode(self._tagsIndex.packData(), n=1, nmax=2),
|
||||
"novelWriter.itemIndex": jsonEncode(self._itemIndex.packData(), n=1, nmax=4),
|
||||
}))
|
||||
except Exception:
|
||||
logger.error("Failed to save index file")
|
||||
logException()
|
||||
return False
|
||||
|
||||
logger.debug("Index saved in %.3f ms", (time() - tStart)*1000)
|
||||
logger.debug("Index saved in %.3f ms", (time() - start)*1000)
|
||||
|
||||
return True
|
||||
|
||||
|
||||
@@ -497,7 +497,8 @@ class GuiMain(QMainWindow):
|
||||
|
||||
# Check if we need to rebuild the index
|
||||
if SHARED.project.index.indexBroken:
|
||||
SHARED.info(self.tr("The project index is outdated or broken. Rebuilding index."))
|
||||
if not SHARED.project.index.indexUpgrade:
|
||||
SHARED.warn(self.tr("The project index is broken. Rebuilding index."))
|
||||
self.rebuildIndex()
|
||||
|
||||
# Make sure the changed status is set to false on things opened
|
||||
@@ -729,7 +730,7 @@ class GuiMain(QMainWindow):
|
||||
|
||||
return
|
||||
|
||||
def rebuildIndex(self, beQuiet: bool = False) -> None:
|
||||
def rebuildIndex(self) -> None:
|
||||
"""Rebuild the entire index."""
|
||||
if SHARED.hasProject:
|
||||
logger.info("Rebuilding index ...")
|
||||
@@ -746,8 +747,7 @@ class GuiMain(QMainWindow):
|
||||
self._updateStatusWordCount()
|
||||
QApplication.restoreOverrideCursor()
|
||||
|
||||
if not beQuiet:
|
||||
SHARED.info(self.tr("The project index has been successfully rebuilt."))
|
||||
SHARED.info(self.tr("The project index has been successfully rebuilt."))
|
||||
|
||||
##
|
||||
# Main Dialogs
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
{
|
||||
"novelWriter.meta": {
|
||||
"version": "0x020800a2",
|
||||
"timestamp": "2025-10-05 17:06:58"
|
||||
},
|
||||
"novelWriter.tagsIndex": {
|
||||
"bod": {"name": "Bod", "display": "Nobody Owens", "handle": "4c4f28287af27", "heading": "T0001", "class": "CHARACTER"},
|
||||
"main": {"name": "Main", "display": "Main", "handle": "2426c6f0ca922", "heading": "T0001", "class": "PLOT"},
|
||||
|
||||
@@ -36,10 +36,10 @@ from novelwriter.common import (
|
||||
describeFont, elide, encodeMimeHandles, firstFloat, fontMatcher,
|
||||
formatFileFilter, formatInt, formatTime, formatTimeStamp, formatVersion,
|
||||
fuzzyTime, getFileSize, hexToInt, isHandle, isItemClass, isItemLayout,
|
||||
isItemType, isListInstance, isTitleTag, jsonEncode, makeFileNameSafe,
|
||||
minmax, numberToRoman, openExternalPath, processDialogSymbols,
|
||||
readTextFile, simplified, transferCase, uniqueCompact, utf16CharMap,
|
||||
xmlElement, xmlIndent, xmlSubElem, yesNo
|
||||
isItemType, isListInstance, isTitleTag, jsonCombine, jsonEncode,
|
||||
makeFileNameSafe, minmax, numberToRoman, openExternalPath,
|
||||
processDialogSymbols, readTextFile, simplified, transferCase,
|
||||
uniqueCompact, utf16CharMap, xmlElement, xmlIndent, xmlSubElem, yesNo
|
||||
)
|
||||
from novelwriter.enum import nwItemClass
|
||||
|
||||
@@ -651,6 +651,17 @@ def testBaseCommon_jsonEncode():
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.base
|
||||
def testBaseCommon_jsonCombine():
|
||||
"""Test the jsonCombine function."""
|
||||
assert jsonCombine({"a": "[1, 2]", "b": "[3, 4]"}) == (
|
||||
'{\n'
|
||||
' "a": [1, 2],\n'
|
||||
' "b": [3, 4]\n'
|
||||
'}\n'
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.base
|
||||
def testBaseCommon_xmlIndent():
|
||||
"""Test the xmlIndent function."""
|
||||
|
||||
@@ -157,7 +157,7 @@ def testCoreIndex_LoadSave(qtbot, monkeypatch, prjLipsum, nwGUI, tstPaths):
|
||||
|
||||
# Check File
|
||||
copyfile(projFile, testFile)
|
||||
assert cmpFiles(testFile, compFile)
|
||||
assert cmpFiles(testFile, compFile, ignoreLines=[3, 4])
|
||||
|
||||
# Write an empty index file and load it
|
||||
projFile.write_text("{}", encoding="utf-8")
|
||||
|
||||
@@ -32,7 +32,8 @@ from PyQt6.QtCore import Qt
|
||||
from PyQt6.QtGui import QPalette
|
||||
from PyQt6.QtWidgets import QInputDialog, QMessageBox
|
||||
|
||||
from novelwriter import CONFIG, SHARED
|
||||
from novelwriter import CONFIG, SHARED, __hexversion__
|
||||
from novelwriter.common import jsonEncode
|
||||
from novelwriter.config import DEF_GUI_DARK, DEF_GUI_LIGHT
|
||||
from novelwriter.constants import nwFiles
|
||||
from novelwriter.dialogs.editlabel import GuiEditLabel
|
||||
@@ -713,7 +714,7 @@ def testGuiMain_Features(qtbot, monkeypatch, nwGUI, projPath, mockRnd):
|
||||
cHandle = SHARED.project.newFile("Jane", C.hCharRoot)
|
||||
newDoc = SHARED.project.storage.getDocument(cHandle)
|
||||
newDoc.writeDocument("# Jane\n\n@tag: Jane\n\n")
|
||||
nwGUI.rebuildIndex(beQuiet=True)
|
||||
nwGUI.rebuildIndex()
|
||||
|
||||
assert SHARED.focusMode is False
|
||||
|
||||
@@ -825,11 +826,11 @@ def testGuiMain_OpenClose(qtbot, monkeypatch, nwGUI, projPath, fncPath, mockRnd)
|
||||
nwGUI.viewDocument(C.hTitlePage)
|
||||
|
||||
# Handle broken index on project open
|
||||
idxData = jsonEncode({"novelWriter.meta": {"version": __hexversion__}})
|
||||
nwGUI.closeProject()
|
||||
idxPath: Path = projPath / "meta" / nwFiles.INDEX_FILE
|
||||
assert idxPath.read_text(encoding="utf-8") != "{}"
|
||||
idxPath.write_text("{}", encoding="utf-8")
|
||||
assert idxPath.read_text(encoding="utf-8") == "{}"
|
||||
idxPath.write_text(idxData, encoding="utf-8")
|
||||
|
||||
nwGUI.openProject(projPath)
|
||||
nwGUI.saveProject()
|
||||
|
||||
@@ -36,7 +36,7 @@ def testGuiStatusBar_Main(qtbot, monkeypatch, nwGUI, projPath, mockRnd):
|
||||
cHandle = SHARED.project.newFile("A Note", C.hCharRoot)
|
||||
newDoc = SHARED.project.storage.getDocument(cHandle)
|
||||
newDoc.writeDocument("# A Note\n\n")
|
||||
nwGUI.rebuildIndex(beQuiet=True)
|
||||
nwGUI.rebuildIndex()
|
||||
|
||||
status = nwGUI.mainStatus
|
||||
|
||||
|
||||
+1
-1
@@ -66,7 +66,7 @@ class C:
|
||||
def cmpFiles(
|
||||
fileOne: str | Path,
|
||||
fileTwo: str | Path,
|
||||
ignoreLines: list | None = None,
|
||||
ignoreLines: list[int] | None = None,
|
||||
ignoreStart: tuple | None = None
|
||||
) -> bool:
|
||||
"""Compare two files, with optional line ignore."""
|
||||
|
||||
Reference in New Issue
Block a user