diff --git a/CMakeLists.txt b/CMakeLists.txt index 58df46dad..f9f66b2d7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,7 +5,8 @@ # This file sets all the variables shared between the projects # like the installation path, compilation flags etc.. -cmake_minimum_required(VERSION 2.6) +# Cmake 3.1 is required to enable C++11 support correctly +cmake_minimum_required(VERSION 3.1) if(POLICY CMP0020) cmake_policy(SET CMP0020 OLD) @@ -36,6 +37,9 @@ ENDIF() # A project name is needed for CPack PROJECT("${PROJECT_NAME}") +# Use c++11 for all targets +set(CMAKE_CXX_STANDARD 11 CACHE STRING "C++ ISO Standard") +set(CMAKE_CXX_STANDARD_REQUIRED True) # Set conventional loops set(CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS true) @@ -171,7 +175,7 @@ IF(WIN32) ENDIF() # Package builder -set(CPACK_PACKAGE_CONTACT "Daenyth+github@gmail.com") +set(CPACK_PACKAGE_CONTACT "Gavin Bisesi ") set(CPACK_PACKAGE_DESCRIPTION_SUMMARY ${PROJECT_NAME}) set(CPACK_PACKAGE_VENDOR "Cockatrice Development Team") set(CPACK_PACKAGE_DESCRIPTION_FILE "${PROJECT_SOURCE_DIR}/README.md") diff --git a/cmake/NSIS.template.in b/cmake/NSIS.template.in index 6a57b55e7..10dc9b752 100644 --- a/cmake/NSIS.template.in +++ b/cmake/NSIS.template.in @@ -16,9 +16,8 @@ InstallDir "$PROGRAMFILES\Cockatrice" !define MUI_HEADERIMAGE_BITMAP "${NSIS_SOURCE_PATH}\cmake\headerimage.bmp" !define MUI_HEADERIMAGE_UNBITMAP "${NSIS_SOURCE_PATH}\cmake\headerimage.bmp" !define MUI_WELCOMEPAGE_TEXT "This wizard will guide you through the installation of Cockatrice.$\r$\n$\r$\nClick Next to continue." -!define MUI_FINISHPAGE_RUN "$INSTDIR/oracle.exe" -!define MUI_FINISHPAGE_RUN_TEXT "Run 'Oracle' now to update your card database" -!define MUI_FINISHPAGE_RUN_PARAMETERS "-dlsets" +!define MUI_FINISHPAGE_RUN "$INSTDIR/cockatrice.exe" +!define MUI_FINISHPAGE_RUN_TEXT "Run 'Cockatrice' now" !insertmacro MUI_PAGE_WELCOME !insertmacro MUI_PAGE_LICENSE "${NSIS_SOURCE_PATH}\COPYING" @@ -68,22 +67,20 @@ Section "Start menu item" SecStartMenu createShortCut "$SMPROGRAMS\Cockatrice\Cockatrice.lnk" "$INSTDIR\cockatrice.exe" createShortCut "$SMPROGRAMS\Cockatrice\Oracle.lnk" "$INSTDIR\oracle.exe" createShortCut "$SMPROGRAMS\Cockatrice\Servatrice.lnk" "$INSTDIR\servatrice.exe" - createShortCut "$SMPROGRAMS\Cockatrice\Usermanual.lnk" "$INSTDIR\Usermanual.pdf" SectionEnd Section "un.Application" UnSecApplication SetShellVarContext all - RMDir /r "$INSTDIR\zonebg" RMDir /r "$INSTDIR\plugins" RMDir /r "$INSTDIR\sounds" + RMDir /r "$INSTDIR\themes" RMDir /r "$INSTDIR\translations" Delete "$INSTDIR\uninstall.exe" Delete "$INSTDIR\cockatrice.exe" Delete "$INSTDIR\oracle.exe" Delete "$INSTDIR\servatrice.exe" - Delete "$INSTDIR\Usermanual.pdf" - Delete "$INSTDIR\libprotobuf.lib" Delete "$INSTDIR\Qt*.dll" + Delete "$INSTDIR\libmysql.dll" Delete "$INSTDIR\icu*.dll" Delete "$INSTDIR\libeay32.dll" Delete "$INSTDIR\ssleay32.dll" @@ -91,7 +88,7 @@ Section "un.Application" UnSecApplication Delete "$INSTDIR\qdebug.txt" Delete "$INSTDIR\servatrice.sql" Delete "$INSTDIR\servatrice.ini.example" - Delete "$INSTDIR\zlib1.dll" + Delete "$INSTDIR\zlib*.dll" RMDir "$INSTDIR" RMDir "$SMPROGRAMS\Cockatrice" diff --git a/cockatrice/CMakeLists.txt b/cockatrice/CMakeLists.txt index f2e62215a..1de79b780 100644 --- a/cockatrice/CMakeLists.txt +++ b/cockatrice/CMakeLists.txt @@ -7,7 +7,6 @@ PROJECT(cockatrice) SET(cockatrice_SOURCES src/abstractcounter.cpp src/counter_general.cpp - src/dlg_add_set_result.cpp src/dlg_creategame.cpp src/dlg_filter_games.cpp src/dlg_connect.cpp @@ -175,6 +174,13 @@ if(Qt5Widgets_FOUND) include_directories(${Qt5Widgets_INCLUDE_DIRS}) list(APPEND COCKATRICE_LIBS Widgets) + # QtConcurrent + find_package(Qt5Concurrent) + if(Qt5Concurrent_FOUND) + include_directories(${Qt5Concurrent_INCLUDE_DIRS}) + list(APPEND ORACLE_LIBS Concurrent) + endif() + # QtNetwork find_package(Qt5Network) if(Qt5Network_FOUND) @@ -238,8 +244,6 @@ INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR}) # Build cockatrice binary and link it ADD_EXECUTABLE(cockatrice WIN32 MACOSX_BUNDLE ${cockatrice_SOURCES} ${cockatrice_QM} ${cockatrice_RESOURCES_RCC} ${cockatrice_MOC_SRCS}) -set_property(TARGET cockatrice PROPERTY CXX_STANDARD 11) -set_property(TARGET cockatrice PROPERTY CXX_STANDARD_REQUIRED ON) if(Qt4_FOUND) if(MSVC) diff --git a/cockatrice/src/abstractcarditem.cpp b/cockatrice/src/abstractcarditem.cpp index 7f9dfe23d..5197f9065 100644 --- a/cockatrice/src/abstractcarditem.cpp +++ b/cockatrice/src/abstractcarditem.cpp @@ -7,22 +7,19 @@ #include "round.h" #endif /* _WIN32 */ #include "carddatabase.h" -#include "cardinfowidget.h" #include "abstractcarditem.h" #include "pictureloader.h" #include "settingscache.h" #include "main.h" #include "gamescene.h" -#include AbstractCardItem::AbstractCardItem(const QString &_name, Player *_owner, int _id, QGraphicsItem *parent) - : ArrowTarget(_owner, parent), infoWidget(0), id(_id), name(_name), tapped(false), facedown(false), tapAngle(0), isHovered(false), realZValue(0) + : ArrowTarget(_owner, parent), id(_id), name(_name), tapped(false), facedown(false), tapAngle(0), bgColor(Qt::transparent), isHovered(false), realZValue(0) { setCursor(Qt::OpenHandCursor); setFlag(ItemIsSelectable); setCacheMode(DeviceCoordinateCache); - connect(db, SIGNAL(cardListChanged()), this, SLOT(cardInfoUpdated())); connect(settingsCache, SIGNAL(displayCardNamesChanged()), this, SLOT(callUpdate())); cardInfoUpdated(); } @@ -46,7 +43,11 @@ void AbstractCardItem::pixmapUpdated() void AbstractCardItem::cardInfoUpdated() { info = db->getCard(name); - connect(info, SIGNAL(pixmapUpdated()), this, SLOT(pixmapUpdated())); + if(info) + connect(info, SIGNAL(pixmapUpdated()), this, SLOT(pixmapUpdated())); + + cacheBgColor(); + update(); } void AbstractCardItem::setRealZValue(qreal _zValue) @@ -89,45 +90,35 @@ void AbstractCardItem::transformPainter(QPainter *painter, const QSizeF &transla void AbstractCardItem::paintPicture(QPainter *painter, const QSizeF &translatedSize, int angle) { qreal scaleFactor = translatedSize.width() / boundingRect().width(); - - CardInfo *imageSource = facedown ? db->getCard() : info; QPixmap translatedPixmap; - // don't even spend time trying to load the picture if our size is too small - if(translatedSize.width() > 10) - PictureLoader::getPixmap(translatedPixmap, imageSource, translatedSize.toSize()); + bool paintImage = true; + + if(facedown) + { + // never reveal card color, always paint the card back + PictureLoader::getPixmap(translatedPixmap, nullptr, translatedSize.toSize()); + } else { + // don't even spend time trying to load the picture if our size is too small + if(translatedSize.width() > 10) + { + PictureLoader::getPixmap(translatedPixmap, info, translatedSize.toSize()); + if(translatedPixmap.isNull()) + paintImage = false; + } else { + paintImage = false; + } + } painter->save(); - QColor bgColor = Qt::transparent; - if (translatedPixmap.isNull()) { - QString colorStr; - if (!color.isEmpty()) - colorStr = color; - else if (info->getColors().size() > 1) - colorStr = "m"; - else if (!info->getColors().isEmpty()) - colorStr = info->getColors().first().toLower(); - - if (colorStr == "b") - bgColor = QColor(0, 0, 0); - else if (colorStr == "u") - bgColor = QColor(0, 140, 180); - else if (colorStr == "w") - bgColor = QColor(255, 250, 140); - else if (colorStr == "r") - bgColor = QColor(230, 0, 0); - else if (colorStr == "g") - bgColor = QColor(0, 160, 0); - else if (colorStr == "m") - bgColor = QColor(250, 190, 30); - else - bgColor = QColor(230, 230, 230); - } else { + + if (paintImage) { painter->save(); transformPainter(painter, translatedSize, angle); painter->drawPixmap(QPointF(1, 1), translatedPixmap); painter->restore(); + } else { + painter->setBrush(bgColor); } - painter->setBrush(bgColor); QPen pen(Qt::black); pen.setJoinStyle(Qt::MiterJoin); @@ -192,11 +183,11 @@ void AbstractCardItem::setName(const QString &_name) return; emit deleteCardInfoPopup(name); - disconnect(info, 0, this, 0); + if(info) + disconnect(info, nullptr, this, nullptr); name = _name; - info = db->getCard(name); - connect(info, SIGNAL(pixmapUpdated()), this, SLOT(pixmapUpdated())); - update(); + + cardInfoUpdated(); } void AbstractCardItem::setHovered(bool _hovered) @@ -216,9 +207,47 @@ void AbstractCardItem::setHovered(bool _hovered) void AbstractCardItem::setColor(const QString &_color) { color = _color; + cacheBgColor(); update(); } +void AbstractCardItem::cacheBgColor() +{ + QChar colorChar; + if (color.isEmpty()) + { + if(info) + colorChar = info->getColorChar(); + } else { + colorChar = color.at(0); + } + + switch(colorChar.toLower().toLatin1()) + { + case 'b': + bgColor = QColor(0, 0, 0); + break; + case 'u': + bgColor = QColor(0, 140, 180); + break; + case 'w': + bgColor = QColor(255, 250, 140); + break; + case 'r': + bgColor = QColor(230, 0, 0); + break; + case 'g': + bgColor = QColor(0, 160, 0); + break; + case 'm': + bgColor = QColor(250, 190, 30); + break; + default: + bgColor = QColor(230, 230, 230); + break; + } +} + void AbstractCardItem::setTapped(bool _tapped, bool canAnimate) { if (tapped == _tapped) diff --git a/cockatrice/src/abstractcarditem.h b/cockatrice/src/abstractcarditem.h index 7f68ddcd2..89fb12803 100644 --- a/cockatrice/src/abstractcarditem.h +++ b/cockatrice/src/abstractcarditem.h @@ -4,9 +4,7 @@ #include "arrowtarget.h" class CardInfo; -class CardInfoWidget; class Player; -class QTimer; const int CARD_WIDTH = 72; const int CARD_HEIGHT = 102; @@ -15,13 +13,13 @@ class AbstractCardItem : public ArrowTarget { Q_OBJECT protected: CardInfo *info; - CardInfoWidget *infoWidget; int id; QString name; bool tapped; bool facedown; int tapAngle; QString color; + QColor bgColor; private: bool isHovered; qreal realZValue; @@ -65,6 +63,7 @@ protected: void mousePressEvent(QGraphicsSceneMouseEvent *event); void mouseReleaseEvent(QGraphicsSceneMouseEvent *event); QVariant itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant &value); + void cacheBgColor(); }; #endif diff --git a/cockatrice/src/arrowitem.cpp b/cockatrice/src/arrowitem.cpp index ba5852265..059abbb3a 100644 --- a/cockatrice/src/arrowitem.cpp +++ b/cockatrice/src/arrowitem.cpp @@ -227,9 +227,9 @@ void ArrowDragItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) if (startZone->getName().compare("hand") == 0) { startCard->playCard(false); CardInfo *ci = startCard->getInfo(); - if (((!settingsCache->getPlayToStack() && ci->getTableRow() == 3) || + if (ci && (((!settingsCache->getPlayToStack() && ci->getTableRow() == 3) || ((settingsCache->getPlayToStack() && ci->getTableRow() != 0) && - startCard->getZone()->getName().toStdString() != "stack"))) + startCard->getZone()->getName().toStdString() != "stack")))) cmd.set_start_zone("stack"); else cmd.set_start_zone(settingsCache->getPlayToStack() ? "stack" :"table"); diff --git a/cockatrice/src/carddatabase.cpp b/cockatrice/src/carddatabase.cpp index 33dee5e6e..917ffe041 100644 --- a/cockatrice/src/carddatabase.cpp +++ b/cockatrice/src/carddatabase.cpp @@ -1,7 +1,6 @@ #include "carddatabase.h" #include "pictureloader.h" #include "settingscache.h" -#include "thememanager.h" #include #include @@ -287,6 +286,22 @@ QString CardInfo::simplifyName(const QString &name) { return simpleName; } +const QChar CardInfo::getColorChar() const +{ + switch(colors.size()) + { + case 0: + return QChar(); + break; + case 1: + return colors.first().isEmpty() ? QChar() : colors.first().at(0); + break; + default: + return QChar('m'); + break; + } +} + static QXmlStreamWriter &operator<<(QXmlStreamWriter &xml, const CardInfo *info) { xml.writeStartElement("card"); @@ -341,39 +356,37 @@ static QXmlStreamWriter &operator<<(QXmlStreamWriter &xml, const CardInfo *info) } CardDatabase::CardDatabase(QObject *parent) - : QObject(parent), noCard(0), loadStatus(NotLoaded) + : QObject(parent), loadStatus(NotLoaded) { - connect(settingsCache, SIGNAL(cardDatabasePathChanged()), this, SLOT(loadCardDatabase())); - connect(settingsCache, SIGNAL(tokenDatabasePathChanged()), this, SLOT(loadTokenDatabase())); - - noCard = new CardInfo(); + connect(settingsCache, SIGNAL(cardDatabasePathChanged()), this, SLOT(loadCardDatabases())); } CardDatabase::~CardDatabase() { clear(); - delete noCard; } void CardDatabase::clear() { + QHashIterator i(cards); + while (i.hasNext()) { + i.next(); + removeCard(i.value()); + i.value()->deleteLater(); + } + + // The pointers themselves were already deleted, so we don't delete them again. + cards.clear(); + simpleNameCards.clear(); + QHashIterator setIt(sets); while (setIt.hasNext()) { setIt.next(); delete setIt.value(); } sets.clear(); - - QHashIterator i(cards); - while (i.hasNext()) { - i.next(); - delete i.value(); - } - cards.clear(); - // The pointers themselves were already deleted, so we don't delete them - // again. - simpleNameCards.clear(); + loadStatus = NotLoaded; } void CardDatabase::addCard(CardInfo *card) @@ -390,22 +403,23 @@ void CardDatabase::removeCard(CardInfo *card) emit cardRemoved(card); } -CardInfo *CardDatabase::getCard(const QString &cardName, bool createIfNotFound) { - return getCardFromMap(cards, cardName, createIfNotFound); +CardInfo *CardDatabase::getCard(const QString &cardName) const +{ + return getCardFromMap(cards, cardName); } -QList CardDatabase::getCards(const QStringList &cardNames) +QList CardDatabase::getCards(const QStringList &cardNames) const { QList cardInfos; foreach(QString cardName, cardNames) - cardInfos.append(getCardFromMap(cards, cardName, false)); + cardInfos.append(getCardFromMap(cards, cardName)); return cardInfos; } -CardInfo *CardDatabase::getCardBySimpleName(const QString &cardName, bool createIfNotFound) { - QString simpleName = CardInfo::simplifyName(cardName); - return getCardFromMap(simpleNameCards, simpleName, createIfNotFound); +CardInfo *CardDatabase::getCardBySimpleName(const QString &cardName) const +{ + return getCardFromMap(simpleNameCards, CardInfo::simplifyName(cardName)); } CardSet *CardDatabase::getSet(const QString &setName) @@ -459,7 +473,7 @@ void CardDatabase::loadSetsFromXml(QXmlStreamReader &xml) } } -void CardDatabase::loadCardsFromXml(QXmlStreamReader &xml, bool tokens) +void CardDatabase::loadCardsFromXml(QXmlStreamReader &xml) { while (!xml.atEnd()) { if (xml.readNext() == QXmlStreamReader::EndElement) @@ -518,28 +532,20 @@ void CardDatabase::loadCardsFromXml(QXmlStreamReader &xml, bool tokens) isToken = xml.readElementText().toInt(); } - if (isToken == tokens) { - addCard(new CardInfo(name, isToken, manacost, cmc, type, pt, text, colors, relatedCards, reverseRelatedCards, upsideDown, loyalty, cipt, tableRow, sets, customPicURLs, muids)); - } + addCard(new CardInfo(name, isToken, manacost, cmc, type, pt, text, colors, relatedCards, reverseRelatedCards, upsideDown, loyalty, cipt, tableRow, sets, customPicURLs, muids)); } } } -CardInfo *CardDatabase::getCardFromMap(CardNameMap &cardMap, const QString &cardName, bool createIfNotFound) { +CardInfo *CardDatabase::getCardFromMap(const CardNameMap &cardMap, const QString &cardName) const +{ if (cardMap.contains(cardName)) return cardMap.value(cardName); - - if (createIfNotFound) { - CardInfo *newCard = new CardInfo(cardName, true); - newCard->addToSet(getSet(CardDatabase::TOKENS_SETNAME)); - cardMap.insert(cardName, newCard); - return newCard; - } - return noCard; + return nullptr; } -LoadStatus CardDatabase::loadFromFile(const QString &fileName, bool tokens) +LoadStatus CardDatabase::loadFromFile(const QString &fileName) { QFile file(fileName); file.open(QIODevice::ReadOnly); @@ -562,11 +568,10 @@ LoadStatus CardDatabase::loadFromFile(const QString &fileName, bool tokens) if (xml.name() == "sets") loadSetsFromXml(xml); else if (xml.name() == "cards") - loadCardsFromXml(xml, tokens); + loadCardsFromXml(xml); } } } - qDebug() << cards.size() << "cards in" << sets.size() << "sets loaded"; if (cards.isEmpty()) return NoCards; @@ -609,57 +614,59 @@ bool CardDatabase::saveToFile(const QString &fileName, bool tokens) return true; } -void CardDatabase::emitCardListChanged() -{ - emit cardListChanged(); -} - -LoadStatus CardDatabase::loadCardDatabase(const QString &path, bool tokens) +LoadStatus CardDatabase::loadCardDatabase(const QString &path) { LoadStatus tempLoadStatus = NotLoaded; if (!path.isEmpty()) - tempLoadStatus = loadFromFile(path, tokens); + tempLoadStatus = loadFromFile(path); - if (tempLoadStatus == Ok) { - SetList allSets; - QHashIterator setsIterator(sets); - while (setsIterator.hasNext()) - allSets.append(setsIterator.next().value()); - allSets.sortByKey(); - - if(!tokens) - checkUnknownSets(); - emit cardListChanged(); - } - - if (!tokens) - loadStatus = tempLoadStatus; - - qDebug() << "loadCardDatabase(): Path =" << path << "Tokens =" << tokens << "Status =" << loadStatus; + qDebug() << "[CardDatabase] loadCardDatabase(): Path =" << path << "Status =" << tempLoadStatus << "Cards =" << cards.size() << "Sets=" << sets.size(); return tempLoadStatus; } -LoadStatus CardDatabase::loadCardDatabase() +LoadStatus CardDatabase::loadCardDatabases() { - return loadCardDatabase(settingsCache->getCardDatabasePath(), false); -} - -LoadStatus CardDatabase::loadTokenDatabase() -{ - return loadCardDatabase(settingsCache->getTokenDatabasePath(), true); -} - -void CardDatabase::loadCustomCardDatabases(const QString &path) -{ - QDir dir(path); - if(!dir.exists()) - return; - + qDebug() << "CardDatabase::loadCardDatabases start"; + // clean old db + clear(); + // load main card database + loadStatus = loadCardDatabase(settingsCache->getCardDatabasePath()); + // laod tokens database + loadCardDatabase(settingsCache->getTokenDatabasePath()); + // load custom card databases + QDir dir(settingsCache->getCustomCardDatabasePath()); foreach(QString fileName, dir.entryList(QStringList("*.xml"), QDir::Files | QDir::Readable, QDir::Name | QDir::IgnoreCase)) { - loadCardDatabase(dir.absoluteFilePath(fileName), false); + loadCardDatabase(dir.absoluteFilePath(fileName)); } + + // AFTER all the cards have been loaded + + // reorder sets (TODO: refactor, this smells) + SetList allSets; + QHashIterator setsIterator(sets); + while (setsIterator.hasNext()) + allSets.append(setsIterator.next().value()); + allSets.sortByKey(); + + // resolve the reverse-related tags + refreshCachedReverseRelatedCards(); + + if(loadStatus == Ok) + { + // check for unknown sets + checkUnknownSets(); + // update deck editors, etc + qDebug() << "CardDatabase::loadCardDatabases success"; + } else { + // bring up thr settings dialog + qDebug() << "CardDatabase::loadCardDatabases failed"; + emit cardDatabaseLoadingFailed(); + } + + // return the loadstatus of the main card database. + return loadStatus; } void CardDatabase::refreshCachedReverseRelatedCards() @@ -716,48 +723,70 @@ void CardDatabase::checkUnknownSets() { SetList sets = getSetList(); - // no set is enabled. Probably this is the first time running trice - if(!sets.getEnabledSetsNum()) + if(sets.getEnabledSetsNum()) { + // if some sets are first found on thus run, ask the user + int numUnknownSets = sets.getUnknownSetsNum(); + if(numUnknownSets > 0) + emit cardDatabaseNewSetsFound(numUnknownSets); + } else { + // No set enabled. Probably this is the first time running trice sets.guessSortKeys(); sets.sortByKey(); sets.enableAll(); + notifyEnabledSetsChanged(); - detectedFirstRun = true; - return; + emit cardDatabaseAllNewSetsEnabled(); } - - detectedFirstRun = false; - - int numUnknownSets = sets.getUnknownSetsNum(); - // no unkown sets. - if(!numUnknownSets) - return; - - QMessageBox msgbox(QMessageBox::Question, tr("New sets found"), tr("%1 new set(s) have been found in the card database. Do you want to enable them?").arg(numUnknownSets), QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel); - - switch(msgbox.exec()) - { - case QMessageBox::No: - sets.markAllAsKnown(); - break; - case QMessageBox::Yes: - sets.enableAllUnknown(); - break; - default: - break; - } - - return; } -bool CardDatabase::hasDetectedFirstRun() +void CardDatabase::enableAllUnknownSets() { - if(detectedFirstRun) - { - detectedFirstRun=false; - return true; - } - - return false; + SetList sets = getSetList(); + sets.enableAllUnknown(); } + +void CardDatabase::markAllSetsAsKnown() +{ + SetList sets = getSetList(); + sets.markAllAsKnown(); +} + +void CardDatabase::notifyEnabledSetsChanged() +{ + // refresh the list of cached set names + foreach(CardInfo * card, cards) + card->refreshCachedSetNames(); + + // inform the carddatabasemodels that they need to re-check their list of cards + emit cardDatabaseEnabledSetsChanged(); +} + +bool CardDatabase::saveCustomTokensToFile() +{ + CardSet * customTokensSet = getSet(CardDatabase::TOKENS_SETNAME); + QString fileName = settingsCache->getCustomCardDatabasePath() + "/" + CardDatabase::TOKENS_SETNAME + ".xml"; + QFile file(fileName); + if (!file.open(QIODevice::WriteOnly)) + return false; + QXmlStreamWriter xml(&file); + + xml.setAutoFormatting(true); + xml.writeStartDocument(); + xml.writeStartElement("cockatrice_carddatabase"); + xml.writeAttribute("version", QString::number(versionNeeded)); + + xml.writeStartElement("cards"); + QHashIterator cardIterator(cards); + while (cardIterator.hasNext()) { + CardInfo *card = cardIterator.next().value(); + if(card->getSets().contains(customTokensSet)) + xml << card; + } + xml.writeEndElement(); // cards + + xml.writeEndElement(); // cockatrice_carddatabase + xml.writeEndDocument(); + + return true; +} \ No newline at end of file diff --git a/cockatrice/src/carddatabase.h b/cockatrice/src/carddatabase.h index fdcfa7df5..834b6c9d5 100644 --- a/cockatrice/src/carddatabase.h +++ b/cockatrice/src/carddatabase.h @@ -90,8 +90,6 @@ private: bool cipt; int tableRow; QString pixmapCacheKey; - - void refreshCachedSetNames(); public: CardInfo(const QString &_name = QString(), bool _isToken = false, @@ -131,6 +129,7 @@ public: void setPowTough(const QString &_powTough) { powtough = _powTough; emit cardInfoChanged(this); } void setText(const QString &_text) { text = _text; emit cardInfoChanged(this); } void setColors(const QStringList &_colors) { colors = _colors; emit cardInfoChanged(this); } + const QChar getColorChar() const; const QStringList &getColors() const { return colors; } const QStringList &getRelatedCards() const { return relatedCards; } const QStringList &getReverseRelatedCards() const { return reverseRelatedCards; } @@ -149,6 +148,7 @@ public: void setMuId(const QString &_set, const int &_muId) { muIds.insert(_set, _muId); } void addToSet(CardSet *set); void emitPixmapUpdated() { emit pixmapUpdated(); } + void refreshCachedSetNames(); /** * Simplify a name to have no punctuation and lowercase all letters, for @@ -183,20 +183,15 @@ protected: */ SetNameMap sets; - /* - * A dummy card returned by getCard() ad a fallback - */ - CardInfo *noCard; - LoadStatus loadStatus; - bool detectedFirstRun; private: static const int versionNeeded; - void loadCardsFromXml(QXmlStreamReader &xml, bool tokens); + void loadCardsFromXml(QXmlStreamReader &xml); void loadSetsFromXml(QXmlStreamReader &xml); - CardInfo *getCardFromMap(CardNameMap &cardMap, const QString &cardName, bool createIfNotFound); + CardInfo *getCardFromMap(const CardNameMap &cardMap, const QString &cardName) const; void checkUnknownSets(); + void refreshCachedReverseRelatedCards(); public: static const char* TOKENS_SETNAME; @@ -205,38 +200,37 @@ public: void clear(); void addCard(CardInfo *card); void removeCard(CardInfo *card); - /* - * Get card object by name. Ensured to return a valid CardInfo * object; check noCard - */ - CardInfo *getCard(const QString &cardName = QString(), bool createIfNotFound = false); - QList getCards(const QStringList &cardNames); + CardInfo *getCard(const QString &cardName) const; + QList getCards(const QStringList &cardNames) const; /* * Get a card by its simple name. The name will be simplified in this * function, so you don't need to simplify it beforehand. */ - CardInfo *getCardBySimpleName(const QString &cardName = QString(), bool createIfNotFound = false); + CardInfo *getCardBySimpleName(const QString &cardName) const; CardSet *getSet(const QString &setName); QList getCardList() const { return cards.values(); } SetList getSetList() const; - LoadStatus loadFromFile(const QString &fileName, bool tokens = false); + LoadStatus loadFromFile(const QString &fileName); bool saveToFile(const QString &fileName, bool tokens = false); + bool saveCustomTokensToFile(); QStringList getAllColors() const; QStringList getAllMainCardTypes() const; LoadStatus getLoadStatus() const { return loadStatus; } - bool getLoadSuccess() const { return loadStatus == Ok; } - bool hasDetectedFirstRun(); - void refreshCachedReverseRelatedCards(); + void enableAllUnknownSets(); + void markAllSetsAsKnown(); + void notifyEnabledSetsChanged(); + public slots: - LoadStatus loadCardDatabase(); - LoadStatus loadTokenDatabase(); - void loadCustomCardDatabases(const QString &path); - void emitCardListChanged(); + LoadStatus loadCardDatabases(); private slots: - LoadStatus loadCardDatabase(const QString &path, bool tokens = false); + LoadStatus loadCardDatabase(const QString &path); signals: - void cardListChanged(); + void cardDatabaseLoadingFailed(); + void cardDatabaseNewSetsFound(int numUnknownSets); + void cardDatabaseAllNewSetsEnabled(); + void cardDatabaseEnabledSetsChanged(); void cardAdded(CardInfo *card); void cardRemoved(CardInfo *card); }; diff --git a/cockatrice/src/carddatabasemodel.cpp b/cockatrice/src/carddatabasemodel.cpp index 9b8a89bcc..a3a070866 100644 --- a/cockatrice/src/carddatabasemodel.cpp +++ b/cockatrice/src/carddatabasemodel.cpp @@ -6,10 +6,11 @@ CardDatabaseModel::CardDatabaseModel(CardDatabase *_db, QObject *parent) : QAbstractListModel(parent), db(_db) { - connect(db, SIGNAL(cardListChanged()), this, SLOT(updateCardList())); connect(db, SIGNAL(cardAdded(CardInfo *)), this, SLOT(cardAdded(CardInfo *))); connect(db, SIGNAL(cardRemoved(CardInfo *)), this, SLOT(cardRemoved(CardInfo *))); - updateCardList(); + connect(db, SIGNAL(cardDatabaseEnabledSetsChanged()), this, SLOT(cardDatabaseEnabledSetsChanged())); + + cardDatabaseEnabledSetsChanged(); } CardDatabaseModel::~CardDatabaseModel() @@ -63,37 +64,6 @@ QVariant CardDatabaseModel::headerData(int section, Qt::Orientation orientation, } } -void CardDatabaseModel::updateCardList() -{ - beginResetModel(); - - for (int i = 0; i < cardList.size(); ++i) - disconnect(cardList[i], 0, this, 0); - - cardList.clear(); - - foreach(CardInfo * card, db->getCardList()) - { - bool hasSet = false; - foreach(CardSet * set, card->getSets()) - { - if(set->getEnabled()) - { - hasSet = true; - break; - } - } - - if(hasSet) - { - cardList.append(card); - connect(card, SIGNAL(cardInfoChanged(CardInfo *)), this, SLOT(cardInfoChanged(CardInfo *))); - } - } - - endResetModel(); -} - void CardDatabaseModel::cardInfoChanged(CardInfo *card) { const int row = cardList.indexOf(card); @@ -103,12 +73,44 @@ void CardDatabaseModel::cardInfoChanged(CardInfo *card) emit dataChanged(index(row, 0), index(row, CARDDBMODEL_COLUMNS - 1)); } +bool CardDatabaseModel::checkCardHasAtLeastOneEnabledSet(CardInfo *card) +{ + foreach(CardSet * set, card->getSets()) + { + if(set->getEnabled()) + return true; + } + + return false; +} + +void CardDatabaseModel::cardDatabaseEnabledSetsChanged() +{ + // remove all the cards no more present in at least one enabled set + foreach(CardInfo * card, cardList) + { + if(!checkCardHasAtLeastOneEnabledSet(card)) + cardRemoved(card); + } + + // re-check all the card currently not shown, maybe their part of a newly-enabled set + foreach(CardInfo * card, db->getCardList()) + { + if(!cardList.contains(card)) + cardAdded(card); + } +} + void CardDatabaseModel::cardAdded(CardInfo *card) { - beginInsertRows(QModelIndex(), cardList.size(), cardList.size()); - cardList.append(card); - connect(card, SIGNAL(cardInfoChanged(CardInfo *)), this, SLOT(cardInfoChanged(CardInfo *))); - endInsertRows(); + if(checkCardHasAtLeastOneEnabledSet(card)) + { + // add the card if it's present in at least one enabled set + beginInsertRows(QModelIndex(), cardList.size(), cardList.size()); + cardList.append(card); + connect(card, SIGNAL(cardInfoChanged(CardInfo *)), this, SLOT(cardInfoChanged(CardInfo *))); + endInsertRows(); + } } void CardDatabaseModel::cardRemoved(CardInfo *card) @@ -118,6 +120,7 @@ void CardDatabaseModel::cardRemoved(CardInfo *card) return; beginRemoveRows(QModelIndex(), row, row); + disconnect(card, 0, this, 0); cardList.removeAt(row); endRemoveRows(); } @@ -220,3 +223,16 @@ void CardDatabaseDisplayModel::filterTreeChanged() { invalidate(); } + +TokenDisplayModel::TokenDisplayModel(QObject *parent) + : CardDatabaseDisplayModel(parent) +{ + +} + +bool TokenDisplayModel::filterAcceptsRow(int sourceRow, const QModelIndex & /*sourceParent*/) const +{ + CardInfo const *info = static_cast(sourceModel())->getCard(sourceRow); + + return info->getIsToken(); +} diff --git a/cockatrice/src/carddatabasemodel.h b/cockatrice/src/carddatabasemodel.h index ba8620256..757a217a9 100644 --- a/cockatrice/src/carddatabasemodel.h +++ b/cockatrice/src/carddatabasemodel.h @@ -25,11 +25,13 @@ public: private: QList cardList; CardDatabase *db; + + inline bool checkCardHasAtLeastOneEnabledSet(CardInfo *card); private slots: - void updateCardList(); void cardAdded(CardInfo *card); void cardRemoved(CardInfo *card); void cardInfoChanged(CardInfo *card); + void cardDatabaseEnabledSetsChanged(); }; class CardDatabaseDisplayModel : public QSortFilterProxyModel { @@ -66,4 +68,12 @@ private slots: void filterTreeChanged(); }; +class TokenDisplayModel : public CardDatabaseDisplayModel { + Q_OBJECT +public: + TokenDisplayModel(QObject *parent = 0); +protected: + bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const; +}; + #endif diff --git a/cockatrice/src/cardframe.cpp b/cockatrice/src/cardframe.cpp index d91a8ecf6..8f694e757 100644 --- a/cockatrice/src/cardframe.cpp +++ b/cockatrice/src/cardframe.cpp @@ -11,7 +11,7 @@ #include CardFrame::CardFrame(const QString &cardName, QWidget *parent) - : QTabWidget(parent), info(0), cardTextOnly(false) + : QTabWidget(parent), info(nullptr), cardTextOnly(false) { setContentsMargins(3, 3, 3, 3); pic = new CardInfoPicture(); @@ -91,9 +91,11 @@ void CardFrame::setViewMode(int mode) void CardFrame::setCard(CardInfo *card) { if (info) - disconnect(info, 0, this, 0); + disconnect(info, nullptr, this, nullptr); info = card; - connect(info, SIGNAL(destroyed()), this, SLOT(clear())); + if(info) + connect(info, SIGNAL(destroyed()), this, SLOT(clear())); + text->setCard(info); pic->setCard(info); } @@ -110,5 +112,5 @@ void CardFrame::setCard(AbstractCardItem *card) void CardFrame::clear() { - setCard(db->getCard()); + setCard((CardInfo*) nullptr); } diff --git a/cockatrice/src/cardinfopicture.cpp b/cockatrice/src/cardinfopicture.cpp index d4f7e1790..58f667639 100644 --- a/cockatrice/src/cardinfopicture.cpp +++ b/cockatrice/src/cardinfopicture.cpp @@ -11,7 +11,7 @@ CardInfoPicture::CardInfoPicture(QWidget *parent) : QWidget(parent), - info(0), + info(nullptr), pixmapDirty(true) { setMinimumHeight(100); @@ -20,9 +20,10 @@ CardInfoPicture::CardInfoPicture(QWidget *parent) void CardInfoPicture::setCard(CardInfo *card) { if (info) - disconnect(info, 0, this, 0); + disconnect(info, nullptr, this, nullptr); info = card; - connect(info, SIGNAL(pixmapUpdated()), this, SLOT(updatePixmap())); + if(info) + connect(info, SIGNAL(pixmapUpdated()), this, SLOT(updatePixmap())); updatePixmap(); } @@ -40,14 +41,7 @@ void CardInfoPicture::updatePixmap() void CardInfoPicture::loadPixmap() { - if(info) - PictureLoader::getPixmap(resizedPixmap, info, size()); - else - resizedPixmap = QPixmap(); - - - if (resizedPixmap.isNull()) - PictureLoader::getPixmap(resizedPixmap, db->getCard(), size()); + PictureLoader::getPixmap(resizedPixmap, info, size()); } void CardInfoPicture::paintEvent(QPaintEvent *) diff --git a/cockatrice/src/cardinfotext.cpp b/cockatrice/src/cardinfotext.cpp index ace2a95f6..2dccdd71e 100644 --- a/cockatrice/src/cardinfotext.cpp +++ b/cockatrice/src/cardinfotext.cpp @@ -8,7 +8,7 @@ #include "main.h" CardInfoText::CardInfoText(QWidget *parent) - : QFrame(parent), info(0) + : QFrame(parent), info(nullptr) { nameLabel1 = new QLabel; nameLabel2 = new QLabel; @@ -53,13 +53,24 @@ CardInfoText::CardInfoText(QWidget *parent) void CardInfoText::setCard(CardInfo *card) { - nameLabel2->setText(card->getName()); - manacostLabel2->setText(card->getManaCost()); - colorLabel2->setText(card->getColors().join("")); - cardtypeLabel2->setText(card->getCardType()); - powtoughLabel2->setText(card->getPowTough()); - loyaltyLabel2->setText(card->getLoyalty() > 0 ? QString::number(card->getLoyalty()) : QString()); - textLabel->setText(card->getText()); + if(card) + { + nameLabel2->setText(card->getName()); + manacostLabel2->setText(card->getManaCost()); + colorLabel2->setText(card->getColors().join("")); + cardtypeLabel2->setText(card->getCardType()); + powtoughLabel2->setText(card->getPowTough()); + loyaltyLabel2->setText(card->getLoyalty() > 0 ? QString::number(card->getLoyalty()) : QString()); + textLabel->setText(card->getText()); + } else { + nameLabel2->setText(""); + manacostLabel2->setText(""); + colorLabel2->setText(""); + cardtypeLabel2->setText(""); + powtoughLabel2->setText(""); + loyaltyLabel2->setText(""); + textLabel->setText(""); + } } void CardInfoText::retranslateUi() diff --git a/cockatrice/src/cardinfowidget.cpp b/cockatrice/src/cardinfowidget.cpp index 807221c6e..6f550b8a7 100644 --- a/cockatrice/src/cardinfowidget.cpp +++ b/cockatrice/src/cardinfowidget.cpp @@ -1,179 +1,57 @@ -#include -#include -#include -#include -#include -#include +#include #include #include "cardinfowidget.h" #include "carditem.h" #include "carddatabase.h" -#include "pictureloader.h" +#include "cardinfopicture.h" +#include "cardinfotext.h" #include "main.h" -#include "settingscache.h" -CardInfoWidget::CardInfoWidget(ResizeMode _mode, const QString &cardName, QWidget *parent, Qt::WindowFlags flags) +CardInfoWidget::CardInfoWidget(const QString &cardName, QWidget *parent, Qt::WindowFlags flags) : QFrame(parent, flags) - , pixmapWidth(0) , aspectRatio((qreal) CARD_HEIGHT / (qreal) CARD_WIDTH) - , minimized(settingsCache->getCardInfoMinimized()) // Initialize the cardinfo view status from cache. - , mode(_mode) - , info(0) + , info(nullptr) { - if (mode == ModeGameTab) { - // Create indexed list of status views for card. - const QStringList cardInfoStatus = QStringList() << tr("Show card only") << tr("Show text only") << tr("Show full info"); - - // Create droplist for cardinfo view selection, and set right current index. - dropList = new QComboBox(); - dropList->addItems(cardInfoStatus); - dropList->setCurrentIndex(minimized); - connect(dropList, SIGNAL(currentIndexChanged(int)), this, SLOT(minimizeClicked(int))); - } + setContentsMargins(3, 3, 3, 3); + pic = new CardInfoPicture(); + pic->setObjectName("pic"); + text = new CardInfoText(); + text->setObjectName("text"); - cardPicture = new QLabel; - cardPicture->setAlignment(Qt::AlignCenter); + QVBoxLayout * layout = new QVBoxLayout(); + layout->setObjectName("layout"); + layout->setContentsMargins(0, 0, 0, 0); + layout->setSpacing(0); + layout->addWidget(pic, 0, Qt::AlignCenter); + layout->addWidget(text, 0, Qt::AlignCenter); + setLayout(layout); - nameLabel1 = new QLabel; - nameLabel2 = new QLabel; - nameLabel2->setWordWrap(true); - manacostLabel1 = new QLabel; - manacostLabel2 = new QLabel; - manacostLabel2->setWordWrap(true); - colorLabel1 = new QLabel; - colorLabel2 = new QLabel; - colorLabel2->setWordWrap(true); - cardtypeLabel1 = new QLabel; - cardtypeLabel2 = new QLabel; - cardtypeLabel2->setWordWrap(true); - powtoughLabel1 = new QLabel; - powtoughLabel2 = new QLabel; - loyaltyLabel1 = new QLabel; - loyaltyLabel2 = new QLabel; - - textLabel = new QTextEdit(); - textLabel->setReadOnly(true); - - QGridLayout *grid = new QGridLayout(this); - int row = 0; - if (mode == ModeGameTab) - grid->addWidget(dropList, row++, 1, 1, 1, Qt::AlignRight); - grid->addWidget(cardPicture, row++, 0, 1, 2); - grid->addWidget(nameLabel1, row, 0); - grid->addWidget(nameLabel2, row++, 1); - grid->addWidget(manacostLabel1, row, 0); - grid->addWidget(manacostLabel2, row++, 1); - grid->addWidget(colorLabel1, row, 0); - grid->addWidget(colorLabel2, row++, 1); - grid->addWidget(cardtypeLabel1, row, 0); - grid->addWidget(cardtypeLabel2, row++, 1); - grid->addWidget(powtoughLabel1, row, 0); - grid->addWidget(powtoughLabel2, row++, 1); - grid->addWidget(loyaltyLabel1, row, 0); - grid->addWidget(loyaltyLabel2, row++, 1); - grid->addWidget(textLabel, row, 0, -1, 2); - grid->setRowStretch(row, 1); - grid->setColumnStretch(1, 1); - - retranslateUi(); setFrameStyle(QFrame::Panel | QFrame::Raised); - if (mode == ModeGameTab) { - textLabel->setMinimumHeight(100); - setFixedWidth(sizeHint().width()); - } else if (mode == ModePopUp) { - QDesktopWidget desktopWidget; - pixmapWidth = desktopWidget.screenGeometry().height() / 3 / aspectRatio; - setFixedWidth(pixmapWidth + 150); - } else - setFixedWidth(250); + QDesktopWidget desktopWidget; + int pixmapHeight = desktopWidget.screenGeometry().height() / 3; + int pixmapWidth = pixmapHeight / aspectRatio; + pic->setFixedWidth(pixmapWidth); + pic->setFixedHeight(pixmapHeight); + setFixedWidth(pixmapWidth + 150); - setCard(getCard(cardName)); - setMinimized(settingsCache->getCardInfoMinimized()); -} - -void CardInfoWidget::minimizeClicked(int newMinimized) -{ - // Set new status, and store it in the settings cache. - setMinimized(newMinimized); - settingsCache->setCardInfoMinimized(newMinimized); -} - -bool CardInfoWidget::shouldShowPowTough() -{ - return !info->getPowTough().isEmpty(); -} - -bool CardInfoWidget::shouldShowLoyalty() -{ - return (info->getLoyalty() > 0); -} - -void CardInfoWidget::setMinimized(int _minimized) -{ - minimized = _minimized; - - // Toggle oracle fields according to selected view. - bool showAll = ((minimized == 1) || (minimized == 2)); - bool showPowTough = info ? (showAll && shouldShowPowTough()) : true; - bool showLoyalty = info ? (showAll && shouldShowLoyalty()) : true; - if (mode == ModeGameTab) { - nameLabel1->setVisible(showAll); - nameLabel2->setVisible(showAll); - manacostLabel1->setVisible(showAll); - manacostLabel2->setVisible(showAll); - colorLabel1->setVisible(showAll); - colorLabel2->setVisible(showAll); - cardtypeLabel1->setVisible(showAll); - cardtypeLabel2->setVisible(showAll); - powtoughLabel1->setVisible(showPowTough); - powtoughLabel2->setVisible(showPowTough); - loyaltyLabel1->setVisible(showLoyalty); - loyaltyLabel2->setVisible(showLoyalty); - textLabel->setVisible(showAll); - } - - cardPicture->hide(); - cardHeightOffset = minimumSizeHint().height() + 10; - - // Set the picture to be shown only at "card only" (0) and "full info" (2) - if (mode == ModeGameTab) { - cardPicture->setVisible((minimized == 0) || (minimized == 2)); - - if (minimized == 0) - setMaximumHeight(cardHeightOffset + width() * aspectRatio); - else - setMaximumHeight(1000000); - } else - cardPicture->show(); - resize(width(), sizeHint().height()); + setCard(cardName); } void CardInfoWidget::setCard(CardInfo *card) { if (info) - disconnect(info, 0, this, 0); + disconnect(info, nullptr, this, nullptr); info = card; - connect(info, SIGNAL(pixmapUpdated()), this, SLOT(updatePixmap())); - connect(info, SIGNAL(destroyed()), this, SLOT(clear())); + if(info) + connect(info, SIGNAL(destroyed()), this, SLOT(clear())); - updatePixmap(); - nameLabel2->setText(card->getName()); - manacostLabel2->setText(card->getManaCost()); - colorLabel2->setText(card->getColors().join("")); - cardtypeLabel2->setText(card->getCardType()); - powtoughLabel2->setText(card->getPowTough()); - loyaltyLabel2->setText(card->getLoyalty() > 0 ? QString::number(card->getLoyalty()) : QString()); - textLabel->setText(card->getText()); - - powtoughLabel1->setVisible(shouldShowPowTough()); - powtoughLabel2->setVisible(shouldShowPowTough()); - loyaltyLabel1->setVisible(shouldShowLoyalty()); - loyaltyLabel2->setVisible(shouldShowLoyalty()); + text->setCard(info); + pic->setCard(info); } void CardInfoWidget::setCard(const QString &cardName) { - setCard(getCard(cardName)); + setCard(db->getCard(cardName)); } void CardInfoWidget::setCard(AbstractCardItem *card) @@ -183,51 +61,5 @@ void CardInfoWidget::setCard(AbstractCardItem *card) void CardInfoWidget::clear() { - setCard(getCard()); -} - -CardInfo *CardInfoWidget::getCard(const QString &cardName) { - return db->getCardBySimpleName(cardName); -} - -void CardInfoWidget::updatePixmap() -{ - if (pixmapWidth == 0) - return; - - QPixmap resizedPixmap; - PictureLoader::getPixmap(resizedPixmap, info, QSize(pixmapWidth, pixmapWidth * aspectRatio)); - - if (resizedPixmap.isNull()) - PictureLoader::getPixmap(resizedPixmap, getCard(), QSize(pixmapWidth, pixmapWidth * aspectRatio)); - cardPicture->setPixmap(resizedPixmap); -} - -void CardInfoWidget::retranslateUi() -{ - nameLabel1->setText(tr("Name:")); - manacostLabel1->setText(tr("Mana cost:")); - colorLabel1->setText(tr("Color(s):")); - cardtypeLabel1->setText(tr("Card type:")); - powtoughLabel1->setText(tr("P / T:")); - loyaltyLabel1->setText(tr("Loyalty:")); -} -void CardInfoWidget::resizeEvent(QResizeEvent * /*event*/) -{ - if (mode == ModePopUp) - return; - if ((minimized == 1) && (mode == ModeGameTab)) { - pixmapWidth = 0; - return; - } - qreal newPixmapWidth = qMax((qreal) 100.0, qMin((qreal) cardPicture->width(), (qreal) ((height() - cardHeightOffset) / aspectRatio))); - if (newPixmapWidth != pixmapWidth) { - pixmapWidth = newPixmapWidth; - updatePixmap(); - } -} - -QString CardInfoWidget::getCardName() const -{ - return nameLabel2->text(); + setCard((CardInfo *) nullptr); } diff --git a/cockatrice/src/cardinfowidget.h b/cockatrice/src/cardinfowidget.h index 19e9cc616..52ab62d3d 100644 --- a/cockatrice/src/cardinfowidget.h +++ b/cockatrice/src/cardinfowidget.h @@ -5,53 +5,21 @@ #include #include -class QLabel; -class QTextEdit; -class QPushButton; -class AbstractCardItem; class CardInfo; -class QResizeEvent; -class QMouseEvent; +class CardInfoPicture; +class CardInfoText; +class AbstractCardItem; class CardInfoWidget : public QFrame { Q_OBJECT -public: - enum ResizeMode { ModeDeckEditor, ModeGameTab, ModePopUp }; - private: - int pixmapWidth; - qreal cardHeightOffset; qreal aspectRatio; - // XXX: Why isn't this an eunm? - int minimized; // 0 - card, 1 - oracle only, 2 - full - ResizeMode mode; - - QComboBox *dropList; - QLabel *cardPicture; - QLabel *nameLabel1, *nameLabel2; - QLabel *manacostLabel1, *manacostLabel2; - QLabel *colorLabel1, *colorLabel2; - QLabel *cardtypeLabel1, *cardtypeLabel2; - QLabel *powtoughLabel1, *powtoughLabel2; - QLabel *loyaltyLabel1, *loyaltyLabel2; - QTextEdit *textLabel; - - bool shouldShowPowTough(); - bool shouldShowLoyalty(); - CardInfo *info; - void setMinimized(int _minimized); - - /* - * Wrapper around db->getCardBySimpleName. - */ - CardInfo *getCard(const QString &cardName = QString()); - + CardInfoPicture *pic; + CardInfoText *text; public: - CardInfoWidget(ResizeMode _mode, const QString &cardName = QString(), QWidget *parent = 0, Qt::WindowFlags f = 0); - void retranslateUi(); - QString getCardName() const; + CardInfoWidget(const QString &cardName, QWidget *parent = 0, Qt::WindowFlags f = 0); public slots: void setCard(CardInfo *card); @@ -60,11 +28,6 @@ public slots: private slots: void clear(); - void updatePixmap(); - void minimizeClicked(int newMinimized); - -protected: - void resizeEvent(QResizeEvent *event); }; #endif diff --git a/cockatrice/src/carditem.cpp b/cockatrice/src/carditem.cpp index 0ae87ee87..99d594782 100644 --- a/cockatrice/src/carditem.cpp +++ b/cockatrice/src/carditem.cpp @@ -107,13 +107,18 @@ void CardItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, painter->save(); transformPainter(painter, translatedSize, tapAngle); - QStringList ptDbSplit = db->getCard(name)->getPowTough().split("/"); - QStringList ptSplit = pt.split("/"); + if(info) + { + QStringList ptSplit = pt.split("/"); + QStringList ptDbSplit = info->getPowTough().split("/"); - if (getFaceDown() || ptDbSplit.at(0) != ptSplit.at(0) || ptDbSplit.at(1) != ptSplit.at(1)) - painter->setPen(QColor(255, 150, 0)); - else + if (getFaceDown() || ptDbSplit.at(0) != ptSplit.at(0) || ptDbSplit.at(1) != ptSplit.at(1)) + painter->setPen(QColor(255, 150, 0)); + else + painter->setPen(Qt::white); + } else { painter->setPen(Qt::white); + } painter->setBackground(Qt::black); painter->setBackgroundMode(Qt::OpaqueMode); @@ -329,7 +334,7 @@ void CardItem::playCard(bool faceDown) if (tz) tz->toggleTapped(); else - zone->getPlayer()->playCard(this, faceDown, info->getCipt()); + zone->getPlayer()->playCard(this, faceDown, info ? info->getCipt() : false); } void CardItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) diff --git a/cockatrice/src/cardlist.cpp b/cockatrice/src/cardlist.cpp index 344662659..d034bccf8 100644 --- a/cockatrice/src/cardlist.cpp +++ b/cockatrice/src/cardlist.cpp @@ -42,8 +42,8 @@ public: inline bool operator()(CardItem *a, CardItem *b) const { if (flags & SortByType) { - QString t1 = a->getInfo()->getMainCardType(); - QString t2 = b->getInfo()->getMainCardType(); + QString t1 = a->getInfo() ? a->getInfo()->getMainCardType() : QString(); + QString t2 = b->getInfo() ? b->getInfo()->getMainCardType() : QString(); if ((t1 == t2) && (flags & SortByName)) return a->getName() < b->getName(); return t1 < t2; diff --git a/cockatrice/src/decklistmodel.cpp b/cockatrice/src/decklistmodel.cpp index d2f1319e6..380a3c262 100644 --- a/cockatrice/src/decklistmodel.cpp +++ b/cockatrice/src/decklistmodel.cpp @@ -44,11 +44,7 @@ void DeckListModel::rebuildTree() continue; CardInfo *info = db->getCard(currentCard->getName()); - QString cardType; - if (!info) - cardType = "unknown"; - else - cardType = info->getMainCardType(); + QString cardType = info ? info->getMainCardType() : "unknown"; InnerDecklistNode *cardTypeNode = dynamic_cast(node->findChild(cardType)); if (!cardTypeNode) cardTypeNode = new InnerDecklistNode(cardType, node); @@ -280,6 +276,9 @@ QModelIndex DeckListModel::addCard(const QString &cardName, const QString &zoneN InnerDecklistNode *zoneNode = createNodeIfNeeded(zoneName, root); CardInfo *info = db->getCard(cardName); + if(!info) + return QModelIndex(); + QString cardType = info->getMainCardType(); InnerDecklistNode *cardTypeNode = createNodeIfNeeded(cardType, zoneNode); diff --git a/cockatrice/src/deckstats_interface.cpp b/cockatrice/src/deckstats_interface.cpp index 1d3b31045..6e73396da 100644 --- a/cockatrice/src/deckstats_interface.cpp +++ b/cockatrice/src/deckstats_interface.cpp @@ -89,7 +89,8 @@ struct CopyIfNotAToken { const InnerDecklistNode *node, const DecklistCardNode *card ) const { - if (!cardDatabase.getCard(card->getName())->getIsToken()) { + CardInfo * dbCard = cardDatabase.getCard(card->getName()); + if (dbCard && !dbCard->getIsToken()) { DecklistCardNode *addedCard = destination.addCard( card->getName(), node->getName() diff --git a/cockatrice/src/deckview.cpp b/cockatrice/src/deckview.cpp index cd5d1022e..db0e3aba1 100644 --- a/cockatrice/src/deckview.cpp +++ b/cockatrice/src/deckview.cpp @@ -176,13 +176,13 @@ void DeckViewCardContainer::paint(QPainter *painter, const QStyleOptionGraphicsI void DeckViewCardContainer::addCard(DeckViewCard *card) { cards.append(card); - cardsByType.insert(card->getInfo()->getMainCardType(), card); + cardsByType.insert(card->getInfo() ? card->getInfo()->getMainCardType() : "", card); } void DeckViewCardContainer::removeCard(DeckViewCard *card) { cards.removeAt(cards.indexOf(card)); - cardsByType.remove(card->getInfo()->getMainCardType(), card); + cardsByType.remove(card->getInfo() ? card->getInfo()->getMainCardType(): "", card); } QList > DeckViewCardContainer::getRowsAndCols() const diff --git a/cockatrice/src/dlg_add_set_result.cpp b/cockatrice/src/dlg_add_set_result.cpp deleted file mode 100644 index ca5107be8..000000000 --- a/cockatrice/src/dlg_add_set_result.cpp +++ /dev/null @@ -1,38 +0,0 @@ -#include "dlg_add_set_result.h" - -#include -#include -#include - -DlgAddSetResult::DlgAddSetResult(QWidget *parent, bool success, QString msg) : QDialog(parent) { - status = new QLabel(this); - message = new QLabel(this); - - if (success) { - setWindowTitle(tr("Success")); - status->setText(QString("Sets/cards added to Cockatrice.")); - message->setText(QString("You must restart Cockatrice to use the new sets/cards.")); - } - else { - setWindowTitle(tr("Failed")); - status->setText(QString("Sets/cards failed to import.")); - message->setText(msg); - } - - QDialogButtonBox *buttonBox = new QDialogButtonBox(this); - ok = new QPushButton(tr("Ok"), this); - buttonBox->addButton(ok, QDialogButtonBox::AcceptRole); - connect(ok, SIGNAL(clicked()), this, SLOT(closeDialog())); - - QVBoxLayout *parentLayout = new QVBoxLayout(this); - parentLayout->addWidget(status); - parentLayout->addWidget(message); - parentLayout->addWidget(buttonBox); - - setLayout(parentLayout); -} - -void DlgAddSetResult::closeDialog() -{ - accept(); -} \ No newline at end of file diff --git a/cockatrice/src/dlg_add_set_result.h b/cockatrice/src/dlg_add_set_result.h deleted file mode 100644 index d76453133..000000000 --- a/cockatrice/src/dlg_add_set_result.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef DLG_ADD_SET_RESULT_H -#define DLG_ADD_SET_RESULT_H - -#include -#include -#include - -class DlgAddSetResult : public QDialog { -Q_OBJECT -public: - DlgAddSetResult(QWidget *parent, bool success, QString msg); -private slots: - void closeDialog(); -private: - QLabel *status, *message; - QPushButton *ok; -}; - -#endif \ No newline at end of file diff --git a/cockatrice/src/dlg_create_token.cpp b/cockatrice/src/dlg_create_token.cpp index 8210d950d..2510e0fb7 100644 --- a/cockatrice/src/dlg_create_token.cpp +++ b/cockatrice/src/dlg_create_token.cpp @@ -27,13 +27,13 @@ DlgCreateToken::DlgCreateToken(const QStringList &_predefinedTokens, QWidget *pa colorLabel = new QLabel(tr("C&olor:")); colorEdit = new QComboBox; - colorEdit->addItem(tr("white"), "w"); - colorEdit->addItem(tr("blue"), "u"); - colorEdit->addItem(tr("black"), "b"); - colorEdit->addItem(tr("red"), "r"); - colorEdit->addItem(tr("green"), "g"); - colorEdit->addItem(tr("multicolor"), "m"); - colorEdit->addItem(tr("colorless"), QString()); + colorEdit->addItem(tr("white"), QChar('w')); + colorEdit->addItem(tr("blue"), QChar('u')); + colorEdit->addItem(tr("black"), QChar('b')); + colorEdit->addItem(tr("red"), QChar('r')); + colorEdit->addItem(tr("green"), QChar('g')); + colorEdit->addItem(tr("multicolor"), QChar('m')); + colorEdit->addItem(tr("colorless"), QChar()); colorLabel->setBuddy(colorEdit); ptLabel = new QLabel(tr("&P/T:")); @@ -132,14 +132,22 @@ DlgCreateToken::DlgCreateToken(const QStringList &_predefinedTokens, QWidget *pa void DlgCreateToken::tokenSelectionChanged(const QModelIndex ¤t, const QModelIndex & /*previous*/) { const QModelIndex realIndex = cardDatabaseDisplayModel->mapToSource(current); - const CardInfo *cardInfo = current.row() >= 0 ? cardDatabaseModel->getCard(realIndex.row()) : db->getCard(); + const CardInfo *cardInfo = current.row() >= 0 ? cardDatabaseModel->getCard(realIndex.row()) : 0; - nameEdit->setText(cardInfo->getName()); - const QString cardColor = cardInfo->getColors().isEmpty() ? QString() : (cardInfo->getColors().size() > 1 ? QString("m") : cardInfo->getColors().first()); - colorEdit->setCurrentIndex(colorEdit->findData(cardColor, Qt::UserRole, Qt::MatchFixedString)); - ptEdit->setText(cardInfo->getPowTough()); - if(settingsCache->getAnnotateTokens()) - annotationEdit->setText(cardInfo->getText()); + if(cardInfo) + { + nameEdit->setText(cardInfo->getName()); + const QChar cardColor = cardInfo->getColorChar(); + colorEdit->setCurrentIndex(colorEdit->findData(cardColor, Qt::UserRole, Qt::MatchFixedString)); + ptEdit->setText(cardInfo->getPowTough()); + if(settingsCache->getAnnotateTokens()) + annotationEdit->setText(cardInfo->getText()); + } else { + nameEdit->setText(""); + colorEdit->setCurrentIndex(colorEdit->findData(QString(), Qt::UserRole, Qt::MatchFixedString)); + ptEdit->setText(""); + annotationEdit->setText(""); + } } void DlgCreateToken::actChooseTokenFromAll(bool checked) @@ -166,7 +174,7 @@ QString DlgCreateToken::getName() const QString DlgCreateToken::getColor() const { - return colorEdit->itemData(colorEdit->currentIndex()).toString(); + return QString(colorEdit->itemData(colorEdit->currentIndex()).toChar()); } QString DlgCreateToken::getPT() const diff --git a/cockatrice/src/dlg_edit_tokens.cpp b/cockatrice/src/dlg_edit_tokens.cpp index 8cf88ee9e..89cf3e010 100644 --- a/cockatrice/src/dlg_edit_tokens.cpp +++ b/cockatrice/src/dlg_edit_tokens.cpp @@ -1,5 +1,7 @@ #include "dlg_edit_tokens.h" +#include "carddatabase.h" #include "carddatabasemodel.h" +#include "main.h" #include #include #include @@ -15,8 +17,8 @@ #include #include -DlgEditTokens::DlgEditTokens(CardDatabaseModel *_cardDatabaseModel, QWidget *parent) - : QDialog(parent), currentCard(0), cardDatabaseModel(_cardDatabaseModel) +DlgEditTokens::DlgEditTokens(QWidget *parent) + : QDialog(parent), currentCard(0) { nameLabel = new QLabel(tr("&Name:")); nameEdit = new QLineEdit; @@ -25,13 +27,13 @@ DlgEditTokens::DlgEditTokens(CardDatabaseModel *_cardDatabaseModel, QWidget *par colorLabel = new QLabel(tr("C&olor:")); colorEdit = new QComboBox; - colorEdit->addItem(tr("white"), "w"); - colorEdit->addItem(tr("blue"), "u"); - colorEdit->addItem(tr("black"), "b"); - colorEdit->addItem(tr("red"), "r"); - colorEdit->addItem(tr("green"), "g"); - colorEdit->addItem(tr("multicolor"), "m"); - colorEdit->addItem(tr("colorless"), QString()); + colorEdit->addItem(tr("white"), QChar('w')); + colorEdit->addItem(tr("blue"), QChar('u')); + colorEdit->addItem(tr("black"), QChar('b')); + colorEdit->addItem(tr("red"), QChar('r')); + colorEdit->addItem(tr("green"), QChar('g')); + colorEdit->addItem(tr("multicolor"), QChar('m')); + colorEdit->addItem(tr("colorless"), QChar()); colorLabel->setBuddy(colorEdit); connect(colorEdit, SIGNAL(currentIndexChanged(int)), this, SLOT(colorChanged(int))); @@ -57,9 +59,11 @@ DlgEditTokens::DlgEditTokens(CardDatabaseModel *_cardDatabaseModel, QWidget *par QGroupBox *tokenDataGroupBox = new QGroupBox(tr("Token data")); tokenDataGroupBox->setLayout(grid); - - cardDatabaseDisplayModel = new CardDatabaseDisplayModel(this); - cardDatabaseDisplayModel->setSourceModel(cardDatabaseModel); + + databaseModel = new CardDatabaseModel(db, this); + databaseModel->setObjectName("databaseModel"); + cardDatabaseDisplayModel = new TokenDisplayModel(this); + cardDatabaseDisplayModel->setSourceModel(databaseModel); cardDatabaseDisplayModel->setIsToken(CardDatabaseDisplayModel::ShowTrue); chooseTokenView = new QTreeView; @@ -116,39 +120,43 @@ DlgEditTokens::DlgEditTokens(CardDatabaseModel *_cardDatabaseModel, QWidget *par void DlgEditTokens::tokenSelectionChanged(const QModelIndex ¤t, const QModelIndex & /* previous */) { const QModelIndex realIndex = cardDatabaseDisplayModel->mapToSource(current); - CardInfo *cardInfo = current.row() >= 0 ? cardDatabaseModel->getCard(realIndex.row()) : cardDatabaseModel->getDatabase()->getCard(); - if (!cardInfo->getName().isEmpty()) - currentCard = cardInfo; - else - currentCard = 0; - - nameEdit->setText(cardInfo->getName()); - const QString cardColor = cardInfo->getColors().isEmpty() ? QString() : (cardInfo->getColors().size() > 1 ? QString("m") : cardInfo->getColors().first()); - colorEdit->setCurrentIndex(colorEdit->findData(cardColor, Qt::UserRole, Qt::MatchFixedString)); - ptEdit->setText(cardInfo->getPowTough()); - annotationEdit->setText(cardInfo->getText()); + currentCard = current.row() >= 0 ? databaseModel->getCard(realIndex.row()) : 0; + + if(currentCard) + { + nameEdit->setText(currentCard->getName()); + const QChar cardColor = currentCard->getColorChar(); + colorEdit->setCurrentIndex(colorEdit->findData(cardColor, Qt::UserRole, Qt::MatchFixedString)); + ptEdit->setText(currentCard->getPowTough()); + annotationEdit->setText(currentCard->getText()); + } else { + nameEdit->setText(""); + colorEdit->setCurrentIndex(colorEdit->findData(QChar(), Qt::UserRole, Qt::MatchFixedString)); + ptEdit->setText(""); + annotationEdit->setText(""); + } } void DlgEditTokens::actAddToken() { QString name; - bool askAgain; + bool askAgain = true; do { name = QInputDialog::getText(this, tr("Add token"), tr("Please enter the name of the token:")); - if (!name.isEmpty() && cardDatabaseModel->getDatabase()->getCard(name, false)) { + if(name.isEmpty()) + return; + if (databaseModel->getDatabase()->getCard(name)) { QMessageBox::critical(this, tr("Error"), tr("The chosen name conflicts with an existing card or token.\nMake sure to enable the 'token set' in the 'Edit sets...' dialog to display them correctly.")); - askAgain = true; - } else + } else { askAgain = false; + } } while (askAgain); - if (name.isEmpty()) - return; CardInfo *card = new CardInfo(name, true); - card->addToSet(cardDatabaseModel->getDatabase()->getSet(CardDatabase::TOKENS_SETNAME)); + card->addToSet(databaseModel->getDatabase()->getSet(CardDatabase::TOKENS_SETNAME)); card->setCardType("Token"); - cardDatabaseModel->getDatabase()->addCard(card); + databaseModel->getDatabase()->addCard(card); } void DlgEditTokens::actRemoveToken() @@ -156,7 +164,7 @@ void DlgEditTokens::actRemoveToken() if (currentCard) { CardInfo *cardToRemove = currentCard; // the currentCard property gets modified during db->removeCard() currentCard = 0; - cardDatabaseModel->getDatabase()->removeCard(cardToRemove); + databaseModel->getDatabase()->removeCard(cardToRemove); delete cardToRemove; } } @@ -164,7 +172,7 @@ void DlgEditTokens::actRemoveToken() void DlgEditTokens::colorChanged(int colorIndex) { if (currentCard) - currentCard->setColors(QStringList() << colorEdit->itemData(colorIndex).toString()); + currentCard->setColors(QStringList() << QString(colorEdit->itemData(colorIndex).toChar())); } void DlgEditTokens::ptChanged(const QString &_pt) diff --git a/cockatrice/src/dlg_edit_tokens.h b/cockatrice/src/dlg_edit_tokens.h index 61d941ffc..2fbb68862 100644 --- a/cockatrice/src/dlg_edit_tokens.h +++ b/cockatrice/src/dlg_edit_tokens.h @@ -5,7 +5,7 @@ class QModelIndex; class CardDatabaseModel; -class CardDatabaseDisplayModel; +class TokenDisplayModel; class QLabel; class QComboBox; class QLineEdit; @@ -24,15 +24,15 @@ private slots: void actRemoveToken(); private: CardInfo *currentCard; - CardDatabaseModel *cardDatabaseModel; - CardDatabaseDisplayModel *cardDatabaseDisplayModel; + CardDatabaseModel *databaseModel; + TokenDisplayModel *cardDatabaseDisplayModel; QStringList predefinedTokens; QLabel *nameLabel, *colorLabel, *ptLabel, *annotationLabel; QComboBox *colorEdit; QLineEdit *nameEdit, *ptEdit, *annotationEdit; QTreeView *chooseTokenView; public: - DlgEditTokens(CardDatabaseModel *_cardDatabaseModel, QWidget *parent = 0); + DlgEditTokens(QWidget *parent = 0); }; #endif diff --git a/cockatrice/src/main.cpp b/cockatrice/src/main.cpp index ccb0fa2e5..03a9d37eb 100644 --- a/cockatrice/src/main.cpp +++ b/cockatrice/src/main.cpp @@ -27,7 +27,6 @@ #include #include #include -#include #include #include #include "QtNetwork/QNetworkInterface" @@ -86,14 +85,6 @@ void installNewTranslator() qApp->installTranslator(translator); } -bool settingsValid() -{ - return QDir(settingsCache->getDeckPath()).exists() && - !settingsCache->getDeckPath().isEmpty() && - QDir(settingsCache->getPicsPath()).exists() && - !settingsCache->getPicsPath().isEmpty(); -} - QString const generateClientID() { QString macList; @@ -156,73 +147,21 @@ int main(int argc, char *argv[]) qsrand(QDateTime::currentDateTime().toTime_t()); -#ifdef PORTABLE_BUILD - const QString dataDir = "data/"; -#elif QT_VERSION < 0x050000 - const QString dataDir = QDesktopServices::storageLocation(QDesktopServices::DataLocation); -#else - const QString dataDir = QStandardPaths::standardLocations(QStandardPaths::DataLocation).first(); -#endif + qDebug("main(): starting main program"); - if (settingsCache->getCardDatabasePath().isEmpty() || - db->loadCardDatabase() != Ok) - settingsCache->setCardDatabasePath(dataDir + "/cards.xml"); + MainWindow ui; + qDebug("main(): MainWindow constructor finished"); - if (settingsCache->getTokenDatabasePath().isEmpty() || - db->loadTokenDatabase() != Ok) - settingsCache->setTokenDatabasePath(dataDir + "/tokens.xml"); + ui.setWindowIcon(QPixmap("theme:cockatrice")); + + settingsCache->setClientID(generateClientID()); - if (!QDir(settingsCache->getDeckPath()).exists() || settingsCache->getDeckPath().isEmpty()) { - QDir().mkpath(dataDir + "/decks"); - settingsCache->setDeckPath(dataDir + "/decks"); - } - if (!QDir(settingsCache->getReplaysPath()).exists() || settingsCache->getReplaysPath().isEmpty()) { - QDir().mkpath(dataDir + "/replays"); - settingsCache->setReplaysPath(dataDir + "/replays"); - } - if (!QDir(settingsCache->getPicsPath()).exists() || settingsCache->getPicsPath().isEmpty()) { - QDir().mkpath(dataDir + "/pics"); - settingsCache->setPicsPath(dataDir + "/pics"); - } - if (!QDir().mkpath(settingsCache->getPicsPath() + "/CUSTOM")) - qDebug() << "Could not create " + settingsCache->getPicsPath().toUtf8() + "/CUSTOM. Will fall back on default card images."; - - if (!settingsValid() || db->getLoadStatus() != Ok) { - qDebug("main(): invalid settings or load status"); - DlgSettings dlgSettings; - dlgSettings.show(); - app.exec(); - } - - // load custom databased after LoadStatus check, so that they don't bring up the settings dialog - if (QDir().mkpath(dataDir + "/customsets")) - { - // if the dir exists (or has just been created) - db->loadCustomCardDatabases(dataDir + "/customsets"); - } else { - qDebug() << "Could not create " + dataDir + "/customsets folder."; - } - - // when all the cards have been loaded, resolve the reverse-related tags - db->refreshCachedReverseRelatedCards(); - - if (settingsValid()) { - qDebug("main(): starting main program"); - - MainWindow ui; - qDebug("main(): MainWindow constructor finished"); - - ui.setWindowIcon(QPixmap("theme:cockatrice")); - - settingsCache->setClientID(generateClientID()); - - ui.show(); - qDebug("main(): ui.show() finished"); + ui.show(); + qDebug("main(): ui.show() finished"); #if QT_VERSION > 0x050000 - app.setAttribute(Qt::AA_UseHighDpiPixmaps); + app.setAttribute(Qt::AA_UseHighDpiPixmaps); #endif - app.exec(); - } + app.exec(); qDebug("Event loop finished, terminating..."); delete db; diff --git a/cockatrice/src/main.h b/cockatrice/src/main.h index 71feb9a72..0326040fd 100644 --- a/cockatrice/src/main.h +++ b/cockatrice/src/main.h @@ -16,6 +16,4 @@ void installNewTranslator(); QString const generateClientID(); -bool settingsValid(); - #endif diff --git a/cockatrice/src/messagelogwidget.h b/cockatrice/src/messagelogwidget.h index 2b12b3c50..cbd785caa 100644 --- a/cockatrice/src/messagelogwidget.h +++ b/cockatrice/src/messagelogwidget.h @@ -7,7 +7,6 @@ class Player; class CardZone; -class CardInfoWidget; class GameEventContext; class CardItem; diff --git a/cockatrice/src/pictureloader.cpp b/cockatrice/src/pictureloader.cpp index b8e405819..6016c9781 100644 --- a/cockatrice/src/pictureloader.cpp +++ b/cockatrice/src/pictureloader.cpp @@ -96,6 +96,7 @@ PictureLoaderWorker::PictureLoaderWorker() downloadRunning(false), loadQueueRunning(false) { picsPath = settingsCache->getPicsPath(); + customPicsPath = settingsCache->getCustomPicsPath(); picDownload = settingsCache->getPicDownload(); connect(this, SIGNAL(startLoadQueue()), this, SLOT(processLoadQueue()), Qt::QueuedConnection); @@ -167,7 +168,7 @@ bool PictureLoaderWorker::cardImageExistsOnDisk(QString & setName, QString & cor imgReader.setDecideFormatFromContent(true); //The list of paths to the folders in which to search for images - QList picsPaths = QList() << picsPath + "/CUSTOM/" + correctedCardname; + QList picsPaths = QList() << customPicsPath + correctedCardname; if(!setName.isEmpty()) { @@ -196,7 +197,7 @@ bool PictureLoaderWorker::cardImageExistsOnDisk(QString & setName, QString & cor QString PictureLoaderWorker::getPicUrl() { - if (!picDownload) return QString(""); + if (!picDownload) return QString(); CardInfo *card = cardBeingDownloaded.getCard(); CardSet *set=cardBeingDownloaded.getCurrentSet(); @@ -236,7 +237,7 @@ QString PictureLoaderWorker::getPicUrl() ) { qDebug() << "Insufficient card data to download" << card->getName() << "Url:" << picUrl; - return QString(""); + return QString(); } return picUrl; @@ -275,12 +276,12 @@ void PictureLoaderWorker::picDownloadFailed() mutex.lock(); loadQueue.prepend(cardBeingDownloaded); mutex.unlock(); - emit startLoadQueue(); } else { qDebug() << "Picture NOT found, download failed, no more sets to try: BAILING OUT (oldset: " << cardBeingDownloaded.getSetName() << " card: " << cardBeingDownloaded.getCard()->getCorrectedName() << ")"; - cardBeingDownloaded = 0; imageLoaded(cardBeingDownloaded.getCard(), QImage()); + cardBeingDownloaded = 0; } + emit startLoadQueue(); } bool PictureLoaderWorker::imageIsBlackListed(const QByteArray &picData) @@ -354,7 +355,7 @@ void PictureLoaderWorker::enqueueImageLoad(CardInfo *card) QMutexLocker locker(&mutex); // avoid queueing the same card more than once - if(card == 0 || card == cardBeingLoaded.getCard() || card == cardBeingDownloaded.getCard()) + if(!card || card == cardBeingLoaded.getCard() || card == cardBeingDownloaded.getCard()) return; foreach(PictureToLoad pic, loadQueue) @@ -363,6 +364,12 @@ void PictureLoaderWorker::enqueueImageLoad(CardInfo *card) return; } + foreach(PictureToLoad pic, cardsToDownload) + { + if(pic.getCard() == card) + return; + } + loadQueue.append(PictureToLoad(card)); emit startLoadQueue(); } @@ -377,6 +384,7 @@ void PictureLoaderWorker::picsPathChanged() { QMutexLocker locker(&mutex); picsPath = settingsCache->getPicsPath(); + customPicsPath = settingsCache->getCustomPicsPath(); } PictureLoader::PictureLoader() @@ -409,11 +417,6 @@ void PictureLoader::getPixmap(QPixmap &pixmap, CardInfo *card, QSize size) { if(card) { - if (card->getName().isEmpty()) { - internalGetCardBackPixmap(pixmap, size); - return; - } - // search for an exact size copy of the picure in cache QString key = card->getPixmapCacheKey(); QString sizekey = key + QLatin1Char('_') + QString::number(size.width()) + QString::number(size.height()); @@ -428,30 +431,28 @@ void PictureLoader::getPixmap(QPixmap &pixmap, CardInfo *card, QSize size) QPixmapCache::insert(sizekey, pixmap); return; } - } - // load a temporary back picture - internalGetCardBackPixmap(pixmap, size); - - if(card) - { // add the card to the load queue getInstance().worker->enqueueImageLoad(card); + } else { + // requesting the image for a null card is a shortcut to get the card background image + internalGetCardBackPixmap(pixmap, size); } } - void PictureLoader::imageLoaded(CardInfo *card, const QImage &image) { if(image.isNull()) - return; - - if(card->getUpsideDownArt()) { - QImage mirrorImage = image.mirrored(true, true); - QPixmapCache::insert(card->getPixmapCacheKey(), QPixmap::fromImage(mirrorImage)); + QPixmapCache::insert(card->getPixmapCacheKey(), QPixmap()); } else { - QPixmapCache::insert(card->getPixmapCacheKey(), QPixmap::fromImage(image)); + if(card->getUpsideDownArt()) + { + QImage mirrorImage = image.mirrored(true, true); + QPixmapCache::insert(card->getPixmapCacheKey(), QPixmap::fromImage(mirrorImage)); + } else { + QPixmapCache::insert(card->getPixmapCacheKey(), QPixmap::fromImage(image)); + } } card->emitPixmapUpdated(); diff --git a/cockatrice/src/pictureloader.h b/cockatrice/src/pictureloader.h index 7934581c0..58c522329 100644 --- a/cockatrice/src/pictureloader.h +++ b/cockatrice/src/pictureloader.h @@ -39,7 +39,7 @@ private: static QStringList md5Blacklist; QThread *pictureLoaderThread; - QString picsPath; + QString picsPath, customPicsPath; QList loadQueue; QMutex mutex; QNetworkAccessManager *networkManager; diff --git a/cockatrice/src/player.cpp b/cockatrice/src/player.cpp index 325523522..336cc5423 100644 --- a/cockatrice/src/player.cpp +++ b/cockatrice/src/player.cpp @@ -1081,7 +1081,8 @@ void Player::actCreateToken() lastTokenName = dlg.getName(); lastTokenPT = dlg.getPT(); - if (CardInfo *correctedCard = db->getCardBySimpleName(lastTokenName, false)) { + CardInfo *correctedCard = db->getCardBySimpleName(lastTokenName); + if (correctedCard) { lastTokenName = correctedCard->getName(); lastTokenTableRow = table->clampValidTableRow(2 - correctedCard->getTableRow()); if (lastTokenPT.isEmpty()) @@ -1114,7 +1115,9 @@ void Player::actCreatePredefinedToken() { QAction *action = static_cast(sender()); CardInfo *cardInfo = db->getCard(action->text()); - + if(!cardInfo) + return; + lastTokenName = cardInfo->getName(); lastTokenColor = cardInfo->getColors().isEmpty() ? QString() : cardInfo->getColors().first().toLower(); lastTokenPT = cardInfo->getPowTough(); @@ -1141,6 +1144,8 @@ void Player::actCreateRelatedCard() if (spaces.at(0).indexOf("/") != -1) // Strip space from creatures spaces.removeFirst(); CardInfo *cardInfo = db->getCard(spaces.join(" ")); + if(!cardInfo) + return; // get the target token's location // TODO: Define this QPoint into its own function along with the one below @@ -1256,9 +1261,13 @@ void Player::eventCreateToken(const Event_CreateToken &event) CardItem *card = new CardItem(this, QString::fromStdString(event.card_name()), event.card_id()); // use db PT if not provided in event if (!QString::fromStdString(event.pt()).isEmpty()) + { card->setPT(QString::fromStdString(event.pt())); - else - card->setPT(db->getCard(QString::fromStdString(event.card_name()))->getPowTough()); + } else { + CardInfo * dbCard = db->getCard(QString::fromStdString(event.card_name())); + if(dbCard) + card->setPT(dbCard->getPowTough()); + } card->setColor(QString::fromStdString(event.color())); card->setAnnotation(QString::fromStdString(event.annotation())); card->setDestroyOnZoneChange(event.destroy_on_zone_change()); @@ -1713,6 +1722,8 @@ void Player::playCard(CardItem *c, bool faceDown, bool tapped) cardToMove->set_card_id(c->getId()); CardInfo *ci = c->getInfo(); + if(!ci) + return; if (!faceDown && ((!settingsCache->getPlayToStack() && ci->getTableRow() == 3) || ((settingsCache->getPlayToStack() && ci->getTableRow() != 0) && c->getZone()->getName().toStdString() != "stack"))) { @@ -2293,7 +2304,8 @@ void Player::actPlay() if(!game->getActiveCard()) return; - playCard(game->getActiveCard(), false, game->getActiveCard()->getInfo()->getCipt()); + bool cipt = game->getActiveCard()->getInfo() ? game->getActiveCard()->getInfo()->getCipt(): false; + playCard(game->getActiveCard(), false, cipt); } void Player::actHide() @@ -2374,20 +2386,23 @@ void Player::updateCardMenu(CardItem *card) if (card->getFaceDown()) cardMenu->addAction(aPeek); - QStringList relatedCards = card->getInfo()->getRelatedCards(); - QStringList reverserelatedCards2Me = card->getInfo()->getReverseRelatedCards2Me(); - if(relatedCards.size() || reverserelatedCards2Me.size()) + if(card->getInfo()) { - QMenu * createRelatedCardMenu = cardMenu->addMenu(tr("Cr&eate related card")); + QStringList relatedCards = card->getInfo()->getRelatedCards(); + QStringList reverserelatedCards2Me = card->getInfo()->getReverseRelatedCards2Me(); + if(relatedCards.size() || reverserelatedCards2Me.size()) + { + QMenu * createRelatedCardMenu = cardMenu->addMenu(tr("Cr&eate related card")); - for (int i = 0; i < relatedCards.size(); ++i) { - QAction *a = createRelatedCardMenu->addAction(relatedCards.at(i)); - connect(a, SIGNAL(triggered()), this, SLOT(actCreateRelatedCard())); - } + for (int i = 0; i < relatedCards.size(); ++i) { + QAction *a = createRelatedCardMenu->addAction(relatedCards.at(i)); + connect(a, SIGNAL(triggered()), this, SLOT(actCreateRelatedCard())); + } - for (int i = 0; i < reverserelatedCards2Me.size(); ++i) { - QAction *a = createRelatedCardMenu->addAction(reverserelatedCards2Me.at(i)); - connect(a, SIGNAL(triggered()), this, SLOT(actCreateRelatedCard())); + for (int i = 0; i < reverserelatedCards2Me.size(); ++i) { + QAction *a = createRelatedCardMenu->addAction(reverserelatedCards2Me.at(i)); + connect(a, SIGNAL(triggered()), this, SLOT(actCreateRelatedCard())); + } } } cardMenu->addSeparator(); @@ -2413,20 +2428,23 @@ void Player::updateCardMenu(CardItem *card) cardMenu->addAction(aDrawArrow); cardMenu->addMenu(moveMenu); - QStringList relatedCards = card->getInfo()->getRelatedCards(); - QStringList reverserelatedCards2Me = card->getInfo()->getReverseRelatedCards2Me(); - if(relatedCards.size() || reverserelatedCards2Me.size()) + if(card->getInfo()) { - QMenu * createRelatedCardMenu = cardMenu->addMenu(tr("Cr&eate related card")); + QStringList relatedCards = card->getInfo()->getRelatedCards(); + QStringList reverserelatedCards2Me = card->getInfo()->getReverseRelatedCards2Me(); + if(relatedCards.size() || reverserelatedCards2Me.size()) + { + QMenu * createRelatedCardMenu = cardMenu->addMenu(tr("Cr&eate related card")); - for (int i = 0; i < relatedCards.size(); ++i) { - QAction *a = createRelatedCardMenu->addAction(relatedCards.at(i)); - connect(a, SIGNAL(triggered()), this, SLOT(actCreateRelatedCard())); - } + for (int i = 0; i < relatedCards.size(); ++i) { + QAction *a = createRelatedCardMenu->addAction(relatedCards.at(i)); + connect(a, SIGNAL(triggered()), this, SLOT(actCreateRelatedCard())); + } - for (int i = 0; i < reverserelatedCards2Me.size(); ++i) { - QAction *a = createRelatedCardMenu->addAction(reverserelatedCards2Me.at(i)); - connect(a, SIGNAL(triggered()), this, SLOT(actCreateRelatedCard())); + for (int i = 0; i < reverserelatedCards2Me.size(); ++i) { + QAction *a = createRelatedCardMenu->addAction(reverserelatedCards2Me.at(i)); + connect(a, SIGNAL(triggered()), this, SLOT(actCreateRelatedCard())); + } } } } else { diff --git a/cockatrice/src/priceupdater.cpp b/cockatrice/src/priceupdater.cpp index e0a06b29d..307cd26f7 100644 --- a/cockatrice/src/priceupdater.cpp +++ b/cockatrice/src/priceupdater.cpp @@ -60,7 +60,9 @@ void DBPriceUpdater::updatePrices() bool bNotFirst=false; for (int i = 0; i < cards.size(); ++i) { - card = db->getCard(cards[i], false); + card = db->getCard(cards[i]); + if(!card) + continue; sets = card->getSets(); for(int j = 0; j < sets.size(); ++j) { diff --git a/cockatrice/src/setsmodel.cpp b/cockatrice/src/setsmodel.cpp index 2dbe90272..76dbe43f1 100644 --- a/cockatrice/src/setsmodel.cpp +++ b/cockatrice/src/setsmodel.cpp @@ -194,7 +194,7 @@ void SetsModel::save(CardDatabase *db) sets.sortByKey(); - db->emitCardListChanged(); + db->notifyEnabledSetsChanged(); } void SetsModel::restore(CardDatabase *db) diff --git a/cockatrice/src/settingscache.cpp b/cockatrice/src/settingscache.cpp index 9d1f66257..e698c905b 100644 --- a/cockatrice/src/settingscache.cpp +++ b/cockatrice/src/settingscache.cpp @@ -1,6 +1,8 @@ #include "settingscache.h" #include #include +#include +#include #include #if QT_VERSION >= 0x050000 @@ -9,20 +11,21 @@ #include #endif +QString SettingsCache::getDataPath() +{ + return +#ifdef PORTABLE_BUILD + qApp->applicationDirPath() + "/data/"; +#elif QT_VERSION >= 0x050000 + QStandardPaths::writableLocation(QStandardPaths::DataLocation); +#else + QDesktopServices::storageLocation(QDesktopServices::DataLocation); +#endif +} + QString SettingsCache::getSettingsPath() { - QString file = qApp->applicationDirPath() + "/settings/"; - -#ifndef PORTABLE_BUILD - #if QT_VERSION >= 0x050000 - file = QStandardPaths::writableLocation(QStandardPaths::DataLocation); - #else - file = QDesktopServices::storageLocation(QDesktopServices::DataLocation); - #endif - file.append("/settings/"); -#endif - - return file; + return getDataPath() + "/settings/"; } void SettingsCache::translateLegacySettings() @@ -119,8 +122,31 @@ void SettingsCache::translateLegacySettings() } } +QString SettingsCache::getSafeConfigPath(QString configEntry, QString defaultPath) const +{ + QString tmp = settings->value(configEntry).toString(); + // if the config settings is empty or refers to a not-existing folder, + // ensure that the defaut path exists and return it + if (!QDir(tmp).exists() || tmp.isEmpty()) { + if(!QDir().mkpath(defaultPath)) + qDebug() << "[SettingsCache] Could not create folder:" << defaultPath; + tmp = defaultPath; + } + return tmp; +} + +QString SettingsCache::getSafeConfigFilePath(QString configEntry, QString defaultPath) const +{ + QString tmp = settings->value(configEntry).toString(); + // if the config settings is empty or refers to a not-existing file, + // return the default Path + if (!QFile::exists(tmp) || tmp.isEmpty()) + tmp = defaultPath; + return tmp; +} SettingsCache::SettingsCache() { + QString dataPath = getDataPath(); QString settingsPath = getSettingsPath(); settings = new QSettings(settingsPath+"global.ini", QSettings::IniFormat, this); shortcutsSettings = new ShortcutsSettings(settingsPath,this); @@ -133,20 +159,20 @@ SettingsCache::SettingsCache() if(!QFile(settingsPath+"global.ini").exists()) translateLegacySettings(); -#ifdef PORTABLE_BUILD - setDeckPath(qApp->applicationDirPath() + "data/decks"); - setReplaysPath(qApp->applicationDirPath() +"data/replays"); - setPicsPath(qApp->applicationDirPath() + "data/pics"); -#endif - notifyAboutUpdates = settings->value("personal/updatenotification", true).toBool(); lang = settings->value("personal/lang").toString(); keepalive = settings->value("personal/keepalive", 5).toInt(); - deckPath = settings->value("paths/decks").toString(); - replaysPath = settings->value("paths/replays").toString(); - picsPath = settings->value("paths/pics").toString(); - cardDatabasePath = settings->value("paths/carddatabase").toString(); - tokenDatabasePath = settings->value("paths/tokendatabase").toString(); + + deckPath = getSafeConfigPath("paths/decks", dataPath + "/decks/"); + replaysPath = getSafeConfigPath("paths/replays", dataPath + "/replays/"); + picsPath = getSafeConfigPath("paths/pics", dataPath + "/pics/"); + // this has never been exposed as an user-configurable setting + customPicsPath = getSafeConfigPath("paths/custompics", picsPath + "/CUSTOM/"); + // this has never been exposed as an user-configurable setting + customCardDatabasePath = getSafeConfigPath("paths/customsets", dataPath + "/customsets/"); + + cardDatabasePath = getSafeConfigFilePath("paths/carddatabase", dataPath + "/cards.xml"); + tokenDatabasePath = getSafeConfigFilePath("paths/tokendatabase", dataPath + "/tokens.xml"); themeName = settings->value("theme/name").toString(); @@ -175,7 +201,6 @@ SettingsCache::SettingsCache() doubleClickToPlay = settings->value("interface/doubleclicktoplay", true).toBool(); playToStack = settings->value("interface/playtostack", true).toBool(); annotateTokens = settings->value("interface/annotatetokens", false).toBool(); - cardInfoMinimized = settings->value("interface/cardinfominimized", 0).toInt(); tabGameSplitterSizes = settings->value("interface/tabgame_splittersizes").toByteArray(); displayCardNames = settings->value("cards/displaycardnames", true).toBool(); horizontalHand = settings->value("hand/horizontal", true).toBool(); @@ -291,6 +316,8 @@ void SettingsCache::setPicsPath(const QString &_picsPath) { picsPath = _picsPath; settings->setValue("paths/pics", picsPath); + // get a new value for customPicsPath, currently derived from picsPath + customPicsPath = getSafeConfigPath("paths/custompics", picsPath + "CUSTOM/"); emit picsPathChanged(); } @@ -305,7 +332,7 @@ void SettingsCache::setTokenDatabasePath(const QString &_tokenDatabasePath) { tokenDatabasePath = _tokenDatabasePath; settings->setValue("paths/tokendatabase", tokenDatabasePath); - emit tokenDatabasePathChanged(); + emit cardDatabasePathChanged(); } void SettingsCache::setThemeName(const QString &_themeName) @@ -363,12 +390,6 @@ void SettingsCache::setAnnotateTokens(int _annotateTokens) settings->setValue("interface/annotatetokens", annotateTokens); } -void SettingsCache::setCardInfoMinimized(int _cardInfoMinimized) -{ - cardInfoMinimized = _cardInfoMinimized; - settings->setValue("interface/cardinfominimized", cardInfoMinimized); -} - void SettingsCache::setTabGameSplitterSizes(const QByteArray &_tabGameSplitterSizes) { tabGameSplitterSizes = _tabGameSplitterSizes; diff --git a/cockatrice/src/settingscache.h b/cockatrice/src/settingscache.h index f9456162a..920472c5a 100644 --- a/cockatrice/src/settingscache.h +++ b/cockatrice/src/settingscache.h @@ -27,7 +27,6 @@ signals: void langChanged(); void picsPathChanged(); void cardDatabasePathChanged(); - void tokenDatabasePathChanged(); void themeChanged(); void picDownloadChanged(); void displayCardNamesChanged(); @@ -54,7 +53,7 @@ private: QByteArray mainWindowGeometry; QString lang; - QString deckPath, replaysPath, picsPath, cardDatabasePath, tokenDatabasePath, themeName; + QString deckPath, replaysPath, picsPath, customPicsPath, cardDatabasePath, customCardDatabasePath, tokenDatabasePath, themeName; bool notifyAboutUpdates; bool picDownload; bool notificationsEnabled; @@ -62,7 +61,6 @@ private: bool doubleClickToPlay; bool playToStack; bool annotateTokens; - int cardInfoMinimized; QByteArray tabGameSplitterSizes; bool displayCardNames; bool horizontalHand; @@ -105,16 +103,21 @@ private: bool spectatorsCanSeeEverything; int keepalive; void translateLegacySettings(); + QString getSafeConfigPath(QString configEntry, QString defaultPath) const; + QString getSafeConfigFilePath(QString configEntry, QString defaultPath) const; bool rememberGameSettings; public: SettingsCache(); + QString getDataPath(); QString getSettingsPath(); const QByteArray &getMainWindowGeometry() const { return mainWindowGeometry; } QString getLang() const { return lang; } QString getDeckPath() const { return deckPath; } QString getReplaysPath() const { return replaysPath; } QString getPicsPath() const { return picsPath; } + QString getCustomPicsPath() const { return customPicsPath; } + QString getCustomCardDatabasePath() const { return customCardDatabasePath; } QString getCardDatabasePath() const { return cardDatabasePath; } QString getTokenDatabasePath() const { return tokenDatabasePath; } QString getThemeName() const { return themeName; } @@ -128,7 +131,6 @@ public: bool getDoubleClickToPlay() const { return doubleClickToPlay; } bool getPlayToStack() const { return playToStack; } bool getAnnotateTokens() const { return annotateTokens; } - int getCardInfoMinimized() const { return cardInfoMinimized; } QByteArray getTabGameSplitterSizes() const { return tabGameSplitterSizes; } bool getDisplayCardNames() const { return displayCardNames; } bool getHorizontalHand() const { return horizontalHand; } @@ -200,7 +202,6 @@ public slots: void setDoubleClickToPlay(int _doubleClickToPlay); void setPlayToStack(int _playToStack); void setAnnotateTokens(int _annotateTokens); - void setCardInfoMinimized(int _cardInfoMinimized); void setTabGameSplitterSizes(const QByteArray &_tabGameSplitterSizes); void setDisplayCardNames(int _displayCardNames); void setHorizontalHand(int _horizontalHand); diff --git a/cockatrice/src/tab.cpp b/cockatrice/src/tab.cpp index bf62170d5..dde9cea18 100644 --- a/cockatrice/src/tab.cpp +++ b/cockatrice/src/tab.cpp @@ -15,7 +15,7 @@ void Tab::showCardInfoPopup(const QPoint &pos, const QString &cardName) infoPopup->deleteLater(); } currentCardName = cardName; - infoPopup = new CardInfoWidget(CardInfoWidget::ModePopUp, cardName, 0, Qt::Widget | Qt::FramelessWindowHint | Qt::X11BypassWindowManagerHint | Qt::WindowStaysOnTopHint); + infoPopup = new CardInfoWidget(cardName, 0, Qt::Widget | Qt::FramelessWindowHint | Qt::X11BypassWindowManagerHint | Qt::WindowStaysOnTopHint); infoPopup->setAttribute(Qt::WA_TransparentForMouseEvents); QRect screenRect = qApp->desktop()->screenGeometry(this); infoPopup->move( diff --git a/cockatrice/src/tab_deck_editor.cpp b/cockatrice/src/tab_deck_editor.cpp index 987870e48..1cb584ff5 100644 --- a/cockatrice/src/tab_deck_editor.cpp +++ b/cockatrice/src/tab_deck_editor.cpp @@ -24,15 +24,11 @@ #include #include #include "tab_deck_editor.h" -#include "window_sets.h" #include "carddatabase.h" #include "pictureloader.h" #include "carddatabasemodel.h" #include "decklistmodel.h" -#include "cardinfowidget.h" #include "dlg_load_deck_from_clipboard.h" -#include "dlg_edit_tokens.h" -#include "dlg_add_set_result.h" #include "main.h" #include "settingscache.h" #include "priceupdater.h" @@ -46,10 +42,6 @@ #include "cardframe.h" #include "filterbuilder.h" -const QStringList TabDeckEditor::fileNameFilters = QStringList() - << QObject::tr("Cockatrice card database (*.xml)") - << QObject::tr("All files (*.*)"); - void SearchLineEdit::keyPressEvent(QKeyEvent *event) { if (treeView && ((event->key() == Qt::Key_Up) || (event->key() == Qt::Key_Down))) @@ -229,9 +221,6 @@ void TabDeckEditor::createMenus() aSaveDeckAs = new QAction(QString(), this); connect(aSaveDeckAs, SIGNAL(triggered()), this, SLOT(actSaveDeckAs())); - aOpenCustomsetsFolder = new QAction(QString(), this); - connect(aOpenCustomsetsFolder, SIGNAL(triggered()), this, SLOT(actOpenCustomsetsFolder())); - aLoadDeckFromClipboard = new QAction(QString(), this); connect(aLoadDeckFromClipboard, SIGNAL(triggered()), this, SLOT(actLoadDeckFromClipboard())); @@ -247,17 +236,13 @@ void TabDeckEditor::createMenus() aClose = new QAction(QString(), this); connect(aClose, SIGNAL(triggered()), this, SLOT(closeRequest())); - aOpenCustomFolder = new QAction(QString(), this); - connect(aOpenCustomFolder, SIGNAL(triggered()), this, SLOT(actOpenCustomFolder())); + aClearFilterAll = new QAction(QString(), this); + aClearFilterAll->setIcon(QPixmap("theme:icons/clearsearch")); + connect(aClearFilterAll, SIGNAL(triggered()), this, SLOT(actClearFilterAll())); - aAddCustomSet = new QAction(QString(), this); - connect(aAddCustomSet, SIGNAL(triggered()), this, SLOT(actAddCustomSet())); - - aEditSets = new QAction(QString(), this); - connect(aEditSets, SIGNAL(triggered()), this, SLOT(actEditSets())); - - aEditTokens = new QAction(QString(), this); - connect(aEditTokens, SIGNAL(triggered()), this, SLOT(actEditTokens())); + aClearFilterOne = new QAction(QString(), this); + aClearFilterOne->setIcon(QPixmap("theme:icons/decrement")); + connect(aClearFilterOne, SIGNAL(triggered()), this, SLOT(actClearFilterOne())); deckMenu = new QMenu(this); deckMenu->addAction(aNewDeck); @@ -269,34 +254,14 @@ void TabDeckEditor::createMenus() deckMenu->addAction(aSaveDeckToClipboard); deckMenu->addSeparator(); deckMenu->addAction(aPrintDeck); - deckMenu->addSeparator(); deckMenu->addAction(aAnalyzeDeck); deckMenu->addSeparator(); + deckMenu->addAction(aClearFilterOne); + deckMenu->addAction(aClearFilterAll); + deckMenu->addSeparator(); deckMenu->addAction(aClose); addTabMenu(deckMenu); - aClearFilterAll = new QAction(QString(), this); - aClearFilterAll->setIcon(QPixmap("theme:icons/clearsearch")); - connect(aClearFilterAll, SIGNAL(triggered()), this, SLOT(actClearFilterAll())); - - aClearFilterOne = new QAction(QString(), this); - aClearFilterOne->setIcon(QPixmap("theme:icons/decrement")); - connect(aClearFilterOne, SIGNAL(triggered()), this, SLOT(actClearFilterOne())); - - dbMenu = new QMenu(this); - dbMenu->addAction(aEditSets); - dbMenu->addAction(aEditTokens); - dbMenu->addSeparator(); - dbMenu->addAction(aClearFilterOne); - dbMenu->addAction(aClearFilterAll); - dbMenu->addSeparator(); -#if defined(Q_OS_WIN) || defined(Q_OS_MAC) - dbMenu->addAction(aOpenCustomFolder); - dbMenu->addAction(aOpenCustomsetsFolder); -#endif - dbMenu->addAction(aAddCustomSet); - addTabMenu(dbMenu); - viewMenu = new QMenu(this); cardInfoDockMenu = viewMenu->addMenu(QString()); @@ -370,7 +335,12 @@ void TabDeckEditor::createCentralFrame() databaseView->setSortingEnabled(true); databaseView->sortByColumn(0, Qt::AscendingOrder); databaseView->setModel(databaseDisplayModel); - databaseView->resizeColumnToContents(0); + databaseView->header()->setStretchLastSection(false); +#if QT_VERSION >= 0x050000 + databaseView->header()->setSectionResizeMode(0, QHeaderView::Stretch); +#else + databaseView->header()->setResizeMode(0, QHeaderView::Stretch); +#endif connect(databaseView->selectionModel(), SIGNAL(currentRowChanged(const QModelIndex &, const QModelIndex &)), this, SLOT(updateCardInfoLeft(const QModelIndex &, const QModelIndex &))); connect(databaseView, SIGNAL(doubleClicked(const QModelIndex &)), this, SLOT(actAddCard())); searchEdit->setTreeView(databaseView); @@ -475,9 +445,6 @@ void TabDeckEditor::refreshShortcuts() aPrintDeck->setShortcuts(settingsCache->shortcuts().getShortcut("TabDeckEditor/aPrintDeck")); aAnalyzeDeck->setShortcuts(settingsCache->shortcuts().getShortcut("TabDeckEditor/aAnalyzeDeck")); aClose->setShortcuts(settingsCache->shortcuts().getShortcut("TabDeckEditor/aClose")); - aOpenCustomFolder->setShortcuts(settingsCache->shortcuts().getShortcut("TabDeckEditor/aOpenCustomFolder")); - aEditSets->setShortcuts(settingsCache->shortcuts().getShortcut("TabDeckEditor/aEditSets")); - aEditTokens->setShortcuts(settingsCache->shortcuts().getShortcut("TabDeckEditor/aEditTokens")); aResetLayout->setShortcuts(settingsCache->shortcuts().getShortcut("TabDeckEditor/aResetLayout")); aClearFilterAll->setShortcuts(settingsCache->shortcuts().getShortcut("TabDeckEditor/aClearFilterAll")); aClearFilterOne->setShortcuts(settingsCache->shortcuts().getShortcut("TabDeckEditor/aClearFilterOne")); @@ -539,7 +506,6 @@ TabDeckEditor::TabDeckEditor(TabSupervisor *_tabSupervisor, QWidget *parent) connect(&settingsCache->shortcuts(), SIGNAL(shortCutchanged()),this,SLOT(refreshShortcuts())); refreshShortcuts(); - QTimer::singleShot(0, this, SLOT(checkFirstRunDetected())); QTimer::singleShot(0, this, SLOT(loadLayout())); } @@ -570,9 +536,6 @@ void TabDeckEditor::retranslateUi() aSaveDeckToClipboard->setText(tr("Save deck to clip&board")); aPrintDeck->setText(tr("&Print deck...")); aAnalyzeDeck->setText(tr("&Analyze deck on deckstats.net")); - aOpenCustomFolder->setText(tr("Open custom image folder")); - aOpenCustomsetsFolder->setText(tr("Open custom sets folder")); - aAddCustomSet->setText(tr("Add custom sets/cards")); aClose->setText(tr("&Close")); aAddCard->setText(tr("Add card to &maindeck")); @@ -585,10 +548,6 @@ void TabDeckEditor::retranslateUi() aDecrement->setText(tr("&Decrement number")); deckMenu->setTitle(tr("&Deck Editor")); - dbMenu->setTitle(tr("C&ard Database")); - - aEditSets->setText(tr("&Edit sets...")); - aEditTokens->setText(tr("Edit &tokens...")); cardInfoDock->setWindowTitle(tr("Card Info")); deckDock->setWindowTitle(tr("Deck")); @@ -800,117 +759,6 @@ void TabDeckEditor::actAnalyzeDeck() interface->analyzeDeck(deckModel->getDeckList()); } - -void TabDeckEditor::actOpenCustomFolder() { - -#if defined(Q_OS_MAC) - - QStringList scriptArgs; - scriptArgs << QLatin1String("-e"); - scriptArgs << QString::fromLatin1("tell application \"Finder\" to open POSIX file \"%1\"").arg(settingsCache->getPicsPath() + "/custom/"); - scriptArgs << QLatin1String("-e"); - scriptArgs << QLatin1String("tell application \"Finder\" to activate"); - - QProcess::execute("/usr/bin/osascript", scriptArgs); -#endif -#if defined(Q_OS_WIN) - QStringList args; - QString pathToFolder = settingsCache->getPicsPath().append("/custom"); - args << QDir::toNativeSeparators(pathToFolder); - QProcess::startDetached("explorer", args); -#endif - -} - -void TabDeckEditor::actOpenCustomsetsFolder() { -#if QT_VERSION < 0x050000 - QString dataDir = QDesktopServices::storageLocation(QDesktopServices::DataLocation); -#else - QString dataDir = QStandardPaths::standardLocations(QStandardPaths::DataLocation).first(); -#endif - -#if defined(Q_OS_MAC) - - QStringList scriptArgs; - scriptArgs << QLatin1String("-e"); - scriptArgs << QString::fromLatin1("tell application \"Finder\" to open POSIX file \"%1\"").arg(dataDir + "/customsets/"); - scriptArgs << QLatin1String("-e"); - scriptArgs << QLatin1String("tell application \"Finder\" to activate"); - - QProcess::execute("/usr/bin/osascript", scriptArgs); -#endif -#if defined(Q_OS_WIN) - QStringList args; - dataDir.append("/customsets"); - args << QDir::toNativeSeparators(dataDir); - QProcess::startDetached("explorer", args); -#endif - -} - -void TabDeckEditor::actAddCustomSet() -{ - -#if (QT_VERSION < QT_VERSION_CHECK(5, 0, 0)) - QString dataDir = QDesktopServices::storageLocation(QDesktopServices::DataLocation); -#else - QString dataDir = QStandardPaths::standardLocations(QStandardPaths::DataLocation).first(); -#endif - - QFileDialog dialog(this, tr("Load sets/cards")); - dialog.setDirectory(dataDir); - dialog.setNameFilters(TabDeckEditor::fileNameFilters); - if (!dialog.exec()) - return; - - QString fileName = dialog.selectedFiles().at(0); - - if (!QFile::exists(fileName)) { - DlgAddSetResult dlg(this, false, QString("Selected file cannot be found.")); - dlg.exec(); - return; - } - - QDir dir(dataDir + "/customsets"); - int nextPrefix = getNextCustomSetPrefix(dir); - - bool res = QFile::copy( - fileName, dir.absolutePath() + "/" + (nextPrefix > 9 ? "" : "0") + - QString::number(nextPrefix) + "." + QFileInfo(fileName).fileName() - ); - - DlgAddSetResult dlg(this, res, QString()); - dlg.exec(); -} - -int TabDeckEditor::getNextCustomSetPrefix(QDir dataDir) { - QStringList files = dataDir.entryList(); - int maxIndex = 0; - - QStringList::const_iterator filesIterator; - for (filesIterator = files.constBegin(); filesIterator != files.constEnd(); ++filesIterator) { - int fileIndex = (*filesIterator).split(".").at(0).toInt(); - if (fileIndex > maxIndex) - maxIndex = fileIndex; - } - - return maxIndex + 1; -} - -void TabDeckEditor::actEditSets() -{ - WndSets *w = new WndSets; - w->setWindowModality(Qt::WindowModal); - w->show(); -} - -void TabDeckEditor::actEditTokens() -{ - DlgEditTokens dlg(databaseModel); - dlg.exec(); - db->saveToFile(settingsCache->getTokenDatabasePath(), true); -} - void TabDeckEditor::actClearFilterAll() { databaseDisplayModel->clearFilterAll(); @@ -1136,15 +984,6 @@ void TabDeckEditor::filterRemove(QAction *action) { filterModel->removeRow(idx.row(), idx.parent()); } -void TabDeckEditor::checkFirstRunDetected() -{ - if(db->hasDetectedFirstRun()) - { - QMessageBox::information(this, tr("Welcome"), tr("Hi! It seems like you're running this version of Cockatrice for the first time.\nAll the sets in the card database have been enabled.\nRead more about changing the set order or disabling specific sets and consequent effects in the \"Edit Sets\" window.")); - actEditSets(); - } -} - // Method uses to sync docks state with menu items state bool TabDeckEditor::eventFilter(QObject * o, QEvent * e) { diff --git a/cockatrice/src/tab_deck_editor.h b/cockatrice/src/tab_deck_editor.h index 13e4203c4..50eb4710e 100644 --- a/cockatrice/src/tab_deck_editor.h +++ b/cockatrice/src/tab_deck_editor.h @@ -53,12 +53,6 @@ class TabDeckEditor : public Tab { void actSaveDeckToClipboard(); void actPrintDeck(); void actAnalyzeDeck(); - void actOpenCustomFolder(); - void actOpenCustomsetsFolder(); - void actAddCustomSet(); - - void actEditSets(); - void actEditTokens(); void actClearFilterAll(); void actClearFilterOne(); @@ -90,13 +84,11 @@ class TabDeckEditor : public Tab { void dockFloatingTriggered(); void dockTopLevelChanged(bool topLevel); private: - static const QStringList fileNameFilters; CardInfo *currentCardInfo() const; void addCardHelper(QString zoneName); void offsetCountAtIndex(const QModelIndex &idx, int offset); void decrementCardHelper(QString zoneName); void recursiveExpand(const QModelIndex &index); - int getNextCustomSetPrefix(QDir dataDir); CardDatabaseModel *databaseModel; CardDatabaseDisplayModel *databaseDisplayModel; @@ -119,9 +111,9 @@ private: QTreeView *filterView; QWidget *filterBox; - QMenu *deckMenu, *dbMenu, *viewMenu, *cardInfoDockMenu, *deckDockMenu, *filterDockMenu; - QAction *aNewDeck, *aLoadDeck, *aSaveDeck, *aSaveDeckAs, *aLoadDeckFromClipboard, *aSaveDeckToClipboard, *aPrintDeck, *aAnalyzeDeck, *aClose, *aOpenCustomFolder, *aOpenCustomsetsFolder, *aAddCustomSet; - QAction *aEditSets, *aEditTokens, *aClearFilterAll, *aClearFilterOne; + QMenu *deckMenu, *viewMenu, *cardInfoDockMenu, *deckDockMenu, *filterDockMenu; + QAction *aNewDeck, *aLoadDeck, *aSaveDeck, *aSaveDeckAs, *aLoadDeckFromClipboard, *aSaveDeckToClipboard, *aPrintDeck, *aAnalyzeDeck, *aClose; + QAction *aClearFilterAll, *aClearFilterOne; QAction *aAddCard, *aAddCardToSideboard, *aRemoveCard, *aIncrement, *aDecrement;// *aUpdatePrices; QAction *aResetLayout; QAction *aCardInfoDockVisible, *aCardInfoDockFloating, *aDeckDockVisible, *aDeckDockFloating, *aFilterDockVisible, *aFilterDockFloating; @@ -149,7 +141,6 @@ public: public slots: void closeRequest(); - void checkFirstRunDetected(); signals: void deckEditorClosing(TabDeckEditor *tab); }; diff --git a/cockatrice/src/tablezone.cpp b/cockatrice/src/tablezone.cpp index eebae0f33..a38a5eb45 100644 --- a/cockatrice/src/tablezone.cpp +++ b/cockatrice/src/tablezone.cpp @@ -148,7 +148,10 @@ void TableZone::handleDropEventByGrid(const QList &dragItems, Ca CardToMove *ctm = cmd.mutable_cards_to_move()->add_card(); ctm->set_card_id(dragItems[i]->getId()); ctm->set_face_down(dragItems[i]->getFaceDown()); - ctm->set_pt(startZone->getName() == name ? std::string() : dragItems[i]->getItem()->getInfo()->getPowTough().toStdString()); + if(startZone->getName() != name && dragItems[i]->getItem()->getInfo()) + ctm->set_pt(dragItems[i]->getItem()->getInfo()->getPowTough().toStdString()); + else + ctm->set_pt(std::string()); } startZone->getPlayer()->sendGameCommand(cmd); diff --git a/cockatrice/src/window_main.cpp b/cockatrice/src/window_main.cpp index bd55a5a8f..0a694476e 100644 --- a/cockatrice/src/window_main.cpp +++ b/cockatrice/src/window_main.cpp @@ -34,6 +34,8 @@ #if QT_VERSION < 0x050000 #include // for Qt::escape() +#else + #include #endif #include "main.h" @@ -51,6 +53,9 @@ #include "tab_game.h" #include "version_string.h" #include "update_checker.h" +#include "carddatabase.h" +#include "window_sets.h" +#include "dlg_edit_tokens.h" #include "pb/game_replay.pb.h" #include "pb/room_commands.pb.h" @@ -69,6 +74,9 @@ #define DOWNLOAD_URL "https://dl.bintray.com/cockatrice/Cockatrice/" const QString MainWindow::appName = "Cockatrice"; +const QStringList MainWindow::fileNameFilters = QStringList() + << QObject::tr("Cockatrice card database (*.xml)") + << QObject::tr("All files (*.*)"); void MainWindow::updateTabMenu(const QList &newMenuList) { @@ -507,6 +515,13 @@ void MainWindow::retranslateUi() cockatriceMenu->setTitle(tr("&Cockatrice")); #endif + dbMenu->setTitle(tr("C&ard Database")); + aOpenCustomFolder->setText(tr("Open custom image folder")); + aOpenCustomsetsFolder->setText(tr("Open custom sets folder")); + aAddCustomSet->setText(tr("Add custom sets/cards")); + aEditSets->setText(tr("&Edit sets...")); + aEditTokens->setText(tr("Edit &tokens...")); + aAbout->setText(tr("&About Cockatrice")); aUpdate->setText(tr("&Update Cockatrice")); helpMenu->setTitle(tr("&Help")); @@ -545,6 +560,21 @@ void MainWindow::createActions() aCheckCardUpdates = new QAction(this); connect(aCheckCardUpdates, SIGNAL(triggered()), this, SLOT(actCheckCardUpdates())); + aOpenCustomsetsFolder = new QAction(QString(), this); + connect(aOpenCustomsetsFolder, SIGNAL(triggered()), this, SLOT(actOpenCustomsetsFolder())); + + aOpenCustomFolder = new QAction(QString(), this); + connect(aOpenCustomFolder, SIGNAL(triggered()), this, SLOT(actOpenCustomFolder())); + + aAddCustomSet = new QAction(QString(), this); + connect(aAddCustomSet, SIGNAL(triggered()), this, SLOT(actAddCustomSet())); + + aEditSets = new QAction(QString(), this); + connect(aEditSets, SIGNAL(triggered()), this, SLOT(actEditSets())); + + aEditTokens = new QAction(QString(), this); + connect(aEditTokens, SIGNAL(triggered()), this, SLOT(actEditTokens())); + #if defined(__APPLE__) /* For OSX */ aSettings->setMenuRole(QAction::PreferencesRole); aExit->setMenuRole(QAction::QuitRole); @@ -580,6 +610,16 @@ void MainWindow::createMenus() cockatriceMenu->addSeparator(); cockatriceMenu->addAction(aExit); + dbMenu = menuBar()->addMenu(QString()); + dbMenu->addAction(aEditSets); + dbMenu->addAction(aEditTokens); + dbMenu->addSeparator(); +#if defined(Q_OS_WIN) || defined(Q_OS_MAC) + dbMenu->addAction(aOpenCustomFolder); + dbMenu->addAction(aOpenCustomsetsFolder); +#endif + dbMenu->addAction(aAddCustomSet); + helpMenu = menuBar()->addMenu(QString()); helpMenu->addAction(aAbout); helpMenu->addAction(aUpdate); @@ -635,6 +675,11 @@ MainWindow::MainWindow(QWidget *parent) connect(&settingsCache->shortcuts(), SIGNAL(shortCutchanged()),this,SLOT(refreshShortcuts())); refreshShortcuts(); + + connect(db, SIGNAL(cardDatabaseLoadingFailed()), this, SLOT(cardDatabaseLoadingFailed())); + connect(db, SIGNAL(cardDatabaseNewSetsFound(int)), this, SLOT(cardDatabaseNewSetsFound(int))); + connect(db, SIGNAL(cardDatabaseAllNewSetsEnabled()), this, SLOT(cardDatabaseAllNewSetsEnabled())); + QtConcurrent::run(db, &CardDatabase::loadCardDatabases); } MainWindow::~MainWindow() @@ -727,6 +772,59 @@ void MainWindow::showWindowIfHidden() { show(); } +void MainWindow::cardDatabaseLoadingFailed() +{ + QMessageBox msgBox; + msgBox.setWindowTitle(tr("Card database")); + msgBox.setIcon(QMessageBox::Question); + msgBox.setText(tr("Cockatrice is unable to load the card database.\n" + "Do you want to update your card database now?\n" + "If unsure or first time user, choose \"Yes\"")); + + QPushButton *yesButton = msgBox.addButton(tr("Yes"), QMessageBox::YesRole); + msgBox.addButton(tr("No"), QMessageBox::NoRole); + QPushButton *settingsButton = msgBox.addButton(tr("Open settings"), QMessageBox::ActionRole); + msgBox.setDefaultButton(yesButton); + + msgBox.exec(); + + if (msgBox.clickedButton() == yesButton) { + actCheckCardUpdates(); + } else if (msgBox.clickedButton() == settingsButton) { + actSettings(); + } +} + +void MainWindow::cardDatabaseNewSetsFound(int numUnknownSets) +{ + QMessageBox msgBox; + msgBox.setWindowTitle(tr("New sets found")); + msgBox.setIcon(QMessageBox::Question); + msgBox.setText(tr("%1 new set(s) have been found in the card database.\n" + "Do you want to enable them?").arg(numUnknownSets)); + + QPushButton *yesButton = msgBox.addButton(tr("Yes"), QMessageBox::YesRole); + QPushButton *noButton = msgBox.addButton(tr("No"), QMessageBox::NoRole); + QPushButton *settingsButton = msgBox.addButton(tr("View sets"), QMessageBox::ActionRole); + msgBox.setDefaultButton(yesButton); + + msgBox.exec(); + + if (msgBox.clickedButton() == yesButton) { + db->enableAllUnknownSets(); + } else if (msgBox.clickedButton() == noButton) { + db->markAllSetsAsKnown(); + } else if (msgBox.clickedButton() == settingsButton) { + actEditSets(); + } +} + +void MainWindow::cardDatabaseAllNewSetsEnabled() +{ + QMessageBox::information(this, tr("Welcome"), tr("Hi! It seems like you're running this version of Cockatrice for the first time.\nAll the sets in the card database have been enabled.\nRead more about changing the set order or disabling specific sets and consequent effects in the \"Edit Sets\" window.")); + actEditSets(); +} + /* CARD UPDATER */ void MainWindow::actCheckCardUpdates() @@ -811,11 +909,9 @@ void MainWindow::cardUpdateFinished(int, QProcess::ExitStatus) cardUpdateProcess->deleteLater(); cardUpdateProcess = 0; - QMessageBox::information(this, tr("Information"), tr("Update completed successfully. Cockatrice will now reload the card database.")); + QMessageBox::information(this, tr("Information"), tr("Update completed successfully.\nCockatrice will now reload the card database.")); - // this will force a database reload - settingsCache->setCardDatabasePath(settingsCache->getCardDatabasePath()); - settingsCache->setTokenDatabasePath(settingsCache->getTokenDatabasePath()); + QtConcurrent::run(db, &CardDatabase::loadCardDatabases); } void MainWindow::refreshShortcuts() @@ -830,9 +926,107 @@ void MainWindow::refreshShortcuts() aSettings->setShortcuts(settingsCache->shortcuts().getShortcut("MainWindow/aSettings")); aExit->setShortcuts(settingsCache->shortcuts().getShortcut("MainWindow/aExit")); aCheckCardUpdates->setShortcuts(settingsCache->shortcuts().getShortcut("MainWindow/aCheckCardUpdates")); + aOpenCustomFolder->setShortcuts(settingsCache->shortcuts().getShortcut("MainWindow/aOpenCustomFolder")); + aEditSets->setShortcuts(settingsCache->shortcuts().getShortcut("MainWindow/aEditSets")); + aEditTokens->setShortcuts(settingsCache->shortcuts().getShortcut("MainWindow/aEditTokens")); } void MainWindow::notifyUserAboutUpdate() { QMessageBox::information(this, tr("Information"), tr("Your client appears to be missing features that the server supports.\nThis usually means that your client version is out of date, please check to see if there is a new client available for download.")); } + +void MainWindow::actOpenCustomFolder() +{ + QString dir = settingsCache->getCustomPicsPath(); +#if defined(Q_OS_MAC) + QStringList scriptArgs; + scriptArgs << QLatin1String("-e"); + scriptArgs << QString::fromLatin1("tell application \"Finder\" to open POSIX file \"%1\"").arg(dir); + scriptArgs << QLatin1String("-e"); + scriptArgs << QLatin1String("tell application \"Finder\" to activate"); + + QProcess::execute("/usr/bin/osascript", scriptArgs); +#elif defined(Q_OS_WIN) + QStringList args; + args << QDir::toNativeSeparators(dir); + QProcess::startDetached("explorer", args); +#endif +} + +void MainWindow::actOpenCustomsetsFolder() +{ + QString dir = settingsCache->getCustomCardDatabasePath(); + +#if defined(Q_OS_MAC) + QStringList scriptArgs; + scriptArgs << QLatin1String("-e"); + scriptArgs << QString::fromLatin1("tell application \"Finder\" to open POSIX file \"%1\"").arg(dir); + scriptArgs << QLatin1String("-e"); + scriptArgs << QLatin1String("tell application \"Finder\" to activate"); + + QProcess::execute("/usr/bin/osascript", scriptArgs); +#elif defined(Q_OS_WIN) + QStringList args; + args << QDir::toNativeSeparators(dir); + QProcess::startDetached("explorer", args); +#endif +} + +void MainWindow::actAddCustomSet() +{ + QFileDialog dialog(this, tr("Load sets/cards"), QDir::homePath()); + dialog.setNameFilters(MainWindow::fileNameFilters); + if (!dialog.exec()) + return; + + QString fileName = dialog.selectedFiles().at(0); + + if (!QFile::exists(fileName)) { + QMessageBox::warning(this, tr("Load sets/cards"), tr("Selected file cannot be found.")); + return; + } + + QDir dir = settingsCache->getCustomCardDatabasePath(); + int nextPrefix = getNextCustomSetPrefix(dir); + + bool res = QFile::copy( + fileName, dir.absolutePath() + "/" + (nextPrefix > 9 ? "" : "0") + + QString::number(nextPrefix) + "." + QFileInfo(fileName).fileName() + ); + + if (res) { + QMessageBox::information(this, tr("Load sets/cards"), tr("The new sets/cards have been added successfully.\nCockatrice will now reload the card database.")); + QtConcurrent::run(db, &CardDatabase::loadCardDatabases); + } else { + QMessageBox::warning(this, tr("Load sets/cards"), tr("Sets/cards failed to import.")); + } +} + +int MainWindow::getNextCustomSetPrefix(QDir dataDir) { + QStringList files = dataDir.entryList(); + int maxIndex = 0; + + QStringList::const_iterator filesIterator; + for (filesIterator = files.constBegin(); filesIterator != files.constEnd(); ++filesIterator) { + int fileIndex = (*filesIterator).split(".").at(0).toInt(); + if (fileIndex > maxIndex) + maxIndex = fileIndex; + } + + return maxIndex + 1; +} + +void MainWindow::actEditSets() +{ + WndSets *w = new WndSets; + w->setWindowModality(Qt::WindowModal); + w->show(); +} + +void MainWindow::actEditTokens() +{ + DlgEditTokens dlg; + dlg.exec(); + db->saveCustomTokensToFile(); +} diff --git a/cockatrice/src/window_main.h b/cockatrice/src/window_main.h index 842eebd0f..b86ec6d6e 100644 --- a/cockatrice/src/window_main.h +++ b/cockatrice/src/window_main.h @@ -79,8 +79,19 @@ private slots: void cardUpdateError(QProcess::ProcessError err); void cardUpdateFinished(int exitCode, QProcess::ExitStatus exitStatus); void refreshShortcuts(); + void cardDatabaseLoadingFailed(); + void cardDatabaseNewSetsFound(int numUnknownSets); + void cardDatabaseAllNewSetsEnabled(); + + void actOpenCustomFolder(); + void actOpenCustomsetsFolder(); + void actAddCustomSet(); + + void actEditSets(); + void actEditTokens(); private: static const QString appName; + static const QStringList fileNameFilters; void setClientStatusTitle(); void retranslateUi(); void createActions(); @@ -88,13 +99,15 @@ private: void createTrayIcon(); void createTrayActions(); + int getNextCustomSetPrefix(QDir dataDir); // TODO: add a preference item to choose updater name for other games inline QString getCardUpdaterBinaryName() { return "oracle"; }; QList tabMenus; - QMenu *cockatriceMenu, *helpMenu; + QMenu *cockatriceMenu, *dbMenu, *helpMenu; QAction *aConnect, *aDisconnect, *aSinglePlayer, *aWatchReplay, *aDeckEditor, *aFullScreen, *aSettings, *aExit, *aAbout, *aCheckCardUpdates, *aRegister, *aUpdate; + QAction *aEditSets, *aEditTokens, *aOpenCustomFolder, *aOpenCustomsetsFolder, *aAddCustomSet; TabSupervisor *tabSupervisor; QMenu *trayIconMenu; diff --git a/cockatrice/src/zoneviewzone.cpp b/cockatrice/src/zoneviewzone.cpp index 191c1d942..4532875bd 100644 --- a/cockatrice/src/zoneviewzone.cpp +++ b/cockatrice/src/zoneviewzone.cpp @@ -116,7 +116,7 @@ void ZoneViewZone::reorganizeCards() QString lastCardType; for (int i = 0; i < cardCount; i++) { CardItem *c = cardsToDisplay.at(i); - QString cardType = c->getInfo()->getMainCardType(); + QString cardType = c->getInfo() ? c->getInfo()->getMainCardType() : ""; if (i){ // if not the first card if (cardType == lastCardType) diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt index d73dc6f83..0aabfbd5c 100644 --- a/common/CMakeLists.txt +++ b/common/CMakeLists.txt @@ -2,7 +2,6 @@ # # provides the common library -CMAKE_MINIMUM_REQUIRED(VERSION 2.6) add_subdirectory(pb) SET(common_SOURCES diff --git a/common/pb/CMakeLists.txt b/common/pb/CMakeLists.txt index 19677b933..70c369fa6 100644 --- a/common/pb/CMakeLists.txt +++ b/common/pb/CMakeLists.txt @@ -2,8 +2,6 @@ # # provides the protobuf interfaces -CMAKE_MINIMUM_REQUIRED(VERSION 2.6) - SET(PROTO_FILES admin_commands.proto card_attributes.proto diff --git a/oracle/CMakeLists.txt b/oracle/CMakeLists.txt index 7851c1d2b..4c0c34a07 100644 --- a/oracle/CMakeLists.txt +++ b/oracle/CMakeLists.txt @@ -130,8 +130,6 @@ ENDIF() # Build oracle binary and link it ADD_EXECUTABLE(oracle WIN32 MACOSX_BUNDLE ${oracle_SOURCES} ${oracle_QM} ${oracle_RESOURCES_RCC} ${oracle_MOC_SRCS}) -set_property(TARGET oracle PROPERTY CXX_STANDARD 11) -set_property(TARGET oracle PROPERTY CXX_STANDARD_REQUIRED ON) if(Qt4_FOUND) if(MSVC) diff --git a/oracle/src/oraclewizard.cpp b/oracle/src/oraclewizard.cpp index 1c6e727d7..7bf75248d 100644 --- a/oracle/src/oraclewizard.cpp +++ b/oracle/src/oraclewizard.cpp @@ -48,19 +48,7 @@ OracleWizard::OracleWizard(QWidget *parent) settings = new QSettings(settingsCache->getSettingsPath()+"global.ini",QSettings::IniFormat, this); connect(settingsCache, SIGNAL(langChanged()), this, SLOT(updateLanguage())); - QString dataDir; - -#ifndef PORTABLE_BUILD - #if QT_VERSION < 0x050000 - QDesktopServices::storageLocation(QDesktopServices::DataLocation); - #else - QStandardPaths::standardLocations(QStandardPaths::DataLocation).first(); - #endif -#else - dataDir.append("data"); -#endif - - importer = new OracleImporter(dataDir, this); + importer = new OracleImporter(settingsCache->getDataPath(), this); addPage(new IntroPage); addPage(new LoadSetsPage); @@ -521,47 +509,19 @@ void SaveSetsPage::updateTotalProgress(int cardsImported, int /* setIndex */, co bool SaveSetsPage::validatePage() { bool ok = false; - QString dataDir; - #ifndef PORTABLE_BUILD -#if QT_VERSION < 0x050000 - dataDir = QDesktopServices::storageLocation(QDesktopServices::DataLocation); -#else - dataDir = QStandardPaths::standardLocations(QStandardPaths::DataLocation).first(); -#endif -#else - dataDir = qApp->applicationDirPath() + "/data"; -#endif - -#ifdef PORTABLE_BUILD - QSettings* settings = new QSettings("settings/global.ini",QSettings::IniFormat,this); - QString defaultPath = "data/cards.xml"; - settings->setValue("paths/carddatabase", defaultPath); -#else - QSettings* settings = new QSettings(settingsCache->getSettingsPath()+"global.ini",QSettings::IniFormat,this); - QString defaultPath = settings->value("paths/carddatabase").toString(); -#endif + QString defaultPath = settingsCache->getCardDatabasePath(); QString windowName = tr("Save card database"); QString fileType = tr("XML; card database (*.xml)"); do { QString fileName; - if (defaultPath.isEmpty()) { - if (defaultPathCheckBox->isChecked()) - fileName = dataDir + "/cards.xml"; - else - fileName = QFileDialog::getSaveFileName(this, windowName, dataDir + "/cards.xml", fileType); + if (defaultPathCheckBox->isChecked()) + fileName = defaultPath; + else + fileName = QFileDialog::getSaveFileName(this, windowName, defaultPath, fileType); - settings->setValue("paths/carddatabase", fileName); - } - else { - if (defaultPathCheckBox->isChecked()) - fileName = defaultPath; - else - fileName = QFileDialog::getSaveFileName(this, windowName, defaultPath, fileType); - } - if (fileName.isEmpty()) { + if (fileName.isEmpty()) return false; - } QFileInfo fi(fileName); QDir fileDir(fi.path()); @@ -741,55 +701,24 @@ void SaveTokensPage::retranslateUi() "Press \"Save\" to save the imported tokens to the Cockatrice tokens database.")); defaultPathCheckBox->setText(tr("Save to the default path (recommended)")); - #ifdef PORTABLE_BUILD - defaultPathCheckBox->setEnabled(false); - #endif } bool SaveTokensPage::validatePage() { bool ok = false; - QString dataDir; - #ifndef PORTABLE_BUILD -#if QT_VERSION < 0x050000 - dataDir = QDesktopServices::storageLocation(QDesktopServices::DataLocation); -#else - dataDir = QStandardPaths::standardLocations(QStandardPaths::DataLocation).first(); -#endif -#else - dataDir = qApp->applicationDirPath() + "/data"; -#endif - -#ifdef PORTABLE_BUILD - QSettings* settings = new QSettings("settings/global.ini",QSettings::IniFormat,this); - QString defaultPath = "data/tokens.xml"; - settings->setValue("paths/tokendatabase", defaultPath); -#else - QSettings* settings = new QSettings(settingsCache->getSettingsPath()+"global.ini",QSettings::IniFormat,this); - QString defaultPath = settings->value("paths/tokendatabase").toString(); -#endif - + QString defaultPath = settingsCache->getTokenDatabasePath(); QString windowName = tr("Save token database"); QString fileType = tr("XML; token database (*.xml)"); do { QString fileName; - if (defaultPath.isEmpty()) { - if (defaultPathCheckBox->isChecked()) - fileName = dataDir + "/tokens.xml"; - else - fileName = QFileDialog::getSaveFileName(this, windowName, dataDir + "/tokens.xml", fileType); - settings->setValue("paths/tokendatabase", fileName); - } - else { - if (defaultPathCheckBox->isChecked()) - fileName = defaultPath; - else - fileName = QFileDialog::getSaveFileName(this, windowName, defaultPath, fileType); - } - if (fileName.isEmpty()) { + if (defaultPathCheckBox->isChecked()) + fileName = defaultPath; + else + fileName = QFileDialog::getSaveFileName(this, windowName, defaultPath, fileType); + + if (fileName.isEmpty()) return false; - } QFileInfo fi(fileName); QDir fileDir(fi.path()); diff --git a/servatrice/CMakeLists.txt b/servatrice/CMakeLists.txt index 6df8f921a..7c2bcb0ee 100644 --- a/servatrice/CMakeLists.txt +++ b/servatrice/CMakeLists.txt @@ -117,8 +117,6 @@ INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR}) # Build servatrice binary and link it ADD_EXECUTABLE(servatrice MACOSX_BUNDLE ${servatrice_SOURCES} ${servatrice_RESOURCES_RCC} ${servatrice_MOC_SRCS}) -set_property(TARGET servatrice PROPERTY CXX_STANDARD 11) -set_property(TARGET servatrice PROPERTY CXX_STANDARD_REQUIRED ON) if(Qt4_FOUND) if(MSVC) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 93deb7df5..5591a9913 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -35,4 +35,6 @@ if(NOT GTEST_FOUND) endif() include_directories(${GTEST_INCLUDE_DIRS}) -target_link_libraries(dummy_test ${GTEST_BOTH_LIBRARIES}) \ No newline at end of file +target_link_libraries(dummy_test ${GTEST_BOTH_LIBRARIES}) + +add_subdirectory(carddatabase) \ No newline at end of file diff --git a/tests/carddatabase/CMakeLists.txt b/tests/carddatabase/CMakeLists.txt new file mode 100644 index 000000000..4f0e1e578 --- /dev/null +++ b/tests/carddatabase/CMakeLists.txt @@ -0,0 +1,44 @@ +ADD_DEFINITIONS("-DCARDDB_DATADIR=\"${CMAKE_CURRENT_SOURCE_DIR}/data/\"") +add_executable(carddatabase_test + carddatabase_test.cpp + ../../cockatrice/src/carddatabase.cpp + +) +if(NOT GTEST_FOUND) + add_dependencies(carddatabase_test gtest) +endif() +target_link_libraries(carddatabase_test ${GTEST_BOTH_LIBRARIES}) +add_test(NAME carddatabase_test COMMAND carddatabase_test) + +# Qt4 stuff +if(Qt4_FOUND) + SET(QT_USE_QTNETWORK TRUE) + SET(QT_USE_QTMULTIMEDIA TRUE) + + # Include directories + INCLUDE(${QT_USE_FILE}) + INCLUDE_DIRECTORIES(${QT_INCLUDES}) + TARGET_LINK_LIBRARIES(carddatabase_test ${QT_LIBRARIES}) +endif() + +# qt5 stuff +if(Qt5Widgets_FOUND) + include_directories(${Qt5Widgets_INCLUDE_DIRS}) + list(APPEND COCKATRICE_LIBS Widgets) + + # QtConcurrent + find_package(Qt5Concurrent) + if(Qt5Concurrent_FOUND) + include_directories(${Qt5Concurrent_INCLUDE_DIRS}) + list(APPEND ORACLE_LIBS Concurrent) + endif() + + # QtNetwork + find_package(Qt5Network) + if(Qt5Network_FOUND) + include_directories(${Qt5Network_INCLUDE_DIRS}) + list(APPEND COCKATRICE_LIBS Network) + endif() + + qt5_use_modules(carddatabase_test ${COCKATRICE_LIBS}) +endif() \ No newline at end of file diff --git a/tests/carddatabase/carddatabase_test.cpp b/tests/carddatabase/carddatabase_test.cpp new file mode 100644 index 000000000..66fcad32d --- /dev/null +++ b/tests/carddatabase/carddatabase_test.cpp @@ -0,0 +1,60 @@ +#include "gtest/gtest.h" + +#include "carddatabase_test.h" + +void CardDatabaseSettings::setSortKey(QString /* shortName */, unsigned int /* sortKey */) { }; +void CardDatabaseSettings::setEnabled(QString /* shortName */, bool /* enabled */) { }; +void CardDatabaseSettings::setIsKnown(QString /* shortName */, bool /* isknown */) { }; +unsigned int CardDatabaseSettings::getSortKey(QString /* shortName */) { return 0; }; +bool CardDatabaseSettings::isEnabled(QString /* shortName */) { return true; }; +bool CardDatabaseSettings::isKnown(QString /* shortName */) { return true; }; + +SettingsCache::SettingsCache() { cardDatabaseSettings = new CardDatabaseSettings(); }; +SettingsCache::~SettingsCache() { delete cardDatabaseSettings; }; +QString SettingsCache::getCustomCardDatabasePath() const { return QString("%1/customsets/").arg(CARDDB_DATADIR); } +QString SettingsCache::getCardDatabasePath() const { return QString("%1/cards.xml").arg(CARDDB_DATADIR); } +QString SettingsCache::getTokenDatabasePath() const { return QString("%1/tokens.xml").arg(CARDDB_DATADIR); } +CardDatabaseSettings& SettingsCache::cardDatabase() const { return *cardDatabaseSettings; } + +SettingsCache *settingsCache; + +void PictureLoader::clearPixmapCache(CardInfo * /* card */) { } + +// include out main header file _after_ the hack is complete +#include "../../cockatrice/src/carddatabase.h" + +namespace { + + TEST(CardDatabaseTest, LoadXml) { + settingsCache = new SettingsCache; + CardDatabase *db = new CardDatabase; + + // ensure the card database is empty at start + ASSERT_EQ(0, db->getCardList().size()) << "Cards not empty at start"; + ASSERT_EQ(0, db->getSetList().size()) << "Sets not empty at start"; + ASSERT_EQ(0, db->getAllColors().size()) << "Colors not empty at start"; + ASSERT_EQ(0, db->getAllMainCardTypes().size()) << "Types not empty at start"; + ASSERT_EQ(NotLoaded, db->getLoadStatus()) << "Incorrect status at start"; + + // load dummy cards and test result + db->loadCardDatabases(); + ASSERT_EQ(6, db->getCardList().size()) << "Wrong card count after load"; + ASSERT_EQ(3, db->getSetList().size()) << "Wrong sets count after load"; + ASSERT_EQ(4, db->getAllColors().size()) << "Wrong colors count after load"; + ASSERT_EQ(2, db->getAllMainCardTypes().size()) << "Wrong types count after load"; + ASSERT_EQ(Ok, db->getLoadStatus()) << "Wrong status after load"; + + // ensure the card database is empty after clear() + db->clear(); + ASSERT_EQ(0, db->getCardList().size()) << "Cards not empty after clear"; + ASSERT_EQ(0, db->getSetList().size()) << "Sets not empty after clear"; + ASSERT_EQ(0, db->getAllColors().size()) << "Colors not empty after clear"; + ASSERT_EQ(0, db->getAllMainCardTypes().size()) << "Types not empty after clear"; + ASSERT_EQ(NotLoaded, db->getLoadStatus()) << "Incorrect status after clear"; + } +} + +int main(int argc, char **argv) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} \ No newline at end of file diff --git a/tests/carddatabase/carddatabase_test.h b/tests/carddatabase/carddatabase_test.h new file mode 100644 index 000000000..a29b28576 --- /dev/null +++ b/tests/carddatabase/carddatabase_test.h @@ -0,0 +1,44 @@ +/* + * Beware of this preprocessor hack used to redefine the settingCache class + * instead of including it and all of its dependencies. + */ + +#include +#include + +#define SETTINGSCACHE_H + +class CardDatabaseSettings +{ +public: + void setSortKey(QString shortName, unsigned int sortKey); + void setEnabled(QString shortName, bool enabled); + void setIsKnown(QString shortName, bool isknown); + + unsigned int getSortKey(QString shortName); + bool isEnabled(QString shortName); + bool isKnown(QString shortName); +}; + +class SettingsCache: public QObject { + Q_OBJECT +private: + CardDatabaseSettings *cardDatabaseSettings; +public: + SettingsCache(); + ~SettingsCache(); + QString getCustomCardDatabasePath() const; + QString getCardDatabasePath() const; + QString getTokenDatabasePath() const; + CardDatabaseSettings& cardDatabase() const; +signals: + void cardDatabasePathChanged(); +}; + + +#define PICTURELOADER_H +class CardInfo; + +class PictureLoader { + void clearPixmapCache(CardInfo *card); +}; diff --git a/tests/carddatabase/data/cards.xml b/tests/carddatabase/data/cards.xml new file mode 100644 index 000000000..c0dc7dd29 --- /dev/null +++ b/tests/carddatabase/data/cards.xml @@ -0,0 +1,27 @@ + + + + + Cat + CAT + G + 2G + 2 + Creature + 3/3 + 0 + Meow! + + + Dog + DOG + R + 2RR + 4 + Creature + 4/4 + 0 + Woof! + + + diff --git a/tests/carddatabase/data/customsets/customset1.xml b/tests/carddatabase/data/customsets/customset1.xml new file mode 100644 index 000000000..b2f187d54 --- /dev/null +++ b/tests/carddatabase/data/customsets/customset1.xml @@ -0,0 +1,27 @@ + + + + + Sparrow + BRD + W + W + 1 + Creature + 1/1 + 0 + + + + Crow + BRD + B + 1B + 2 + Creature + 2/2 + 0 + + + + diff --git a/tests/carddatabase/data/tokens.xml b/tests/carddatabase/data/tokens.xml new file mode 100644 index 000000000..03b539a5a --- /dev/null +++ b/tests/carddatabase/data/tokens.xml @@ -0,0 +1,29 @@ + + + + + Kitten + CAT + G + + + Token + 1/1 + 0 + + 1 + + + Puppy + DOG + R + + + Token + 1/1 + 0 + + 1 + + + diff --git a/travis-dependencies.sh b/travis-dependencies.sh index 8a64dd3c3..4409885d9 100755 --- a/travis-dependencies.sh +++ b/travis-dependencies.sh @@ -11,9 +11,10 @@ if [[ $TRAVIS_OS_NAME == "osx" ]] ; then brew upgrade cmake else - # common prerequisites + sudo add-apt-repository -y ppa:smspillaz/cmake-master sudo apt-get update -qq + sudo apt-get -y purge cmake sudo apt-get install -y libprotobuf-dev protobuf-compiler cmake bc if (( QT4 )); then @@ -28,15 +29,7 @@ else # prerequisites for tests if [[ $BUILDTYPE == "Debug" ]]; then - if [[ $DIST == "precise" ]]; then - sudo add-apt-repository -y ppa:george-edison55/precise-backports - sudo apt-get update -qq - sudo apt-get install -y cmake cmake-data libgtest-dev - else - sudo add-apt-repository -y ppa:george-edison55/cmake-3.x - sudo apt-get update -qq - sudo apt-get install -y cmake cmake-extras libgtest-dev - fi + sudo apt-get install -y libgtest-dev sudo mkdir /usr/src/gtest/build cd /usr/src/gtest/build