mirror of
https://github.com/RetroShare/RetroShare.git
synced 2025-06-07 06:02:41 -04:00
Merge pull request #2362 from csoler/v0.6-BugFixing_10
A few fixes in People tab
This commit is contained in:
commit
eee2fe43cf
8 changed files with 193 additions and 108 deletions
|
@ -301,14 +301,35 @@ public:
|
||||||
const std::set<RsGxsId>& gxsIdMembers = std::set<RsGxsId>(),
|
const std::set<RsGxsId>& gxsIdMembers = std::set<RsGxsId>(),
|
||||||
const std::set<RsPgpId>& localMembers = std::set<RsPgpId>() ) = 0;
|
const std::set<RsPgpId>& localMembers = std::set<RsPgpId>() ) = 0;
|
||||||
|
|
||||||
/**
|
// TODO. If so, remove the other editCircle that has the same name, otherwise jsonapi will crash
|
||||||
* @brief Edit own existing circle
|
//
|
||||||
* @jsonapi{development}
|
// /**
|
||||||
* @param[inout] cData Circle data with modifications, storage for data
|
// * @brief Edit an existing circle
|
||||||
* updatedad during the operation.
|
// * @jsonapi{development}
|
||||||
* @return false if something failed, true otherwhise
|
// * @param[in] circleId Optional storage to output created circle id
|
||||||
*/
|
// * @param[in] circleName String containing cirlce name
|
||||||
virtual bool editCircle(RsGxsCircleGroup& cData) = 0;
|
// * @param[in] circleType Circle type
|
||||||
|
// * @param[in] restrictedId Optional id of a pre-existent circle that see the
|
||||||
|
// * created circle. Meaningful only if circleType == EXTERNAL, must be null
|
||||||
|
// * in all other cases.
|
||||||
|
// * @param[in] authorId Optional author of the circle.
|
||||||
|
// * @param[in] gxsIdMembers GXS ids of the members of the circle.
|
||||||
|
// * @param[in] localMembers PGP ids of the members if the circle.
|
||||||
|
// * @return false if something failed, true otherwhise
|
||||||
|
// */
|
||||||
|
// virtual bool editCircle( const RsGxsCircleId& circleId, const std::string& circleName, RsGxsCircleType circleType,
|
||||||
|
// const RsGxsCircleId& restrictedId,
|
||||||
|
// const RsGxsId& authorId, const std::set<RsGxsId>& gxsIdMembers,
|
||||||
|
// const std::set<RsPgpId>& localMembers ) =0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Edit own existing circle
|
||||||
|
* @jsonapi{development}
|
||||||
|
* @param[inout] cData Circle data with modifications, storage for data
|
||||||
|
* updatedad during the operation.
|
||||||
|
* @return false if something failed, true otherwhise
|
||||||
|
*/
|
||||||
|
virtual bool editCircle(RsGxsCircleGroup& cData) = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Get circle details. Memory cached
|
* @brief Get circle details. Memory cached
|
||||||
|
|
|
@ -194,96 +194,111 @@ bool p3GxsCircles::createCircle(
|
||||||
{
|
{
|
||||||
// 1 - Check consistency of the request data
|
// 1 - Check consistency of the request data
|
||||||
|
|
||||||
if(circleName.empty())
|
if(!checkCircleParamConsistency(circleName,circleType,restrictedId,authorId,gxsIdMembers,localMembers))
|
||||||
{
|
{
|
||||||
RsErr() << __PRETTY_FUNCTION__ << " Circle name is empty" << std::endl;
|
RsErr() << __PRETTY_FUNCTION__ << " Circle parameters are inconsistent" << std::endl;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch(circleType)
|
|
||||||
{
|
|
||||||
case RsGxsCircleType::PUBLIC:
|
|
||||||
if(!restrictedId.isNull())
|
|
||||||
{
|
|
||||||
RsErr() << __PRETTY_FUNCTION__ << " restrictedId: " << restrictedId
|
|
||||||
<< " must be null with RsGxsCircleType::PUBLIC"
|
|
||||||
<< std::endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case RsGxsCircleType::EXTERNAL:
|
|
||||||
if(restrictedId.isNull())
|
|
||||||
{
|
|
||||||
RsErr() << __PRETTY_FUNCTION__ << " restrictedId can't be null "
|
|
||||||
<< "with RsGxsCircleType::EXTERNAL" << std::endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case RsGxsCircleType::NODES_GROUP:
|
|
||||||
if(localMembers.empty())
|
|
||||||
{
|
|
||||||
RsErr() << __PRETTY_FUNCTION__ << " localMembers can't be empty "
|
|
||||||
<< "with RsGxsCircleType::NODES_GROUP" << std::endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case RsGxsCircleType::LOCAL:
|
|
||||||
break;
|
|
||||||
case RsGxsCircleType::EXT_SELF:
|
|
||||||
if(!restrictedId.isNull())
|
|
||||||
{
|
|
||||||
RsErr() << __PRETTY_FUNCTION__ << " restrictedId: " << restrictedId
|
|
||||||
<< " must be null with RsGxsCircleType::EXT_SELF"
|
|
||||||
<< std::endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if(gxsIdMembers.empty())
|
|
||||||
{
|
|
||||||
RsErr() << __PRETTY_FUNCTION__ << " gxsIdMembers can't be empty "
|
|
||||||
<< "with RsGxsCircleType::EXT_SELF" << std::endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case RsGxsCircleType::YOUR_EYES_ONLY:
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
RsErr() << __PRETTY_FUNCTION__ << " Invalid circle type: "
|
|
||||||
<< static_cast<uint32_t>(circleType) << std::endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 2 - Create the actual request
|
// 2 - Create the actual request
|
||||||
|
|
||||||
RsGxsCircleGroup cData;
|
RsGxsCircleGroup cData;
|
||||||
cData.mMeta.mGroupName = circleName;
|
cData.mMeta.mGroupName = circleName;
|
||||||
cData.mMeta.mAuthorId = authorId;
|
cData.mMeta.mAuthorId = authorId;
|
||||||
cData.mMeta.mCircleType = static_cast<uint32_t>(circleType);
|
cData.mMeta.mCircleType = static_cast<uint32_t>(circleType);
|
||||||
cData.mMeta.mGroupFlags = GXS_SERV::FLAG_PRIVACY_PUBLIC;
|
cData.mMeta.mGroupFlags = GXS_SERV::FLAG_PRIVACY_PUBLIC;
|
||||||
cData.mMeta.mCircleId = restrictedId;
|
cData.mMeta.mCircleId = restrictedId;
|
||||||
cData.mLocalFriends = localMembers;
|
cData.mMeta.mSignFlags = GXS_SERV::FLAG_GROUP_SIGN_PUBLISH_NONEREQ | GXS_SERV::FLAG_AUTHOR_AUTHENTICATION_REQUIRED;
|
||||||
cData.mInvitedMembers = gxsIdMembers;
|
cData.mLocalFriends = localMembers;
|
||||||
|
cData.mInvitedMembers = gxsIdMembers;
|
||||||
|
|
||||||
|
|
||||||
// 3 - Send it and wait, for a sync response.
|
// 3 - Send it and wait, for a sync response.
|
||||||
|
|
||||||
uint32_t token;
|
uint32_t token;
|
||||||
createGroup(token, cData);
|
createGroup(token, cData);
|
||||||
|
|
||||||
if(waitToken(token) != RsTokenService::COMPLETE)
|
if(waitToken(token) != RsTokenService::COMPLETE)
|
||||||
{
|
{
|
||||||
std::cerr << __PRETTY_FUNCTION__ << "Error! GXS operation failed." << std::endl;
|
std::cerr << __PRETTY_FUNCTION__ << "Error! GXS operation failed." << std::endl;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!RsGenExchange::getPublishedGroupMeta(token, cData.mMeta))
|
if(!RsGenExchange::getPublishedGroupMeta(token, cData.mMeta))
|
||||||
{
|
{
|
||||||
std::cerr << __PRETTY_FUNCTION__ << "Error! Failure getting created" << " group data." << std::endl;
|
std::cerr << __PRETTY_FUNCTION__ << "Error! Failure getting created" << " group data." << std::endl;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
circleId = static_cast<RsGxsCircleId>(cData.mMeta.mGroupId);
|
circleId = static_cast<RsGxsCircleId>(cData.mMeta.mGroupId);
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
bool p3GxsCircles::checkCircleParamConsistency( const std::string& circleName, RsGxsCircleType circleType,
|
||||||
|
const RsGxsCircleId& restrictedId,
|
||||||
|
const RsGxsId& authorId, const std::set<RsGxsId>& gxsIdMembers,
|
||||||
|
const std::set<RsPgpId>& localMembers ) const
|
||||||
|
{
|
||||||
|
if(circleName.empty())
|
||||||
|
{
|
||||||
|
RsErr() << __PRETTY_FUNCTION__ << " Circle name is empty" << std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(circleType)
|
||||||
|
{
|
||||||
|
case RsGxsCircleType::PUBLIC:
|
||||||
|
if(!restrictedId.isNull())
|
||||||
|
{
|
||||||
|
RsErr() << __PRETTY_FUNCTION__ << " restrictedId: " << restrictedId
|
||||||
|
<< " must be null with RsGxsCircleType::PUBLIC"
|
||||||
|
<< std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case RsGxsCircleType::EXTERNAL:
|
||||||
|
if(restrictedId.isNull())
|
||||||
|
{
|
||||||
|
RsErr() << __PRETTY_FUNCTION__ << " restrictedId can't be null "
|
||||||
|
<< "with RsGxsCircleType::EXTERNAL" << std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case RsGxsCircleType::NODES_GROUP:
|
||||||
|
if(localMembers.empty())
|
||||||
|
{
|
||||||
|
RsErr() << __PRETTY_FUNCTION__ << " localMembers can't be empty "
|
||||||
|
<< "with RsGxsCircleType::NODES_GROUP" << std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case RsGxsCircleType::LOCAL:
|
||||||
|
break;
|
||||||
|
case RsGxsCircleType::EXT_SELF:
|
||||||
|
if(!restrictedId.isNull())
|
||||||
|
{
|
||||||
|
RsErr() << __PRETTY_FUNCTION__ << " restrictedId: " << restrictedId
|
||||||
|
<< " must be null with RsGxsCircleType::EXT_SELF"
|
||||||
|
<< std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if(gxsIdMembers.empty())
|
||||||
|
{
|
||||||
|
RsErr() << __PRETTY_FUNCTION__ << " gxsIdMembers can't be empty "
|
||||||
|
<< "with RsGxsCircleType::EXT_SELF" << std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case RsGxsCircleType::YOUR_EYES_ONLY:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
RsErr() << __PRETTY_FUNCTION__ << " Invalid circle type: "
|
||||||
|
<< static_cast<uint32_t>(circleType) << std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool p3GxsCircles::editCircle(RsGxsCircleGroup& cData)
|
bool p3GxsCircles::editCircle(RsGxsCircleGroup& cData)
|
||||||
{
|
{
|
||||||
uint32_t token;
|
uint32_t token;
|
||||||
|
@ -306,6 +321,52 @@ bool p3GxsCircles::editCircle(RsGxsCircleGroup& cData)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool p3GxsCircles::editCircle(const RsGxsCircleId &circleId, const std::string& circleName, RsGxsCircleType circleType, const RsGxsCircleId& restrictedId,
|
||||||
|
const RsGxsId& authorId, const std::set<RsGxsId>& gxsIdMembers,
|
||||||
|
const std::set<RsPgpId>& localMembers )
|
||||||
|
{
|
||||||
|
// 1 - Check consistency of the request data
|
||||||
|
|
||||||
|
if(!checkCircleParamConsistency(circleName,circleType,restrictedId,authorId,gxsIdMembers,localMembers))
|
||||||
|
{
|
||||||
|
RsErr() << __PRETTY_FUNCTION__ << " Circle data is not consistent." << std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2 - Create the actual request
|
||||||
|
|
||||||
|
RsGxsCircleGroup cData;
|
||||||
|
cData.mMeta.mGroupId = RsGxsGroupId(circleId);
|
||||||
|
cData.mMeta.mGroupName = circleName;
|
||||||
|
cData.mMeta.mAuthorId = authorId;
|
||||||
|
cData.mMeta.mCircleType = static_cast<uint32_t>(circleType);
|
||||||
|
cData.mMeta.mGroupFlags = GXS_SERV::FLAG_PRIVACY_PUBLIC;
|
||||||
|
cData.mMeta.mCircleId = restrictedId;
|
||||||
|
cData.mLocalFriends = localMembers;
|
||||||
|
cData.mInvitedMembers = gxsIdMembers;
|
||||||
|
|
||||||
|
// 3 - Send it and wait, for a sync response.
|
||||||
|
|
||||||
|
uint32_t token;
|
||||||
|
updateGroup(token, cData);
|
||||||
|
|
||||||
|
if(waitToken(token) != RsTokenService::COMPLETE)
|
||||||
|
{
|
||||||
|
std::cerr << __PRETTY_FUNCTION__ << "Error! GXS operation failed."
|
||||||
|
<< std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!RsGenExchange::getPublishedGroupMeta(token, cData.mMeta))
|
||||||
|
{
|
||||||
|
std::cerr << __PRETTY_FUNCTION__ << "Error! Failure getting updated"
|
||||||
|
<< " group data." << std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
bool p3GxsCircles::getCirclesSummaries(std::list<RsGroupMetaData>& circles)
|
bool p3GxsCircles::getCirclesSummaries(std::list<RsGroupMetaData>& circles)
|
||||||
{
|
{
|
||||||
uint32_t token;
|
uint32_t token;
|
||||||
|
|
|
@ -227,7 +227,12 @@ public:
|
||||||
const std::set<RsPgpId>& localMembers = std::set<RsPgpId>()
|
const std::set<RsPgpId>& localMembers = std::set<RsPgpId>()
|
||||||
) override;
|
) override;
|
||||||
|
|
||||||
/// @see RsGxsCircles
|
bool editCircle( const RsGxsCircleId& circleId,const std::string& circleName, RsGxsCircleType circleType,
|
||||||
|
const RsGxsCircleId& restrictedId,
|
||||||
|
const RsGxsId& authorId, const std::set<RsGxsId>& gxsIdMembers,
|
||||||
|
const std::set<RsPgpId>& localMembers ) ;
|
||||||
|
|
||||||
|
/// @see RsGxsCircles
|
||||||
bool editCircle(RsGxsCircleGroup& cData) override;
|
bool editCircle(RsGxsCircleGroup& cData) override;
|
||||||
|
|
||||||
/// @see RsGxsCircles
|
/// @see RsGxsCircles
|
||||||
|
@ -303,6 +308,10 @@ public:
|
||||||
virtual void service_tick() override;
|
virtual void service_tick() override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
bool checkCircleParamConsistency( const std::string& circleName, RsGxsCircleType circleType,
|
||||||
|
const RsGxsCircleId& restrictedId,
|
||||||
|
const RsGxsId& authorId, const std::set<RsGxsId>& gxsIdMembers,
|
||||||
|
const std::set<RsPgpId>& localMembers ) const ;
|
||||||
|
|
||||||
// overloads p3Config
|
// overloads p3Config
|
||||||
virtual bool saveList(bool &cleanup, std::list<RsItem *>&saveList) override;
|
virtual bool saveList(bool &cleanup, std::list<RsItem *>&saveList) override;
|
||||||
|
|
|
@ -1139,6 +1139,7 @@ bool p3IdService::updateIdentity( const RsGxsId& id, const std::string& name, co
|
||||||
goto LabelUpdateIdentityCleanup;
|
goto LabelUpdateIdentityCleanup;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
mKeyCache.erase(id);
|
||||||
|
|
||||||
if(!updateGroup(token, group))
|
if(!updateGroup(token, group))
|
||||||
{
|
{
|
||||||
|
@ -1154,6 +1155,9 @@ bool p3IdService::updateIdentity( const RsGxsId& id, const std::string& name, co
|
||||||
goto LabelUpdateIdentityCleanup;
|
goto LabelUpdateIdentityCleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// clean the Identity cache as well
|
||||||
|
cache_request_load(id);
|
||||||
|
|
||||||
LabelUpdateIdentityCleanup:
|
LabelUpdateIdentityCleanup:
|
||||||
if(!pseudonimous && !pgpPassword.empty())
|
if(!pseudonimous && !pgpPassword.empty())
|
||||||
rsNotify->clearPgpPassphrase();
|
rsNotify->clearPgpPassphrase();
|
||||||
|
|
|
@ -449,7 +449,9 @@ void CreateCircleDialog::createCircle()
|
||||||
case GxsIdChooser::KnowId:
|
case GxsIdChooser::KnowId:
|
||||||
case GxsIdChooser::UnKnowId:
|
case GxsIdChooser::UnKnowId:
|
||||||
circle.mMeta.mAuthorId = authorId;
|
circle.mMeta.mAuthorId = authorId;
|
||||||
#ifdef DEBUG_CREATE_CIRCLE_DIALOG
|
circle.mMeta.mAuthenFlags = GXS_SERV::GRP_OPTION_AUTHEN_AUTHOR_SIGN;
|
||||||
|
|
||||||
|
#ifdef DEBUG_CREATE_CIRCLE_DIALOG
|
||||||
std::cerr << "CreateCircleDialog::createCircle() AuthorId: " << authorId;
|
std::cerr << "CreateCircleDialog::createCircle() AuthorId: " << authorId;
|
||||||
std::cerr << std::endl;
|
std::cerr << std::endl;
|
||||||
#endif
|
#endif
|
||||||
|
@ -457,6 +459,8 @@ void CreateCircleDialog::createCircle()
|
||||||
break;
|
break;
|
||||||
case GxsIdChooser::NoId:
|
case GxsIdChooser::NoId:
|
||||||
case GxsIdChooser::None:
|
case GxsIdChooser::None:
|
||||||
|
circle.mMeta.mAuthorId.clear();
|
||||||
|
circle.mMeta.mAuthenFlags = 0;
|
||||||
default: ;
|
default: ;
|
||||||
#ifdef DEBUG_CREATE_CIRCLE_DIALOG
|
#ifdef DEBUG_CREATE_CIRCLE_DIALOG
|
||||||
std::cerr << "CreateCircleDialog::createCircle() No AuthorId Chosen!";
|
std::cerr << "CreateCircleDialog::createCircle() No AuthorId Chosen!";
|
||||||
|
|
|
@ -408,9 +408,7 @@ IdDialog::IdDialog(QWidget *parent)
|
||||||
connect(ui->autoBanIdentities_CB, SIGNAL(toggled(bool)), this, SLOT(toggleAutoBanIdentities(bool)));
|
connect(ui->autoBanIdentities_CB, SIGNAL(toggled(bool)), this, SLOT(toggleAutoBanIdentities(bool)));
|
||||||
|
|
||||||
updateIdTimer.setSingleShot(true);
|
updateIdTimer.setSingleShot(true);
|
||||||
updateCircleTimer.setSingleShot(true);
|
|
||||||
connect(&updateIdTimer, SIGNAL(timeout()), this, SLOT(updateIdList()));
|
connect(&updateIdTimer, SIGNAL(timeout()), this, SLOT(updateIdList()));
|
||||||
connect(&updateCircleTimer, SIGNAL(timeout()), this, SLOT(updateCircles()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void IdDialog::handleEvent_main_thread(std::shared_ptr<const RsEvent> event)
|
void IdDialog::handleEvent_main_thread(std::shared_ptr<const RsEvent> event)
|
||||||
|
@ -429,7 +427,10 @@ void IdDialog::handleEvent_main_thread(std::shared_ptr<const RsEvent> event)
|
||||||
case RsGxsIdentityEventCode::UPDATED_IDENTITY:
|
case RsGxsIdentityEventCode::UPDATED_IDENTITY:
|
||||||
if (isVisible())
|
if (isVisible())
|
||||||
{
|
{
|
||||||
updateIdTimer.start(5000);
|
if(rsIdentity->isOwnId(RsGxsId(e->mIdentityId)))
|
||||||
|
updateIdList();
|
||||||
|
else
|
||||||
|
updateIdTimer.start(3000); // use a timer for events not generated by local changes
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
needUpdateIdsOnNextShow = true;
|
needUpdateIdsOnNextShow = true;
|
||||||
|
@ -460,9 +461,7 @@ void IdDialog::handleEvent_main_thread(std::shared_ptr<const RsEvent> event)
|
||||||
case RsGxsCircleEventCode::CACHE_DATA_UPDATED:
|
case RsGxsCircleEventCode::CACHE_DATA_UPDATED:
|
||||||
|
|
||||||
if (isVisible())
|
if (isVisible())
|
||||||
{
|
updateCircles();
|
||||||
updateCircleTimer.start(5000);
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
needUpdateCirclesOnNextShow = true;
|
needUpdateCirclesOnNextShow = true;
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -154,7 +154,6 @@ private:
|
||||||
RsEventsHandlerId_t mEventHandlerId_circles;
|
RsEventsHandlerId_t mEventHandlerId_circles;
|
||||||
|
|
||||||
QTimer updateIdTimer;
|
QTimer updateIdTimer;
|
||||||
QTimer updateCircleTimer;
|
|
||||||
bool needUpdateIdsOnNextShow;
|
bool needUpdateIdsOnNextShow;
|
||||||
bool needUpdateCirclesOnNextShow;
|
bool needUpdateCirclesOnNextShow;
|
||||||
|
|
||||||
|
|
|
@ -1213,18 +1213,6 @@ NewFriendList QTreeView#peerTreeWidget {
|
||||||
font-size: 12pt;
|
font-size: 12pt;
|
||||||
}
|
}
|
||||||
|
|
||||||
NewFriendList QTreeView::branch:has-children:!has-siblings:closed,
|
|
||||||
NewFriendList QTreeView::branch:closed:has-children:has-siblings {
|
|
||||||
border-image: none;
|
|
||||||
image: url(:/images/arrow-right.png);
|
|
||||||
}
|
|
||||||
|
|
||||||
NewFriendList QTreeView::branch:open:has-children:!has-siblings,
|
|
||||||
NewFriendList QTreeView::branch:open:has-children:has-siblings {
|
|
||||||
border-image: none;
|
|
||||||
image: url(:/images/arrow-down.png);
|
|
||||||
}
|
|
||||||
|
|
||||||
WikiEditDialog QPushButton#pushButton_History {
|
WikiEditDialog QPushButton#pushButton_History {
|
||||||
font: bold;
|
font: bold;
|
||||||
font-size: 15px;
|
font-size: 15px;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue