mirror of
https://github.com/RetroShare/RetroShare.git
synced 2025-12-23 12:23:19 -05:00
reworked settings
now there is only one global object for loading and saving settings RshareSettings *Settings; the class RSettings can be used too, but it is not prefered, because the default settings has no affect git-svn-id: http://svn.code.sf.net/p/retroshare/code/trunk@2964 b45a01b8-16f6-495d-af2f-9b41ad6348cc
This commit is contained in:
parent
e68e6b54ef
commit
6baf56285b
39 changed files with 336 additions and 390 deletions
|
|
@ -69,10 +69,9 @@ AppearancePage::save(QString &errmsg)
|
|||
QString languageCode =
|
||||
LanguageSupport::languageCode(ui.cmboLanguage->currentText());
|
||||
|
||||
RshareSettings settings;
|
||||
settings.setLanguageCode(languageCode);
|
||||
settings.setInterfaceStyle(ui.cmboStyle->currentText());
|
||||
settings.setSheetName(ui.styleSheetCombo->currentText());
|
||||
Settings->setLanguageCode(languageCode);
|
||||
Settings->setInterfaceStyle(ui.cmboStyle->currentText());
|
||||
Settings->setSheetName(ui.styleSheetCombo->currentText());
|
||||
|
||||
/* Set to new style */
|
||||
Rshare::setStyle(ui.cmboStyle->currentText());
|
||||
|
|
@ -85,21 +84,19 @@ AppearancePage::save(QString &errmsg)
|
|||
void
|
||||
AppearancePage::load()
|
||||
{
|
||||
RshareSettings settings;
|
||||
|
||||
int index = ui.cmboLanguage->findData(settings.getLanguageCode());
|
||||
int index = ui.cmboLanguage->findData(Settings->getLanguageCode());
|
||||
ui.cmboLanguage->setCurrentIndex(index);
|
||||
|
||||
index = ui.cmboStyle->findData(Rshare::style().toLower());
|
||||
ui.cmboStyle->setCurrentIndex(index);
|
||||
|
||||
ui.styleSheetCombo->setCurrentIndex(ui.styleSheetCombo->findText(settings.getSheetName()));
|
||||
ui.styleSheetCombo->setCurrentIndex(ui.styleSheetCombo->findText(Settings->getSheetName()));
|
||||
|
||||
/** load saved internal styleSheet **/
|
||||
//QFile file(":/qss/" + (settings.getSheetName().toLower()) + ".qss");
|
||||
|
||||
/** load saved extern Stylesheets **/
|
||||
QFile file(QApplication::applicationDirPath() + "/qss/" + (settings.getSheetName().toLower()) + ".qss");
|
||||
QFile file(QApplication::applicationDirPath() + "/qss/" + (Settings->getSheetName().toLower()) + ".qss");
|
||||
|
||||
file.open(QFile::ReadOnly);
|
||||
QString styleSheet = QLatin1String(file.readAll());
|
||||
|
|
|
|||
|
|
@ -22,13 +22,13 @@
|
|||
#include "rsiface/rspeers.h" //for rsPeers variable
|
||||
#include "rsiface/rsiface.h"
|
||||
|
||||
#include "rsharesettings.h"
|
||||
|
||||
#include <QtGui>
|
||||
|
||||
#include <rshare.h>
|
||||
#include "ChatPage.h"
|
||||
|
||||
#include "rsettings.h"
|
||||
|
||||
/** Constructor */
|
||||
ChatPage::ChatPage(QWidget * parent, Qt::WFlags flags)
|
||||
: ConfigPage(parent, flags)
|
||||
|
|
@ -52,12 +52,14 @@ ChatPage::closeEvent (QCloseEvent * event)
|
|||
bool
|
||||
ChatPage::save(QString &errmsg)
|
||||
{
|
||||
RSettings settings(QString("Chat"));
|
||||
Settings->beginGroup(QString("Chat"));
|
||||
|
||||
settings.setValue(QString::fromUtf8("Emoteicons_PrivatChat"), emotePrivatChat());
|
||||
settings.setValue(QString::fromUtf8("Emoteicons_GroupChat"), emoteGroupChat());
|
||||
settings.setValue(QString::fromUtf8("GroupChat_History"), groupchatHistory());
|
||||
settings.setValue(QString::fromUtf8("ChatScreenFont"), fontTempChat.toString());
|
||||
Settings->setValue(QString::fromUtf8("Emoteicons_PrivatChat"), emotePrivatChat());
|
||||
Settings->setValue(QString::fromUtf8("Emoteicons_GroupChat"), emoteGroupChat());
|
||||
Settings->setValue(QString::fromUtf8("GroupChat_History"), groupchatHistory());
|
||||
Settings->setValue(QString::fromUtf8("ChatScreenFont"), fontTempChat.toString());
|
||||
|
||||
Settings->endGroup();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
@ -66,14 +68,16 @@ ChatPage::save(QString &errmsg)
|
|||
void
|
||||
ChatPage::load()
|
||||
{
|
||||
RSettings settings(QString("Chat"));
|
||||
Settings->beginGroup(QString("Chat"));
|
||||
|
||||
ui.checkBox_emoteprivchat->setChecked(settings.value(QString::fromUtf8("Emoteicons_PrivatChat"), true).toBool());
|
||||
ui.checkBox_emotegroupchat->setChecked(settings.value(QString::fromUtf8("Emoteicons_GroupChat"), true).toBool());
|
||||
ui.checkBox_groupchathistory->setChecked(settings.value(QString::fromUtf8("GroupChat_History"), true).toBool());
|
||||
ui.checkBox_emoteprivchat->setChecked(Settings->value(QString::fromUtf8("Emoteicons_PrivatChat"), true).toBool());
|
||||
ui.checkBox_emotegroupchat->setChecked(Settings->value(QString::fromUtf8("Emoteicons_GroupChat"), true).toBool());
|
||||
ui.checkBox_groupchathistory->setChecked(Settings->value(QString::fromUtf8("GroupChat_History"), true).toBool());
|
||||
|
||||
fontTempChat.fromString(Settings->value(QString::fromUtf8("ChatScreenFont")).toString());
|
||||
|
||||
Settings->endGroup();
|
||||
|
||||
fontTempChat.fromString(settings.value(QString::fromUtf8("ChatScreenFont")).toString());
|
||||
|
||||
ui.labelChatFontPreview->setText(fontTempChat.rawName());
|
||||
ui.labelChatFontPreview->setFont(fontTempChat);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -166,12 +166,8 @@ FileAssociationsPage::save (QString &errmsg)
|
|||
void
|
||||
FileAssociationsPage::load()
|
||||
{
|
||||
RshareSettings settings;
|
||||
// QSettings* settings = new QSettings( qApp->applicationDirPath()+"/sett.ini",
|
||||
// QSettings::IniFormat);
|
||||
//
|
||||
// settings.beginGroup("FileAssotiations");
|
||||
QStringList keys = settings.allKeys();
|
||||
// Settings->beginGroup("FileAssotiations");
|
||||
QStringList keys = Settings->allKeys();
|
||||
|
||||
table->setRowCount( keys.count() );
|
||||
|
||||
|
|
@ -179,7 +175,7 @@ FileAssociationsPage::load()
|
|||
QStringList::const_iterator ki;
|
||||
for(ki=keys.constBegin(); ki!=keys.constEnd(); ki++)
|
||||
{
|
||||
QString val = (settings.value(*ki, "")).toString();
|
||||
QString val = (Settings->value(*ki, "")).toString();
|
||||
|
||||
addNewItemToTable( rowi, 0, *ki );
|
||||
addNewItemToTable( rowi, 1, val );
|
||||
|
|
@ -187,7 +183,6 @@ FileAssociationsPage::load()
|
|||
rowi++;
|
||||
}
|
||||
|
||||
//delete settings;
|
||||
if (keys.count()==0)
|
||||
{
|
||||
removeAction->setEnabled(false);
|
||||
|
|
@ -206,8 +201,7 @@ FileAssociationsPage::remove()
|
|||
QTableWidgetItem const * titem = table->item( currentRow,0);
|
||||
QString key = (titem->data(QTableWidgetItem::Type)).toString();
|
||||
|
||||
RshareSettings settings;
|
||||
settings.remove(key);
|
||||
Settings->remove(key);
|
||||
table->removeRow( currentRow );
|
||||
|
||||
if ( table->rowCount()==0 )
|
||||
|
|
@ -235,8 +229,7 @@ FileAssociationsPage::addnew()
|
|||
QString currCmd = afad.resultCommand() ;
|
||||
|
||||
|
||||
RshareSettings settings;
|
||||
if ( !settings.contains(currType) )//new item should be added only if
|
||||
if ( !Settings->contains(currType) )//new item should be added only if
|
||||
{ // it wasn't entered before.
|
||||
int nridx = table->rowCount();//new row index
|
||||
table->setRowCount(nridx+1);
|
||||
|
|
@ -257,7 +250,7 @@ FileAssociationsPage::addnew()
|
|||
}
|
||||
}
|
||||
|
||||
settings.setValue(currType, currCmd);
|
||||
Settings->setValue(currType, currCmd);
|
||||
|
||||
removeAction->setEnabled(true);
|
||||
editAction->setEnabled(true);
|
||||
|
|
@ -290,8 +283,7 @@ FileAssociationsPage::edit()
|
|||
|
||||
titem->setData(QTableWidgetItem::Type, currCmd);
|
||||
|
||||
RshareSettings settings;
|
||||
settings.setValue(currType, currCmd);
|
||||
Settings->setValue(currType, currCmd);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -55,14 +55,13 @@ GeneralPage::~GeneralPage()
|
|||
bool
|
||||
GeneralPage::save(QString &errmsg)
|
||||
{
|
||||
RshareSettings settings;
|
||||
settings.setValue(QString::fromUtf8("StartMinimized"), startMinimized());
|
||||
Settings->setValue(QString::fromUtf8("StartMinimized"), startMinimized());
|
||||
|
||||
settings.setValue(QString::fromUtf8("doQuit"), quit());
|
||||
Settings->setValue(QString::fromUtf8("doQuit"), quit());
|
||||
|
||||
settings.setValue(QString::fromUtf8("ClosetoTray"), closetoTray());
|
||||
Settings->setValue(QString::fromUtf8("ClosetoTray"), closetoTray());
|
||||
|
||||
settings.setRunRetroshareOnBoot(
|
||||
Settings->setRunRetroshareOnBoot(
|
||||
ui.chkRunRetroshareAtSystemStartup->isChecked());
|
||||
|
||||
return true;
|
||||
|
|
@ -72,14 +71,13 @@ GeneralPage::save(QString &errmsg)
|
|||
void
|
||||
GeneralPage::load()
|
||||
{
|
||||
RshareSettings settings;
|
||||
ui.chkRunRetroshareAtSystemStartup->setChecked(settings.runRetroshareOnBoot());
|
||||
ui.chkRunRetroshareAtSystemStartup->setChecked(Settings->runRetroshareOnBoot());
|
||||
|
||||
ui.checkStartMinimized->setChecked(settings.value(QString::fromUtf8("StartMinimized"), false).toBool());
|
||||
ui.checkStartMinimized->setChecked(Settings->value(QString::fromUtf8("StartMinimized"), false).toBool());
|
||||
|
||||
ui.checkQuit->setChecked(settings.value(QString::fromUtf8("doQuit"), false).toBool());
|
||||
ui.checkQuit->setChecked(Settings->value(QString::fromUtf8("doQuit"), false).toBool());
|
||||
|
||||
ui.checkClosetoTray->setChecked(settings.value(QString::fromUtf8("ClosetoTray"), false).toBool());
|
||||
ui.checkClosetoTray->setChecked(Settings->value(QString::fromUtf8("ClosetoTray"), false).toBool());
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -104,8 +102,7 @@ bool GeneralPage::closetoTray() const {
|
|||
void
|
||||
GeneralPage::toggleShowOnStartup(bool checked)
|
||||
{
|
||||
RshareSettings settings;
|
||||
settings.setShowMainWindowAtStart(checked);
|
||||
Settings->setShowMainWindowAtStart(checked);
|
||||
}
|
||||
|
||||
void GeneralPage::setAutoLogin(){
|
||||
|
|
|
|||
|
|
@ -108,10 +108,9 @@ NotifyPage::save(QString &errmsg)
|
|||
if (ui.chat_Focus->isChecked())
|
||||
chatflags |= RS_CHAT_FOCUS;
|
||||
|
||||
RshareSettings settings;
|
||||
settings.setNotifyFlags(notifyflags);
|
||||
settings.setNewsFeedFlags(newsflags);
|
||||
settings.setChatFlags(chatflags);
|
||||
Settings->setNotifyFlags(notifyflags);
|
||||
Settings->setNewsFeedFlags(newsflags);
|
||||
Settings->setChatFlags(chatflags);
|
||||
|
||||
load();
|
||||
return true;
|
||||
|
|
@ -122,11 +121,9 @@ NotifyPage::save(QString &errmsg)
|
|||
void NotifyPage::load()
|
||||
{
|
||||
/* extract from rsNotify the flags */
|
||||
RshareSettings settings;
|
||||
|
||||
uint notifyflags = settings.getNotifyFlags();
|
||||
uint newsflags = settings.getNewsFeedFlags();
|
||||
uint chatflags = settings.getChatFlags();
|
||||
uint notifyflags = Settings->getNotifyFlags();
|
||||
uint newsflags = Settings->getNewsFeedFlags();
|
||||
uint chatflags = Settings->getChatFlags();
|
||||
|
||||
ui.popup_Connect->setChecked(notifyflags & RS_POPUP_CONNECT);
|
||||
ui.popup_NewMsg->setChecked(notifyflags & RS_POPUP_MSG);
|
||||
|
|
|
|||
|
|
@ -56,25 +56,24 @@ SoundPage::~SoundPage()
|
|||
bool
|
||||
SoundPage::save(QString &errmsg)
|
||||
{
|
||||
RshareSettings settings;
|
||||
settings.beginGroup("Sound");
|
||||
settings.beginGroup("Enable");
|
||||
settings.setValue("User_go_Online",ui.checkBoxSound->isChecked());
|
||||
Settings->beginGroup("Sound");
|
||||
Settings->beginGroup("Enable");
|
||||
Settings->setValue("User_go_Online",ui.checkBoxSound->isChecked());
|
||||
//settings.setValue("User_go_Offline",ui.checkBoxSound_2->isChecked());
|
||||
settings.setValue("FileSend_Finished",ui.checkBoxSound_3->isChecked());
|
||||
settings.setValue("FileRecive_Incoming",ui.checkBoxSound_4->isChecked());
|
||||
settings.setValue("FileRecive_Finished",ui.checkBoxSound_5->isChecked());
|
||||
settings.setValue("NewChatMessage",ui.checkBoxSound_6->isChecked());
|
||||
settings.endGroup();
|
||||
settings.beginGroup("SoundFilePath");
|
||||
settings.setValue("User_go_Online",ui.txt_SoundFile->text());
|
||||
Settings->setValue("FileSend_Finished",ui.checkBoxSound_3->isChecked());
|
||||
Settings->setValue("FileRecive_Incoming",ui.checkBoxSound_4->isChecked());
|
||||
Settings->setValue("FileRecive_Finished",ui.checkBoxSound_5->isChecked());
|
||||
Settings->setValue("NewChatMessage",ui.checkBoxSound_6->isChecked());
|
||||
Settings->endGroup();
|
||||
Settings->beginGroup("SoundFilePath");
|
||||
Settings->setValue("User_go_Online",ui.txt_SoundFile->text());
|
||||
//settings.setValue("User_go_Offline",ui.txt_SoundFile2->text());
|
||||
settings.setValue("FileSend_Finished",ui.txt_SoundFile3->text());
|
||||
settings.setValue("FileRecive_Incoming",ui.txt_SoundFile4->text());
|
||||
settings.setValue("FileRecive_Finished",ui.txt_SoundFile5->text());
|
||||
settings.setValue("NewChatMessage",ui.txt_SoundFile6->text());
|
||||
settings.endGroup();
|
||||
settings.endGroup();
|
||||
Settings->setValue("FileSend_Finished",ui.txt_SoundFile3->text());
|
||||
Settings->setValue("FileRecive_Incoming",ui.txt_SoundFile4->text());
|
||||
Settings->setValue("FileRecive_Finished",ui.txt_SoundFile5->text());
|
||||
Settings->setValue("NewChatMessage",ui.txt_SoundFile6->text());
|
||||
Settings->endGroup();
|
||||
Settings->endGroup();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
@ -85,15 +84,14 @@ SoundPage::save(QString &errmsg)
|
|||
void
|
||||
SoundPage::load()
|
||||
{
|
||||
RshareSettings settings;
|
||||
settings.beginGroup("Sound");
|
||||
settings.beginGroup("SoundFilePath");
|
||||
ui.txt_SoundFile->setText(settings.value("User_go_Online","").toString());
|
||||
Settings->beginGroup("Sound");
|
||||
Settings->beginGroup("SoundFilePath");
|
||||
ui.txt_SoundFile->setText(Settings->value("User_go_Online","").toString());
|
||||
//ui.txt_SoundFile2->setText(settings.value("User_go_Offline","").toString());
|
||||
ui.txt_SoundFile3->setText(settings.value("FileSend_Finished","").toString());
|
||||
ui.txt_SoundFile4->setText(settings.value("FileRecive_Incoming","").toString());
|
||||
ui.txt_SoundFile5->setText(settings.value("FileRecive_Finished","").toString());
|
||||
ui.txt_SoundFile6->setText(settings.value("NewChatMessage","").toString());
|
||||
ui.txt_SoundFile3->setText(Settings->value("FileSend_Finished","").toString());
|
||||
ui.txt_SoundFile4->setText(Settings->value("FileRecive_Incoming","").toString());
|
||||
ui.txt_SoundFile5->setText(Settings->value("FileRecive_Finished","").toString());
|
||||
ui.txt_SoundFile6->setText(Settings->value("NewChatMessage","").toString());
|
||||
|
||||
if(!ui.txt_SoundFile->text().isEmpty())ui.checkBoxSound->setEnabled(true);
|
||||
//if(!ui.txt_SoundFile2->text().isEmpty())ui.checkBoxSound_2->setEnabled(true);
|
||||
|
|
@ -102,17 +100,17 @@ SoundPage::load()
|
|||
if(!ui.txt_SoundFile5->text().isEmpty())ui.checkBoxSound_5->setEnabled(true);
|
||||
if(!ui.txt_SoundFile6->text().isEmpty())ui.checkBoxSound_6->setEnabled(true);
|
||||
|
||||
settings.endGroup();
|
||||
Settings->endGroup();
|
||||
|
||||
settings.beginGroup("Enable");
|
||||
ui.checkBoxSound->setChecked(settings.value("User_go_Online",false).toBool());
|
||||
Settings->beginGroup("Enable");
|
||||
ui.checkBoxSound->setChecked(Settings->value("User_go_Online",false).toBool());
|
||||
//ui.checkBoxSound_2->setChecked(settings.value("User_go_Offline",false).toBool());
|
||||
ui.checkBoxSound_3->setChecked(settings.value("FileSend_Finished",false).toBool());
|
||||
ui.checkBoxSound_4->setChecked(settings.value("FileRecive_Incoming",false).toBool());
|
||||
ui.checkBoxSound_5->setChecked(settings.value("FileRecive_Finished",false).toBool());
|
||||
ui.checkBoxSound_6->setChecked(settings.value("NewChatMessage",false).toBool());
|
||||
settings.endGroup();
|
||||
settings.endGroup();
|
||||
ui.checkBoxSound_3->setChecked(Settings->value("FileSend_Finished",false).toBool());
|
||||
ui.checkBoxSound_4->setChecked(Settings->value("FileRecive_Incoming",false).toBool());
|
||||
ui.checkBoxSound_5->setChecked(Settings->value("FileRecive_Finished",false).toBool());
|
||||
ui.checkBoxSound_6->setChecked(Settings->value("NewChatMessage",false).toBool());
|
||||
Settings->endGroup();
|
||||
Settings->endGroup();
|
||||
}
|
||||
|
||||
void SoundPage::on_cmd_openFile()
|
||||
|
|
|
|||
|
|
@ -64,6 +64,22 @@ RSettings::setValue(const QString &key, const QVariant &val)
|
|||
QSettings::setValue(key, val);
|
||||
}
|
||||
|
||||
QVariant RSettings::valueFromGroup(const QString &group, const QString &key, const QVariant &defaultVal)
|
||||
{
|
||||
beginGroup(group);
|
||||
QVariant val = value(key, defaultVal);
|
||||
endGroup();
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
void RSettings::setValueToGroup(const QString &group, const QString &key, const QVariant &val)
|
||||
{
|
||||
beginGroup(group);
|
||||
setValue(key, val);
|
||||
endGroup();
|
||||
}
|
||||
|
||||
/** Sets the default setting for <b>key</b> to <b>val</b>. */
|
||||
void
|
||||
RSettings::setDefault(const QString &key, const QVariant &val)
|
||||
|
|
|
|||
|
|
@ -54,6 +54,10 @@ public:
|
|||
/** Sets the value associated with <b>key</b> to <b>val</b>. */
|
||||
virtual void setValue(const QString &key, const QVariant &val);
|
||||
|
||||
virtual QVariant valueFromGroup(const QString &group, const QString &key,
|
||||
const QVariant &defaultVal = QVariant());
|
||||
virtual void setValueToGroup(const QString &group, const QString &key, const QVariant &val);
|
||||
|
||||
protected:
|
||||
/** Sets the default setting for <b>key</b> to <b>val</b>. */
|
||||
void setDefault(const QString &key, const QVariant &val);
|
||||
|
|
|
|||
|
|
@ -69,8 +69,14 @@
|
|||
#define DEFAULT_BWGRAPH_FILTER (BWGRAPH_SEND|BWGRAPH_REC)
|
||||
#define DEFAULT_BWGRAPH_ALWAYS_ON_TOP false
|
||||
|
||||
RshareSettings::RshareSettings(std::string filename) : RSettings(filename) {
|
||||
initSettings();
|
||||
// the one and only global settings object
|
||||
RshareSettings *Settings = NULL;
|
||||
|
||||
/*static*/ void RshareSettings::Create ()
|
||||
{
|
||||
if (Settings == NULL) {
|
||||
Settings = new RshareSettings ();
|
||||
}
|
||||
}
|
||||
|
||||
/** Default Constructor */
|
||||
|
|
|
|||
|
|
@ -48,13 +48,8 @@ class RshareSettings : public RSettings
|
|||
{
|
||||
|
||||
public:
|
||||
/** Default constructor. */
|
||||
RshareSettings();
|
||||
|
||||
/** Default constructor. */
|
||||
RshareSettings(std::string filename);
|
||||
|
||||
void initSettings();
|
||||
/* create settings object */
|
||||
static void Create ();
|
||||
|
||||
/** Gets the currently preferred language code for RShare. */
|
||||
QString getLanguageCode();
|
||||
|
|
@ -119,22 +114,27 @@ public:
|
|||
uint getNotifyFlags();
|
||||
void setNotifyFlags(uint flags);
|
||||
|
||||
//! Save placement, state and size information of a window.
|
||||
void saveWidgetInformation(QWidget *widget);
|
||||
|
||||
//! Save placement, state and size information of a window.
|
||||
void saveWidgetInformation(QWidget *widget);
|
||||
|
||||
//! Load placement, state and size information of a window.
|
||||
void loadWidgetInformation(QWidget *widget);
|
||||
|
||||
//! Method overload. Save window and toolbar information.
|
||||
void saveWidgetInformation(QMainWindow *widget, QToolBar *toolBar);
|
||||
//! Load placement, state and size information of a window.
|
||||
void loadWidgetInformation(QWidget *widget);
|
||||
|
||||
//! Method overload. Restore window and toolbar information.
|
||||
void loadWidgetInformation(QMainWindow *widget, QToolBar *toolBar);
|
||||
//! Method overload. Save window and toolbar information.
|
||||
void saveWidgetInformation(QMainWindow *widget, QToolBar *toolBar);
|
||||
|
||||
//! Method overload. Restore window and toolbar information.
|
||||
void loadWidgetInformation(QMainWindow *widget, QToolBar *toolBar);
|
||||
|
||||
protected:
|
||||
/** Default constructor. */
|
||||
RshareSettings();
|
||||
|
||||
void initSettings();
|
||||
};
|
||||
|
||||
// the one and only global settings object
|
||||
extern RshareSettings *Settings;
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue