File indexing completed on 2024-05-05 05:40:32
0001 #include "network/channelmodel.h" 0002 0003 #include "network/serverconnection.h" 0004 #include "network/treeitem.h" 0005 0006 #include <QIcon> 0007 #include <QJsonArray> 0008 #include <QJsonDocument> 0009 #include <QJsonObject> 0010 #include <QList> 0011 #include <QSettings> 0012 #include <array> 0013 0014 #ifdef QT_WIDGETS_LIB 0015 #include <QApplication> 0016 #include <QFont> 0017 #include <QInputDialog> 0018 #include <QStyle> 0019 #endif 0020 0021 #include "network/channel.h" 0022 #include "network/receiveevent.h" 0023 0024 quint64 computeTotalSize(const std::map<Channel*, quint64>& map) 0025 { 0026 quint64 totalSize= 0; 0027 for(auto pair : map) 0028 { 0029 totalSize+= pair.second; 0030 } 0031 return totalSize; 0032 } 0033 0034 ////////////////////////////////////// 0035 /// ClientMimeData 0036 ///////////////////////////////////// 0037 0038 ClientMimeData::ClientMimeData() 0039 { 0040 setData("application/rolisteam.networkclient.list", QByteArray()); 0041 } 0042 0043 void ClientMimeData::addClient(ServerConnection* m, const QModelIndex index) 0044 { 0045 if(nullptr != m) 0046 { 0047 m_clientList.insert(index, m); 0048 } 0049 } 0050 const QMap<QModelIndex, ServerConnection*>& ClientMimeData::getList() const 0051 { 0052 return m_clientList; 0053 } 0054 bool ClientMimeData::hasFormat(const QString& mimeType) const 0055 { 0056 return ((mimeType == "application/rolisteam.networkclient.list") || QMimeData::hasFormat(mimeType)); 0057 } 0058 0059 ////////////////////////////////////// 0060 /// ChannelModel 0061 ///////////////////////////////////// 0062 0063 ChannelModel::ChannelModel() {} 0064 0065 ChannelModel::~ChannelModel() 0066 { 0067 qDeleteAll(m_root); 0068 std::vector<Channel*> keys; 0069 0070 transform(std::begin(m_sizeMap), std::end(m_sizeMap), back_inserter(keys), 0071 [](decltype(m_sizeMap)::value_type const& pair) { return pair.first; }); 0072 m_sizeMap.clear(); 0073 qDeleteAll(keys); 0074 } 0075 0076 QModelIndex ChannelModel::index(int row, int column, const QModelIndex& parent) const 0077 { 0078 if(row < 0) 0079 return QModelIndex(); 0080 if(column < 0) 0081 return QModelIndex(); 0082 0083 TreeItem* childItem= nullptr; 0084 if(!parent.isValid()) 0085 { 0086 if(m_root.size() > row) 0087 childItem= m_root.at(row); 0088 } 0089 else 0090 { 0091 TreeItem* parentItem= static_cast<TreeItem*>(parent.internalPointer()); 0092 childItem= parentItem->getChildAt(row); 0093 } 0094 0095 if(childItem) 0096 { 0097 return createIndex(row, column, childItem); 0098 } 0099 else 0100 return QModelIndex(); 0101 } 0102 0103 std::pair<quint64, QString> ChannelModel::convert(quint64 size) const 0104 { 0105 constexpr int cap= 1024; 0106 std::size_t i= 0; 0107 std::array<QString, 3> units= {tr("Bytes"), tr("KiB"), tr("MiB")}; 0108 while(size > cap && i < units.size()) 0109 { 0110 size/= cap; 0111 ++i; 0112 } 0113 return std::make_pair(size, units[i]); 0114 } 0115 0116 QVariant ChannelModel::data(const QModelIndex& index, int role) const 0117 { 0118 if(!index.isValid()) 0119 return QVariant(); 0120 0121 TreeItem* tmp= static_cast<TreeItem*>(index.internalPointer()); 0122 if(tmp != nullptr) 0123 { 0124 if((role == Qt::DisplayRole) || (Qt::EditRole == role)) 0125 { 0126 if(!tmp->isLeaf() && role == Qt::DisplayRole) 0127 { 0128 auto channel= dynamic_cast<Channel*>(tmp); 0129 if(nullptr == channel) 0130 return {}; 0131 if(isAdmin(m_localPlayerId) || isGM(m_localPlayerId, channel->uuid())) 0132 { 0133 auto size= channel->memorySize(); 0134 auto pair= convert(size); 0135 return QStringLiteral("%1 (%2 %3)").arg(tmp->name()).arg(pair.first).arg(pair.second); 0136 } 0137 } 0138 return tmp->name(); 0139 } 0140 #ifdef QT_WIDGETS_LIB 0141 else if(role == Qt::FontRole) 0142 { 0143 if(tmp->isLeaf()) 0144 { 0145 auto parent= tmp->getParentItem(); 0146 if(parent) 0147 { 0148 auto channel= dynamic_cast<Channel*>(parent); 0149 if(channel) 0150 { 0151 if(channel->currentGM() == tmp) 0152 { 0153 QFont font; 0154 font.setBold(true); 0155 return font; 0156 } 0157 } 0158 } 0159 } 0160 } 0161 else if(role == Qt::DecorationRole) 0162 { 0163 if(!tmp->isLeaf()) 0164 { 0165 auto channel= dynamic_cast<Channel*>(tmp); 0166 QStyle* style= qApp->style(); 0167 if(nullptr != style && nullptr != channel) 0168 { 0169 if(channel->password().isEmpty()) 0170 return style->standardIcon(QStyle::SP_DirIcon); 0171 else 0172 return style->standardIcon(QStyle::SP_DirClosedIcon); 0173 } 0174 } 0175 } 0176 #endif 0177 } 0178 return QVariant(); 0179 } 0180 0181 bool ChannelModel::setData(const QModelIndex& index, const QVariant& value, int) 0182 { 0183 bool rightToSetName= isAdmin(m_localPlayerId); 0184 if((!rightToSetName && !localIsGM()) || !index.isValid()) 0185 return false; 0186 0187 auto tmp= static_cast<TreeItem*>(index.internalPointer()); 0188 0189 if(nullptr == tmp) 0190 return false; 0191 0192 if(tmp->isLeaf()) 0193 return false; 0194 0195 auto chan= dynamic_cast<Channel*>(tmp); 0196 if(!chan) 0197 return false; 0198 0199 if(isGM(m_localPlayerId, chan->uuid()) && !rightToSetName) 0200 { 0201 rightToSetName= chan->getCurrentGmId() == m_localPlayerId; 0202 } 0203 0204 if(rightToSetName) 0205 { 0206 tmp->setName(value.toString()); 0207 emit channelNameChanged(chan->name(), chan->uuid()); 0208 return true; 0209 } 0210 return false; 0211 } 0212 0213 QModelIndex ChannelModel::parent(const QModelIndex& child) const 0214 { 0215 if(!child.isValid()) 0216 return QModelIndex(); 0217 0218 TreeItem* childItem= static_cast<TreeItem*>(child.internalPointer()); 0219 if(nullptr != childItem) 0220 { 0221 TreeItem* parentItem= childItem->getParentItem(); 0222 0223 if(m_root.contains(childItem)) 0224 { 0225 return QModelIndex(); 0226 } 0227 if(m_root.contains(parentItem)) 0228 { 0229 return createIndex(m_root.indexOf(parentItem), 0, parentItem); 0230 } 0231 return createIndex(parentItem->rowInParent(), 0, parentItem); 0232 } 0233 return QModelIndex(); 0234 } 0235 0236 int ChannelModel::rowCount(const QModelIndex& parent) const 0237 { 0238 int result= 0; 0239 if(!parent.isValid()) 0240 { 0241 result= m_root.size(); 0242 } 0243 else 0244 { 0245 TreeItem* item= static_cast<TreeItem*>(parent.internalPointer()); 0246 if(nullptr != item) 0247 { 0248 result= item->childCount(); 0249 } 0250 } 0251 return result; 0252 } 0253 0254 int ChannelModel::columnCount(const QModelIndex&) const 0255 { 0256 return 1; 0257 } 0258 0259 QString ChannelModel::addChannel(QString name, QByteArray password) 0260 { 0261 Channel* chan= new Channel(name); 0262 chan->setPassword(password); 0263 QModelIndex index; 0264 addChannelToIndex(chan, index); 0265 return chan->uuid(); 0266 } 0267 QModelIndex ChannelModel::addChannelToIndex(Channel* channel, const QModelIndex& parent) 0268 { 0269 int row= -1; 0270 if(!parent.isValid()) 0271 { 0272 beginInsertRows(parent, m_root.size(), m_root.size()); 0273 appendChannel(channel); 0274 endInsertRows(); 0275 row= m_root.size() - 1; 0276 } 0277 else 0278 { 0279 Channel* item= static_cast<Channel*>(parent.internalPointer()); 0280 if(nullptr != item) 0281 { 0282 addChannelToChannel(channel, item); 0283 row= item->childCount() - 1; 0284 } 0285 } 0286 return index(row, 0, parent); 0287 } 0288 bool ChannelModel::addChannelToChannel(Channel* child, Channel* parent) 0289 { 0290 if(child == nullptr) 0291 return false; 0292 0293 bool result= false; 0294 if(nullptr == parent) 0295 { 0296 auto index= addChannelToIndex(child, QModelIndex()); 0297 result= index.isValid(); 0298 } 0299 else 0300 { 0301 QModelIndex index= channelToIndex(parent); 0302 beginInsertRows(index, parent->childCount(), parent->childCount()); 0303 parent->addChild(child); 0304 endInsertRows(); 0305 result= true; 0306 } 0307 return result; 0308 } 0309 0310 void ChannelModel::renameChannel(const QString& senderId, const QString& id, const QString& value) 0311 { 0312 bool right= isAdmin(senderId); 0313 if(!right) 0314 { 0315 right= isGM(senderId, id); 0316 } 0317 if(!right) 0318 return; 0319 0320 auto item= getItemById(id); 0321 if(nullptr == item) 0322 return; 0323 0324 item->setName(value); 0325 } 0326 0327 void ChannelModel::appendChannel(Channel* channel) 0328 { 0329 m_root.append(channel); 0330 connect(channel, &Channel::memorySizeChanged, this, &ChannelModel::modelChanged); 0331 connect(channel, &Channel::lockedChanged, this, &ChannelModel::modelChanged); 0332 connect(channel, &Channel::itemChanged, this, &ChannelModel::modelChanged); 0333 connect(channel, &Channel::nameChanged, this, &ChannelModel::modelChanged); 0334 connect(channel, &Channel::uuidChanged, this, &ChannelModel::modelChanged); 0335 } 0336 0337 QModelIndex ChannelModel::channelToIndex(Channel* channel) 0338 { 0339 QList<TreeItem*> listOfParent; 0340 TreeItem* tmp= channel; 0341 while(nullptr != tmp) 0342 { 0343 listOfParent.prepend(tmp); 0344 tmp= tmp->getParentItem(); 0345 } 0346 QModelIndex parent; 0347 for(auto item : listOfParent) 0348 { 0349 if(nullptr == item->getParentItem()) 0350 { 0351 parent= index(m_root.indexOf(item), 0, parent); 0352 } 0353 else 0354 { 0355 parent= index(item->rowInParent(), 0, parent); 0356 } 0357 } 0358 return parent; 0359 } 0360 0361 void ChannelModel::setLocalPlayerId(const QString& id) 0362 { 0363 m_localPlayerId= id; 0364 } 0365 0366 Qt::ItemFlags ChannelModel::flags(const QModelIndex& index) const 0367 { 0368 if(!index.isValid()) 0369 return Qt::NoItemFlags; 0370 0371 TreeItem* item= static_cast<TreeItem*>(index.internalPointer()); 0372 0373 auto admin= isAdmin(m_localPlayerId); 0374 if(admin && item->isLeaf()) 0375 { 0376 return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDragEnabled; 0377 } 0378 else if(admin && !item->isLeaf()) 0379 { 0380 return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable | Qt::ItemIsDropEnabled; 0381 } 0382 else 0383 { 0384 return Qt::ItemIsEnabled | Qt::ItemIsSelectable; 0385 } 0386 } 0387 bool ChannelModel::hasChildren(const QModelIndex& parent) const 0388 { 0389 if(!parent.isValid()) // root 0390 { 0391 return !m_root.isEmpty(); //==0?false:true; 0392 } 0393 else 0394 { 0395 TreeItem* childItem= static_cast<TreeItem*>(parent.internalPointer()); 0396 if(childItem->childCount() == 0) 0397 return false; 0398 else 0399 return true; 0400 } 0401 } 0402 QStringList ChannelModel::mimeTypes() const 0403 { 0404 QStringList types; 0405 types << "application/rolisteam.networkclient.list"; 0406 return types; 0407 } 0408 Qt::DropActions ChannelModel::supportedDropActions() const 0409 { 0410 return Qt::MoveAction; 0411 } 0412 QMimeData* ChannelModel::mimeData(const QModelIndexList& indexes) const 0413 { 0414 ClientMimeData* mimeData= new ClientMimeData(); 0415 0416 for(const QModelIndex& index : indexes) 0417 { 0418 if((index.isValid()) && (index.column() == 0)) 0419 { 0420 ServerConnection* item= static_cast<ServerConnection*>(index.internalPointer()); 0421 mimeData->addClient(item, index); 0422 } 0423 } 0424 return mimeData; 0425 } 0426 0427 bool ChannelModel::moveMediaItem(QList<ServerConnection*> items, const QModelIndex& parentToBe, int row, 0428 QList<QModelIndex>& formerPosition) 0429 { 0430 Q_UNUSED(row) 0431 Q_UNUSED(formerPosition) 0432 if(!isAdmin(m_localPlayerId)) 0433 return {}; 0434 0435 if(!parentToBe.isValid()) 0436 return {}; 0437 0438 Channel* item= static_cast<Channel*>(parentToBe.internalPointer()); 0439 QString id= item->uuid(); 0440 0441 QByteArray pw; 0442 #ifdef QT_WIDGETS_LIB 0443 qDebug() << "password:"<<item->password().size() << item->password(); 0444 if(!item->password().isEmpty()) 0445 { 0446 pw= QInputDialog::getText(nullptr, tr("Channel Password"), 0447 tr("Channel %1 required password:").arg(item->name()), QLineEdit::Password) 0448 .toUtf8() 0449 .toBase64(); 0450 } 0451 #endif 0452 0453 for(auto client : items) 0454 { 0455 if(id.isEmpty()) 0456 continue; 0457 0458 NetworkMessageWriter msg(NetMsg::AdministrationCategory, NetMsg::JoinChannel); 0459 msg.string8(id); 0460 msg.string8(client->uuid()); 0461 msg.byteArray32(pw); 0462 msg.sendToServer(); 0463 0464 } 0465 return true; 0466 } 0467 bool ChannelModel::dropMimeData(const QMimeData* data, Qt::DropAction action, int row, int column, 0468 const QModelIndex& parent) 0469 { 0470 Q_UNUSED(column); 0471 0472 if(action == Qt::IgnoreAction) 0473 return false; 0474 0475 bool added= false; 0476 0477 if(data->hasFormat("application/rolisteam.networkclient.list")) 0478 { 0479 const ClientMimeData* clientData= qobject_cast<const ClientMimeData*>(data); 0480 0481 if(nullptr != clientData) 0482 { 0483 QList<ServerConnection*> clientList= clientData->getList().values(); 0484 QList<QModelIndex> indexList= clientData->getList().keys(); 0485 { 0486 if(action == Qt::MoveAction) 0487 { 0488 added= moveMediaItem(clientList, parent, row, indexList); 0489 } 0490 } 0491 } 0492 } 0493 return added; 0494 } 0495 bool ChannelModel::addConnectionToDefaultChannel(ServerConnection* client) 0496 { 0497 if(m_defaultChannel.isEmpty()) 0498 { 0499 qDebug() << "call addConnectionToDefaultChannel while channel is empty"; 0500 if(!m_root.isEmpty()) 0501 { 0502 auto item= m_root.at(0); 0503 if(nullptr != item) 0504 { 0505 m_defaultChannel= item->uuid(); 0506 } 0507 } 0508 else 0509 { 0510 return false; 0511 } 0512 } 0513 0514 return addConnectionToChannel(m_defaultChannel, client); 0515 } 0516 0517 bool ChannelModel::addConnectionToChannel(QString chanId, ServerConnection* client) 0518 { 0519 bool found= false; 0520 for(auto& item : m_root) 0521 { 0522 if(nullptr != item && !found) 0523 { 0524 found= item->addChildInto(chanId, client); 0525 } 0526 } 0527 return found; 0528 } 0529 0530 bool ChannelModel::moveClient(Channel* origin, const QString& id, Channel* dest) 0531 { 0532 if(nullptr == dest || nullptr == origin) 0533 return false; 0534 0535 auto sourceParent= channelToIndex(origin); 0536 auto client= origin->getClientById(id); 0537 auto indxSource= origin->indexOf(client); 0538 auto destParent= channelToIndex(dest); 0539 auto indexDest= dest->childCount(); 0540 0541 if(!sourceParent.isValid() || !destParent.isValid()) 0542 return false; 0543 0544 beginMoveRows(sourceParent, indxSource, indxSource, destParent, indexDest); 0545 origin->removeChild(client); 0546 dest->addChild(client); 0547 endMoveRows(); 0548 return true; 0549 } 0550 0551 const QList<TreeItem*>& ChannelModel::modelData() 0552 { 0553 return m_root; 0554 } 0555 0556 void ChannelModel::resetData(QList<TreeItem*> data) 0557 { 0558 qDeleteAll(m_root); 0559 m_root.clear(); 0560 beginResetModel(); 0561 m_root= data; 0562 endResetModel(); 0563 } 0564 0565 void ChannelModel::kick(const QString& id, bool isAdmin, const QString& senderId) 0566 { 0567 for(auto& item : m_root) 0568 { 0569 if(nullptr == item) 0570 continue; 0571 0572 item->kick(id, isAdmin, senderId); 0573 } 0574 } 0575 0576 bool ChannelModel::isAdmin(const QString& id) const 0577 { 0578 auto player= getServerConnectionById(id); 0579 if(nullptr == player) 0580 return false; 0581 return player->isAdmin(); 0582 } 0583 0584 bool ChannelModel::isGM(const QString& id, const QString& chanId) const 0585 { 0586 auto player= getServerConnectionById(id); 0587 auto item= getItemById(chanId); 0588 if(nullptr == player || item == nullptr) 0589 return false; 0590 0591 auto chan= dynamic_cast<Channel*>(item); 0592 if(nullptr == chan) 0593 return false; 0594 0595 return chan->currentGM() == player; 0596 } 0597 0598 TreeItem* ChannelModel::getItemById(QString id) const 0599 { 0600 for(auto& item : m_root) 0601 { 0602 if(nullptr != item) 0603 { 0604 if(item->uuid() == id) 0605 { 0606 return item; 0607 } 0608 else 0609 { 0610 TreeItem* child= item->getChildById(id); 0611 if(nullptr != child) 0612 { 0613 return child; 0614 } 0615 } 0616 } 0617 } 0618 return nullptr; 0619 } 0620 0621 ServerConnection* ChannelModel::getServerConnectionById(QString id) const 0622 { 0623 ServerConnection* client= nullptr; 0624 for(auto& item : m_root) 0625 { 0626 if(nullptr == item) 0627 continue; 0628 0629 if(!item->isLeaf()) 0630 { 0631 auto channel= dynamic_cast<Channel*>(item); 0632 if(nullptr != channel) 0633 { 0634 client= channel->getClientById(id); 0635 } 0636 } 0637 0638 if(nullptr != client) 0639 break; 0640 } 0641 return client; 0642 } 0643 0644 void ChannelModel::removeChild(QString id) 0645 { 0646 auto item= getItemById(id); 0647 if(nullptr == item) //&&(!item->isLeaf()) 0648 return; 0649 0650 auto parent= item->getParentItem(); 0651 if(nullptr != parent) 0652 { 0653 Channel* channel= dynamic_cast<Channel*>(parent); 0654 if(nullptr != channel) 0655 { 0656 QModelIndex index= channelToIndex(channel); 0657 beginRemoveRows(index, channel->indexOf(item), channel->indexOf(item)); 0658 channel->removeChild(item); 0659 endRemoveRows(); 0660 } 0661 } 0662 else 0663 { 0664 QModelIndex index; 0665 beginRemoveRows(index, m_root.indexOf(item), m_root.indexOf(item)); 0666 m_root.removeAll(item); 0667 endRemoveRows(); 0668 } 0669 } 0670 void ChannelModel::cleanUp() 0671 { 0672 beginResetModel(); 0673 qDeleteAll(m_root); 0674 m_root.clear(); 0675 endResetModel(); 0676 } 0677 void ChannelModel::setChannelMemorySize(Channel* chan, quint64 size) 0678 { 0679 if(m_shield) 0680 return; 0681 m_sizeMap[chan]= size; 0682 0683 emit totalSizeChanged(computeTotalSize(m_sizeMap)); 0684 } 0685 0686 void ChannelModel::emptyChannelMemory() 0687 { 0688 m_shield= true; 0689 for(auto pair : m_sizeMap) 0690 { 0691 QMetaObject::invokeMethod(pair.first, "clearData", Qt::QueuedConnection); 0692 pair.second= 0; 0693 } 0694 m_shield= false; 0695 } 0696 bool ChannelModel::localIsGM() const 0697 { 0698 auto local= getServerConnectionById(m_localPlayerId); 0699 if(local == nullptr) 0700 return false; 0701 0702 return local->isGM(); 0703 }