Fix some minor issues (#1632)
This commit is contained in:
@@ -2012,20 +2012,25 @@ class GuiDocEditor(QPlainTextEdit):
|
|||||||
cPos = cursor.position()
|
cPos = cursor.position()
|
||||||
bPos = cursor.block().position()
|
bPos = cursor.block().position()
|
||||||
bLen = cursor.block().length()
|
bLen = cursor.block().length()
|
||||||
|
apos = nwUnicode.U_APOS + nwUnicode.U_RSQUO
|
||||||
|
|
||||||
# Scan backwards
|
# Scan backward
|
||||||
sPos = cPos
|
sPos = cPos
|
||||||
for i in range(cPos - bPos):
|
for i in range(cPos - bPos):
|
||||||
sPos = cPos - i - 1
|
sPos = cPos - i - 1
|
||||||
if not self._qDocument.characterAt(sPos).isalnum():
|
cOne = self._qDocument.characterAt(sPos)
|
||||||
|
cTwo = self._qDocument.characterAt(sPos - 1)
|
||||||
|
if not (cOne.isalnum() or cOne in apos and cTwo.isalnum()):
|
||||||
sPos += 1
|
sPos += 1
|
||||||
break
|
break
|
||||||
|
|
||||||
# Scan forwards
|
# Scan forward
|
||||||
ePos = cPos
|
ePos = cPos
|
||||||
for i in range(bPos + bLen - cPos):
|
for i in range(bPos + bLen - cPos):
|
||||||
ePos = cPos + i
|
ePos = cPos + i
|
||||||
if not self._qDocument.characterAt(ePos).isalnum():
|
cOne = self._qDocument.characterAt(ePos)
|
||||||
|
cTwo = self._qDocument.characterAt(ePos + 1)
|
||||||
|
if not (cOne.isalnum() or cOne in apos and cTwo.isalnum()):
|
||||||
break
|
break
|
||||||
|
|
||||||
if ePos - sPos <= 0:
|
if ePos - sPos <= 0:
|
||||||
|
|||||||
@@ -206,18 +206,18 @@ class GuiNovelToolBar(QWidget):
|
|||||||
|
|
||||||
# Novel Selector
|
# Novel Selector
|
||||||
selFont = self.font()
|
selFont = self.font()
|
||||||
selFont.setWeight(QFont.Bold)
|
selFont.setWeight(QFont.Weight.Bold)
|
||||||
self.novelPrefix = self.tr("Outline of {0}")
|
self.novelPrefix = self.tr("Outline of {0}")
|
||||||
self.novelValue = NovelSelector(self)
|
self.novelValue = NovelSelector(self)
|
||||||
self.novelValue.setFont(selFont)
|
self.novelValue.setFont(selFont)
|
||||||
self.novelValue.setMinimumWidth(CONFIG.pxInt(150))
|
self.novelValue.setMinimumWidth(CONFIG.pxInt(150))
|
||||||
self.novelValue.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
|
self.novelValue.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding)
|
||||||
self.novelValue.novelSelectionChanged.connect(self.setCurrentRoot)
|
self.novelValue.novelSelectionChanged.connect(self.setCurrentRoot)
|
||||||
|
|
||||||
self.tbNovel = QToolButton(self)
|
self.tbNovel = QToolButton(self)
|
||||||
self.tbNovel.setToolTip(self.tr("Novel Root"))
|
self.tbNovel.setToolTip(self.tr("Novel Root"))
|
||||||
self.tbNovel.setIconSize(QSize(iPx, iPx))
|
self.tbNovel.setIconSize(QSize(iPx, iPx))
|
||||||
self.tbNovel.clicked.connect(self._openNovelSelector)
|
self.tbNovel.clicked.connect(self.novelValue.showPopup)
|
||||||
|
|
||||||
# Refresh Button
|
# Refresh Button
|
||||||
self.tbRefresh = QToolButton(self)
|
self.tbRefresh = QToolButton(self)
|
||||||
@@ -244,7 +244,7 @@ class GuiNovelToolBar(QWidget):
|
|||||||
self.tbMore.setToolTip(self.tr("More Options"))
|
self.tbMore.setToolTip(self.tr("More Options"))
|
||||||
self.tbMore.setIconSize(QSize(iPx, iPx))
|
self.tbMore.setIconSize(QSize(iPx, iPx))
|
||||||
self.tbMore.setMenu(self.mMore)
|
self.tbMore.setMenu(self.mMore)
|
||||||
self.tbMore.setPopupMode(QToolButton.InstantPopup)
|
self.tbMore.setPopupMode(QToolButton.ToolButtonPopupMode.InstantPopup)
|
||||||
|
|
||||||
# Assemble
|
# Assemble
|
||||||
self.outerBox = QHBoxLayout()
|
self.outerBox = QHBoxLayout()
|
||||||
@@ -275,7 +275,7 @@ class GuiNovelToolBar(QWidget):
|
|||||||
self.tbMore.setIcon(SHARED.theme.getIcon("menu"))
|
self.tbMore.setIcon(SHARED.theme.getIcon("menu"))
|
||||||
|
|
||||||
qPalette = self.palette()
|
qPalette = self.palette()
|
||||||
qPalette.setBrush(QPalette.Window, qPalette.base())
|
qPalette.setBrush(QPalette.ColorRole.Window, qPalette.base())
|
||||||
self.setPalette(qPalette)
|
self.setPalette(qPalette)
|
||||||
|
|
||||||
# StyleSheets
|
# StyleSheets
|
||||||
@@ -327,12 +327,6 @@ class GuiNovelToolBar(QWidget):
|
|||||||
# Private Slots
|
# Private Slots
|
||||||
##
|
##
|
||||||
|
|
||||||
@pyqtSlot()
|
|
||||||
def _openNovelSelector(self) -> None:
|
|
||||||
"""Trigger the dropdown list of the novel selector."""
|
|
||||||
self.novelValue.showPopup()
|
|
||||||
return
|
|
||||||
|
|
||||||
@pyqtSlot()
|
@pyqtSlot()
|
||||||
def _refreshNovelTree(self) -> None:
|
def _refreshNovelTree(self) -> None:
|
||||||
"""Rebuild the current tree."""
|
"""Rebuild the current tree."""
|
||||||
@@ -408,14 +402,14 @@ class GuiNovelTree(QTreeWidget):
|
|||||||
cMg = CONFIG.pxInt(6)
|
cMg = CONFIG.pxInt(6)
|
||||||
|
|
||||||
self.setIconSize(QSize(iPx, iPx))
|
self.setIconSize(QSize(iPx, iPx))
|
||||||
self.setFrameStyle(QFrame.NoFrame)
|
self.setFrameStyle(QFrame.Shape.NoFrame)
|
||||||
self.setUniformRowHeights(True)
|
self.setUniformRowHeights(True)
|
||||||
self.setAllColumnsShowFocus(True)
|
self.setAllColumnsShowFocus(True)
|
||||||
self.setHeaderHidden(True)
|
self.setHeaderHidden(True)
|
||||||
self.setIndentation(0)
|
self.setIndentation(0)
|
||||||
self.setColumnCount(4)
|
self.setColumnCount(4)
|
||||||
self.setSelectionBehavior(QAbstractItemView.SelectRows)
|
self.setSelectionBehavior(QAbstractItemView.SelectionBehavior.SelectRows)
|
||||||
self.setSelectionMode(QAbstractItemView.SingleSelection)
|
self.setSelectionMode(QAbstractItemView.SelectionMode.SingleSelection)
|
||||||
self.setExpandsOnDoubleClick(False)
|
self.setExpandsOnDoubleClick(False)
|
||||||
self.setDragEnabled(False)
|
self.setDragEnabled(False)
|
||||||
|
|
||||||
@@ -423,10 +417,10 @@ class GuiNovelTree(QTreeWidget):
|
|||||||
treeHeader = self.header()
|
treeHeader = self.header()
|
||||||
treeHeader.setStretchLastSection(False)
|
treeHeader.setStretchLastSection(False)
|
||||||
treeHeader.setMinimumSectionSize(iPx + cMg)
|
treeHeader.setMinimumSectionSize(iPx + cMg)
|
||||||
treeHeader.setSectionResizeMode(self.C_TITLE, QHeaderView.Stretch)
|
treeHeader.setSectionResizeMode(self.C_TITLE, QHeaderView.ResizeMode.Stretch)
|
||||||
treeHeader.setSectionResizeMode(self.C_WORDS, QHeaderView.ResizeToContents)
|
treeHeader.setSectionResizeMode(self.C_WORDS, QHeaderView.ResizeMode.ResizeToContents)
|
||||||
treeHeader.setSectionResizeMode(self.C_EXTRA, QHeaderView.ResizeToContents)
|
treeHeader.setSectionResizeMode(self.C_EXTRA, QHeaderView.ResizeMode.ResizeToContents)
|
||||||
treeHeader.setSectionResizeMode(self.C_MORE, QHeaderView.ResizeToContents)
|
treeHeader.setSectionResizeMode(self.C_MORE, QHeaderView.ResizeMode.ResizeToContents)
|
||||||
|
|
||||||
# Pre-Generate Tree Formatting
|
# Pre-Generate Tree Formatting
|
||||||
fH1 = self.font()
|
fH1 = self.font()
|
||||||
@@ -455,14 +449,14 @@ class GuiNovelTree(QTreeWidget):
|
|||||||
"""Set or update tree widget settings."""
|
"""Set or update tree widget settings."""
|
||||||
# Scroll bars
|
# Scroll bars
|
||||||
if CONFIG.hideVScroll:
|
if CONFIG.hideVScroll:
|
||||||
self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
|
self.setVerticalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff)
|
||||||
else:
|
else:
|
||||||
self.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded)
|
self.setVerticalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAsNeeded)
|
||||||
|
|
||||||
if CONFIG.hideHScroll:
|
if CONFIG.hideHScroll:
|
||||||
self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
|
self.setHorizontalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff)
|
||||||
else:
|
else:
|
||||||
self.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded)
|
self.setHorizontalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAsNeeded)
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -522,21 +516,16 @@ class GuiNovelTree(QTreeWidget):
|
|||||||
|
|
||||||
def refreshHandle(self, tHandle: str) -> None:
|
def refreshHandle(self, tHandle: str) -> None:
|
||||||
"""Refresh the data for a given handle."""
|
"""Refresh the data for a given handle."""
|
||||||
idxData = SHARED.project.index.getItemData(tHandle)
|
if idxData := SHARED.project.index.getItemData(tHandle):
|
||||||
if idxData is None:
|
logger.debug("Refreshing meta data for item '%s'", tHandle)
|
||||||
return
|
for sTitle, tHeading in idxData.items():
|
||||||
|
sKey = f"{tHandle}:{sTitle}"
|
||||||
logger.debug("Refreshing meta data for item '%s'", tHandle)
|
if trItem := self._treeMap.get(sKey, None):
|
||||||
for sTitle, tHeading in idxData.items():
|
self._updateTreeItemValues(trItem, tHeading, tHandle, sTitle)
|
||||||
sKey = f"{tHandle}:{sTitle}"
|
else:
|
||||||
trItem = self._treeMap.get(sKey, None)
|
logger.debug("Heading '%s' not in novel tree", sKey)
|
||||||
if trItem is None:
|
self.refreshTree()
|
||||||
logger.debug("Heading '%s' not in novel tree", sKey)
|
return
|
||||||
self.refreshTree()
|
|
||||||
return
|
|
||||||
|
|
||||||
self._updateTreeItemValues(trItem, tHeading, tHandle, sTitle)
|
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|
||||||
def getSelectedHandle(self) -> tuple[str | None, str | None]:
|
def getSelectedHandle(self) -> tuple[str | None, str | None]:
|
||||||
@@ -567,27 +556,25 @@ class GuiNovelTree(QTreeWidget):
|
|||||||
self._lastColSize = minmax(colSize, 15, 75)/100.0
|
self._lastColSize = minmax(colSize, 15, 75)/100.0
|
||||||
return
|
return
|
||||||
|
|
||||||
def setActiveHandle(self, tHandle: str | None) -> None:
|
def setActiveHandle(self, tHandle: str | None, doScroll: bool = False) -> None:
|
||||||
"""Highlight the rows associated with a given handle."""
|
"""Highlight the rows associated with a given handle."""
|
||||||
tStart = time()
|
didScroll = False
|
||||||
|
|
||||||
self._actHandle = tHandle
|
self._actHandle = tHandle
|
||||||
for i in range(self.topLevelItemCount()):
|
for i in range(self.topLevelItemCount()):
|
||||||
tItem = self.topLevelItem(i)
|
if tItem := self.topLevelItem(i):
|
||||||
if tItem is not None:
|
|
||||||
if tItem.data(self.C_DATA, self.D_HANDLE) == tHandle:
|
if tItem.data(self.C_DATA, self.D_HANDLE) == tHandle:
|
||||||
tItem.setBackground(self.C_TITLE, self.palette().alternateBase())
|
tItem.setBackground(self.C_TITLE, self.palette().alternateBase())
|
||||||
tItem.setBackground(self.C_WORDS, self.palette().alternateBase())
|
tItem.setBackground(self.C_WORDS, self.palette().alternateBase())
|
||||||
tItem.setBackground(self.C_EXTRA, self.palette().alternateBase())
|
tItem.setBackground(self.C_EXTRA, self.palette().alternateBase())
|
||||||
tItem.setBackground(self.C_MORE, self.palette().alternateBase())
|
tItem.setBackground(self.C_MORE, self.palette().alternateBase())
|
||||||
|
if doScroll and not didScroll:
|
||||||
|
self.scrollToItem(tItem, QAbstractItemView.ScrollHint.PositionAtCenter)
|
||||||
|
didScroll = True
|
||||||
else:
|
else:
|
||||||
tItem.setBackground(self.C_TITLE, self.palette().base())
|
tItem.setBackground(self.C_TITLE, self.palette().base())
|
||||||
tItem.setBackground(self.C_WORDS, self.palette().base())
|
tItem.setBackground(self.C_WORDS, self.palette().base())
|
||||||
tItem.setBackground(self.C_EXTRA, self.palette().base())
|
tItem.setBackground(self.C_EXTRA, self.palette().base())
|
||||||
tItem.setBackground(self.C_MORE, self.palette().base())
|
tItem.setBackground(self.C_MORE, self.palette().base())
|
||||||
|
|
||||||
logger.debug("Highlighted Novel Tree in %.3f ms", (time() - tStart)*1000)
|
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|
||||||
##
|
##
|
||||||
@@ -601,12 +588,12 @@ class GuiNovelTree(QTreeWidget):
|
|||||||
"""
|
"""
|
||||||
super().mousePressEvent(event)
|
super().mousePressEvent(event)
|
||||||
|
|
||||||
if event.button() == Qt.LeftButton:
|
if event.button() == Qt.MouseButton.LeftButton:
|
||||||
selItem = self.indexAt(event.pos())
|
selItem = self.indexAt(event.pos())
|
||||||
if not selItem.isValid():
|
if not selItem.isValid():
|
||||||
self.clearSelection()
|
self.clearSelection()
|
||||||
|
|
||||||
elif event.button() == Qt.MiddleButton:
|
elif event.button() == Qt.MouseButton.MiddleButton:
|
||||||
selItem = self.itemAt(event.pos())
|
selItem = self.itemAt(event.pos())
|
||||||
if not isinstance(selItem, QTreeWidgetItem):
|
if not isinstance(selItem, QTreeWidgetItem):
|
||||||
return
|
return
|
||||||
@@ -637,7 +624,10 @@ class GuiNovelTree(QTreeWidget):
|
|||||||
trItem = self.topLevelItem(i)
|
trItem = self.topLevelItem(i)
|
||||||
if isinstance(trItem, QTreeWidgetItem):
|
if isinstance(trItem, QTreeWidgetItem):
|
||||||
lastText = trItem.data(self.C_DATA, self.D_EXTRA)
|
lastText = trItem.data(self.C_DATA, self.D_EXTRA)
|
||||||
trItem.setText(self.C_EXTRA, fMetric.elidedText(lastText, Qt.ElideRight, eliW))
|
trItem.setText(
|
||||||
|
self.C_EXTRA,
|
||||||
|
fMetric.elidedText(lastText, Qt.TextElideMode.ElideRight, eliW)
|
||||||
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
##
|
##
|
||||||
@@ -693,7 +683,7 @@ class GuiNovelTree(QTreeWidget):
|
|||||||
newItem.setData(self.C_DATA, self.D_HANDLE, tHandle)
|
newItem.setData(self.C_DATA, self.D_HANDLE, tHandle)
|
||||||
newItem.setData(self.C_DATA, self.D_TITLE, sTitle)
|
newItem.setData(self.C_DATA, self.D_TITLE, sTitle)
|
||||||
newItem.setData(self.C_DATA, self.D_KEY, tKey)
|
newItem.setData(self.C_DATA, self.D_KEY, tKey)
|
||||||
newItem.setTextAlignment(self.C_WORDS, Qt.AlignRight)
|
newItem.setTextAlignment(self.C_WORDS, Qt.AlignmentFlag.AlignRight)
|
||||||
|
|
||||||
self._updateTreeItemValues(newItem, novIdx, tHandle, sTitle)
|
self._updateTreeItemValues(newItem, novIdx, tHandle, sTitle)
|
||||||
self._treeMap[tKey] = newItem
|
self._treeMap[tKey] = newItem
|
||||||
@@ -712,16 +702,16 @@ class GuiNovelTree(QTreeWidget):
|
|||||||
iLevel = nwHeaders.H_LEVEL.get(idxItem.level, 0)
|
iLevel = nwHeaders.H_LEVEL.get(idxItem.level, 0)
|
||||||
hDec = SHARED.theme.getHeaderDecoration(iLevel)
|
hDec = SHARED.theme.getHeaderDecoration(iLevel)
|
||||||
|
|
||||||
trItem.setData(self.C_TITLE, Qt.DecorationRole, hDec)
|
trItem.setData(self.C_TITLE, Qt.ItemDataRole.DecorationRole, hDec)
|
||||||
trItem.setText(self.C_TITLE, idxItem.title)
|
trItem.setText(self.C_TITLE, idxItem.title)
|
||||||
trItem.setFont(self.C_TITLE, self._hFonts[iLevel])
|
trItem.setFont(self.C_TITLE, self._hFonts[iLevel])
|
||||||
trItem.setText(self.C_WORDS, f"{idxItem.wordCount:n}")
|
trItem.setText(self.C_WORDS, f"{idxItem.wordCount:n}")
|
||||||
trItem.setData(self.C_MORE, Qt.DecorationRole, self._pMore)
|
trItem.setData(self.C_MORE, Qt.ItemDataRole.DecorationRole, self._pMore)
|
||||||
|
|
||||||
# Custom column
|
# Custom column
|
||||||
mW = int(self._lastColSize * self.viewport().width())
|
mW = int(self._lastColSize * self.viewport().width())
|
||||||
lastText, toolTip = self._getLastColumnText(tHandle, sTitle)
|
lastText, toolTip = self._getLastColumnText(tHandle, sTitle)
|
||||||
elideText = self.fontMetrics().elidedText(lastText, Qt.ElideRight, mW)
|
elideText = self.fontMetrics().elidedText(lastText, Qt.TextElideMode.ElideRight, mW)
|
||||||
trItem.setText(self.C_EXTRA, elideText)
|
trItem.setText(self.C_EXTRA, elideText)
|
||||||
trItem.setData(self.C_DATA, self.D_EXTRA, lastText)
|
trItem.setData(self.C_DATA, self.D_EXTRA, lastText)
|
||||||
trItem.setToolTip(self.C_EXTRA, toolTip)
|
trItem.setToolTip(self.C_EXTRA, toolTip)
|
||||||
|
|||||||
@@ -606,7 +606,7 @@ class GuiMain(QMainWindow):
|
|||||||
if self.docEditor.loadText(tHandle, tLine):
|
if self.docEditor.loadText(tHandle, tLine):
|
||||||
SHARED.project.data.setLastHandle(tHandle, "editor")
|
SHARED.project.data.setLastHandle(tHandle, "editor")
|
||||||
self.projView.setSelectedHandle(tHandle, doScroll=doScroll)
|
self.projView.setSelectedHandle(tHandle, doScroll=doScroll)
|
||||||
self.novelView.setActiveHandle(tHandle)
|
self.novelView.setActiveHandle(tHandle, doScroll=doScroll)
|
||||||
if changeFocus:
|
if changeFocus:
|
||||||
self.docEditor.setFocus()
|
self.docEditor.setFocus()
|
||||||
else:
|
else:
|
||||||
|
|||||||
@@ -27,12 +27,12 @@ from pathlib import Path
|
|||||||
from tools import C, buildTestProject
|
from tools import C, buildTestProject
|
||||||
|
|
||||||
from PyQt5.QtGui import QFocusEvent
|
from PyQt5.QtGui import QFocusEvent
|
||||||
from PyQt5.QtCore import Qt, QEvent
|
from PyQt5.QtCore import QPoint, Qt, QEvent
|
||||||
from PyQt5.QtWidgets import QInputDialog, QToolTip
|
from PyQt5.QtWidgets import QInputDialog, QToolTip
|
||||||
|
|
||||||
from novelwriter import CONFIG, SHARED
|
from novelwriter import CONFIG, SHARED
|
||||||
from novelwriter.enum import nwWidget, nwItemType
|
from novelwriter.enum import nwWidget, nwItemType
|
||||||
from novelwriter.gui.noveltree import NovelTreeColumn
|
from novelwriter.gui.noveltree import GuiNovelTree, NovelTreeColumn
|
||||||
from novelwriter.dialogs.editlabel import GuiEditLabel
|
from novelwriter.dialogs.editlabel import GuiEditLabel
|
||||||
|
|
||||||
|
|
||||||
@@ -192,12 +192,32 @@ def testGuiNovelTree_TreeItems(qtbot, monkeypatch, nwGUI, projPath, mockRnd):
|
|||||||
mIndex = novelTree.model().index(2, novelTree.C_MORE)
|
mIndex = novelTree.model().index(2, novelTree.C_MORE)
|
||||||
with monkeypatch.context() as mp:
|
with monkeypatch.context() as mp:
|
||||||
mp.setattr(QToolTip, "showText", showText)
|
mp.setattr(QToolTip, "showText", showText)
|
||||||
|
|
||||||
|
ttText = ""
|
||||||
novelTree._treeItemClicked(mIndex)
|
novelTree._treeItemClicked(mIndex)
|
||||||
assert ttText == (
|
assert ttText == (
|
||||||
"<p><b>Point of View</b>: Jane<br><b>Focus</b>: Jane</p>"
|
"<p><b>Point of View</b>: Jane<br><b>Focus</b>: Jane</p>"
|
||||||
"<p><b>Synopsis</b>: This is a scene.</p>"
|
"<p><b>Synopsis</b>: This is a scene.</p>"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
ttText = ""
|
||||||
|
novelTree._popMetaBox(QPoint(1, 1), C.hInvalid, "T0001")
|
||||||
|
assert ttText == ""
|
||||||
|
|
||||||
|
# Set Default Root
|
||||||
|
# ================
|
||||||
|
SHARED.project.data.setLastHandle(C.hInvalid, "novelTree")
|
||||||
|
novelView.openProjectTasks()
|
||||||
|
assert novelBar.novelValue.handle == C.hNovelRoot
|
||||||
|
|
||||||
|
# Tree Focus
|
||||||
|
# ==========
|
||||||
|
with monkeypatch.context() as mp:
|
||||||
|
mp.setattr(GuiNovelTree, "hasFocus", lambda *a: False)
|
||||||
|
assert novelView.treeHasFocus() is False
|
||||||
|
mp.setattr(GuiNovelTree, "hasFocus", lambda *a: True)
|
||||||
|
assert novelView.treeHasFocus() is True
|
||||||
|
|
||||||
# Other Checks
|
# Other Checks
|
||||||
# ============
|
# ============
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user