FetchWorker: Fix issue with missing MacOS assets on MacOS
Using `LegendaryCore.get_game_and_dlc_list` with platform `Windows` updated the assets only for the `Windows` builds of the games missing `Win32` and `MacOS` assets on clean installs. This caused Rare to not include MacOS install options on MacOS (duh!). This might also have been the cause that users were unable to launch games, since they where only offered the `Windows` build of the games (big duh!). To fix this, fetch the assets for `Win32` and `MacOS` games before getting the final list of games and dlcs based on the `Windows` platform. In this regard, also re-use the existing options for getting metadata to give the option to the user to include them when updating assets. Also add an option to include Unreal engine assets which until now were fetched unconditionally. * Include Unreal: When the user option is `true` or debugging. Defaults to `false` * Update Win32: When the user option is `true` or debugging. Defaults to `false` * Update MacOS: Force on MacOS, when the option is `true` or debugging on other platforms. Defaults to `true` on MacOS and is disabled, `false` on others Furthermore, respect legendary's `default_platform` config option and set it in the config on new configurations. The new method in our LegendaryCore monkey allows us to use that option in RareGame when doing version checks on not installed games, and not defaulting to `Windows`. Finally, set `install_platform_fallback` to false in a new config to avoid unwanted side-effects.
This commit is contained in:
parent
687218d29b
commit
1677ea762c
|
@ -45,8 +45,6 @@ class Rare(RareApp):
|
|||
self.signals = RareCore.instance().signals()
|
||||
self.core = RareCore.instance().core()
|
||||
|
||||
config_helper.init_config_handler(self.core)
|
||||
|
||||
lang = self.settings.value("language", self.core.language_code, type=str)
|
||||
self.load_translator(lang)
|
||||
|
||||
|
|
|
@ -284,7 +284,9 @@ class GameInfo(QWidget, SideTabContents):
|
|||
)
|
||||
|
||||
self.ui.platform.setText(
|
||||
self.rgame.igame.platform if self.rgame.is_installed and not self.rgame.is_non_asset else "Windows"
|
||||
self.rgame.igame.platform
|
||||
if self.rgame.is_installed and not self.rgame.is_non_asset
|
||||
else self.core.default_platform
|
||||
)
|
||||
|
||||
self.ui.lbl_grade.setDisabled(
|
||||
|
|
|
@ -74,7 +74,6 @@ class UbiConnectWorker(Worker):
|
|||
def __init__(self, core: LegendaryCore, ubi_account_id, partner_link_id):
|
||||
super(UbiConnectWorker, self).__init__()
|
||||
self.signals = UbiConnectWorker.Signals()
|
||||
self.setAutoDelete(True)
|
||||
self.core = core
|
||||
self.ubi_account_id = ubi_account_id
|
||||
self.partner_link_id = partner_link_id
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import platform
|
||||
import platform as pf
|
||||
import re
|
||||
from logging import getLogger
|
||||
from typing import Tuple
|
||||
from typing import Tuple, List
|
||||
|
||||
from PyQt5.QtCore import QObject, pyqtSignal, QThreadPool, QSettings
|
||||
from PyQt5.QtWidgets import QSizePolicy, QWidget, QFileDialog, QMessageBox
|
||||
|
@ -19,14 +19,21 @@ class RefreshGameMetaWorker(Worker):
|
|||
class Signals(QObject):
|
||||
finished = pyqtSignal()
|
||||
|
||||
def __init__(self):
|
||||
def __init__(self, platforms: List[str], include_unreal: bool):
|
||||
super(RefreshGameMetaWorker, self).__init__()
|
||||
self.signals = RefreshGameMetaWorker.Signals()
|
||||
self.setAutoDelete(True)
|
||||
self.core = LegendaryCoreSingleton()
|
||||
if platforms:
|
||||
self.platforms = platforms
|
||||
else:
|
||||
self.platforms = ["Windows"]
|
||||
self.skip_ue = not include_unreal
|
||||
|
||||
def run_real(self) -> None:
|
||||
self.core.get_game_and_dlc_list(True, force_refresh=True)
|
||||
for platform in self.platforms:
|
||||
self.core.get_game_and_dlc_list(
|
||||
True, platform=platform, force_refresh=True, skip_ue=self.skip_ue
|
||||
)
|
||||
self.signals.finished.emit()
|
||||
|
||||
|
||||
|
@ -34,7 +41,7 @@ class LegendarySettings(QWidget, Ui_LegendarySettings):
|
|||
def __init__(self, parent=None):
|
||||
super(LegendarySettings, self).__init__(parent=parent)
|
||||
self.setupUi(self)
|
||||
self.settings = QSettings()
|
||||
self.settings = QSettings(self)
|
||||
|
||||
self.core = LegendaryCoreSingleton()
|
||||
|
||||
|
@ -82,20 +89,36 @@ class LegendarySettings(QWidget, Ui_LegendarySettings):
|
|||
)
|
||||
self.locale_layout.addWidget(self.locale_edit)
|
||||
|
||||
self.win32_cb.setChecked(self.settings.value("win32_meta", False, bool))
|
||||
self.win32_cb.stateChanged.connect(lambda: self.settings.setValue("win32_meta", self.win32_cb.isChecked()))
|
||||
self.fetch_win32_check.setChecked(self.settings.value("win32_meta", False, bool))
|
||||
self.fetch_win32_check.stateChanged.connect(
|
||||
lambda: self.settings.setValue("win32_meta", self.fetch_win32_check.isChecked())
|
||||
)
|
||||
|
||||
self.mac_cb.setChecked(self.settings.value("mac_meta", platform.system() == "Darwin", bool))
|
||||
self.mac_cb.stateChanged.connect(lambda: self.settings.setValue("mac_meta", self.mac_cb.isChecked()))
|
||||
self.fetch_macos_check.setChecked(self.settings.value("macos_meta", pf.system() == "Darwin", bool))
|
||||
self.fetch_macos_check.stateChanged.connect(
|
||||
lambda: self.settings.setValue("macos_meta", self.fetch_macos_check.isChecked())
|
||||
)
|
||||
self.fetch_macos_check.setDisabled(pf.system() == "Darwin")
|
||||
|
||||
self.refresh_game_meta_btn.clicked.connect(self.refresh_game_meta)
|
||||
self.fetch_unreal_check.setChecked(self.settings.value("unreal_meta", False, bool))
|
||||
self.fetch_unreal_check.stateChanged.connect(
|
||||
lambda: self.settings.setValue("unreal_meta", self.fetch_unreal_check.isChecked())
|
||||
)
|
||||
|
||||
def refresh_game_meta(self):
|
||||
self.refresh_game_meta_btn.setDisabled(True)
|
||||
self.refresh_game_meta_btn.setText(self.tr("Loading"))
|
||||
worker = RefreshGameMetaWorker()
|
||||
worker.signals.finished.connect(lambda: self.refresh_game_meta_btn.setDisabled(False))
|
||||
worker.signals.finished.connect(lambda: self.refresh_game_meta_btn.setText(self.tr("Refresh game meta")))
|
||||
self.refresh_metadata_button.clicked.connect(self.refresh_metadata)
|
||||
# FIXME: Disable the button for now because it interferes with RareCore
|
||||
self.refresh_metadata_button.setEnabled(False)
|
||||
self.refresh_metadata_button.setVisible(False)
|
||||
|
||||
def refresh_metadata(self):
|
||||
self.refresh_metadata_button.setDisabled(True)
|
||||
platforms = []
|
||||
if self.fetch_win32_check.isChecked():
|
||||
platforms.append("Win32")
|
||||
if self.fetch_macos_check.isChecked():
|
||||
platforms.append("Mac")
|
||||
worker = RefreshGameMetaWorker(platforms, self.fetch_unreal_check.isChecked())
|
||||
worker.signals.finished.connect(lambda: self.refresh_metadata_button.setDisabled(False))
|
||||
QThreadPool.globalInstance().start(worker)
|
||||
|
||||
@staticmethod
|
||||
|
|
|
@ -3,6 +3,7 @@ import json
|
|||
import logging
|
||||
import os
|
||||
from multiprocessing import Queue
|
||||
from sys import platform as sys_platform
|
||||
from uuid import uuid4
|
||||
|
||||
# On Windows the monkeypatching of `run_real` below doesn't work like on Linux
|
||||
|
@ -17,8 +18,8 @@ from legendary.models.game import Game, InstalledGame
|
|||
from legendary.models.manifest import ManifestMeta
|
||||
|
||||
from rare.lgndr.downloader.mp.manager import DLManager
|
||||
from rare.lgndr.lfs.lgndry import LGDLFS
|
||||
from rare.lgndr.glue.exception import LgndrException, LgndrLogHandler
|
||||
from rare.lgndr.lfs.lgndry import LGDLFS
|
||||
|
||||
legendary.core.DLManager = DLManager
|
||||
legendary.core.LGDLFS = LGDLFS
|
||||
|
@ -50,6 +51,11 @@ class LegendaryCore(LegendaryCoreReal):
|
|||
return ret
|
||||
return unlock
|
||||
|
||||
@property
|
||||
def default_platform(self) -> str:
|
||||
os_default = "Mac" if sys_platform == "darwin" else "Windows"
|
||||
return self.lgd.config.get("Legendary", "default_platform", fallback=os_default)
|
||||
|
||||
# skip_sync defaults to false but since Rare is persistent, skip by default
|
||||
# def get_installed_game(self, app_name, skip_sync=True) -> InstalledGame:
|
||||
# return super(LegendaryCore, self).get_installed_game(app_name, skip_sync)
|
||||
|
|
|
@ -166,7 +166,8 @@ class RareGame(RareGameSlim):
|
|||
|
||||
def update_game(self):
|
||||
self.game = self.core.get_game(
|
||||
self.app_name, update_meta=False, platform=self.igame.platform if self.igame else "Windows"
|
||||
self.app_name, update_meta=False,
|
||||
platform=self.igame.platform if self.igame else self.core.default_platform
|
||||
)
|
||||
|
||||
def update_igame(self):
|
||||
|
@ -228,7 +229,7 @@ class RareGame(RareGameSlim):
|
|||
if self.igame is not None:
|
||||
return self.game.app_version(self.igame.platform)
|
||||
else:
|
||||
return self.game.app_version()
|
||||
return self.game.app_version(self.core.default_platform)
|
||||
|
||||
@property
|
||||
def has_update(self) -> bool:
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import configparser
|
||||
import os
|
||||
import platform
|
||||
import time
|
||||
from argparse import Namespace
|
||||
from itertools import chain
|
||||
|
@ -25,6 +26,7 @@ from .workers import (
|
|||
)
|
||||
from .workers.uninstall import uninstall_game
|
||||
from .workers.worker import QueueWorkerInfo, QueueWorkerState
|
||||
from rare.utils import config_helper
|
||||
|
||||
logger = getLogger("RareCore")
|
||||
|
||||
|
@ -54,9 +56,10 @@ class RareCore(QObject):
|
|||
self.args(args)
|
||||
self.signals(init=True)
|
||||
self.core(init=True)
|
||||
config_helper.init_config_handler(self.__core)
|
||||
self.image_manager(init=True)
|
||||
|
||||
self.settings = QSettings()
|
||||
self.settings = QSettings(self)
|
||||
|
||||
self.queue_workers: List[QueueWorker] = []
|
||||
self.queue_threadpool = QThreadPool()
|
||||
|
@ -140,6 +143,9 @@ class RareCore(QObject):
|
|||
for section in ["Legendary", "default", "default.env"]:
|
||||
if section not in self.__core.lgd.config.sections():
|
||||
self.__core.lgd.config.add_section(section)
|
||||
# Set some platform defaults
|
||||
self.__core.lgd.config.set("Legendary", "default_platform", self.__core.default_platform)
|
||||
self.__core.lgd.config.set("Legendary", "install_platform_fallback", False)
|
||||
# workaround if egl sync enabled, but no programdata_path
|
||||
# programdata_path might be unset if logging in through the browser
|
||||
if self.__core.egl_sync_enabled:
|
||||
|
@ -357,7 +363,7 @@ class RareCore(QObject):
|
|||
yield game.game
|
||||
|
||||
@property
|
||||
def dlcs(self) -> Dict[str, Game]:
|
||||
def dlcs(self) -> Dict[str, set[RareGame]]:
|
||||
"""!
|
||||
RareGames that ARE DLCs themselves
|
||||
"""
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
import platform
|
||||
import time
|
||||
from argparse import Namespace
|
||||
from enum import IntEnum
|
||||
from logging import getLogger
|
||||
|
||||
from PyQt5.QtCore import QObject, pyqtSignal
|
||||
from PyQt5.QtCore import QObject, pyqtSignal, QSettings
|
||||
from requests.exceptions import ConnectionError, HTTPError
|
||||
|
||||
from rare.lgndr.core import LegendaryCore
|
||||
|
@ -27,19 +28,54 @@ class FetchWorker(Worker):
|
|||
self.signals = FetchWorker.Signals()
|
||||
self.core = core
|
||||
self.args = args
|
||||
self.settings = QSettings()
|
||||
|
||||
def run_real(self):
|
||||
# Fetch regular EGL games with assets
|
||||
self.signals.progress.emit(0, self.signals.tr("Updating game metadata"))
|
||||
start_time = time.time()
|
||||
|
||||
want_unreal = self.settings.value("unreal_meta", False, bool) or self.args.debug
|
||||
want_win32 = self.settings.value("win32_meta", False, bool)
|
||||
want_macos = self.settings.value("macos_meta", False, bool)
|
||||
need_macos = platform.system() == "Darwin"
|
||||
need_windows = not any([want_win32, want_macos, need_macos, self.args.debug])
|
||||
|
||||
if want_win32 or self.args.debug:
|
||||
logger.info(
|
||||
"Requesting Win32 metadata due to %s, %s Unreal engine",
|
||||
"settings" if want_win32 else "debug",
|
||||
"with" if want_unreal else "without"
|
||||
)
|
||||
self.signals.progress.emit(00, self.signals.tr("Updating game metadata for Windows"))
|
||||
self.core.get_game_and_dlc_list(
|
||||
update_assets=not self.args.offline, platform="Win32", skip_ue=not want_unreal
|
||||
)
|
||||
|
||||
if need_macos or want_macos or self.args.debug:
|
||||
logger.info(
|
||||
"Requesting MacOS metadata due to %s, %s Unreal engine",
|
||||
platform if need_macos else "settings" if want_macos else "debug",
|
||||
"with" if want_unreal else "without"
|
||||
)
|
||||
self.signals.progress.emit(15, self.signals.tr("Updating game metadata for MacOS"))
|
||||
self.core.get_game_and_dlc_list(
|
||||
update_assets=not self.args.offline, platform="Mac", skip_ue=not want_unreal
|
||||
)
|
||||
|
||||
if need_windows:
|
||||
self.signals.progress.emit(00, self.signals.tr("Updating game metadata for Windows"))
|
||||
logger.info(
|
||||
"Requesting Windows metadata, %s Unreal engine",
|
||||
"with" if want_unreal else "without"
|
||||
)
|
||||
games, dlc_dict = self.core.get_game_and_dlc_list(
|
||||
update_assets=not self.args.offline, platform="Windows", skip_ue=False
|
||||
update_assets=need_windows, platform="Windows", skip_ue=not want_unreal
|
||||
)
|
||||
logger.debug(f"Games {len(games)}, games with DLCs {len(dlc_dict)}")
|
||||
logger.debug(f"Request games: {time.time() - start_time} seconds")
|
||||
|
||||
# Fetch non-asset games
|
||||
self.signals.progress.emit(10, self.signals.tr("Updating non-asset metadata"))
|
||||
self.signals.progress.emit(30, self.signals.tr("Updating non-asset game metadata"))
|
||||
start_time = time.time()
|
||||
try:
|
||||
na_games, na_dlc_dict = self.core.get_non_asset_library_items(force_refresh=False, skip_ue=False)
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
# Form implementation generated from reading ui file 'rare/ui/components/tabs/settings/legendary.ui'
|
||||
#
|
||||
# Created by: PyQt5 UI code generator 5.15.7
|
||||
# Created by: PyQt5 UI code generator 5.15.10
|
||||
#
|
||||
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
|
||||
# run again. Do not edit this file unless you know what you are doing.
|
||||
|
@ -14,7 +14,7 @@ from PyQt5 import QtCore, QtGui, QtWidgets
|
|||
class Ui_LegendarySettings(object):
|
||||
def setupUi(self, LegendarySettings):
|
||||
LegendarySettings.setObjectName("LegendarySettings")
|
||||
LegendarySettings.resize(595, 334)
|
||||
LegendarySettings.resize(681, 456)
|
||||
LegendarySettings.setWindowTitle("LegendarySettings")
|
||||
self.legendary_layout = QtWidgets.QHBoxLayout(LegendarySettings)
|
||||
self.legendary_layout.setObjectName("legendary_layout")
|
||||
|
@ -125,21 +125,30 @@ class Ui_LegendarySettings(object):
|
|||
self.clean_button = QtWidgets.QPushButton(self.cleanup_group)
|
||||
self.clean_button.setObjectName("clean_button")
|
||||
self.cleanup_layout.addWidget(self.clean_button)
|
||||
self.right_layout.addWidget(self.cleanup_group, 0, QtCore.Qt.AlignTop)
|
||||
self.meta_group = QtWidgets.QGroupBox(LegendarySettings)
|
||||
self.meta_group.setObjectName("meta_group")
|
||||
self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.meta_group)
|
||||
self.right_layout.addWidget(self.cleanup_group)
|
||||
self.metadata_group = QtWidgets.QGroupBox(LegendarySettings)
|
||||
self.metadata_group.setObjectName("metadata_group")
|
||||
self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.metadata_group)
|
||||
self.verticalLayout_2.setObjectName("verticalLayout_2")
|
||||
self.win32_cb = QtWidgets.QCheckBox(self.meta_group)
|
||||
self.win32_cb.setObjectName("win32_cb")
|
||||
self.verticalLayout_2.addWidget(self.win32_cb)
|
||||
self.mac_cb = QtWidgets.QCheckBox(self.meta_group)
|
||||
self.mac_cb.setObjectName("mac_cb")
|
||||
self.verticalLayout_2.addWidget(self.mac_cb)
|
||||
self.refresh_game_meta_btn = QtWidgets.QPushButton(self.meta_group)
|
||||
self.refresh_game_meta_btn.setObjectName("refresh_game_meta_btn")
|
||||
self.verticalLayout_2.addWidget(self.refresh_game_meta_btn)
|
||||
self.right_layout.addWidget(self.meta_group)
|
||||
self.fetch_win32_check = QtWidgets.QCheckBox(self.metadata_group)
|
||||
self.fetch_win32_check.setObjectName("fetch_win32_check")
|
||||
self.verticalLayout_2.addWidget(self.fetch_win32_check)
|
||||
self.fetch_macos_check = QtWidgets.QCheckBox(self.metadata_group)
|
||||
self.fetch_macos_check.setObjectName("fetch_macos_check")
|
||||
self.verticalLayout_2.addWidget(self.fetch_macos_check)
|
||||
self.fetch_unreal_check = QtWidgets.QCheckBox(self.metadata_group)
|
||||
self.fetch_unreal_check.setObjectName("fetch_unreal_check")
|
||||
self.verticalLayout_2.addWidget(self.fetch_unreal_check)
|
||||
self.metadata_info = QtWidgets.QLabel(self.metadata_group)
|
||||
font = QtGui.QFont()
|
||||
font.setItalic(True)
|
||||
self.metadata_info.setFont(font)
|
||||
self.metadata_info.setObjectName("metadata_info")
|
||||
self.verticalLayout_2.addWidget(self.metadata_info)
|
||||
self.refresh_metadata_button = QtWidgets.QPushButton(self.metadata_group)
|
||||
self.refresh_metadata_button.setObjectName("refresh_metadata_button")
|
||||
self.verticalLayout_2.addWidget(self.refresh_metadata_button)
|
||||
self.right_layout.addWidget(self.metadata_group)
|
||||
spacerItem1 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
|
||||
self.right_layout.addItem(spacerItem1)
|
||||
self.legendary_layout.addLayout(self.right_layout)
|
||||
|
@ -162,10 +171,12 @@ class Ui_LegendarySettings(object):
|
|||
self.cleanup_group.setTitle(_translate("LegendarySettings", "Cleanup"))
|
||||
self.clean_keep_manifests_button.setText(_translate("LegendarySettings", "Clean, but keep manifests"))
|
||||
self.clean_button.setText(_translate("LegendarySettings", "Remove everything"))
|
||||
self.meta_group.setTitle(_translate("LegendarySettings", "Game metadata"))
|
||||
self.win32_cb.setText(_translate("LegendarySettings", "Load 32bit data"))
|
||||
self.mac_cb.setText(_translate("LegendarySettings", "Load MacOS data"))
|
||||
self.refresh_game_meta_btn.setText(_translate("LegendarySettings", "Refresh game meta"))
|
||||
self.metadata_group.setTitle(_translate("LegendarySettings", "Platforms"))
|
||||
self.fetch_win32_check.setText(_translate("LegendarySettings", "Include Win32 games"))
|
||||
self.fetch_macos_check.setText(_translate("LegendarySettings", "Include MacOS games"))
|
||||
self.fetch_unreal_check.setText(_translate("LegendarySettings", "Include Unreal engine"))
|
||||
self.metadata_info.setText(_translate("LegendarySettings", "Restart Rare to apply"))
|
||||
self.refresh_metadata_button.setText(_translate("LegendarySettings", "Refresh metadata"))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
|
|
@ -6,8 +6,8 @@
|
|||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>595</width>
|
||||
<height>334</height>
|
||||
<width>681</width>
|
||||
<height>456</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
|
@ -200,7 +200,7 @@
|
|||
<layout class="QVBoxLayout" name="locale_layout"/>
|
||||
</widget>
|
||||
</item>
|
||||
<item alignment="Qt::AlignTop">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="cleanup_group">
|
||||
<property name="title">
|
||||
<string>Cleanup</string>
|
||||
|
@ -227,29 +227,48 @@
|
|||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="meta_group">
|
||||
<widget class="QGroupBox" name="metadata_group">
|
||||
<property name="title">
|
||||
<string>Game metadata</string>
|
||||
<string>Platforms</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="win32_cb">
|
||||
<widget class="QCheckBox" name="fetch_win32_check">
|
||||
<property name="text">
|
||||
<string>Load 32bit data</string>
|
||||
<string>Include Win32 games</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="mac_cb">
|
||||
<widget class="QCheckBox" name="fetch_macos_check">
|
||||
<property name="text">
|
||||
<string>Load MacOS data</string>
|
||||
<string>Include MacOS games</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="refresh_game_meta_btn">
|
||||
<widget class="QCheckBox" name="fetch_unreal_check">
|
||||
<property name="text">
|
||||
<string>Refresh game meta</string>
|
||||
<string>Include Unreal engine</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="metadata_info">
|
||||
<property name="font">
|
||||
<font>
|
||||
<italic>true</italic>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Restart Rare to apply</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="refresh_metadata_button">
|
||||
<property name="text">
|
||||
<string>Refresh metadata</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
|
Loading…
Reference in a new issue