mirror of
https://github.com/LorenEteval/Furious.git
synced 2026-09-22 23:08:08 +03:00
708 lines
22 KiB
Python
708 lines
22 KiB
Python
# Copyright (C) 2024-present Loren Eteval & contributors <loren.eteval@proton.me>
|
|
#
|
|
# This file is part of Furious.
|
|
#
|
|
# This program is free software: you can redistribute it and/or modify
|
|
# it under the terms of the GNU General Public License as published by
|
|
# the Free Software Foundation, either version 3 of the License, or
|
|
# (at your option) any later version.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
|
|
"""Provide widgets for user subs Qt table view."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from Furious.Frozenlib import *
|
|
from Furious.Library import *
|
|
from Furious.Qt import *
|
|
from Furious.Qt import gettext as _
|
|
|
|
from PySide6 import QtCore
|
|
from PySide6.QtGui import *
|
|
from PySide6.QtWidgets import *
|
|
|
|
from typing import Union, Callable
|
|
|
|
import logging
|
|
import functools
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
__all__ = ['UserSubsQTableView']
|
|
|
|
# Migrate legacy settings
|
|
registerAppSettings('SubscriptionWidgetSectionSizeTable')
|
|
registerAppSettings('UserSubsHeaderViewState')
|
|
|
|
|
|
class UserSubsQTableViewHorizontalHeader(AppQHeaderView):
|
|
"""Provide the user subs Qt table view horizontal table header."""
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
"""Initialize the UserSubsQTableViewHorizontalHeader."""
|
|
super().__init__(QtCore.Qt.Orientation.Horizontal, *args, **kwargs)
|
|
|
|
|
|
class UserSubsQTableViewVerticalHeader(AppQHeaderView):
|
|
"""Provide the user subs Qt table view vertical table header."""
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
"""Initialize the UserSubsQTableViewVerticalHeader."""
|
|
super().__init__(QtCore.Qt.Orientation.Vertical, *args, **kwargs)
|
|
|
|
|
|
class UserSubsQTableViewHeaders:
|
|
"""Describe and render user subs Qt table view table columns."""
|
|
|
|
def __init__(self, name: str, func: Callable[[dict], str] = None):
|
|
"""Initialize the UserSubsQTableViewHeaders."""
|
|
self.name = name
|
|
self.func = func
|
|
|
|
def __call__(self, item: dict) -> str:
|
|
"""Invoke the user subs Qt table view headers as a callable."""
|
|
if callable(self.func):
|
|
return self.func(item)
|
|
else:
|
|
return ''
|
|
|
|
def __eq__(self, other):
|
|
"""Compare the user subs Qt table view headers with another value."""
|
|
return str(self) == str(other)
|
|
|
|
def __str__(self):
|
|
"""Return the display text for the user subs Qt table view headers."""
|
|
return self.name
|
|
|
|
|
|
class UserSubsAppQComboBox(AppQComboBox):
|
|
"""Represent user subs app q combo box."""
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
"""Initialize the UserSubsAppQComboBox."""
|
|
super().__init__(*args, **kwargs)
|
|
|
|
def retranslate(self):
|
|
# Do not emit 'currentTextChanged' when retranslate
|
|
"""Refresh translated text for the user subs app q combo box."""
|
|
with Mixins.QBlockSignalContext(self):
|
|
super().retranslate()
|
|
|
|
|
|
class UserSubsTableModel(QtCore.QAbstractTableModel):
|
|
"""Expose user subs table data through a Qt item model."""
|
|
|
|
def __init__(
|
|
self,
|
|
headers: list[UserSubsQTableViewHeaders],
|
|
itemKey: list[str],
|
|
parent=None,
|
|
):
|
|
"""Initialize the UserSubsTableModel."""
|
|
super().__init__(parent)
|
|
|
|
self.headers = headers
|
|
self.itemKey = itemKey
|
|
|
|
def rowCount(self, parent=QtCore.QModelIndex()) -> int:
|
|
"""Return the number of rows exposed by the model."""
|
|
if parent.isValid():
|
|
return 0
|
|
|
|
return len(Storage.UserSubs())
|
|
|
|
def columnCount(self, parent=QtCore.QModelIndex()) -> int:
|
|
"""Return the number of columns exposed by the model."""
|
|
if parent.isValid():
|
|
return 0
|
|
|
|
return len(self.headers)
|
|
|
|
def flags(self, index):
|
|
"""Return the Qt item flags for a model index."""
|
|
if not index.isValid():
|
|
return QtCore.Qt.ItemFlag.NoItemFlags
|
|
|
|
flags = QtCore.Qt.ItemFlag.ItemIsEnabled | QtCore.Qt.ItemFlag.ItemIsSelectable
|
|
|
|
if self.itemKey[index.column()] not in ['autoupdate', 'proxy']:
|
|
flags |= QtCore.Qt.ItemFlag.ItemIsEditable
|
|
|
|
return flags
|
|
|
|
def data(self, index, role=QtCore.Qt.ItemDataRole.DisplayRole):
|
|
"""Return the data managed by the user subs table model."""
|
|
if not index.isValid():
|
|
return None
|
|
|
|
row = index.row()
|
|
column = index.column()
|
|
|
|
if row < 0 or row >= len(Storage.UserSubs()):
|
|
return None
|
|
|
|
if column < 0 or column >= len(self.headers):
|
|
return None
|
|
|
|
subsob = self.subsObjectByRow(row)
|
|
text = self.headers[column](subsob)
|
|
|
|
if role == QtCore.Qt.ItemDataRole.DisplayRole:
|
|
if self.itemKey[column] in ['autoupdate', 'proxy']:
|
|
return _(text)
|
|
|
|
return text
|
|
|
|
if role == QtCore.Qt.ItemDataRole.EditRole:
|
|
return text
|
|
|
|
if role == QtCore.Qt.ItemDataRole.ToolTipRole:
|
|
return text
|
|
|
|
if role == QtCore.Qt.ItemDataRole.FontRole:
|
|
return QFont(AppFontName())
|
|
|
|
return None
|
|
|
|
def setData(self, index, value, role=QtCore.Qt.ItemDataRole.EditRole) -> bool:
|
|
"""Update model data for the requested role."""
|
|
if role != QtCore.Qt.ItemDataRole.EditRole or not index.isValid():
|
|
return False
|
|
|
|
row = index.row()
|
|
column = index.column()
|
|
|
|
if row < 0 or row >= len(Storage.UserSubs()):
|
|
return False
|
|
|
|
mapped = self.itemKey[column]
|
|
|
|
if mapped in ['autoupdate', 'proxy']:
|
|
return False
|
|
|
|
self.subsObjectByRow(row)[mapped] = str(value)
|
|
self.dataChanged.emit(index, index, [])
|
|
|
|
return True
|
|
|
|
def headerData(
|
|
self,
|
|
section: int,
|
|
orientation: QtCore.Qt.Orientation,
|
|
role=QtCore.Qt.ItemDataRole.DisplayRole,
|
|
):
|
|
"""Return display data for a table header section."""
|
|
if role != QtCore.Qt.ItemDataRole.DisplayRole:
|
|
return None
|
|
|
|
if orientation == QtCore.Qt.Orientation.Horizontal:
|
|
if 0 <= section < len(self.headers):
|
|
return _(str(self.headers[section]))
|
|
|
|
return None
|
|
|
|
return section + 1
|
|
|
|
@staticmethod
|
|
def uniqueByRow(row: int) -> str:
|
|
"""Return the unique by row value used by the user subs table model."""
|
|
return list(Storage.UserSubs().keys())[row]
|
|
|
|
@classmethod
|
|
def subsObjectByRow(cls, row: int) -> dict:
|
|
"""Return the subs object by row value used by the user subs table model."""
|
|
return Storage.UserSubs()[cls.uniqueByRow(row)]
|
|
|
|
def emitRowChanged(self, row: int, column: Union[int, None] = None):
|
|
"""Handle emit row changed for the user subs table model."""
|
|
if row < 0 or row >= self.rowCount():
|
|
return
|
|
|
|
if column is None:
|
|
left = self.index(row, 0)
|
|
right = self.index(row, self.columnCount() - 1)
|
|
else:
|
|
left = self.index(row, column)
|
|
right = left
|
|
|
|
self.dataChanged.emit(left, right, [])
|
|
|
|
def emitAllChanged(self):
|
|
"""Handle emit all changed for the user subs table model."""
|
|
if self.rowCount() == 0 or self.columnCount() == 0:
|
|
return
|
|
|
|
self.dataChanged.emit(
|
|
self.index(0, 0),
|
|
self.index(self.rowCount() - 1, self.columnCount() - 1),
|
|
[],
|
|
)
|
|
|
|
|
|
# Headers VALUE
|
|
_TRANSLATABLE_HEADERS = [
|
|
_('Never'),
|
|
_('Every 5 mins'),
|
|
_('Every 10 mins'),
|
|
_('Every 15 mins'),
|
|
_('Every 30 mins'),
|
|
_('Every 45 mins'),
|
|
_('Every 1 hour'),
|
|
_('Every 2 hours'),
|
|
_('Every 3 hours'),
|
|
_('Every 6 hours'),
|
|
_('Every 8 hours'),
|
|
_('Every 10 hours'),
|
|
_('Every 12 hours'),
|
|
_('Every 24 hours'),
|
|
_('Use current proxy'),
|
|
_('Force proxy'),
|
|
_('No proxy'),
|
|
_('Remark'),
|
|
_('Auto Update'),
|
|
_('Auto Update Use Proxy'),
|
|
]
|
|
|
|
|
|
class UserSubsQTableView(Mixins.QTranslatable, AppQTableView):
|
|
"""Represent user subs Qt table view."""
|
|
|
|
RowHeight = 42
|
|
|
|
AutoUpdateOptions = {
|
|
'': None,
|
|
'Never': None,
|
|
'Every 5 mins': 5 * 60 * 1000,
|
|
'Every 10 mins': 10 * 60 * 1000,
|
|
'Every 15 mins': 15 * 60 * 1000,
|
|
'Every 30 mins': 30 * 60 * 1000,
|
|
'Every 45 mins': 45 * 60 * 1000,
|
|
'Every 1 hour': 1 * 60 * 60 * 1000,
|
|
'Every 2 hours': 2 * 60 * 60 * 1000,
|
|
'Every 3 hours': 3 * 60 * 60 * 1000,
|
|
'Every 6 hours': 6 * 60 * 60 * 1000,
|
|
'Every 8 hours': 8 * 60 * 60 * 1000,
|
|
'Every 10 hours': 10 * 60 * 60 * 1000,
|
|
'Every 12 hours': 12 * 60 * 60 * 1000,
|
|
'Every 24 hours': 24 * 60 * 60 * 1000,
|
|
}
|
|
|
|
ProxyOptions = {
|
|
'': lambda: None,
|
|
'Use current proxy': lambda: Storage.Extras.UserHttpProxy(),
|
|
'Force proxy': lambda: '127.0.0.1:10809',
|
|
'No proxy': lambda: None,
|
|
}
|
|
|
|
Headers = [
|
|
UserSubsQTableViewHeaders('Remark', lambda item: item.get('remark', '')),
|
|
UserSubsQTableViewHeaders('URL', lambda item: item.get('webURL', '')),
|
|
UserSubsQTableViewHeaders(
|
|
'Auto Update', lambda item: item.get('autoupdate', '')
|
|
),
|
|
UserSubsQTableViewHeaders(
|
|
'Auto Update Use Proxy', lambda item: item.get('proxy', '')
|
|
),
|
|
]
|
|
|
|
# Corresponds to 'Headers'
|
|
ItemKey = ['remark', 'webURL', 'autoupdate', 'proxy']
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
"""Initialize the UserSubsQTableView."""
|
|
self.deleteUniqueCallback = kwargs.pop('deleteUniqueCallback', None)
|
|
|
|
super().__init__(*args, **kwargs)
|
|
|
|
self.timers = list(QtCore.QTimer() for i in range(len(Storage.UserSubs())))
|
|
self.timerConnected = list(False for i in range(len(Storage.UserSubs())))
|
|
self.sourceModel = UserSubsTableModel(self.Headers, self.ItemKey, parent=self)
|
|
self.setModel(self.sourceModel)
|
|
|
|
# Install custom header
|
|
self.setHorizontalHeader(
|
|
UserSubsQTableViewHorizontalHeader(
|
|
parent=self,
|
|
legacySectionSizeSettingsName='SubscriptionWidgetSectionSizeTable',
|
|
sectionSizeSettingsName='UserSubsHeaderViewState',
|
|
)
|
|
)
|
|
self.setVerticalHeader(UserSubsQTableViewVerticalHeader(self))
|
|
self.setDefaultRowHeight(self.RowHeight)
|
|
|
|
self.horizontalHeader().setCustomSectionResizeMode()
|
|
self.horizontalHeader().restoreSectionSize()
|
|
|
|
self.setSortingEnabled(False)
|
|
|
|
# Selection
|
|
self.setSelectionColor(AppHue.disconnectedColor())
|
|
self.setSelectionBehavior(QAbstractItemView.SelectionBehavior.SelectRows)
|
|
self.setSelectionMode(QAbstractItemView.SelectionMode.ExtendedSelection)
|
|
|
|
# No drag and drop
|
|
self.setDragEnabled(False)
|
|
self.setDragDropMode(QAbstractItemView.DragDropMode.NoDragDrop)
|
|
self.setDropIndicatorShown(False)
|
|
self.setDefaultDropAction(QtCore.Qt.DropAction.IgnoreAction)
|
|
|
|
contextMenuActions = [
|
|
AppQAction(
|
|
_('Delete'),
|
|
callback=lambda: self.deleteSelectedItem(),
|
|
),
|
|
]
|
|
|
|
self.contextMenu = AppQMenu(*contextMenuActions)
|
|
self.setContextMenuPolicy(QtCore.Qt.ContextMenuPolicy.CustomContextMenu)
|
|
|
|
# Signals
|
|
self.customContextMenuRequested.connect(self.handleCustomContextMenuRequested)
|
|
|
|
# Flush all data to table
|
|
self.flushAll()
|
|
|
|
@property
|
|
def selectedIndex(self):
|
|
"""Return the selected index value."""
|
|
return sorted(
|
|
list(set(index.row() for index in self.selectionModel().selectedRows()))
|
|
)
|
|
|
|
@QtCore.Slot(QtCore.QPoint)
|
|
def handleCustomContextMenuRequested(self, point):
|
|
"""Handle custom context menu requested."""
|
|
self.contextMenu.exec(self.viewport().mapToGlobal(point))
|
|
|
|
def deleteSelectedItem(self):
|
|
"""Delete selected item."""
|
|
indexes = self.selectedIndex
|
|
|
|
if len(indexes) == 0:
|
|
# Nothing to do
|
|
return
|
|
|
|
def handleResultCode(_indexes, code):
|
|
"""Handle result code."""
|
|
if code == PySide6Legacy.enumValueWrapper(
|
|
AppQMessageBox.StandardButton.Yes
|
|
):
|
|
for i in range(len(_indexes)):
|
|
deleteIndex = _indexes[i] - i
|
|
deleteUnique = list(Storage.UserSubs().keys())[deleteIndex]
|
|
|
|
self.sourceModel.beginRemoveRows(
|
|
QtCore.QModelIndex(),
|
|
deleteIndex,
|
|
deleteIndex,
|
|
)
|
|
|
|
Storage.UserSubs().pop(deleteUnique)
|
|
|
|
# Begin timer cleanup
|
|
qtimer = self.timers[deleteIndex]
|
|
|
|
assert isinstance(qtimer, QtCore.QTimer)
|
|
|
|
if self.timerConnected[deleteIndex]:
|
|
try:
|
|
qtimer.timeout.disconnect()
|
|
except Exception as ex:
|
|
# Any non-exit exceptions
|
|
|
|
# Disconnect all previous signals if possible
|
|
pass
|
|
|
|
qtimer.stop()
|
|
# End timer cleanup
|
|
|
|
# Remove timer from list
|
|
self.timers.pop(deleteIndex)
|
|
self.timerConnected.pop(deleteIndex)
|
|
|
|
self.sourceModel.endRemoveRows()
|
|
|
|
if callable(self.deleteUniqueCallback):
|
|
self.deleteUniqueCallback(deleteUnique)
|
|
|
|
self.flushAll()
|
|
else:
|
|
# Do not delete
|
|
pass
|
|
|
|
if PLATFORM == 'Windows':
|
|
# Windows
|
|
mbox = MBoxQuestionDelete(icon=AppQMessageBox.Icon.Question)
|
|
else:
|
|
# macOS & linux
|
|
mbox = MBoxQuestionDelete(
|
|
icon=AppQMessageBox.Icon.Question, parent=self.parent()
|
|
)
|
|
mbox.setWindowModality(QtCore.Qt.WindowModality.WindowModal)
|
|
|
|
mbox.isMulti = bool(len(indexes) > 1)
|
|
mbox.possibleRemark = self.sourceModel.data(
|
|
self.sourceModel.index(indexes[0], 0),
|
|
QtCore.Qt.ItemDataRole.DisplayRole,
|
|
)
|
|
mbox.setText(mbox.customText())
|
|
mbox.finished.connect(functools.partial(handleResultCode, indexes))
|
|
|
|
# Show the MessageBox asynchronously
|
|
mbox.open()
|
|
|
|
def handleAutoUpdateComboBoxCurrentTextChanged(self, text: str, row: int):
|
|
"""Handle auto update combo box current text changed."""
|
|
textEnglish = _(text, 'EN')
|
|
|
|
unique = list(Storage.UserSubs().keys())[row]
|
|
subsob = Storage.UserSubs()[unique]
|
|
|
|
remark, webURL = subsob['remark'], subsob['webURL']
|
|
|
|
try:
|
|
timems = self.AutoUpdateOptions[textEnglish]
|
|
except KeyError:
|
|
# Invalid key. Reset
|
|
logger.error(f'\'{textEnglish}\' is not in auto update options. Reset')
|
|
|
|
textEnglish = ''
|
|
|
|
# Write to subs object
|
|
subsob['autoupdate'] = textEnglish
|
|
|
|
timems = self.AutoUpdateOptions[textEnglish]
|
|
|
|
qtimer = self.timers[row]
|
|
|
|
assert isinstance(qtimer, QtCore.QTimer)
|
|
|
|
if timems is not None:
|
|
logger.info(
|
|
f'start auto update job for subscription ({remark}, {webURL}). '
|
|
f'Interval is {timems // (60 * 1000)} mins'
|
|
)
|
|
|
|
def getHttpProxy(_subsob):
|
|
"""Return HTTP proxy."""
|
|
return self.ProxyOptions[_subsob.get('proxy', '')]()
|
|
|
|
if self.timerConnected[row]:
|
|
try:
|
|
qtimer.timeout.disconnect()
|
|
except Exception as ex:
|
|
# Any non-exit exceptions
|
|
|
|
# Disconnect all previous signals if possible
|
|
pass
|
|
|
|
qtimer.timeout.connect(
|
|
functools.partial(
|
|
self.updateSubsByUnique,
|
|
unique=unique,
|
|
httpProxy=functools.partial(getHttpProxy, subsob),
|
|
)
|
|
)
|
|
self.timerConnected[row] = True
|
|
qtimer.start(timems)
|
|
else:
|
|
logger.info(f'stop auto update job for subscription ({remark}, {webURL})')
|
|
|
|
if self.timerConnected[row]:
|
|
try:
|
|
qtimer.timeout.disconnect()
|
|
except Exception as ex:
|
|
# Any non-exit exceptions
|
|
|
|
# Disconnect all previous signals if possible
|
|
pass
|
|
|
|
self.timerConnected[row] = False
|
|
|
|
qtimer.stop()
|
|
|
|
# Write to subs object
|
|
subsob['autoupdate'] = textEnglish
|
|
self.sourceModel.emitRowChanged(row, self.Headers.index('Auto Update'))
|
|
|
|
# Return potentially fixed value
|
|
return textEnglish
|
|
|
|
def handleProxyComboBoxCurrentTextChanged(self, text: str, row: int):
|
|
"""Handle proxy combo box current text changed."""
|
|
textEnglish = _(text, 'EN')
|
|
|
|
unique = list(Storage.UserSubs().keys())[row]
|
|
subsob = Storage.UserSubs()[unique]
|
|
|
|
try:
|
|
proxyFn = self.ProxyOptions[textEnglish]
|
|
except KeyError:
|
|
# Invalid key. Reset
|
|
logger.error(f'\'{textEnglish}\' is not in proxy options. Reset')
|
|
|
|
textEnglish = ''
|
|
|
|
# Write to subs object
|
|
subsob['proxy'] = textEnglish
|
|
|
|
proxyFn = self.ProxyOptions[textEnglish]
|
|
|
|
assert callable(proxyFn)
|
|
|
|
# Write to subs object
|
|
subsob['proxy'] = textEnglish
|
|
self.sourceModel.emitRowChanged(
|
|
row, self.Headers.index('Auto Update Use Proxy')
|
|
)
|
|
|
|
# Return potentially fixed value
|
|
return textEnglish
|
|
|
|
def flushItem(self, row, column, item):
|
|
"""Refresh item."""
|
|
if row < 0 or row >= self.sourceModel.rowCount():
|
|
return
|
|
|
|
index = self.sourceModel.index(row, column)
|
|
|
|
if column == self.Headers.index('Auto Update'):
|
|
header = self.Headers[column]
|
|
|
|
newItem = UserSubsAppQComboBox(parent=self.viewport())
|
|
newItem.addItems(list(_(key) for key in self.AutoUpdateOptions.keys()))
|
|
newItem.setFont(QFont(AppFontName()))
|
|
|
|
itemIndex = newItem.findText(
|
|
_(self.handleAutoUpdateComboBoxCurrentTextChanged(header(item), row))
|
|
)
|
|
|
|
if itemIndex >= 0:
|
|
newItem.setCurrentIndex(itemIndex)
|
|
|
|
newItem.currentTextChanged.connect(
|
|
functools.partial(
|
|
self.handleAutoUpdateComboBoxCurrentTextChanged,
|
|
row=row,
|
|
)
|
|
)
|
|
|
|
self.setIndexWidget(index, newItem)
|
|
self.sourceModel.emitRowChanged(row, column)
|
|
elif column == self.Headers.index('Auto Update Use Proxy'):
|
|
header = self.Headers[column]
|
|
|
|
newItem = UserSubsAppQComboBox(parent=self.viewport())
|
|
newItem.addItems(list(_(key) for key in self.ProxyOptions.keys()))
|
|
newItem.setFont(QFont(AppFontName()))
|
|
|
|
itemIndex = newItem.findText(
|
|
_(self.handleProxyComboBoxCurrentTextChanged(header(item), row))
|
|
)
|
|
|
|
if itemIndex >= 0:
|
|
newItem.setCurrentIndex(itemIndex)
|
|
|
|
newItem.currentTextChanged.connect(
|
|
functools.partial(
|
|
self.handleProxyComboBoxCurrentTextChanged,
|
|
row=row,
|
|
)
|
|
)
|
|
|
|
self.setIndexWidget(index, newItem)
|
|
self.sourceModel.emitRowChanged(row, column)
|
|
else:
|
|
self.sourceModel.emitRowChanged(row, column)
|
|
|
|
def flushRow(self, row, item):
|
|
"""Refresh row."""
|
|
for column in list(range(self.sourceModel.columnCount())):
|
|
self.flushItem(row, column, item)
|
|
|
|
def flushAll(self):
|
|
"""Refresh all."""
|
|
self.sourceModel.emitAllChanged()
|
|
|
|
for index, key in enumerate(Storage.UserSubs()):
|
|
self.flushRow(index, Storage.UserSubs()[key])
|
|
|
|
def appendNewItem(self, **kwargs):
|
|
"""Append new item."""
|
|
unique, remark, webURL, autoupdate, proxy = (
|
|
kwargs.pop('unique', ''),
|
|
kwargs.pop('remark', ''),
|
|
kwargs.pop('webURL', ''),
|
|
# Below values are not filled when adding item via Gui
|
|
kwargs.pop('autoupdate', ''),
|
|
kwargs.pop('proxy', ''),
|
|
)
|
|
|
|
# The internal subs object
|
|
subsob = {
|
|
unique: {
|
|
'remark': remark,
|
|
'webURL': webURL,
|
|
'autoupdate': autoupdate,
|
|
'proxy': proxy,
|
|
}
|
|
}
|
|
|
|
if unique in Storage.UserSubs():
|
|
row = list(Storage.UserSubs().keys()).index(unique)
|
|
Storage.UserSubs().update(subsob)
|
|
self.flushRow(row, subsob[unique])
|
|
else:
|
|
row = self.sourceModel.rowCount()
|
|
|
|
# Add timer
|
|
self.timers.append(QtCore.QTimer())
|
|
self.timerConnected.append(False)
|
|
|
|
self.sourceModel.beginInsertRows(QtCore.QModelIndex(), row, row)
|
|
Storage.UserSubs().update(subsob)
|
|
self.sourceModel.endInsertRows()
|
|
|
|
self.flushRow(row, subsob[unique])
|
|
|
|
@staticmethod
|
|
def updateSubsByUnique(
|
|
unique: str, httpProxy: Union[str, Callable, None], **kwargs
|
|
):
|
|
"""Update subs by unique."""
|
|
showMessageBox = kwargs.pop('showMessageBox', False)
|
|
|
|
if callable(httpProxy):
|
|
try:
|
|
realHttpProxy = httpProxy()
|
|
except Exception as ex:
|
|
# Any non-exit exceptions
|
|
|
|
logger.error(
|
|
f'error while configuring http proxy: {ex}. '
|
|
f'Update subscription uses no proxy'
|
|
)
|
|
|
|
realHttpProxy = None
|
|
else:
|
|
realHttpProxy = httpProxy
|
|
|
|
APP().mainWindow.updateSubsByUnique(
|
|
unique, realHttpProxy, showMessageBox=showMessageBox, **kwargs
|
|
)
|
|
|
|
def retranslate(self):
|
|
"""Refresh translated text for the user subs Qt table view."""
|
|
self.sourceModel.headerDataChanged.emit(
|
|
QtCore.Qt.Orientation.Horizontal,
|
|
0,
|
|
len(self.Headers) - 1,
|
|
)
|