added load/save of default nickname, plus some debugging

git-svn-id: http://svn.code.sf.net/p/retroshare/code/branches/v0.5-ChatLobby@4737 b45a01b8-16f6-495d-af2f-9b41ad6348cc
This commit is contained in:
csoler 2011-12-26 22:43:54 +00:00
parent 9b79d70fa8
commit cc57ab2462
11 changed files with 211 additions and 51 deletions

View File

@ -238,6 +238,8 @@ virtual void getPendingChatLobbyInvites(std::list<ChatLobbyInvite>& invites) = 0
virtual void unsubscribeChatLobby(const ChatLobbyId& lobby_id) = 0; virtual void unsubscribeChatLobby(const ChatLobbyId& lobby_id) = 0;
virtual bool setNickNameForChatLobby(const ChatLobbyId& lobby_id,const std::string& nick) = 0; virtual bool setNickNameForChatLobby(const ChatLobbyId& lobby_id,const std::string& nick) = 0;
virtual bool getNickNameForChatLobby(const ChatLobbyId& lobby_id,std::string& nick) = 0 ; virtual bool getNickNameForChatLobby(const ChatLobbyId& lobby_id,std::string& nick) = 0 ;
virtual bool setDefaultNickNameForChatLobby(const std::string& nick) = 0;
virtual bool getDefaultNickNameForChatLobby(std::string& nick) = 0 ;
virtual ChatLobbyId createChatLobby(const std::string& lobby_name,const std::list<std::string>& invited_friends) = 0 ; virtual ChatLobbyId createChatLobby(const std::string& lobby_name,const std::list<std::string>& invited_friends) = 0 ;
/****************************************/ /****************************************/

View File

@ -281,6 +281,15 @@ void p3Msgs::unsubscribeChatLobby(const ChatLobbyId& lobby_id)
{ {
mChatSrv->unsubscribeChatLobby(lobby_id) ; mChatSrv->unsubscribeChatLobby(lobby_id) ;
} }
bool p3Msgs::setDefaultNickNameForChatLobby(const std::string& nick)
{
return mChatSrv->setDefaultNickNameForChatLobby(nick) ;
}
bool p3Msgs::getDefaultNickNameForChatLobby(std::string& nick_name)
{
return mChatSrv->getDefaultNickNameForChatLobby(nick_name) ;
}
bool p3Msgs::setNickNameForChatLobby(const ChatLobbyId& lobby_id,const std::string& nick) bool p3Msgs::setNickNameForChatLobby(const ChatLobbyId& lobby_id,const std::string& nick)
{ {
return mChatSrv->setNickNameForChatLobby(lobby_id,nick) ; return mChatSrv->setNickNameForChatLobby(lobby_id,nick) ;

View File

@ -178,6 +178,8 @@ class p3Msgs: public RsMsgs
virtual void unsubscribeChatLobby(const ChatLobbyId& lobby_id) ; virtual void unsubscribeChatLobby(const ChatLobbyId& lobby_id) ;
virtual bool setNickNameForChatLobby(const ChatLobbyId& lobby_id,const std::string&) ; virtual bool setNickNameForChatLobby(const ChatLobbyId& lobby_id,const std::string&) ;
virtual bool getNickNameForChatLobby(const ChatLobbyId&,std::string& nick) ; virtual bool getNickNameForChatLobby(const ChatLobbyId&,std::string& nick) ;
virtual bool setDefaultNickNameForChatLobby(const std::string&) ;
virtual bool getDefaultNickNameForChatLobby(std::string& nick) ;
virtual ChatLobbyId createChatLobby(const std::string& lobby_name,const std::list<std::string>& invited_friends) ; virtual ChatLobbyId createChatLobby(const std::string& lobby_name,const std::list<std::string>& invited_friends) ;
private: private:

View File

@ -34,18 +34,16 @@
#include "pqi/p3historymgr.h" #include "pqi/p3historymgr.h"
#include "services/p3chatservice.h" #include "services/p3chatservice.h"
#include "serialiser/rsconfigitems.h"
/**** /****
* #define CHAT_DEBUG 1 * #define CHAT_DEBUG 1
****/ ****/
/************ NOTE ********************************* static const int CONNECTION_CHALLENGE_MAX_COUNT = 15 ; // sends a connexion challenge every 15 messages
* This Service is so simple that there is no static const int LOBBY_CACHE_CLEANING_PERIOD = 10 ; // sends a connexion challenge every 15 messages
* mutex protection required! static const time_t MAX_KEEP_MSG_RECORD = 240 ; // keep msg record for 240 secs max.
*
*/
static const int CONNECTION_CHALLENGE_MAX_COUNT = 10 ; // sends a connexion challenge every 10 messages
p3ChatService::p3ChatService(p3LinkMgr *lm, p3HistoryMgr *historyMgr) p3ChatService::p3ChatService(p3LinkMgr *lm, p3HistoryMgr *historyMgr)
:p3Service(RS_SERVICE_TYPE_CHAT), p3Config(CONFIG_TYPE_CHAT), mChatMtx("p3ChatService"), mLinkMgr(lm) , mHistoryMgr(historyMgr) :p3Service(RS_SERVICE_TYPE_CHAT), p3Config(CONFIG_TYPE_CHAT), mChatMtx("p3ChatService"), mLinkMgr(lm) , mHistoryMgr(historyMgr)
@ -63,6 +61,15 @@ int p3ChatService::tick()
receiveChatQueue(); receiveChatQueue();
} }
static time_t last_clean_time = 0 ;
time_t now = time(NULL) ;
if(last_clean_time + LOBBY_CACHE_CLEANING_PERIOD < now)
{
cleanLobbyCaches() ;
last_clean_time = now ;
}
return 0; return 0;
} }
@ -1168,6 +1175,16 @@ bool p3ChatService::loadList(std::list<RsItem*>& load)
continue; continue;
} }
RsConfigKeyValueSet *vitem = NULL ;
if(NULL != (vitem = dynamic_cast<RsConfigKeyValueSet*>(*it)))
for(std::list<RsTlvKeyValue>::const_iterator kit = vitem->tlvkvs.pairs.begin(); kit != vitem->tlvkvs.pairs.end(); ++kit)
if(kit->key == "DEFAULT_NICK_NAME")
{
std::cerr << "Loaded config default nick name for chat: " << kit->value << std::endl ;
_default_nick_name = kit->value ;
}
// delete unknown items // delete unknown items
delete *it; delete *it;
} }
@ -1217,6 +1234,14 @@ bool p3ChatService::saveList(bool& cleanup, std::list<RsItem*>& list)
list.push_back(ci); list.push_back(ci);
} }
RsConfigKeyValueSet *vitem = new RsConfigKeyValueSet ;
RsTlvKeyValue kv;
kv.key = "DEFAULT_NICK_NAME" ;
kv.value = _default_nick_name ;
vitem->tlvkvs.pairs.push_back(kv) ;
list.push_back(vitem) ;
return true; return true;
} }
@ -1230,6 +1255,7 @@ RsSerialiser *p3ChatService::setupSerialiser()
{ {
RsSerialiser *rss = new RsSerialiser ; RsSerialiser *rss = new RsSerialiser ;
rss->addSerialType(new RsChatSerialiser) ; rss->addSerialType(new RsChatSerialiser) ;
rss->addSerialType(new RsGeneralConfigSerialiser());
return rss ; return rss ;
} }
@ -1412,7 +1438,7 @@ void p3ChatService::handleConnectionChallenge(RsChatLobbyConnectChallengeItem *i
{ {
RsStackMutex stack(mChatMtx); /********** STACK LOCKED MTX ******/ RsStackMutex stack(mChatMtx); /********** STACK LOCKED MTX ******/
for(std::map<ChatLobbyId,ChatLobbyEntry>::const_iterator it(_chat_lobbys.begin());it!=_chat_lobbys.end() && !found;++it) for(std::map<ChatLobbyId,ChatLobbyEntry>::iterator it(_chat_lobbys.begin());it!=_chat_lobbys.end() && !found;++it)
for(std::map<ChatLobbyMsgId,time_t>::const_iterator it2(it->second.msg_cache.begin());it2!=it->second.msg_cache.end() && !found;++it2) for(std::map<ChatLobbyMsgId,time_t>::const_iterator it2(it->second.msg_cache.begin());it2!=it->second.msg_cache.end() && !found;++it2)
{ {
uint64_t code = makeConnexionChallengeCode(it->first,it2->first) ; uint64_t code = makeConnexionChallengeCode(it->first,it2->first) ;
@ -1425,11 +1451,14 @@ void p3ChatService::handleConnectionChallenge(RsChatLobbyConnectChallengeItem *i
lobby_id = it->first ; lobby_id = it->first ;
found = true ; found = true ;
// also add the peer to the list of participating friends
it->second.participating_friends.insert(item->PeerId()) ;
} }
} }
} }
if(found) if(found) // send invitation. As the peer already has the lobby, the invitation will most likely be accepted.
invitePeerToLobby(lobby_id, item->PeerId()) ; invitePeerToLobby(lobby_id, item->PeerId()) ;
else else
std::cerr << " Challenge denied: no existing cached msg has matching Id." << std::endl; std::cerr << " Challenge denied: no existing cached msg has matching Id." << std::endl;
@ -1520,10 +1549,6 @@ void p3ChatService::invitePeerToLobby(const ChatLobbyId& lobby_id, const std::st
item->PeerId(peer_id) ; item->PeerId(peer_id) ;
sendItem(item) ; sendItem(item) ;
// Adds the invitation into the invitation cache.
//
it->second.invitations_sent[peer_id] = time(NULL) ;
} }
void p3ChatService::handleRecvLobbyInvite(RsChatLobbyInviteItem *item) void p3ChatService::handleRecvLobbyInvite(RsChatLobbyInviteItem *item)
{ {
@ -1692,6 +1717,17 @@ void p3ChatService::unsubscribeChatLobby(const ChatLobbyId& id)
// send a lobby leaving packet. To be implemented. // send a lobby leaving packet. To be implemented.
} }
bool p3ChatService::setDefaultNickNameForChatLobby(const std::string& nick)
{
_default_nick_name = nick;
IndicateConfigChanged() ;
return true ;
}
bool p3ChatService::getDefaultNickNameForChatLobby(std::string& nick)
{
nick = _default_nick_name ;
return true ;
}
bool p3ChatService::getNickNameForChatLobby(const ChatLobbyId& lobby_id,std::string& nick) bool p3ChatService::getNickNameForChatLobby(const ChatLobbyId& lobby_id,std::string& nick)
{ {
RsStackMutex stack(mChatMtx); /********** STACK LOCKED MTX ******/ RsStackMutex stack(mChatMtx); /********** STACK LOCKED MTX ******/
@ -1726,3 +1762,27 @@ bool p3ChatService::setNickNameForChatLobby(const ChatLobbyId& lobby_id,const st
return true ; return true ;
} }
void p3ChatService::cleanLobbyCaches()
{
std::cerr << "Cleaning chat lobby caches." << std::endl;
RsStackMutex stack(mChatMtx); /********** STACK LOCKED MTX ******/
time_t now = time(NULL) ;
for(std::map<ChatLobbyId,ChatLobbyEntry>::iterator it = _chat_lobbys.begin();it!=_chat_lobbys.end();++it)
for(std::map<ChatLobbyMsgId,time_t>::iterator it2(it->second.msg_cache.begin());it2!=it->second.msg_cache.end();)
if(it2->second + MAX_KEEP_MSG_RECORD < now)
{
std::cerr << " removing old msg 0x" << std::hex << it2->first << ", time=" << std::dec << it2->second << std::endl;
std::map<ChatLobbyMsgId,time_t>::iterator tmp(it2) ;
++tmp ;
it->second.msg_cache.erase(it2) ;
it2 = tmp ;
}
else
++it2 ;
}

View File

@ -160,9 +160,11 @@ class p3ChatService: public p3Service, public p3Config, public pqiMonitor
void denyLobbyInvite(const ChatLobbyId& id) ; void denyLobbyInvite(const ChatLobbyId& id) ;
void getPendingChatLobbyInvites(std::list<ChatLobbyInvite>& invites) ; void getPendingChatLobbyInvites(std::list<ChatLobbyInvite>& invites) ;
void invitePeerToLobby(const ChatLobbyId&, const std::string&) ; void invitePeerToLobby(const ChatLobbyId&, const std::string&) ;
bool setNickNameForChatLobby(const ChatLobbyId& lobby_id,const std::string& nick) ;
void unsubscribeChatLobby(const ChatLobbyId& lobby_id) ; void unsubscribeChatLobby(const ChatLobbyId& lobby_id) ;
bool setNickNameForChatLobby(const ChatLobbyId& lobby_id,const std::string& nick) ;
bool getNickNameForChatLobby(const ChatLobbyId& lobby_id,std::string& nick) ; bool getNickNameForChatLobby(const ChatLobbyId& lobby_id,std::string& nick) ;
bool setDefaultNickNameForChatLobby(const std::string& nick) ;
bool getDefaultNickNameForChatLobby(std::string& nick) ;
ChatLobbyId createChatLobby(const std::string& lobby_name,const std::list<std::string>& invited_friends) ; ChatLobbyId createChatLobby(const std::string& lobby_name,const std::list<std::string>& invited_friends) ;
protected: protected:
@ -217,6 +219,7 @@ class p3ChatService: public p3Service, public p3Config, public pqiMonitor
void checkAndRedirectMsgToLobby(RsChatMsgItem*) ; void checkAndRedirectMsgToLobby(RsChatMsgItem*) ;
void handleConnectionChallenge(RsChatLobbyConnectChallengeItem *item) ; void handleConnectionChallenge(RsChatLobbyConnectChallengeItem *item) ;
void sendConnectionChallenge(ChatLobbyId id) ; void sendConnectionChallenge(ChatLobbyId id) ;
void cleanLobbyCaches() ;
static std::string makeVirtualPeerId(ChatLobbyId) ; static std::string makeVirtualPeerId(ChatLobbyId) ;
static uint64_t makeConnexionChallengeCode(ChatLobbyId lobby_id,ChatLobbyMsgId msg_id) ; static uint64_t makeConnexionChallengeCode(ChatLobbyId lobby_id,ChatLobbyMsgId msg_id) ;
@ -243,11 +246,7 @@ class p3ChatService: public p3Service, public p3Config, public pqiMonitor
{ {
public: public:
std::map<ChatLobbyMsgId,time_t> msg_cache ; std::map<ChatLobbyMsgId,time_t> msg_cache ;
std::map<std::string,time_t> invitations_sent ;
std::string virtual_peer_id ; std::string virtual_peer_id ;
static const time_t MAX_KEEP_MSG_RECORD = 240 ; // keep msg record for 240 secs max.
void cleanCache() ;
int connexion_challenge_count ; int connexion_challenge_count ;
}; };

View File

@ -53,6 +53,8 @@ ChatLobbyDialog::ChatLobbyDialog(const std::string& dialog_id,const ChatLobbyId&
ui.avatarWidget->hide() ; ui.avatarWidget->hide() ;
PopupChatDialog::updateStatus(QString::fromStdString(getPeerId()),RS_STATUS_ONLINE) ; PopupChatDialog::updateStatus(QString::fromStdString(getPeerId()),RS_STATUS_ONLINE) ;
QObject::connect(this,SIGNAL(close()),this,SLOT(closeAndAsk())) ;
} }
/** Destructor. */ /** Destructor. */
@ -63,6 +65,15 @@ ChatLobbyDialog::~ChatLobbyDialog()
rsMsgs->unsubscribeChatLobby(lobby_id) ; rsMsgs->unsubscribeChatLobby(lobby_id) ;
} }
void ChatLobbyDialog::closeEvent(QCloseEvent* e)
{
std::cerr << "In close event!" << std::endl;
if(QMessageBox::Yes == QMessageBox::question(NULL,tr("Unsubsribe to lobby?"),tr("Do you want to unsubscribe to this chat lobby?"),QMessageBox::Yes, QMessageBox::No))
rsMsgs->unsubscribeChatLobby(lobby_id) ;
PopupChatDialog::closeEvent(e) ;
}
void ChatLobbyDialog::setNickName(const QString& nick) void ChatLobbyDialog::setNickName(const QString& nick)
{ {
rsMsgs->setNickNameForChatLobby(lobby_id,nick.toStdString()) ; rsMsgs->setNickNameForChatLobby(lobby_id,nick.toStdString()) ;

View File

@ -55,6 +55,7 @@ class ChatLobbyDialog: public PopupChatDialog
// The following methods are differentfrom those of the parent: // The following methods are differentfrom those of the parent:
// //
virtual void updateStatus(const QString &peer_id, int status) ; // needs grouped status. Not yet implemented. virtual void updateStatus(const QString &peer_id, int status) ; // needs grouped status. Not yet implemented.
virtual void closeEvent(QCloseEvent*) ;
protected slots: protected slots:
void setNickName(const QString&) ; void setNickName(const QString&) ;

View File

@ -36,8 +36,12 @@ CreateLobbyDialog::CreateLobbyDialog(const std::list<std::string>& peer_list,QWi
ui = new Ui::CreateLobbyDialog() ; ui = new Ui::CreateLobbyDialog() ;
ui->setupUi(this); ui->setupUi(this);
std::string default_nick ;
rsMsgs->getDefaultNickNameForChatLobby(default_nick) ;
ui->lobbyName_LE->setPlaceholderText(tr("Put a sensible lobby name here")) ; ui->lobbyName_LE->setPlaceholderText(tr("Put a sensible lobby name here")) ;
ui->nickName_LE->setPlaceholderText(tr("Your nickname")) ; ui->nickName_LE->setPlaceholderText(tr("Your nickname for this lobby")) ;
ui->nickName_LE->setText(QString::fromStdString(default_nick)) ;
connect( ui->shareButton, SIGNAL( clicked ( bool ) ), this, SLOT( createLobby( ) ) ); connect( ui->shareButton, SIGNAL( clicked ( bool ) ), this, SLOT( createLobby( ) ) );
connect( ui->cancelButton, SIGNAL( clicked ( bool ) ), this, SLOT( cancel( ) ) ); connect( ui->cancelButton, SIGNAL( clicked ( bool ) ), this, SLOT( cancel( ) ) );
@ -99,6 +103,10 @@ void CreateLobbyDialog::createLobby()
std::cerr << "gui: Created chat lobby " << std::hex << id << std::endl ; std::cerr << "gui: Created chat lobby " << std::hex << id << std::endl ;
// set nick name !
rsMsgs->setNickNameForChatLobby(id,ui->nickName_LE->text().toStdString()) ;
// open chat window !! // open chat window !!
std::string vpid ; std::string vpid ;

View File

@ -280,12 +280,19 @@ void PopupChatDialog::processSettings(bool bLoad)
} }
else if (rsMsgs->isLobbyId(id, lobby_id)) else if (rsMsgs->isLobbyId(id, lobby_id))
{ {
popupchatdialog = new ChatLobbyDialog(id,lobby_id,QString::fromStdString(id)); std::list<ChatLobbyInfo> linfos;
chatDialogs[id] = popupchatdialog; rsMsgs->getChatLobbyList(linfos) ;
PopupChatWindow *window = PopupChatWindow::getWindow(false); for(std::list<ChatLobbyInfo>::const_iterator it(linfos.begin());it!=linfos.end();++it)
window->addDialog(popupchatdialog); if( (*it).lobby_id == lobby_id)
} {
popupchatdialog = new ChatLobbyDialog(id,lobby_id,QString::fromStdString((*it).lobby_name));
chatDialogs[id] = popupchatdialog;
PopupChatWindow *window = PopupChatWindow::getWindow(false);
window->addDialog(popupchatdialog);
}
}
} }
} }

View File

@ -28,6 +28,7 @@
#include "rsharesettings.h" #include "rsharesettings.h"
#include <retroshare/rshistory.h> #include <retroshare/rshistory.h>
#include <retroshare/rsmsgs.h>
#define VARIANT_STANDARD "Standard" #define VARIANT_STANDARD "Standard"
@ -115,6 +116,8 @@ ChatPage::save(QString &/*errmsg*/)
rsHistory->setSaveCount(true, ui.publicChatSaveCount->value()); rsHistory->setSaveCount(true, ui.publicChatSaveCount->value());
rsHistory->setSaveCount(false, ui.privateChatSaveCount->value()); rsHistory->setSaveCount(false, ui.privateChatSaveCount->value());
rsMsgs->setDefaultNickNameForChatLobby(ui.chatLobbyNick_LE->text().toStdString()) ;
ChatStyleInfo info; ChatStyleInfo info;
QListWidgetItem *item = ui.publicList->currentItem(); QListWidgetItem *item = ui.publicList->currentItem();
if (item) { if (item) {
@ -175,6 +178,10 @@ ChatPage::load()
publicStylePath = loadStyleInfo(ChatStyle::TYPE_PUBLIC, ui.publicList, ui.publicComboBoxVariant, publicStyleVariant); publicStylePath = loadStyleInfo(ChatStyle::TYPE_PUBLIC, ui.publicList, ui.publicComboBoxVariant, publicStyleVariant);
privateStylePath = loadStyleInfo(ChatStyle::TYPE_PRIVATE, ui.privateList, ui.privateComboBoxVariant, privateStyleVariant); privateStylePath = loadStyleInfo(ChatStyle::TYPE_PRIVATE, ui.privateList, ui.privateComboBoxVariant, privateStyleVariant);
historyStylePath = loadStyleInfo(ChatStyle::TYPE_HISTORY, ui.historyList, ui.historyComboBoxVariant, historyStyleVariant); historyStylePath = loadStyleInfo(ChatStyle::TYPE_HISTORY, ui.historyList, ui.historyComboBoxVariant, historyStyleVariant);
std::string nick ;
rsMsgs->getDefaultNickNameForChatLobby(nick) ;
ui.chatLobbyNick_LE->setText(QString::fromStdString(nick)) ;
} }
void ChatPage::on_pushButtonChangeChatFont_clicked() void ChatPage::on_pushButtonChangeChatFont_clicked()

View File

@ -521,35 +521,89 @@
<property name="title"> <property name="title">
<string>Chat Settings</string> <string>Chat Settings</string>
</property> </property>
<layout class="QGridLayout" name="gridLayout_4"> <layout class="QHBoxLayout" name="horizontalLayout_3">
<item row="0" column="0"> <item>
<widget class="QCheckBox" name="checkBox_emoteprivchat"> <layout class="QVBoxLayout" name="verticalLayout_3">
<property name="text"> <item>
<string>Enable Emoticons Privat Chat</string> <widget class="QCheckBox" name="checkBox_emoteprivchat">
</property> <property name="text">
<property name="checked"> <string>Enable Emoticons Privat Chat</string>
<bool>true</bool> </property>
</property> <property name="checked">
</widget> <bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="checkBox_emotegroupchat">
<property name="text">
<string>Enable Emoticons Group Chat</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="sendMessageWithCtrlReturn">
<property name="text">
<string>Send message with Ctrl+Return</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Default nickname for chat lobbies:</string>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Maximum</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLineEdit" name="chatLobbyNick_LE">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
</layout>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</item> </item>
<item row="1" column="0"> <item>
<widget class="QCheckBox" name="checkBox_emotegroupchat">
<property name="text">
<string>Enable Emoticons Group Chat</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QCheckBox" name="sendMessageWithCtrlReturn">
<property name="text">
<string>Send message with Ctrl+Return</string>
</property>
</widget>
</item>
<item row="0" column="1" rowspan="4">
<widget class="QGroupBox" name="groupBoxIRCColors"> <widget class="QGroupBox" name="groupBoxIRCColors">
<property name="maximumSize"> <property name="maximumSize">
<size> <size>