#include "runepagelist.h" #include "ui_runepagelist.h" #include #include #include #include #include #include "clipboardpopup.h" #include "runeeditor.h" RunePageList::RunePageList(QWidget* parent) : QListWidget(parent), ui(new Ui::RunePageList) { ui->setupUi(this); QObject::connect(this, &QListWidget::itemChanged, this, &RunePageList::itemChangedCallback); QObject::connect(this, &QListWidget::customContextMenuRequested, this, &RunePageList::openContextMenu); } RunePageList::~RunePageList() { delete this->ui; } void RunePageList::loadRunePages(const std::vector& pages) { clearItems(); for(const ClientAPI::RunePage& rp : pages) { addRunepageItem(rp.name, rp.id, rp.runepage, rp.isCurrent); } } void RunePageList::loadRunePages(const std::vector>& pages) { clearItems(); for(size_t i = 0; i < pages.size(); ++i) { std::shared_ptr rp = pages.at(i); addRunepageItem(rp->name, i, rp->runepage); } } void RunePageList::setRuneInfos(const std::vector& runeInfo, const std::vector& runeStyles) { this->runeInfo = &runeInfo; this->runeStyles = &runeStyles; } void RunePageList::dropEvent(QDropEvent* event) { if(event->source() == nullptr || event->source() != other) { event->ignore(); return; } auto selected = other->selectedItems(); if(selected.size() != 1) { event->ignore(); return; } QListWidgetItem* item = selected.at(0); // compare rune pages for duplicates? // QListWidget::dropEvent(event); // save change QString name = item->text(); const RunePage* oldPage = (RunePage*) item->data(RolePointer).toULongLong(); emit runepageChanged(-1, name, *oldPage); } void RunePageList::itemChangedCallback(QListWidgetItem* item) { int pageId = item->data(RunePageList::RoleId).toUInt(); QString newName = item->text(); const ::RunePage* page = (::RunePage*) item->data(RunePageList::RolePointer).toULongLong(); emit runepageChanged(pageId, newName, *page); } void RunePageList::openContextMenu(const QPoint& pos) { QPoint globalPos = mapToGlobal(pos); QMenu menu; menu.addAction(QIcon(":/icons/edit.svg"), RunePageList::tr("Edit (Beta)"), this, &RunePageList::editCurrentItem); menu.addAction(QIcon(":/icons/duplicate.svg"), RunePageList::tr("Duplicate"), this, &RunePageList::duplicateCurrentItem); menu.addAction(QIcon(":/icons/export.svg"), RunePageList::tr("Export"), this, &RunePageList::exportCurrentItem); menu.addAction(QIcon(":/icons/import.svg"), RunePageList::tr("Import"), this, &RunePageList::importItem); menu.addAction(QIcon(":/icons/delete.svg"), RunePageList::tr("Delete"), this, &RunePageList::deleteCurrentItem); menu.exec(globalPos); } void RunePageList::deleteCurrentItem() { QListWidgetItem* item = currentItem(); if (item) { uint32_t id = item->data(RoleId).toUInt(); RunePage* page = (RunePage*) item->data(RolePointer).toULongLong(); removeItemWidget(item); delete item; delete page; emit runepageDeleted(id); } } void RunePageList::editCurrentItem() { QListWidgetItem* item = currentItem(); if(!item) return; RunePage* rp = (RunePage*) item->data(RolePointer).toULongLong(); const uint32_t id = item->data(RoleId).toUInt(); RuneEditor re; re.setName(item->text()); re.setClient(*client); re.setRunepage(*rp); int result = re.exec(); // check result - save if(result == QDialog::Accepted) { // update config emit runepageChanged(id, re.getName(), re.getRunepage()); } } void RunePageList::duplicateCurrentItem() { QListWidgetItem* item = currentItem(); if(!item) return; const RunePage* rp = (RunePage*) item->data(RolePointer).toULongLong(); QString name = item->text(); static const QRegularExpression regex(".*(\\d)+$"); QRegularExpressionMatchIterator regexIt = regex.globalMatch(name); int num = 0; if(regexIt.hasNext()) { QRegularExpressionMatch match = regexIt.next(); QStringRef ref = match.capturedRef(1); name.chop(ref.size()); num = ref.toInt(); } name += QString::number(num+1); emit runepageChanged(-1, name, *rp); } void RunePageList::exportCurrentItem() { QListWidgetItem* item = currentItem(); if(!item) return; const RunePage* rp = (RunePage*) item->data(RolePointer).toULongLong(); Config::RunePageConfig rpc; rpc.name = item->text(); rpc.runepage = *rp; QJsonDocument rpcDoc(rpc); // cast to QJsonObject QByteArray jsonBytes = rpcDoc.toJson(QJsonDocument::Compact).toBase64(); QString runePageString = QString::fromLocal8Bit(jsonBytes); ClipboardPopup popup(ClipboardPopup::Direction::Copy); popup.setText(runePageString); popup.exec(); } void RunePageList::importItem() { ClipboardPopup popup(ClipboardPopup::Direction::Paste); if(popup.exec() != QDialog::Accepted) { return; } QString text = popup.getText(); QByteArray jsonBytes = QByteArray::fromBase64(text.toLocal8Bit()); QJsonDocument rpcDoc = QJsonDocument::fromJson(jsonBytes); if(rpcDoc.isObject()) { QJsonObject rpcJson = rpcDoc.object(); Config::RunePageConfig rpc = rpcJson; // implicit cast if(rpc.name.isEmpty() || !rpc.runepage) { // invalid return; } emit runepageChanged(-1, rpc.name, rpc.runepage); } } void RunePageList::clearItems() { while(count()) { QListWidgetItem* item = takeItem(0); delete (RunePage*) item->data(RolePointer).toULongLong(); delete item; } clear(); } void RunePageList::addRunepageItem(QString name, int id, const ::RunePage& rp, bool isCurrent) { QListWidgetItem* item = new QListWidgetItem(name); item->setData(RoleId, (uint) id); item->setData(RolePointer, (qulonglong) new ::RunePage(rp)); const DataDragon::ChampData& champData = findChamp(name); if(champData.key != -1) { QPixmap iamge = dd->getImage(champData.id); item->setIcon(iamge); } QString tooltipStr; if(id != -1) { tooltipStr = QString("id: %0\n").arg(id); } tooltipStr += getRuneDescription(rp); item->setToolTip(tooltipStr); item->setFlags(item->flags() | Qt::ItemIsEditable); if(isCurrent) { item->setSelected(true); } addItem(item); } const DataDragon::ChampData& RunePageList::findChamp(const QString& name) { if(!dd) { return DataDragon::EMPTYCHAMP; } // try direct int count = 0; const DataDragon::ChampData& directChampData = dd->getBestMatchingChamp(name, &count); if(directChampData.key != -1) { return directChampData; } // not specific if(count > 1) { return DataDragon::EMPTYCHAMP; } // try for substrings static const QRegularExpression splittingRegex("\\W+"); QStringList list = name.split(splittingRegex, QString::SplitBehavior::SkipEmptyParts); QSet matchedIds; const DataDragon::ChampData* lastMatched = nullptr; for(const QString& entry : list) { count = 0; const DataDragon::ChampData& splitChampData = dd->getBestMatchingChamp(entry, &count); if(count == 1) { matchedIds.insert(splitChampData.key); lastMatched = &splitChampData; } else if(count > 1) { // not specific return DataDragon::EMPTYCHAMP; } } if(lastMatched && matchedIds.size() == 1) { return *lastMatched; } // not specific or not found return DataDragon::EMPTYCHAMP; } QString RunePageList::getRuneDescription(const ::RunePage& runepage) { QString outStr; outStr.reserve(100); QTextStream out(&outStr); if(! (bool) runepage) { return {}; } out << getRuneStyleByID(runepage.primaryStyle) << ' ' << RunePageList::tr("with") << ' ' << getRuneStyleByID(runepage.secondaryStyle); for(uint32_t rune : runepage.selectedAspects) { out << '\n' << getRuneText(rune); } return outStr; } QString RunePageList::getRuneText(uint32_t id) { if(runeInfo != nullptr) { for(const RuneAspekt& ra : *runeInfo) { if(ra.id == id) { return ra.name; } } } return QString("(%0)").arg(id); } QString RunePageList::getRuneStyleByID(uint32_t id) { if(runeStyles != nullptr) { auto it = std::find_if(runeStyles->begin(), runeStyles->end(), [id](const RuneStyle& rs) { return rs.id == id; }); if(it != runeStyles->end()) { return it->name; } } return QString("(%0)").arg(id); }