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 }