mirror of
https://github.com/Cockatrice/Cockatrice.git
synced 2026-06-28 17:43:54 -07:00
[LayoutSettings] Move over layout settings in global.ini (#6587)
* [LayoutSettings] Move over some settings from general * remove unused setting
This commit is contained in:
parent
a80a0531a6
commit
804a60f1ea
7 changed files with 49 additions and 61 deletions
|
|
@ -268,9 +268,6 @@ SettingsCache::SettingsCache()
|
||||||
picDownload = settings->value("personal/picturedownload", true).toBool();
|
picDownload = settings->value("personal/picturedownload", true).toBool();
|
||||||
showStatusBar = settings->value("personal/showStatusBar", false).toBool();
|
showStatusBar = settings->value("personal/showStatusBar", false).toBool();
|
||||||
|
|
||||||
mainWindowGeometry = settings->value("interface/main_window_geometry").toByteArray();
|
|
||||||
tokenDialogGeometry = settings->value("interface/token_dialog_geometry").toByteArray();
|
|
||||||
setsDialogGeometry = settings->value("interface/sets_dialog_geometry").toByteArray();
|
|
||||||
notificationsEnabled = settings->value("interface/notificationsenabled", true).toBool();
|
notificationsEnabled = settings->value("interface/notificationsenabled", true).toBool();
|
||||||
spectatorNotificationsEnabled = settings->value("interface/specnotificationsenabled", false).toBool();
|
spectatorNotificationsEnabled = settings->value("interface/specnotificationsenabled", false).toBool();
|
||||||
buddyConnectNotificationsEnabled = settings->value("interface/buddyconnectnotificationsenabled", true).toBool();
|
buddyConnectNotificationsEnabled = settings->value("interface/buddyconnectnotificationsenabled", true).toBool();
|
||||||
|
|
@ -280,7 +277,6 @@ SettingsCache::SettingsCache()
|
||||||
doNotDeleteArrowsInSubPhases = settings->value("interface/doNotDeleteArrowsInSubPhases", true).toBool();
|
doNotDeleteArrowsInSubPhases = settings->value("interface/doNotDeleteArrowsInSubPhases", true).toBool();
|
||||||
startingHandSize = settings->value("interface/startinghandsize", 7).toInt();
|
startingHandSize = settings->value("interface/startinghandsize", 7).toInt();
|
||||||
annotateTokens = settings->value("interface/annotatetokens", false).toBool();
|
annotateTokens = settings->value("interface/annotatetokens", false).toBool();
|
||||||
tabGameSplitterSizes = settings->value("interface/tabgame_splittersizes").toByteArray();
|
|
||||||
knownMissingFeatures = settings->value("interface/knownmissingfeatures", "").toString();
|
knownMissingFeatures = settings->value("interface/knownmissingfeatures", "").toString();
|
||||||
useTearOffMenus = settings->value("interface/usetearoffmenus", true).toBool();
|
useTearOffMenus = settings->value("interface/usetearoffmenus", true).toBool();
|
||||||
cardViewInitialRowsMax = settings->value("interface/cardViewInitialRowsMax", 14).toInt();
|
cardViewInitialRowsMax = settings->value("interface/cardViewInitialRowsMax", 14).toInt();
|
||||||
|
|
@ -713,12 +709,6 @@ void SettingsCache::setAnnotateTokens(QT_STATE_CHANGED_T _annotateTokens)
|
||||||
settings->setValue("interface/annotatetokens", annotateTokens);
|
settings->setValue("interface/annotatetokens", annotateTokens);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SettingsCache::setTabGameSplitterSizes(const QByteArray &_tabGameSplitterSizes)
|
|
||||||
{
|
|
||||||
tabGameSplitterSizes = _tabGameSplitterSizes;
|
|
||||||
settings->setValue("interface/tabgame_splittersizes", tabGameSplitterSizes);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SettingsCache::setShowShortcuts(QT_STATE_CHANGED_T _showShortcuts)
|
void SettingsCache::setShowShortcuts(QT_STATE_CHANGED_T _showShortcuts)
|
||||||
{
|
{
|
||||||
showShortcuts = static_cast<bool>(_showShortcuts);
|
showShortcuts = static_cast<bool>(_showShortcuts);
|
||||||
|
|
@ -1090,24 +1080,6 @@ void SettingsCache::setIgnoreUnregisteredUserMessages(QT_STATE_CHANGED_T _ignore
|
||||||
settings->setValue("chat/ignore_unregistered_messages", ignoreUnregisteredUserMessages);
|
settings->setValue("chat/ignore_unregistered_messages", ignoreUnregisteredUserMessages);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SettingsCache::setMainWindowGeometry(const QByteArray &_mainWindowGeometry)
|
|
||||||
{
|
|
||||||
mainWindowGeometry = _mainWindowGeometry;
|
|
||||||
settings->setValue("interface/main_window_geometry", mainWindowGeometry);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SettingsCache::setTokenDialogGeometry(const QByteArray &_tokenDialogGeometry)
|
|
||||||
{
|
|
||||||
tokenDialogGeometry = _tokenDialogGeometry;
|
|
||||||
settings->setValue("interface/token_dialog_geometry", tokenDialogGeometry);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SettingsCache::setSetsDialogGeometry(const QByteArray &_setsDialogGeometry)
|
|
||||||
{
|
|
||||||
setsDialogGeometry = _setsDialogGeometry;
|
|
||||||
settings->setValue("interface/sets_dialog_geometry", setsDialogGeometry);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SettingsCache::setPixmapCacheSize(const int _pixmapCacheSize)
|
void SettingsCache::setPixmapCacheSize(const int _pixmapCacheSize)
|
||||||
{
|
{
|
||||||
pixmapCacheSize = _pixmapCacheSize;
|
pixmapCacheSize = _pixmapCacheSize;
|
||||||
|
|
|
||||||
|
|
@ -205,9 +205,6 @@ private:
|
||||||
DebugSettings *debugSettings;
|
DebugSettings *debugSettings;
|
||||||
CardCounterSettings *cardCounterSettings;
|
CardCounterSettings *cardCounterSettings;
|
||||||
|
|
||||||
QByteArray mainWindowGeometry;
|
|
||||||
QByteArray tokenDialogGeometry;
|
|
||||||
QByteArray setsDialogGeometry;
|
|
||||||
QString lang;
|
QString lang;
|
||||||
QString deckPath, filtersPath, replaysPath, picsPath, redirectCachePath, customPicsPath, cardDatabasePath,
|
QString deckPath, filtersPath, replaysPath, picsPath, redirectCachePath, customPicsPath, cardDatabasePath,
|
||||||
customCardDatabasePath, themesPath, spoilerDatabasePath, tokenDatabasePath, themeName, homeTabBackgroundSource;
|
customCardDatabasePath, themesPath, spoilerDatabasePath, tokenDatabasePath, themeName, homeTabBackgroundSource;
|
||||||
|
|
@ -238,7 +235,6 @@ private:
|
||||||
bool doNotDeleteArrowsInSubPhases;
|
bool doNotDeleteArrowsInSubPhases;
|
||||||
int startingHandSize;
|
int startingHandSize;
|
||||||
bool annotateTokens;
|
bool annotateTokens;
|
||||||
QByteArray tabGameSplitterSizes;
|
|
||||||
bool showShortcuts;
|
bool showShortcuts;
|
||||||
bool showGameSelectorFilterToolbar;
|
bool showGameSelectorFilterToolbar;
|
||||||
bool displayCardNames;
|
bool displayCardNames;
|
||||||
|
|
@ -345,18 +341,6 @@ public:
|
||||||
QString getSettingsPath();
|
QString getSettingsPath();
|
||||||
[[nodiscard]] QString getCachePath() const;
|
[[nodiscard]] QString getCachePath() const;
|
||||||
[[nodiscard]] QString getNetworkCachePath() const;
|
[[nodiscard]] QString getNetworkCachePath() const;
|
||||||
[[nodiscard]] const QByteArray &getMainWindowGeometry() const
|
|
||||||
{
|
|
||||||
return mainWindowGeometry;
|
|
||||||
}
|
|
||||||
[[nodiscard]] const QByteArray &getTokenDialogGeometry() const
|
|
||||||
{
|
|
||||||
return tokenDialogGeometry;
|
|
||||||
}
|
|
||||||
[[nodiscard]] const QByteArray &getSetsDialogGeometry() const
|
|
||||||
{
|
|
||||||
return setsDialogGeometry;
|
|
||||||
}
|
|
||||||
[[nodiscard]] QString getLang() const
|
[[nodiscard]] QString getLang() const
|
||||||
{
|
{
|
||||||
return lang;
|
return lang;
|
||||||
|
|
@ -555,10 +539,6 @@ public:
|
||||||
{
|
{
|
||||||
return annotateTokens;
|
return annotateTokens;
|
||||||
}
|
}
|
||||||
[[nodiscard]] QByteArray getTabGameSplitterSizes() const
|
|
||||||
{
|
|
||||||
return tabGameSplitterSizes;
|
|
||||||
}
|
|
||||||
[[nodiscard]] bool getShowShortcuts() const
|
[[nodiscard]] bool getShowShortcuts() const
|
||||||
{
|
{
|
||||||
return showShortcuts;
|
return showShortcuts;
|
||||||
|
|
@ -995,9 +975,6 @@ public:
|
||||||
public slots:
|
public slots:
|
||||||
void setDownloadSpoilerStatus(bool _spoilerStatus);
|
void setDownloadSpoilerStatus(bool _spoilerStatus);
|
||||||
|
|
||||||
void setMainWindowGeometry(const QByteArray &_mainWindowGeometry);
|
|
||||||
void setTokenDialogGeometry(const QByteArray &_tokenDialog);
|
|
||||||
void setSetsDialogGeometry(const QByteArray &_setsDialog);
|
|
||||||
void setLang(const QString &_lang);
|
void setLang(const QString &_lang);
|
||||||
void setShowTipsOnStartup(bool _showTipsOnStartup);
|
void setShowTipsOnStartup(bool _showTipsOnStartup);
|
||||||
void setSeenTips(const QList<int> &_seenTips);
|
void setSeenTips(const QList<int> &_seenTips);
|
||||||
|
|
@ -1034,7 +1011,6 @@ public slots:
|
||||||
void setDoNotDeleteArrowsInSubPhases(QT_STATE_CHANGED_T _doNotDeleteArrowsInSubPhases);
|
void setDoNotDeleteArrowsInSubPhases(QT_STATE_CHANGED_T _doNotDeleteArrowsInSubPhases);
|
||||||
void setStartingHandSize(int _startingHandSize);
|
void setStartingHandSize(int _startingHandSize);
|
||||||
void setAnnotateTokens(QT_STATE_CHANGED_T _annotateTokens);
|
void setAnnotateTokens(QT_STATE_CHANGED_T _annotateTokens);
|
||||||
void setTabGameSplitterSizes(const QByteArray &_tabGameSplitterSizes);
|
|
||||||
void setShowShortcuts(QT_STATE_CHANGED_T _showShortcuts);
|
void setShowShortcuts(QT_STATE_CHANGED_T _showShortcuts);
|
||||||
void setShowGameSelectorFilterToolbar(QT_STATE_CHANGED_T _showGameSelectorFilterToolbar);
|
void setShowGameSelectorFilterToolbar(QT_STATE_CHANGED_T _showGameSelectorFilterToolbar);
|
||||||
void setDisplayCardNames(QT_STATE_CHANGED_T _displayCardNames);
|
void setDisplayCardNames(QT_STATE_CHANGED_T _displayCardNames);
|
||||||
|
|
|
||||||
|
|
@ -146,13 +146,13 @@ DlgCreateToken::DlgCreateToken(const QStringList &_predefinedTokens, QWidget *pa
|
||||||
setWindowTitle(tr("Create token"));
|
setWindowTitle(tr("Create token"));
|
||||||
|
|
||||||
resize(600, 500);
|
resize(600, 500);
|
||||||
restoreGeometry(SettingsCache::instance().getTokenDialogGeometry());
|
restoreGeometry(SettingsCache::instance().layouts().getTokenDialogGeometry());
|
||||||
}
|
}
|
||||||
|
|
||||||
void DlgCreateToken::closeEvent(QCloseEvent *event)
|
void DlgCreateToken::closeEvent(QCloseEvent *event)
|
||||||
{
|
{
|
||||||
event->accept();
|
event->accept();
|
||||||
SettingsCache::instance().setTokenDialogGeometry(saveGeometry());
|
SettingsCache::instance().layouts().setTokenDialogGeometry(saveGeometry());
|
||||||
}
|
}
|
||||||
|
|
||||||
void DlgCreateToken::faceDownCheckBoxToggled(bool checked)
|
void DlgCreateToken::faceDownCheckBoxToggled(bool checked)
|
||||||
|
|
@ -225,13 +225,13 @@ void DlgCreateToken::actChooseTokenFromDeck(bool checked)
|
||||||
|
|
||||||
void DlgCreateToken::actOk()
|
void DlgCreateToken::actOk()
|
||||||
{
|
{
|
||||||
SettingsCache::instance().setTokenDialogGeometry(saveGeometry());
|
SettingsCache::instance().layouts().setTokenDialogGeometry(saveGeometry());
|
||||||
accept();
|
accept();
|
||||||
}
|
}
|
||||||
|
|
||||||
void DlgCreateToken::actReject()
|
void DlgCreateToken::actReject()
|
||||||
{
|
{
|
||||||
SettingsCache::instance().setTokenDialogGeometry(saveGeometry());
|
SettingsCache::instance().layouts().setTokenDialogGeometry(saveGeometry());
|
||||||
reject();
|
reject();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -189,11 +189,11 @@ WndSets::WndSets(QWidget *parent) : QMainWindow(parent)
|
||||||
|
|
||||||
setWindowTitle(tr("Manage sets"));
|
setWindowTitle(tr("Manage sets"));
|
||||||
setMinimumSize(800, 500);
|
setMinimumSize(800, 500);
|
||||||
auto &geometry = SettingsCache::instance().getSetsDialogGeometry();
|
auto geometry = SettingsCache::instance().layouts().getSetsDialogGeometry();
|
||||||
if (!geometry.isEmpty()) {
|
if (!geometry.isEmpty()) {
|
||||||
restoreGeometry(geometry);
|
restoreGeometry(geometry);
|
||||||
}
|
}
|
||||||
auto &headerState = SettingsCache::instance().layouts().getSetsDialogHeaderState();
|
auto headerState = SettingsCache::instance().layouts().getSetsDialogHeaderState();
|
||||||
if (!headerState.isEmpty()) {
|
if (!headerState.isEmpty()) {
|
||||||
view->header()->restoreState(headerState);
|
view->header()->restoreState(headerState);
|
||||||
view->header()->setSortIndicator(SORT_RESET, Qt::DescendingOrder);
|
view->header()->setSortIndicator(SORT_RESET, Qt::DescendingOrder);
|
||||||
|
|
@ -209,7 +209,7 @@ WndSets::~WndSets()
|
||||||
|
|
||||||
void WndSets::closeEvent(QCloseEvent * /*ev*/)
|
void WndSets::closeEvent(QCloseEvent * /*ev*/)
|
||||||
{
|
{
|
||||||
SettingsCache::instance().setSetsDialogGeometry(saveGeometry());
|
SettingsCache::instance().layouts().setSetsDialogGeometry(saveGeometry());
|
||||||
}
|
}
|
||||||
|
|
||||||
void WndSets::saveHeaderState()
|
void WndSets::saveHeaderState()
|
||||||
|
|
|
||||||
|
|
@ -879,7 +879,7 @@ MainWindow::MainWindow(QWidget *parent)
|
||||||
|
|
||||||
retranslateUi();
|
retranslateUi();
|
||||||
|
|
||||||
if (!restoreGeometry(SettingsCache::instance().getMainWindowGeometry())) {
|
if (!restoreGeometry(SettingsCache::instance().layouts().getMainWindowGeometry())) {
|
||||||
setWindowState(Qt::WindowMaximized);
|
setWindowState(Qt::WindowMaximized);
|
||||||
}
|
}
|
||||||
aFullScreen->setChecked(static_cast<bool>(windowState() & Qt::WindowFullScreen));
|
aFullScreen->setChecked(static_cast<bool>(windowState() & Qt::WindowFullScreen));
|
||||||
|
|
@ -1098,7 +1098,7 @@ void MainWindow::closeEvent(QCloseEvent *event)
|
||||||
tip->close();
|
tip->close();
|
||||||
|
|
||||||
event->accept();
|
event->accept();
|
||||||
SettingsCache::instance().setMainWindowGeometry(saveGeometry());
|
SettingsCache::instance().layouts().setMainWindowGeometry(saveGeometry());
|
||||||
tabSupervisor->deleteLater();
|
tabSupervisor->deleteLater();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,9 +4,11 @@ const static QString STATE_PROP = "state";
|
||||||
const static QString GEOMETRY_PROP = "geometry";
|
const static QString GEOMETRY_PROP = "geometry";
|
||||||
const static QString SIZE_PROP = "widgetSize";
|
const static QString SIZE_PROP = "widgetSize";
|
||||||
|
|
||||||
|
const static QString GROUP_MAIN_WINDOW = "mainWindow";
|
||||||
const static QString GROUP_DECK_EDITOR = "deckEditor";
|
const static QString GROUP_DECK_EDITOR = "deckEditor";
|
||||||
const static QString GROUP_DECK_EDITOR_DB = "deckEditorDb";
|
const static QString GROUP_DECK_EDITOR_DB = "deckEditorDb";
|
||||||
const static QString GROUP_SETS_DIALOG = "setsDialog";
|
const static QString GROUP_SETS_DIALOG = "setsDialog";
|
||||||
|
const static QString GROUP_TOKEN_DIALOG = "tokenDialog";
|
||||||
const static QString GROUP_GAME_PLAY_AREA = "gamePlayArea";
|
const static QString GROUP_GAME_PLAY_AREA = "gamePlayArea";
|
||||||
const static QString GROUP_REPLAY_PLAY_AREA = "replayPlayArea";
|
const static QString GROUP_REPLAY_PLAY_AREA = "replayPlayArea";
|
||||||
|
|
||||||
|
|
@ -15,6 +17,16 @@ LayoutsSettings::LayoutsSettings(const QString &settingPath, QObject *parent)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void LayoutsSettings::setMainWindowGeometry(const QByteArray &value)
|
||||||
|
{
|
||||||
|
setValue(value, GEOMETRY_PROP, GROUP_MAIN_WINDOW);
|
||||||
|
}
|
||||||
|
|
||||||
|
QByteArray LayoutsSettings::getMainWindowGeometry()
|
||||||
|
{
|
||||||
|
return getValue(GEOMETRY_PROP, GROUP_MAIN_WINDOW).toByteArray();
|
||||||
|
}
|
||||||
|
|
||||||
const QByteArray LayoutsSettings::getDeckEditorLayoutState()
|
const QByteArray LayoutsSettings::getDeckEditorLayoutState()
|
||||||
{
|
{
|
||||||
return getValue(STATE_PROP, GROUP_DECK_EDITOR).toByteArray();
|
return getValue(STATE_PROP, GROUP_DECK_EDITOR).toByteArray();
|
||||||
|
|
@ -110,6 +122,26 @@ void LayoutsSettings::setSetsDialogHeaderState(const QByteArray &value)
|
||||||
setValue(value, STATE_PROP, GROUP_SETS_DIALOG, "header");
|
setValue(value, STATE_PROP, GROUP_SETS_DIALOG, "header");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void LayoutsSettings::setSetsDialogGeometry(const QByteArray &value)
|
||||||
|
{
|
||||||
|
setValue(value, GEOMETRY_PROP, GROUP_SETS_DIALOG);
|
||||||
|
}
|
||||||
|
|
||||||
|
QByteArray LayoutsSettings::getSetsDialogGeometry()
|
||||||
|
{
|
||||||
|
return getValue(GEOMETRY_PROP, GROUP_SETS_DIALOG).toByteArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
void LayoutsSettings::setTokenDialogGeometry(const QByteArray &value)
|
||||||
|
{
|
||||||
|
setValue(value, GEOMETRY_PROP, GROUP_TOKEN_DIALOG);
|
||||||
|
}
|
||||||
|
|
||||||
|
QByteArray LayoutsSettings::getTokenDialogGeometry()
|
||||||
|
{
|
||||||
|
return getValue(GEOMETRY_PROP, GROUP_TOKEN_DIALOG).toByteArray();
|
||||||
|
}
|
||||||
|
|
||||||
void LayoutsSettings::setGamePlayAreaGeometry(const QByteArray &value)
|
void LayoutsSettings::setGamePlayAreaGeometry(const QByteArray &value)
|
||||||
{
|
{
|
||||||
setValue(value, GEOMETRY_PROP, GROUP_GAME_PLAY_AREA);
|
setValue(value, GEOMETRY_PROP, GROUP_GAME_PLAY_AREA);
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,8 @@ class LayoutsSettings : public SettingsManager
|
||||||
friend class SettingsCache;
|
friend class SettingsCache;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
void setMainWindowGeometry(const QByteArray &value);
|
||||||
|
|
||||||
void setDeckEditorLayoutState(const QByteArray &value);
|
void setDeckEditorLayoutState(const QByteArray &value);
|
||||||
void setDeckEditorGeometry(const QByteArray &value);
|
void setDeckEditorGeometry(const QByteArray &value);
|
||||||
void setDeckEditorCardDatabaseSize(const QSize &value);
|
void setDeckEditorCardDatabaseSize(const QSize &value);
|
||||||
|
|
@ -26,6 +28,8 @@ public:
|
||||||
void setDeckEditorFilterSize(const QSize &value);
|
void setDeckEditorFilterSize(const QSize &value);
|
||||||
void setDeckEditorDbHeaderState(const QByteArray &value);
|
void setDeckEditorDbHeaderState(const QByteArray &value);
|
||||||
void setSetsDialogHeaderState(const QByteArray &value);
|
void setSetsDialogHeaderState(const QByteArray &value);
|
||||||
|
void setSetsDialogGeometry(const QByteArray &value);
|
||||||
|
void setTokenDialogGeometry(const QByteArray &value);
|
||||||
|
|
||||||
void setGamePlayAreaGeometry(const QByteArray &value);
|
void setGamePlayAreaGeometry(const QByteArray &value);
|
||||||
void setGamePlayAreaState(const QByteArray &value);
|
void setGamePlayAreaState(const QByteArray &value);
|
||||||
|
|
@ -40,6 +44,8 @@ public:
|
||||||
void setReplayPlayerListSize(const QSize &value);
|
void setReplayPlayerListSize(const QSize &value);
|
||||||
void setReplayReplaySize(const QSize &value);
|
void setReplayReplaySize(const QSize &value);
|
||||||
|
|
||||||
|
QByteArray getMainWindowGeometry();
|
||||||
|
|
||||||
const QByteArray getDeckEditorLayoutState();
|
const QByteArray getDeckEditorLayoutState();
|
||||||
const QByteArray getDeckEditorGeometry();
|
const QByteArray getDeckEditorGeometry();
|
||||||
QSize getDeckEditorCardDatabaseSize();
|
QSize getDeckEditorCardDatabaseSize();
|
||||||
|
|
@ -49,6 +55,8 @@ public:
|
||||||
QSize getDeckEditorFilterSize();
|
QSize getDeckEditorFilterSize();
|
||||||
const QByteArray getDeckEditorDbHeaderState();
|
const QByteArray getDeckEditorDbHeaderState();
|
||||||
const QByteArray getSetsDialogHeaderState();
|
const QByteArray getSetsDialogHeaderState();
|
||||||
|
QByteArray getSetsDialogGeometry();
|
||||||
|
QByteArray getTokenDialogGeometry();
|
||||||
|
|
||||||
const QByteArray getGamePlayAreaLayoutState();
|
const QByteArray getGamePlayAreaLayoutState();
|
||||||
const QByteArray getGamePlayAreaGeometry();
|
const QByteArray getGamePlayAreaGeometry();
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue