diff --git a/acquisition.pro b/acquisition.pro index af92c39e..6ed977c8 100644 --- a/acquisition.pro +++ b/acquisition.pro @@ -4,13 +4,13 @@ TEMPLATE = app QT += core gui network testlib win32 { - QT += winextras - QT.testlib.CONFIG -= console + QT += winextras + QT.testlib.CONFIG -= console } unix { - LIBS += -ldl - QMAKE_CXXFLAGS += -Wno-inconsistent-missing-override + LIBS += -ldl + QMAKE_CXXFLAGS += -Wno-inconsistent-missing-override } nowebengine { @@ -23,112 +23,112 @@ greaterThan(QT_MAJOR_VERSION, 4): QT += widgets include(deps/QsLog/QsLog.pri) -INCLUDEPATH += src deps deps/boost-header-only "C:\Qt\Tools\OpenSSL\Win_x64\include" +INCLUDEPATH += src deps deps/boost-header-only "C:\Program Files\OpenSSL-Win64\include" SOURCES += \ - deps/sqlite/sqlite3.c \ - src/application.cpp \ - src/autoonline.cpp \ - src/bucket.cpp \ - src/buyoutmanager.cpp \ - src/column.cpp \ - src/currencymanager.cpp \ - src/influence.cpp \ - src/sqlitedatastore.cpp \ - src/filesystem.cpp \ - src/filters.cpp \ - src/flowlayout.cpp \ - src/imagecache.cpp \ - src/influence.cpp \ - src/item.cpp \ - src/itemlocation.cpp \ - src/items_model.cpp \ - src/itemsmanager.cpp \ - src/itemsmanagerworker.cpp \ - src/itemtooltip.cpp \ - src/logindialog.cpp \ - src/logpanel.cpp \ - src/main.cpp \ - src/mainwindow.cpp \ - src/memorydatastore.cpp \ - src/modlist.cpp \ - src/modsfilter.cpp \ - src/porting.cpp \ - src/replytimeout.cpp \ - src/search.cpp \ - src/shop.cpp \ - src/steamlogindialog.cpp \ - src/tabcache.cpp \ - src/updatechecker.cpp \ - src/util.cpp \ - src/version.cpp \ - src/verticalscrollarea.cpp \ - test/testdata.cpp \ - test/testitem.cpp \ - test/testitemsmanager.cpp \ - test/testmain.cpp \ - test/testshop.cpp \ - test/testutil.cpp + deps/sqlite/sqlite3.c \ + src/application.cpp \ + src/autoonline.cpp \ + src/bucket.cpp \ + src/buyoutmanager.cpp \ + src/column.cpp \ + src/currencymanager.cpp \ + src/influence.cpp \ + src/sqlitedatastore.cpp \ + src/filesystem.cpp \ + src/filters.cpp \ + src/flowlayout.cpp \ + src/imagecache.cpp \ + src/influence.cpp \ + src/item.cpp \ + src/itemlocation.cpp \ + src/items_model.cpp \ + src/itemsmanager.cpp \ + src/itemsmanagerworker.cpp \ + src/itemtooltip.cpp \ + src/logindialog.cpp \ + src/logpanel.cpp \ + src/main.cpp \ + src/mainwindow.cpp \ + src/memorydatastore.cpp \ + src/modlist.cpp \ + src/modsfilter.cpp \ + src/porting.cpp \ + src/replytimeout.cpp \ + src/search.cpp \ + src/shop.cpp \ + src/steamlogindialog.cpp \ + src/tabcache.cpp \ + src/updatechecker.cpp \ + src/util.cpp \ + src/version.cpp \ + src/verticalscrollarea.cpp \ + test/testdata.cpp \ + test/testitem.cpp \ + test/testitemsmanager.cpp \ + test/testmain.cpp \ + test/testshop.cpp \ + test/testutil.cpp HEADERS += \ - deps/sqlite/sqlite3.h \ - src/application.h \ - src/autoonline.h \ - src/bucket.h \ - src/buyoutmanager.h \ - src/column.h \ - src/currencymanager.h \ - src/datastore.h \ - src/influence.h \ - src/sqlitedatastore.h \ - src/filesystem.h \ - src/filters.h \ - src/flowlayout.h \ - src/imagecache.h \ - src/influence.h \ - src/item.h \ - src/itemconstants.h \ - src/itemlocation.h \ - src/items_model.h \ - src/itemsmanager.h \ - src/itemsmanagerworker.h \ - src/itemtooltip.h \ - src/logindialog.h \ - src/logpanel.h \ - src/mainwindow.h \ - src/memorydatastore.h \ - src/modlist.h \ - src/modsfilter.h \ - src/porting.h \ - src/rapidjson_util.h \ - src/replytimeout.h \ - src/search.h \ - src/selfdestructingreply.h \ - src/shop.h \ - src/steamlogindialog.h \ - src/tabcache.h \ - src/updatechecker.h \ - src/util.h \ - src/version.h \ - src/version_defines.h \ - src/verticalscrollarea.h \ - test/testdata.h \ - test/testitem.h \ - test/testitemsmanager.h \ - test/testmain.h \ - test/testshop.h \ - test/testutil.h + deps/sqlite/sqlite3.h \ + src/application.h \ + src/autoonline.h \ + src/bucket.h \ + src/buyoutmanager.h \ + src/column.h \ + src/currencymanager.h \ + src/datastore.h \ + src/influence.h \ + src/sqlitedatastore.h \ + src/filesystem.h \ + src/filters.h \ + src/flowlayout.h \ + src/imagecache.h \ + src/influence.h \ + src/item.h \ + src/itemconstants.h \ + src/itemlocation.h \ + src/items_model.h \ + src/itemsmanager.h \ + src/itemsmanagerworker.h \ + src/itemtooltip.h \ + src/logindialog.h \ + src/logpanel.h \ + src/mainwindow.h \ + src/memorydatastore.h \ + src/modlist.h \ + src/modsfilter.h \ + src/porting.h \ + src/rapidjson_util.h \ + src/replytimeout.h \ + src/search.h \ + src/selfdestructingreply.h \ + src/shop.h \ + src/steamlogindialog.h \ + src/tabcache.h \ + src/updatechecker.h \ + src/util.h \ + src/version.h \ + src/version_defines.h \ + src/verticalscrollarea.h \ + test/testdata.h \ + test/testitem.h \ + test/testitemsmanager.h \ + test/testmain.h \ + test/testshop.h \ + test/testutil.h FORMS += \ - forms/mainwindow.ui \ - forms/logindialog.ui \ - forms/steamlogindialog.ui + forms/mainwindow.ui \ + forms/logindialog.ui \ + forms/steamlogindialog.ui #CONFIG += c++11 DEPENDPATH *= $${INCLUDEPATH} RESOURCES += resources.qrc \ - deps/qdarkstyle/style.qrc + deps/qdarkstyle/style.qrc RC_FILE = resources.rc diff --git a/src/application.h b/src/application.h index 0bd0b535..d962889a 100644 --- a/src/application.h +++ b/src/application.h @@ -1,20 +1,20 @@ /* - Copyright 2014 Ilya Zhuravlev + Copyright 2014 Ilya Zhuravlev - This file is part of Acquisition. + This file is part of Acquisition. - Acquisition is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. + Acquisition is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. - Acquisition is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. + Acquisition is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. - You should have received a copy of the GNU General Public License - along with Acquisition. If not, see . + You should have received a copy of the GNU General Public License + along with Acquisition. If not, see . */ #pragma once @@ -33,35 +33,35 @@ class Shop; class CurrencyManager; class Application : public QObject { - Q_OBJECT + Q_OBJECT public: - Application(); - ~Application(); - Application(const Application&) = delete; - Application& operator=(const Application&) = delete; - // Should be called by login dialog after login - void InitLogin(std::unique_ptr login_manager, const std::string &league, const std::string &email, bool mock_data = false); - const std::string &league() const { return league_; } - const std::string &email() const { return email_; } - ItemsManager &items_manager() { return *items_manager_; } - DataStore &data() const { return *data_; } - DataStore &sensitive_data() const { return *sensitive_data_; } - BuyoutManager &buyout_manager() const { return *buyout_manager_; } - QNetworkAccessManager &logged_in_nm() const { return *logged_in_nm_; } - Shop &shop() const { return *shop_; } - CurrencyManager ¤cy_manager() const { return *currency_manager_; } + Application(); + ~Application(); + Application(const Application&) = delete; + Application& operator=(const Application&) = delete; + // Should be called by login dialog after login + void InitLogin(std::unique_ptr login_manager, const std::string &league, const std::string &email, bool mock_data = false); + const std::string &league() const { return league_; } + const std::string &email() const { return email_; } + ItemsManager &items_manager() { return *items_manager_; } + DataStore &data() const { return *data_; } + DataStore &sensitive_data() const { return *sensitive_data_; } + BuyoutManager &buyout_manager() const { return *buyout_manager_; } + QNetworkAccessManager &logged_in_nm() const { return *logged_in_nm_; } + Shop &shop() const { return *shop_; } + CurrencyManager ¤cy_manager() const { return *currency_manager_; } public slots: - void OnItemsRefreshed(bool initial_refresh); + void OnItemsRefreshed(bool initial_refresh); private: - std::string league_; - std::string email_; - std::unique_ptr data_; - // stores sensitive data that you'd rather not share, like control.poe.trade secret URL - std::unique_ptr sensitive_data_; - std::unique_ptr buyout_manager_; - std::unique_ptr shop_; - std::unique_ptr logged_in_nm_; - std::unique_ptr items_manager_; - std::unique_ptr currency_manager_; - void SaveDbOnNewVersion(); + std::string league_; + std::string email_; + std::unique_ptr data_; + // stores sensitive data that you'd rather not share, like control.poe.trade secret URL + std::unique_ptr sensitive_data_; + std::unique_ptr buyout_manager_; + std::unique_ptr shop_; + std::unique_ptr logged_in_nm_; + std::unique_ptr items_manager_; + std::unique_ptr currency_manager_; + void SaveDbOnNewVersion(); }; diff --git a/src/autoonline.h b/src/autoonline.h index fc1490d7..40acbadb 100644 --- a/src/autoonline.h +++ b/src/autoonline.h @@ -1,20 +1,20 @@ /* - Copyright 2015 Ilya Zhuravlev + Copyright 2015 Ilya Zhuravlev - This file is part of Acquisition. + This file is part of Acquisition. - Acquisition is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. + Acquisition is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. - Acquisition is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. + Acquisition is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. - You should have received a copy of the GNU General Public License - along with Acquisition. If not, see . + You should have received a copy of the GNU General Public License + along with Acquisition. If not, see . */ #pragma once @@ -26,27 +26,27 @@ class DataStore; class AutoOnline : public QObject { - Q_OBJECT + Q_OBJECT public: - AutoOnline(DataStore &data, DataStore &sensitive_data); - void SetUrl(const std::string &url); - void SetEnabled(bool enabled); - bool enabled() { return enabled_; } - bool IsUrlSet() { return !url_.empty(); } - bool IsRemoteScriptSet() { return !process_script_.empty(); } - void SendOnlineUpdate(bool online); - void SetRemoteScript(const std::string& script); + AutoOnline(DataStore &data, DataStore &sensitive_data); + void SetUrl(const std::string &url); + void SetEnabled(bool enabled); + bool enabled() { return enabled_; } + bool IsUrlSet() { return !url_.empty(); } + bool IsRemoteScriptSet() { return !process_script_.empty(); } + void SendOnlineUpdate(bool online); + void SetRemoteScript(const std::string& script); public slots: - void Check(); + void Check(); signals: - void Update(bool running); + void Update(bool running); private: - DataStore &data_; - DataStore &sensitive_data_; - bool enabled_; - std::string url_; - std::string process_script_; - bool previous_status_; - QTimer timer_; - QNetworkAccessManager nm_; + DataStore &data_; + DataStore &sensitive_data_; + bool enabled_; + std::string url_; + std::string process_script_; + bool previous_status_; + QTimer timer_; + QNetworkAccessManager nm_; }; diff --git a/src/bucket.h b/src/bucket.h index f4052598..50fac2ad 100644 --- a/src/bucket.h +++ b/src/bucket.h @@ -9,15 +9,15 @@ // Items are "bucketed" by their location: stash tab / character. class Bucket { public: - Bucket(); - explicit Bucket(const ItemLocation &location); - void AddItem(const std::shared_ptr &item); - const Items &items() const { return items_; } - const std::shared_ptr &item(int row) const; - const ItemLocation &location() const { return location_; } - void Sort(const Column &column, Qt::SortOrder order); + Bucket(); + explicit Bucket(const ItemLocation &location); + void AddItem(const std::shared_ptr &item); + const Items &items() const { return items_; } + const std::shared_ptr &item(int row) const; + const ItemLocation &location() const { return location_; } + void Sort(const Column &column, Qt::SortOrder order); private: - Items items_; - ItemLocation location_; + Items items_; + ItemLocation location_; }; diff --git a/src/buyoutmanager.h b/src/buyoutmanager.h index 83ab6fa7..6722a1bd 100644 --- a/src/buyoutmanager.h +++ b/src/buyoutmanager.h @@ -1,20 +1,20 @@ /* - Copyright 2014 Ilya Zhuravlev + Copyright 2014 Ilya Zhuravlev - This file is part of Acquisition. + This file is part of Acquisition. - Acquisition is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. + Acquisition is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. - Acquisition is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. + Acquisition is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. - You should have received a copy of the GNU General Public License - along with Acquisition. If not, see . + You should have received a copy of the GNU General Public License + along with Acquisition. If not, see . */ #pragma once @@ -26,169 +26,169 @@ class ItemLocation; enum CurrencyType { - CURRENCY_NONE, - CURRENCY_ORB_OF_ALTERATION, - CURRENCY_ORB_OF_FUSING, - CURRENCY_ORB_OF_ALCHEMY, - CURRENCY_CHAOS_ORB, - CURRENCY_GCP, - CURRENCY_EXALTED_ORB, - CURRENCY_CHROMATIC_ORB, - CURRENCY_JEWELLERS_ORB, - CURRENCY_ORB_OF_CHANCE, - CURRENCY_CARTOGRAPHERS_CHISEL, - CURRENCY_ORB_OF_SCOURING, - CURRENCY_BLESSED_ORB, - CURRENCY_ORB_OF_REGRET, - CURRENCY_REGAL_ORB, - CURRENCY_DIVINE_ORB, - CURRENCY_VAAL_ORB, - CURRENCY_PERANDUS_COIN, - CURRENCY_MIRROR_OF_KALANDRA, - CURRENCY_SILVER_COIN, + CURRENCY_NONE, + CURRENCY_ORB_OF_ALTERATION, + CURRENCY_ORB_OF_FUSING, + CURRENCY_ORB_OF_ALCHEMY, + CURRENCY_CHAOS_ORB, + CURRENCY_GCP, + CURRENCY_EXALTED_ORB, + CURRENCY_CHROMATIC_ORB, + CURRENCY_JEWELLERS_ORB, + CURRENCY_ORB_OF_CHANCE, + CURRENCY_CARTOGRAPHERS_CHISEL, + CURRENCY_ORB_OF_SCOURING, + CURRENCY_BLESSED_ORB, + CURRENCY_ORB_OF_REGRET, + CURRENCY_REGAL_ORB, + CURRENCY_DIVINE_ORB, + CURRENCY_VAAL_ORB, + CURRENCY_PERANDUS_COIN, + CURRENCY_MIRROR_OF_KALANDRA, + CURRENCY_SILVER_COIN, }; enum BuyoutType { - BUYOUT_TYPE_IGNORE, - BUYOUT_TYPE_BUYOUT, - BUYOUT_TYPE_FIXED, - BUYOUT_TYPE_CURRENT_OFFER, - BUYOUT_TYPE_NO_PRICE, - BUYOUT_TYPE_INHERIT, + BUYOUT_TYPE_IGNORE, + BUYOUT_TYPE_BUYOUT, + BUYOUT_TYPE_FIXED, + BUYOUT_TYPE_CURRENT_OFFER, + BUYOUT_TYPE_NO_PRICE, + BUYOUT_TYPE_INHERIT, }; enum BuyoutSource { - BUYOUT_SOURCE_NONE, - BUYOUT_SOURCE_MANUAL, - BUYOUT_SOURCE_GAME, - BUYOUT_SOURCE_AUTO + BUYOUT_SOURCE_NONE, + BUYOUT_SOURCE_MANUAL, + BUYOUT_SOURCE_GAME, + BUYOUT_SOURCE_AUTO }; struct Currency { - typedef std::map CurrencyTypeMap; - typedef std::map CurrencyRankMap; + typedef std::map CurrencyTypeMap; + typedef std::map CurrencyRankMap; - Currency() = default; - Currency(CurrencyType in_type): type(in_type) { }; + Currency() = default; + Currency(CurrencyType in_type): type(in_type) { }; - CurrencyType type{CURRENCY_NONE}; + CurrencyType type{CURRENCY_NONE}; - static std::vector Types(); - static Currency FromIndex(int i); - static Currency FromTag(std::string tag); + static std::vector Types(); + static Currency FromIndex(int i); + static Currency FromTag(std::string tag); - bool operator==(const Currency& rhs) const { return type == rhs.type; } - bool operator!=(const Currency& rhs) const { return type != rhs.type; } - bool operator<(const Currency& rhs) const { return type < rhs.type; } + bool operator==(const Currency& rhs) const { return type == rhs.type; } + bool operator!=(const Currency& rhs) const { return type != rhs.type; } + bool operator<(const Currency& rhs) const { return type < rhs.type; } - const std::string &AsString() const; - const std::string &AsTag() const; - const int &AsRank() const; + const std::string &AsString() const; + const std::string &AsTag() const; + const int &AsRank() const; private: - static const std::string currency_type_error_; - static const CurrencyTypeMap currency_type_as_string_; - static const CurrencyTypeMap currency_type_as_tag_; - static const CurrencyRankMap currency_type_as_rank_; + static const std::string currency_type_error_; + static const CurrencyTypeMap currency_type_as_string_; + static const CurrencyTypeMap currency_type_as_tag_; + static const CurrencyRankMap currency_type_as_rank_; }; struct Buyout { - typedef std::map BuyoutTypeMap; - typedef std::map BuyoutSourceMap; - - double value; - BuyoutType type; - BuyoutSource source{BUYOUT_SOURCE_MANUAL}; - Currency currency; - QDateTime last_update; - bool inherited = false; - bool operator==(const Buyout &o) const; - bool operator!=(const Buyout &o) const; - bool IsValid() const; - bool IsActive() const; - bool IsInherited() const { return inherited || type == BUYOUT_TYPE_INHERIT; }; - bool IsSavable() const { return IsValid() && !(type == BUYOUT_TYPE_INHERIT); }; - bool IsPostable() const; - bool IsPriced() const; - bool IsGameSet() const; - bool RequiresRefresh() const; - - static BuyoutType TagAsBuyoutType(std::string tag); - static BuyoutType IndexAsBuyoutType(int index); - static BuyoutSource TagAsBuyoutSource(std::string tag); - - std::string AsText() const; - const std::string &BuyoutTypeAsTag() const; - const std::string &BuyoutTypeAsPrefix() const; - const std::string &BuyoutSourceAsTag() const; - const std::string &CurrencyAsTag() const; - - Buyout() : - value(0), - type(BUYOUT_TYPE_INHERIT), - currency(CURRENCY_NONE) - {} - Buyout(double value_, BuyoutType type_, Currency currency_, QDateTime last_update_) : - value(value_), - type(type_), - currency(currency_), - last_update(last_update_) - {} + typedef std::map BuyoutTypeMap; + typedef std::map BuyoutSourceMap; + + double value; + BuyoutType type; + BuyoutSource source{BUYOUT_SOURCE_MANUAL}; + Currency currency; + QDateTime last_update; + bool inherited = false; + bool operator==(const Buyout &o) const; + bool operator!=(const Buyout &o) const; + bool IsValid() const; + bool IsActive() const; + bool IsInherited() const { return inherited || type == BUYOUT_TYPE_INHERIT; }; + bool IsSavable() const { return IsValid() && !(type == BUYOUT_TYPE_INHERIT); }; + bool IsPostable() const; + bool IsPriced() const; + bool IsGameSet() const; + bool RequiresRefresh() const; + + static BuyoutType TagAsBuyoutType(std::string tag); + static BuyoutType IndexAsBuyoutType(int index); + static BuyoutSource TagAsBuyoutSource(std::string tag); + + std::string AsText() const; + const std::string &BuyoutTypeAsTag() const; + const std::string &BuyoutTypeAsPrefix() const; + const std::string &BuyoutSourceAsTag() const; + const std::string &CurrencyAsTag() const; + + Buyout() : + value(0), + type(BUYOUT_TYPE_INHERIT), + currency(CURRENCY_NONE) + {} + Buyout(double value_, BuyoutType type_, Currency currency_, QDateTime last_update_) : + value(value_), + type(type_), + currency(currency_), + last_update(last_update_) + {} private: - static const std::string buyout_type_error_; - static const BuyoutTypeMap buyout_type_as_tag_; - static const BuyoutTypeMap buyout_type_as_prefix_; - static const BuyoutSourceMap buyout_source_as_tag_; + static const std::string buyout_type_error_; + static const BuyoutTypeMap buyout_type_as_tag_; + static const BuyoutTypeMap buyout_type_as_prefix_; + static const BuyoutSourceMap buyout_source_as_tag_; }; class DataStore; class BuyoutManager { public: - explicit BuyoutManager(DataStore &data); - void Set(const Item &item, const Buyout &buyout); - Buyout Get(const Item &item) const; + explicit BuyoutManager(DataStore &data); + void Set(const Item &item, const Buyout &buyout); + Buyout Get(const Item &item) const; - void SetTab(const std::string &tab, const Buyout &buyout); - Buyout GetTab(const std::string &tab) const; - void CompressTabBuyouts(); - void CompressItemBuyouts(const Items &items); + void SetTab(const std::string &tab, const Buyout &buyout); + Buyout GetTab(const std::string &tab) const; + void CompressTabBuyouts(); + void CompressItemBuyouts(const Items &items); - void SetRefreshChecked(const ItemLocation &tab, bool value); - bool GetRefreshChecked(const ItemLocation &tab) const; + void SetRefreshChecked(const ItemLocation &tab, bool value); + bool GetRefreshChecked(const ItemLocation &tab) const; - bool GetRefreshLocked(const ItemLocation &tab) const; - void SetRefreshLocked(const ItemLocation &tab); - void ClearRefreshLocks(); + bool GetRefreshLocked(const ItemLocation &tab) const; + void SetRefreshLocked(const ItemLocation &tab); + void ClearRefreshLocks(); - void SetStashTabLocations(const std::vector &tabs); - const std::vector GetStashTabLocations() const; - void Clear(); + void SetStashTabLocations(const std::vector &tabs); + const std::vector GetStashTabLocations() const; + void Clear(); - Buyout StringToBuyout(std::string); + Buyout StringToBuyout(std::string); - void Save(); - void Load(); + void Save(); + void Load(); - void MigrateItem(const Item &item); + void MigrateItem(const Item &item); private: - Currency StringToCurrencyType(std::string currency) const; - BuyoutType StringToBuyoutType(std::string bo_str) const; - - std::string Serialize(const std::map &buyouts); - void Deserialize(const std::string &data, std::map *buyouts); - - std::string Serialize(const std::map &obj); - void Deserialize(const std::string &data, std::map &obj); - - DataStore &data_; - std::map buyouts_; - std::map tab_buyouts_; - std::map refresh_checked_; - std::set refresh_locked_; - bool save_needed_; - std::vector tabs_; - static const std::map string_to_buyout_type_; - static const std::map string_to_currency_type_; + Currency StringToCurrencyType(std::string currency) const; + BuyoutType StringToBuyoutType(std::string bo_str) const; + + std::string Serialize(const std::map &buyouts); + void Deserialize(const std::string &data, std::map *buyouts); + + std::string Serialize(const std::map &obj); + void Deserialize(const std::string &data, std::map &obj); + + DataStore &data_; + std::map buyouts_; + std::map tab_buyouts_; + std::map refresh_checked_; + std::set refresh_locked_; + bool save_needed_; + std::vector tabs_; + static const std::map string_to_buyout_type_; + static const std::map string_to_currency_type_; }; diff --git a/src/column.h b/src/column.h index 2f044e53..7abe3618 100644 --- a/src/column.h +++ b/src/column.h @@ -1,20 +1,20 @@ /* - Copyright 2014 Ilya Zhuravlev + Copyright 2014 Ilya Zhuravlev - This file is part of Acquisition. + This file is part of Acquisition. - Acquisition is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. + Acquisition is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. - Acquisition is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. + Acquisition is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. - You should have received a copy of the GNU General Public License - along with Acquisition. If not, see . + You should have received a copy of the GNU General Public License + along with Acquisition. If not, see . */ #pragma once @@ -29,139 +29,139 @@ class BuyoutManager; class Column { public: - virtual std::string name() const = 0; - virtual QVariant value(const Item &item) const = 0; - virtual QVariant icon(const Item &item) const = 0; - virtual QColor color(const Item &item) const; - virtual bool lt(const Item* lhs, const Item* rhs) const; - virtual ~Column() {} + virtual std::string name() const = 0; + virtual QVariant value(const Item &item) const = 0; + virtual QVariant icon(const Item &item) const = 0; + virtual QColor color(const Item &item) const; + virtual bool lt(const Item* lhs, const Item* rhs) const; + virtual ~Column() {} private: - std::tuple multivalue(const Item *item) const; + std::tuple multivalue(const Item *item) const; }; class NameColumn : public Column { public: - std::string name() const; - QVariant value(const Item &item) const; - QColor color(const Item &item) const; - QVariant icon(const Item &item) const {return NULL;} + std::string name() const; + QVariant value(const Item &item) const; + QColor color(const Item &item) const; + QVariant icon(const Item &item) const {return NULL;} }; class CorruptedColumn : public Column { public: - std::string name() const; - QVariant value(const Item &item) const; - QVariant icon(const Item &item) const {return NULL;} + std::string name() const; + QVariant value(const Item &item) const; + QVariant icon(const Item &item) const {return NULL;} }; class CraftedColumn : public Column { public: - std::string name() const; - QVariant value(const Item &item) const; - QVariant icon(const Item &item) const {return NULL;} + std::string name() const; + QVariant value(const Item &item) const; + QVariant icon(const Item &item) const {return NULL;} }; class EnchantedColumn : public Column { public: - std::string name() const; - QVariant value(const Item &item) const; - QVariant icon(const Item &item) const {return NULL;} + std::string name() const; + QVariant value(const Item &item) const; + QVariant icon(const Item &item) const {return NULL;} }; class InfluncedColumn : public Column { public: - std::string name() const; - QVariant value(const Item &item) const; - QVariant icon(const Item &item) const; + std::string name() const; + QVariant value(const Item &item) const; + QVariant icon(const Item &item) const; }; // Returns values from item -> properties class PropertyColumn : public Column { public: - explicit PropertyColumn(const std::string &name); - PropertyColumn(const std::string &name, const std::string &property); - std::string name() const; - QVariant value(const Item &item) const; - QVariant icon(const Item &item) const {return NULL;} + explicit PropertyColumn(const std::string &name); + PropertyColumn(const std::string &name, const std::string &property); + std::string name() const; + QVariant value(const Item &item) const; + QVariant icon(const Item &item) const {return NULL;} private: - std::string name_; - std::string property_; + std::string name_; + std::string property_; }; class DPSColumn : public Column { public: - std::string name() const; - QVariant value(const Item &item) const; - QVariant icon(const Item &item) const {return NULL;} + std::string name() const; + QVariant value(const Item &item) const; + QVariant icon(const Item &item) const {return NULL;} }; class pDPSColumn : public Column { public: - std::string name() const; - QVariant value(const Item &item) const; - QVariant icon(const Item &item) const {return NULL;} + std::string name() const; + QVariant value(const Item &item) const; + QVariant icon(const Item &item) const {return NULL;} }; class eDPSColumn : public Column { public: - std::string name() const; - QVariant value(const Item &item) const; - QVariant icon(const Item &item) const {return NULL;} + std::string name() const; + QVariant value(const Item &item) const; + QVariant icon(const Item &item) const {return NULL;} }; class ElementalDamageColumn : public Column { public: - explicit ElementalDamageColumn(int index); - std::string name() const; - QVariant value(const Item &item) const; - QColor color(const Item &item) const; - QVariant icon(const Item &item) const {return NULL;} + explicit ElementalDamageColumn(int index); + std::string name() const; + QVariant value(const Item &item) const; + QColor color(const Item &item) const; + QVariant icon(const Item &item) const {return NULL;} private: - size_t index_; + size_t index_; }; class ChaosDamageColumn : public Column { public: - std::string name() const; - QVariant value(const Item &item) const; - QColor color(const Item &item) const; - QVariant icon(const Item &item) const {return NULL;} + std::string name() const; + QVariant value(const Item &item) const; + QColor color(const Item &item) const; + QVariant icon(const Item &item) const {return NULL;} }; class cDPSColumn : public Column { public: - std::string name() const; - QVariant value(const Item &item) const; - QVariant icon(const Item &item) const {return NULL;} + std::string name() const; + QVariant value(const Item &item) const; + QVariant icon(const Item &item) const {return NULL;} }; class PriceColumn : public Column { public: - explicit PriceColumn(const BuyoutManager &bo_manager); - std::string name() const; - QVariant value(const Item &item) const; - QColor color(const Item &item) const; - bool lt(const Item *lhs, const Item *rhs) const; - QVariant icon(const Item &item) const {return NULL;} + explicit PriceColumn(const BuyoutManager &bo_manager); + std::string name() const; + QVariant value(const Item &item) const; + QColor color(const Item &item) const; + bool lt(const Item *lhs, const Item *rhs) const; + QVariant icon(const Item &item) const {return NULL;} private: - std::tuple multivalue(const Item *item) const; - const BuyoutManager &bo_manager_; + std::tuple multivalue(const Item *item) const; + const BuyoutManager &bo_manager_; }; class DateColumn : public Column { public: - explicit DateColumn(const BuyoutManager &bo_manager); - std::string name() const; - QVariant value(const Item &item) const; - bool lt(const Item *lhs, const Item *rhs) const; - QVariant icon(const Item &item) const {return NULL;} + explicit DateColumn(const BuyoutManager &bo_manager); + std::string name() const; + QVariant value(const Item &item) const; + bool lt(const Item *lhs, const Item *rhs) const; + QVariant icon(const Item &item) const {return NULL;} private: - const BuyoutManager &bo_manager_; + const BuyoutManager &bo_manager_; }; class ItemlevelColumn : public Column { public: - std::string name() const; - QVariant value(const Item &item) const; - QVariant icon(const Item &item) const {return NULL;} + std::string name() const; + QVariant value(const Item &item) const; + QVariant icon(const Item &item) const {return NULL;} }; diff --git a/src/currencymanager.h b/src/currencymanager.h index e77873e8..bfb6408a 100644 --- a/src/currencymanager.h +++ b/src/currencymanager.h @@ -1,20 +1,20 @@ /* - Copyright 2015 Guillaume DUPUY + Copyright 2015 Guillaume DUPUY - This file is part of Acquisition. + This file is part of Acquisition. - Acquisition is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. + Acquisition is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. - Acquisition is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. + Acquisition is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. - You should have received a copy of the GNU General Public License - along with Acquisition. If not, see . + You should have received a copy of the GNU General Public License + along with Acquisition. If not, see . */ #pragma once @@ -25,174 +25,174 @@ #include "application.h" #include "buyoutmanager.h" struct CurrencyRatio { - Currency curr1; - Currency curr2; - double value1; - double value2; - CurrencyRatio() : - curr1(CURRENCY_NONE), - curr2(CURRENCY_NONE), - value1(0), - value2(0) - {} - CurrencyRatio(Currency c1, Currency c2, double v1, double v2) : - curr1(c1), - curr2(c2), - value1(v1), - value2(v2) - {} + Currency curr1; + Currency curr2; + double value1; + double value2; + CurrencyRatio() : + curr1(CURRENCY_NONE), + curr2(CURRENCY_NONE), + value1(0), + value2(0) + {} + CurrencyRatio(Currency c1, Currency c2, double v1, double v2) : + curr1(c1), + curr2(c2), + value1(v1), + value2(v2) + {} }; struct CurrencyItem { - int count; - Currency currency; - std::string name; - CurrencyRatio exalt; - CurrencyRatio chaos; - CurrencyItem(int co, Currency curr, double chaos_ratio, double exalt_ratio) { - count = co; - currency = curr; - name = curr.AsString(); - chaos = CurrencyRatio(currency, CURRENCY_CHAOS_ORB, chaos_ratio, 1); - exalt = CurrencyRatio(currency, CURRENCY_EXALTED_ORB, exalt_ratio, 1); - } + int count; + Currency currency; + std::string name; + CurrencyRatio exalt; + CurrencyRatio chaos; + CurrencyItem(int co, Currency curr, double chaos_ratio, double exalt_ratio) { + count = co; + currency = curr; + name = curr.AsString(); + chaos = CurrencyRatio(currency, CURRENCY_CHAOS_ORB, chaos_ratio, 1); + exalt = CurrencyRatio(currency, CURRENCY_EXALTED_ORB, exalt_ratio, 1); + } }; struct CurrencyLabels { - QLabel *name; - QLabel *count; - QLabel *chaos_ratio; - QLabel *chaos_value; - QLabel *exalt_ratio; - QLabel *exalt_value; - QLabel *exalt_total; - QLabel *chaos_total; - QLabel *wisdom_total; - CurrencyLabels() { - name = new QLabel("Name"); - count = new QLabel("Count"); - chaos_ratio = new QLabel("Amount a chaos Orb can buy"); - chaos_value = new QLabel("Value in Chaos Orb"); - exalt_ratio = new QLabel("Amount an Exalted Orb can buy"); - exalt_value = new QLabel("Value in Exalted Orb"); - exalt_total = new QLabel("Total Exalted Orbs"); - chaos_total = new QLabel("Total Chaos Orbs"); - wisdom_total = new QLabel("Total Scrolls of Wisdom"); - } + QLabel *name; + QLabel *count; + QLabel *chaos_ratio; + QLabel *chaos_value; + QLabel *exalt_ratio; + QLabel *exalt_value; + QLabel *exalt_total; + QLabel *chaos_total; + QLabel *wisdom_total; + CurrencyLabels() { + name = new QLabel("Name"); + count = new QLabel("Count"); + chaos_ratio = new QLabel("Amount a chaos Orb can buy"); + chaos_value = new QLabel("Value in Chaos Orb"); + exalt_ratio = new QLabel("Amount an Exalted Orb can buy"); + exalt_value = new QLabel("Value in Exalted Orb"); + exalt_total = new QLabel("Total Exalted Orbs"); + chaos_total = new QLabel("Total Chaos Orbs"); + wisdom_total = new QLabel("Total Scrolls of Wisdom"); + } }; class CurrencyDialog; class CurrencyWidget : public QWidget { - Q_OBJECT + Q_OBJECT public slots: - void Update(); - void UpdateVisual(bool show_chaos, bool show_exalt); - bool IsNone() const { return currency_->currency.type==CURRENCY_NONE;} + void Update(); + void UpdateVisual(bool show_chaos, bool show_exalt); + bool IsNone() const { return currency_->currency.type==CURRENCY_NONE;} public: - CurrencyWidget(std::shared_ptr currency); - //Visual stuff - QLabel *name; - QLabel *count; - QDoubleSpinBox *chaos_ratio; - QDoubleSpinBox *chaos_value; - QDoubleSpinBox *exalt_ratio; - QDoubleSpinBox *exalt_value; + CurrencyWidget(std::shared_ptr currency); + //Visual stuff + QLabel *name; + QLabel *count; + QDoubleSpinBox *chaos_ratio; + QDoubleSpinBox *chaos_value; + QDoubleSpinBox *exalt_ratio; + QDoubleSpinBox *exalt_value; private: - //Data - std::shared_ptr currency_; + //Data + std::shared_ptr currency_; }; // For now we just serialize/deserialize 'value' inside CurrencyManager // Later we might need more logic if GGG adds more currency types and we want to be backwards compatible struct CurrencyUpdate { - long long timestamp; - std::string value; + long long timestamp; + std::string value; }; const std::vector CurrencyForWisdom({ - "Scroll of Wisdom", - "Portal Scroll", - "Armourer's Scrap", - "Blacksmith's Whetstone", - "Orb of Transmutation" -}); + "Scroll of Wisdom", + "Portal Scroll", + "Armourer's Scrap", + "Blacksmith's Whetstone", + "Orb of Transmutation" + }); const std::vector CurrencyWisdomValue({ - 1, - 1, - 2, - 4, - 4 -}); + 1, + 1, + 2, + 4, + 4 + }); class CurrencyManager; class CurrencyDialog : public QDialog { - Q_OBJECT + Q_OBJECT public: - CurrencyDialog(CurrencyManager &manager, bool show_chaos, bool show_exalt); - bool ShowChaos() const { return show_chaos_->isChecked();} - bool ShowExalt() const { return show_exalt_->isChecked();} + CurrencyDialog(CurrencyManager &manager, bool show_chaos, bool show_exalt); + bool ShowChaos() const { return show_chaos_->isChecked();} + bool ShowExalt() const { return show_exalt_->isChecked();} public slots: - void Update(); - void UpdateVisual(); - void UpdateVisibility(bool show_chaos, bool show_exalt); - void UpdateTotalValue(); + void Update(); + void UpdateVisual(); + void UpdateVisibility(bool show_chaos, bool show_exalt); + void UpdateTotalValue(); private: - CurrencyManager ¤cy_manager_; - std::vector currencies_widgets_; - CurrencyLabels *headers_; - QVBoxLayout *layout_; - QLabel *total_exalt_value_; - QLabel *total_chaos_value_; - QLabel *total_wisdom_value_; - QCheckBox *show_chaos_; - QCheckBox *show_exalt_; - QFrame *separator_; - QVBoxLayout* GenerateLayout(bool show_chaos, bool show_exalt); - void UpdateTotalWisdomValue(); + CurrencyManager ¤cy_manager_; + std::vector currencies_widgets_; + CurrencyLabels *headers_; + QVBoxLayout *layout_; + QLabel *total_exalt_value_; + QLabel *total_chaos_value_; + QLabel *total_wisdom_value_; + QCheckBox *show_chaos_; + QCheckBox *show_exalt_; + QFrame *separator_; + QVBoxLayout* GenerateLayout(bool show_chaos, bool show_exalt); + void UpdateTotalWisdomValue(); }; class CurrencyManager : public QWidget { - Q_OBJECT + Q_OBJECT public: - explicit CurrencyManager(Application &app); - ~CurrencyManager(); - void ClearCurrency(); - // Called in itemmanagerworker::ParseItem - void ParseSingleItem(const Item &item); - //void UpdateBaseValue(int ind, double value); - const std::vector> ¤cies() const { return currencies_;} - double TotalExaltedValue(); - double TotalChaosValue(); - int TotalWisdomValue(); - void DisplayCurrency(); - void Update(); - // CSV export - void ExportCurrency(); + explicit CurrencyManager(Application &app); + ~CurrencyManager(); + void ClearCurrency(); + // Called in itemmanagerworker::ParseItem + void ParseSingleItem(const Item &item); + //void UpdateBaseValue(int ind, double value); + const std::vector> ¤cies() const { return currencies_;} + double TotalExaltedValue(); + double TotalChaosValue(); + int TotalWisdomValue(); + void DisplayCurrency(); + void Update(); + // CSV export + void ExportCurrency(); private: - Application &app_; - DataStore &data_; - std::vector> currencies_; - // We only need the "count" of a CurrencyItem so int will be enough - std::vector wisdoms_; - std::shared_ptr dialog_; - // Used only the first time we launch the app - void FirstInitCurrency(); - //Migrate from old storage (csv-like serializing) to new one (using json) - void MigrateCurrency(); - void InitCurrency(); - void SaveCurrencyItems(); - std::string Serialize(const std::vector> ¤cies); - void Deserialize(const std::string &data, std::vector> *currencies); - void Save(); + Application &app_; + DataStore &data_; + std::vector> currencies_; + // We only need the "count" of a CurrencyItem so int will be enough + std::vector wisdoms_; + std::shared_ptr dialog_; + // Used only the first time we launch the app + void FirstInitCurrency(); + //Migrate from old storage (csv-like serializing) to new one (using json) + void MigrateCurrency(); + void InitCurrency(); + void SaveCurrencyItems(); + std::string Serialize(const std::vector> ¤cies); + void Deserialize(const std::string &data, std::vector> *currencies); + void Save(); public slots: - void SaveCurrencyValue(); + void SaveCurrencyValue(); }; diff --git a/src/datastore.h b/src/datastore.h index 10debe58..9add8928 100644 --- a/src/datastore.h +++ b/src/datastore.h @@ -1,20 +1,20 @@ /* - Copyright 2014 Ilya Zhuravlev + Copyright 2014 Ilya Zhuravlev - This file is part of Acquisition. + This file is part of Acquisition. - Acquisition is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. + Acquisition is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. - Acquisition is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. + Acquisition is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. - You should have received a copy of the GNU General Public License - along with Acquisition. If not, see . + You should have received a copy of the GNU General Public License + along with Acquisition. If not, see . */ #pragma once @@ -27,17 +27,17 @@ class DataStore { public: - virtual ~DataStore() {}; - virtual void Set(const std::string &key, const std::string &value) = 0; - virtual void SetTabs(const ItemLocationType &type, const std::string &value) = 0; - virtual void SetItems(const ItemLocation &loc, const std::string &value) = 0; - virtual std::string Get(const std::string &key, const std::string &default_value = "") = 0; - virtual std::string GetTabs(const ItemLocationType &type, const std::string &default_value = "") = 0; - virtual std::string GetItems(const ItemLocation &loc, const std::string &default_value = "") = 0; - virtual void InsertCurrencyUpdate(const CurrencyUpdate &update) = 0; - virtual std::vector GetAllCurrency() = 0; - virtual void SetBool(const std::string &key, bool value) = 0; - virtual bool GetBool(const std::string &key, bool default_value = false) = 0; - virtual void SetInt(const std::string &key, int value) = 0; - virtual int GetInt(const std::string &key, int default_value = 0) = 0; + virtual ~DataStore() {}; + virtual void Set(const std::string &key, const std::string &value) = 0; + virtual void SetTabs(const ItemLocationType &type, const std::string &value) = 0; + virtual void SetItems(const ItemLocation &loc, const std::string &value) = 0; + virtual std::string Get(const std::string &key, const std::string &default_value = "") = 0; + virtual std::string GetTabs(const ItemLocationType &type, const std::string &default_value = "") = 0; + virtual std::string GetItems(const ItemLocation &loc, const std::string &default_value = "") = 0; + virtual void InsertCurrencyUpdate(const CurrencyUpdate &update) = 0; + virtual std::vector GetAllCurrency() = 0; + virtual void SetBool(const std::string &key, bool value) = 0; + virtual bool GetBool(const std::string &key, bool default_value = false) = 0; + virtual void SetInt(const std::string &key, int value) = 0; + virtual int GetInt(const std::string &key, int default_value = 0) = 0; }; diff --git a/src/filesystem.h b/src/filesystem.h index 349eb00c..71afc534 100644 --- a/src/filesystem.h +++ b/src/filesystem.h @@ -1,20 +1,20 @@ /* - Copyright 2015 Ilya Zhuravlev + Copyright 2015 Ilya Zhuravlev - This file is part of Acquisition. + This file is part of Acquisition. - Acquisition is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. + Acquisition is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. - Acquisition is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. + Acquisition is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. - You should have received a copy of the GNU General Public License - along with Acquisition. If not, see . + You should have received a copy of the GNU General Public License + along with Acquisition. If not, see . */ #pragma once @@ -22,7 +22,7 @@ #include namespace Filesystem { - void Init(); - std::string UserDir(); - void SetUserDir(const std::string &dir); -} \ No newline at end of file + void Init(); + std::string UserDir(); + void SetUserDir(const std::string &dir); +} diff --git a/src/filters.h b/src/filters.h index e5edee07..41f82d9b 100644 --- a/src/filters.h +++ b/src/filters.h @@ -1,20 +1,20 @@ /* - Copyright 2014 Ilya Zhuravlev + Copyright 2014 Ilya Zhuravlev - This file is part of Acquisition. + This file is part of Acquisition. - Acquisition is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. + Acquisition is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. - Acquisition is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. + Acquisition is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. - You should have received a copy of the GNU General Public License - along with Acquisition. If not, see . + You should have received a copy of the GNU General Public License + along with Acquisition. If not, see . */ #pragma once @@ -42,26 +42,26 @@ class QAbstractListModel; */ class Filter { public: - virtual void FromForm(FilterData *data) = 0; - virtual void ToForm(FilterData *data) = 0; - virtual void ResetForm() = 0; - virtual bool Matches(const std::shared_ptr &item, FilterData *data) = 0; - virtual ~Filter() {}; - std::unique_ptr CreateData(); + virtual void FromForm(FilterData *data) = 0; + virtual void ToForm(FilterData *data) = 0; + virtual void ResetForm() = 0; + virtual bool Matches(const std::shared_ptr &item, FilterData *data) = 0; + virtual ~Filter() {}; + std::unique_ptr CreateData(); }; struct ModFilterData { - ModFilterData(const std::string &mod_, double min_, double max_, bool min_filled_, bool max_filled_) : - mod(mod_), - min(min_), - max(max_), - min_filled(min_filled_), - max_filled(max_filled_) - {} - - std::string mod; - double min, max; - bool min_filled, max_filled; + ModFilterData(const std::string &mod_, double min_, double max_, bool min_filled_, bool max_filled_) : + mod(mod_), + min(min_), + max(max_), + min_filled(min_filled_), + max_filled(max_filled_) + {} + + std::string mod; + double min, max; + bool min_filled, max_filled; }; /* @@ -70,252 +70,252 @@ struct ModFilterData { */ class FilterData { public: - FilterData(Filter *filter); - Filter *filter () { return filter_; } - bool Matches(const std::shared_ptr item); - void FromForm(); - void ToForm(); - // Various types of data for various filters - // It's probably not a very elegant solution but it works. - std::string text_query; - double min, max; - bool min_filled, max_filled; - int r, g, b; - bool r_filled, g_filled, b_filled; - bool checked; - std::vector mod_data; + FilterData(Filter *filter); + Filter *filter () { return filter_; } + bool Matches(const std::shared_ptr item); + void FromForm(); + void ToForm(); + // Various types of data for various filters + // It's probably not a very elegant solution but it works. + std::string text_query; + double min, max; + bool min_filled, max_filled; + int r, g, b; + bool r_filled, g_filled, b_filled; + bool checked; + std::vector mod_data; private: - Filter *filter_; + Filter *filter_; }; class NameSearchFilter : public Filter { public: - explicit NameSearchFilter(QLayout *parent); - void FromForm(FilterData *data); - void ToForm(FilterData *data); - void ResetForm(); - bool Matches(const std::shared_ptr &item, FilterData *data); - void Initialize(QLayout *parent); + explicit NameSearchFilter(QLayout *parent); + void FromForm(FilterData *data); + void ToForm(FilterData *data); + void ResetForm(); + bool Matches(const std::shared_ptr &item, FilterData *data); + void Initialize(QLayout *parent); private: - QLineEdit *textbox_; + QLineEdit *textbox_; }; class CategorySearchFilter : public Filter { public: - explicit CategorySearchFilter(QLayout *parent, QAbstractListModel *model); - void FromForm(FilterData *data); - void ToForm(FilterData *data); - void ResetForm(); - bool Matches(const std::shared_ptr &item, FilterData *data); - void Initialize(QLayout *parent); - static const std::string k_Default; + explicit CategorySearchFilter(QLayout *parent, QAbstractListModel *model); + void FromForm(FilterData *data); + void ToForm(FilterData *data); + void ResetForm(); + bool Matches(const std::shared_ptr &item, FilterData *data); + void Initialize(QLayout *parent); + static const std::string k_Default; private: - QComboBox *combobox_; - QCompleter *completer_; - QAbstractListModel *model_; + QComboBox *combobox_; + QCompleter *completer_; + QAbstractListModel *model_; }; class RaritySearchFilter : public Filter { public: - explicit RaritySearchFilter(QLayout *parent, QAbstractListModel *model); - void FromForm(FilterData *data); - void ToForm(FilterData *data); - void ResetForm(); - bool Matches(const std::shared_ptr &item, FilterData *data); - void Initialize(QLayout *parent); - static const std::string k_Default; - static const QStringList RARITY_LIST; + explicit RaritySearchFilter(QLayout *parent, QAbstractListModel *model); + void FromForm(FilterData *data); + void ToForm(FilterData *data); + void ResetForm(); + bool Matches(const std::shared_ptr &item, FilterData *data); + void Initialize(QLayout *parent); + static const std::string k_Default; + static const QStringList RARITY_LIST; private: - QComboBox *combobox_; - QAbstractListModel *model_; + QComboBox *combobox_; + QAbstractListModel *model_; }; class MinMaxFilter : public Filter { public: - MinMaxFilter(QLayout *parent, std::string property); - MinMaxFilter(QLayout *parent, std::string property, std::string caption); - void FromForm(FilterData *data); - void ToForm(FilterData *data); - void ResetForm(); - bool Matches(const std::shared_ptr &item, FilterData *data); - void Initialize(QLayout *parent); + MinMaxFilter(QLayout *parent, std::string property); + MinMaxFilter(QLayout *parent, std::string property, std::string caption); + void FromForm(FilterData *data); + void ToForm(FilterData *data); + void ResetForm(); + bool Matches(const std::shared_ptr &item, FilterData *data); + void Initialize(QLayout *parent); protected: - virtual double GetValue(const std::shared_ptr &item) = 0; - virtual bool IsValuePresent(const std::shared_ptr &item) = 0; + virtual double GetValue(const std::shared_ptr &item) = 0; + virtual bool IsValuePresent(const std::shared_ptr &item) = 0; - std::string property_, caption_; + std::string property_, caption_; private: - QLineEdit *textbox_min_, *textbox_max_; + QLineEdit *textbox_min_, *textbox_max_; }; class SimplePropertyFilter : public MinMaxFilter { public: - SimplePropertyFilter(QLayout *parent, std::string property) : - MinMaxFilter(parent, property) {} - SimplePropertyFilter(QLayout *parent, std::string property, std::string caption) : - MinMaxFilter(parent, property, caption) {} + SimplePropertyFilter(QLayout *parent, std::string property) : + MinMaxFilter(parent, property) {} + SimplePropertyFilter(QLayout *parent, std::string property, std::string caption) : + MinMaxFilter(parent, property, caption) {} protected: - bool IsValuePresent(const std::shared_ptr &item); - double GetValue(const std::shared_ptr &item); + bool IsValuePresent(const std::shared_ptr &item); + double GetValue(const std::shared_ptr &item); }; // Just like SimplePropertyFilter but assumes given default value instead of excluding items class DefaultPropertyFilter : public SimplePropertyFilter { public: - DefaultPropertyFilter(QLayout *parent, std::string property, double default_value) : - SimplePropertyFilter(parent, property), - default_value_(default_value) - {} - DefaultPropertyFilter(QLayout *parent, std::string property, std::string caption, double default_value) : - SimplePropertyFilter(parent, property, caption), - default_value_(default_value) - {} + DefaultPropertyFilter(QLayout *parent, std::string property, double default_value) : + SimplePropertyFilter(parent, property), + default_value_(default_value) + {} + DefaultPropertyFilter(QLayout *parent, std::string property, std::string caption, double default_value) : + SimplePropertyFilter(parent, property, caption), + default_value_(default_value) + {} protected: - bool IsValuePresent(const std::shared_ptr & /* item */) { return true; } - double GetValue(const std::shared_ptr &item); + bool IsValuePresent(const std::shared_ptr & /* item */) { return true; } + double GetValue(const std::shared_ptr &item); private: - double default_value_; + double default_value_; }; class RequiredStatFilter : public MinMaxFilter { public: - RequiredStatFilter(QLayout *parent, std::string property) : - MinMaxFilter(parent, property) {} - RequiredStatFilter(QLayout *parent, std::string property, std::string caption) : - MinMaxFilter(parent, property, caption) {} + RequiredStatFilter(QLayout *parent, std::string property) : + MinMaxFilter(parent, property) {} + RequiredStatFilter(QLayout *parent, std::string property, std::string caption) : + MinMaxFilter(parent, property, caption) {} private: - bool IsValuePresent(const std::shared_ptr & /* item */) { return true; } - double GetValue(const std::shared_ptr &item); + bool IsValuePresent(const std::shared_ptr & /* item */) { return true; } + double GetValue(const std::shared_ptr &item); }; class ItemMethodFilter : public MinMaxFilter { public: - ItemMethodFilter(QLayout *parent, std::function func, std::string caption); + ItemMethodFilter(QLayout *parent, std::function func, std::string caption); private: - bool IsValuePresent(const std::shared_ptr & /* item */) { return true; } - double GetValue(const std::shared_ptr &item); - std::function func_; + bool IsValuePresent(const std::shared_ptr & /* item */) { return true; } + double GetValue(const std::shared_ptr &item); + std::function func_; }; class SocketsFilter : public MinMaxFilter { public: - SocketsFilter(QLayout *parent, std::string property) : - MinMaxFilter(parent, property) {} - SocketsFilter(QLayout *parent, std::string property, std::string caption) : - MinMaxFilter(parent, property, caption) {} - bool IsValuePresent(const std::shared_ptr & /* item */) { return true; } - double GetValue(const std::shared_ptr &item); + SocketsFilter(QLayout *parent, std::string property) : + MinMaxFilter(parent, property) {} + SocketsFilter(QLayout *parent, std::string property, std::string caption) : + MinMaxFilter(parent, property, caption) {} + bool IsValuePresent(const std::shared_ptr & /* item */) { return true; } + double GetValue(const std::shared_ptr &item); }; class LinksFilter : public MinMaxFilter { public: - LinksFilter(QLayout *parent, std::string property) : - MinMaxFilter(parent, property) {} - LinksFilter(QLayout *parent, std::string property, std::string caption) : - MinMaxFilter(parent, property, caption) {} - bool IsValuePresent(const std::shared_ptr & /* item */) { return true; } - double GetValue(const std::shared_ptr &item); + LinksFilter(QLayout *parent, std::string property) : + MinMaxFilter(parent, property) {} + LinksFilter(QLayout *parent, std::string property, std::string caption) : + MinMaxFilter(parent, property, caption) {} + bool IsValuePresent(const std::shared_ptr & /* item */) { return true; } + double GetValue(const std::shared_ptr &item); }; class SocketsColorsFilter : public Filter { public: - SocketsColorsFilter() {} - explicit SocketsColorsFilter(QLayout *parent); - void FromForm(FilterData *data); - void ToForm(FilterData *data); - void ResetForm(); - bool Matches(const std::shared_ptr &item, FilterData *data); - void Initialize(QLayout *parent, const char* caption); + SocketsColorsFilter() {} + explicit SocketsColorsFilter(QLayout *parent); + void FromForm(FilterData *data); + void ToForm(FilterData *data); + void ResetForm(); + bool Matches(const std::shared_ptr &item, FilterData *data); + void Initialize(QLayout *parent, const char* caption); protected: - bool Check(int need_r, int need_g, int need_b, int got_r, int got_g, int got_b, int got_w); - QLineEdit *textbox_r_, *textbox_g_, *textbox_b_; + bool Check(int need_r, int need_g, int need_b, int got_r, int got_g, int got_b, int got_w); + QLineEdit *textbox_r_, *textbox_g_, *textbox_b_; }; class LinksColorsFilter : public SocketsColorsFilter { public: - explicit LinksColorsFilter(QLayout *parent); - bool Matches(const std::shared_ptr &item, FilterData *data); + explicit LinksColorsFilter(QLayout *parent); + bool Matches(const std::shared_ptr &item, FilterData *data); }; class BooleanFilter : public Filter { public: - BooleanFilter(QLayout *parent, std::string property, std::string caption); - void FromForm(FilterData *data); - void ToForm(FilterData *data); - void ResetForm(); - bool Matches(const std::shared_ptr &item, FilterData *data); - void Initialize(QLayout *parent); + BooleanFilter(QLayout *parent, std::string property, std::string caption); + void FromForm(FilterData *data); + void ToForm(FilterData *data); + void ResetForm(); + bool Matches(const std::shared_ptr &item, FilterData *data); + void Initialize(QLayout *parent); private: - QCheckBox *checkbox_; + QCheckBox *checkbox_; protected: - std::string property_, caption_; + std::string property_, caption_; }; class AltartFilter : public BooleanFilter { public: - AltartFilter(QLayout *parent, std::string property, std::string caption): - BooleanFilter(parent, property, caption) {} - using BooleanFilter::BooleanFilter; - bool Matches(const std::shared_ptr &item, FilterData *data); + AltartFilter(QLayout *parent, std::string property, std::string caption): + BooleanFilter(parent, property, caption) {} + using BooleanFilter::BooleanFilter; + bool Matches(const std::shared_ptr &item, FilterData *data); }; class PricedFilter : public BooleanFilter { public: - PricedFilter(QLayout *parent, std::string property, std::string caption, const BuyoutManager &bm) : - BooleanFilter(parent, property, caption), - bm_(bm) - {} - bool Matches(const std::shared_ptr &item, FilterData *data); + PricedFilter(QLayout *parent, std::string property, std::string caption, const BuyoutManager &bm) : + BooleanFilter(parent, property, caption), + bm_(bm) + {} + bool Matches(const std::shared_ptr &item, FilterData *data); private: - const BuyoutManager &bm_; + const BuyoutManager &bm_; }; class UnidentifiedFilter : public BooleanFilter { public: - UnidentifiedFilter(QLayout *parent, std::string property, std::string caption): - BooleanFilter(parent, property, caption) {} - using BooleanFilter::BooleanFilter; - bool Matches(const std::shared_ptr &item, FilterData *data); + UnidentifiedFilter(QLayout *parent, std::string property, std::string caption): + BooleanFilter(parent, property, caption) {} + using BooleanFilter::BooleanFilter; + bool Matches(const std::shared_ptr &item, FilterData *data); }; class CraftedFilter : public BooleanFilter { public: - CraftedFilter(QLayout *parent, std::string property, std::string caption): - BooleanFilter(parent, property, caption) {} - using BooleanFilter::BooleanFilter; - bool Matches(const std::shared_ptr &item, FilterData *data); + CraftedFilter(QLayout *parent, std::string property, std::string caption): + BooleanFilter(parent, property, caption) {} + using BooleanFilter::BooleanFilter; + bool Matches(const std::shared_ptr &item, FilterData *data); }; class EnchantedFilter : public BooleanFilter { public: - EnchantedFilter(QLayout *parent, std::string property, std::string caption): - BooleanFilter(parent, property, caption) {} - using BooleanFilter::BooleanFilter; - bool Matches(const std::shared_ptr &item, FilterData *data); + EnchantedFilter(QLayout *parent, std::string property, std::string caption): + BooleanFilter(parent, property, caption) {} + using BooleanFilter::BooleanFilter; + bool Matches(const std::shared_ptr &item, FilterData *data); }; class InfluencedFilter : public BooleanFilter { public: - InfluencedFilter(QLayout *parent, std::string property, std::string caption): - BooleanFilter(parent, property, caption) {} - using BooleanFilter::BooleanFilter; - bool Matches(const std::shared_ptr &item, FilterData *data); + InfluencedFilter(QLayout *parent, std::string property, std::string caption): + BooleanFilter(parent, property, caption) {} + using BooleanFilter::BooleanFilter; + bool Matches(const std::shared_ptr &item, FilterData *data); }; class CorruptedFilter : public BooleanFilter { public: - CorruptedFilter(QLayout *parent, std::string property, std::string caption): - BooleanFilter(parent, property, caption) {} - using BooleanFilter::BooleanFilter; - bool Matches(const std::shared_ptr &item, FilterData *data); + CorruptedFilter(QLayout *parent, std::string property, std::string caption): + BooleanFilter(parent, property, caption) {} + using BooleanFilter::BooleanFilter; + bool Matches(const std::shared_ptr &item, FilterData *data); }; class ItemlevelFilter : public MinMaxFilter { public: - ItemlevelFilter(QLayout *parent, std::string property) : - MinMaxFilter(parent, property) {} - ItemlevelFilter(QLayout *parent, std::string property, std::string caption) : - MinMaxFilter(parent, property, caption) {} - bool IsValuePresent(const std::shared_ptr & /* item */) { return true; } - double GetValue(const std::shared_ptr &item); + ItemlevelFilter(QLayout *parent, std::string property) : + MinMaxFilter(parent, property) {} + ItemlevelFilter(QLayout *parent, std::string property, std::string caption) : + MinMaxFilter(parent, property, caption) {} + bool IsValuePresent(const std::shared_ptr & /* item */) { return true; } + double GetValue(const std::shared_ptr &item); }; diff --git a/src/flowlayout.h b/src/flowlayout.h index 5aa7ba4e..346fac45 100644 --- a/src/flowlayout.h +++ b/src/flowlayout.h @@ -48,30 +48,30 @@ class FlowLayout : public QLayout { public: - FlowLayout(QWidget *parent, int margin = -1, int hSpacing = -1, int vSpacing = -1); - FlowLayout(int margin = -1, int hSpacing = -1, int vSpacing = -1); - ~FlowLayout(); + FlowLayout(QWidget *parent, int margin = -1, int hSpacing = -1, int vSpacing = -1); + FlowLayout(int margin = -1, int hSpacing = -1, int vSpacing = -1); + ~FlowLayout(); - void addItem(QLayoutItem *item); - int horizontalSpacing() const; - int verticalSpacing() const; - Qt::Orientations expandingDirections() const; - bool hasHeightForWidth() const; - int heightForWidth(int) const; - int count() const; - QLayoutItem *itemAt(int index) const; - QSize minimumSize() const; - void setGeometry(const QRect &rect); - QSize sizeHint() const; - QLayoutItem *takeAt(int index); + void addItem(QLayoutItem *item); + int horizontalSpacing() const; + int verticalSpacing() const; + Qt::Orientations expandingDirections() const; + bool hasHeightForWidth() const; + int heightForWidth(int) const; + int count() const; + QLayoutItem *itemAt(int index) const; + QSize minimumSize() const; + void setGeometry(const QRect &rect); + QSize sizeHint() const; + QLayoutItem *takeAt(int index); private: - int doLayout(const QRect &rect, bool testOnly) const; - int smartSpacing(QStyle::PixelMetric pm) const; + int doLayout(const QRect &rect, bool testOnly) const; + int smartSpacing(QStyle::PixelMetric pm) const; - QList itemList; - int m_hSpace; - int m_vSpace; + QList itemList; + int m_hSpace; + int m_vSpace; }; #endif diff --git a/src/item.cpp b/src/item.cpp index a3a8904f..88e21536 100644 --- a/src/item.cpp +++ b/src/item.cpp @@ -294,7 +294,7 @@ std::string Item::PrettyName() const { void Item::CalculateCategories(const rapidjson::Value &json) { // Derive item type 'category' hierarchy from icon path. std::smatch sm; - if (std::regex_search(icon_, sm, std::regex("Art/.*?/(.*)/"))) { + if (std::regex_search(icon_, sm, std::regex("image/.*?/.*?/([^0-9]*)"))) { std::string match = sm.str(1); boost::split(category_vector_,match,boost::is_any_of("/")); //Compress terms with redundant identifiers diff --git a/src/itemsmanagerworker.cpp b/src/itemsmanagerworker.cpp index 772ef3fc..8498018f 100644 --- a/src/itemsmanagerworker.cpp +++ b/src/itemsmanagerworker.cpp @@ -1,20 +1,20 @@ /* - Copyright 2014 Ilya Zhuravlev + Copyright 2014 Ilya Zhuravlev - This file is part of Acquisition. + This file is part of Acquisition. - Acquisition is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. + Acquisition is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. - Acquisition is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. + Acquisition is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. - You should have received a copy of the GNU General Public License - along with Acquisition. If not, see . + You should have received a copy of the GNU General Public License + along with Acquisition. If not, see . */ #include "itemsmanagerworker.h" @@ -48,657 +48,665 @@ const char *kMainPage = "https://www.pathofexile.com/"; const char *kCharacterSocketedJewels = "https://www.pathofexile.com/character-window/get-passive-skills"; ItemsManagerWorker::ItemsManagerWorker(Application &app, QThread *thread) : - data_(app.data()), - signal_mapper_(nullptr), - league_(app.league()), - updating_(false), - bo_manager_(app.buyout_manager()), - account_name_(app.email()) + data_(app.data()), + signal_mapper_(nullptr), + league_(app.league()), + updating_(false), + bo_manager_(app.buyout_manager()), + account_name_(app.email()) { - QUrl poe(kMainPage); + QUrl poe(kMainPage); - QDir cache_path{std::string{Filesystem::UserDir() + "/tabcache/" + account_name_ + "/" + league_}.c_str()}; + QDir cache_path{std::string{Filesystem::UserDir() + "/tabcache/" + account_name_ + "/" + league_}.c_str()}; - QLOG_DEBUG() << "Cache directory: " << cache_path.path(); + QLOG_DEBUG() << "Cache directory: " << cache_path.path(); - tab_cache_->setCacheDirectory(cache_path.path()); - tab_cache_->setMaximumCacheSize(kMaxCacheSize); + tab_cache_->setCacheDirectory(cache_path.path()); + tab_cache_->setMaximumCacheSize(kMaxCacheSize); - // setCache takes ownership of tab_cache ptr so we don't need to destruct it - network_manager_.setCache(tab_cache_); - network_manager_.cookieJar()->setCookiesFromUrl(app.logged_in_nm().cookieJar()->cookiesForUrl(poe), poe); - network_manager_.moveToThread(thread); + // setCache takes ownership of tab_cache ptr so we don't need to destruct it + network_manager_.setCache(tab_cache_); + network_manager_.cookieJar()->setCookiesFromUrl(app.logged_in_nm().cookieJar()->cookiesForUrl(poe), poe); + network_manager_.moveToThread(thread); } ItemsManagerWorker::~ItemsManagerWorker() { - if (signal_mapper_) - delete signal_mapper_; + if (signal_mapper_) + delete signal_mapper_; } void ItemsManagerWorker::Init() { - tabs_.clear(); - tab_id_index_.clear(); - - //Get cached tabs (item tabs not search tabs) - for(ItemLocationType type : {ItemLocationType::STASH, ItemLocationType::CHARACTER}){ - std::string tabs = data_.GetTabs(type); - tabs_signature_ = CreateTabsSignatureVector(tabs); - if (tabs.size() != 0) { - rapidjson::Document doc; - if (doc.Parse(tabs.c_str()).HasParseError()) { - QLOG_ERROR() << "Malformed tabs data:" << tabs.c_str() << "The error was" - << rapidjson::GetParseError_En(doc.GetParseError()); - continue; - } - for (auto &tab : doc) { - //constructor values to fill in - int index; - std::string tabUniqueId, name; - int r, g, b; - - if(type == ItemLocationType::STASH){ - if(tab_id_index_.count(tab["id"].GetString())){ - continue; - } - if (!tab.HasMember("n") || !tab["n"].IsString()) { - QLOG_ERROR() << "Malformed tabs data:" << tabs.c_str() << "Tab doesn't contain its name (field 'n')."; - continue; - } - - index = tab["i"].GetInt(); - tabUniqueId = tab["id"].GetString(); - name = tab["n"].GetString(); - r = tab["colour"]["r"].GetInt(); - g = tab["colour"]["g"].GetInt(); - b = tab["colour"]["b"].GetInt(); - } else { - if(tab_id_index_.count(tab["name"].GetString())){ - continue; - } - - if(tab.HasMember("i")) - index = tab["i"].GetInt(); - else - index = tabs_.size(); - - tabUniqueId = tab["name"].GetString(); - name = tab["name"].GetString(); - r = 0; - g = 0; - b = 0; - } - - ItemLocation loc(index, tabUniqueId, name, type, r, g, b); - loc.set_json(tab, doc.GetAllocator()); - tabs_.push_back(loc); - tab_id_index_.insert(loc.get_tab_uniq_id()); - } - } - } - - items_.clear(); - - //Get cached items - for (auto tab : tabs_){ - std::string items = data_.GetItems(tab); - if (items.size() != 0) { - rapidjson::Document doc; - doc.Parse(items.c_str()); - for (auto item = doc.Begin(); item != doc.End(); ++item) - items_.push_back(std::make_shared(*item, tab)); - } - } - - //let ItemManager know that the retrieval of cached items/tabs has been completed (calls ItemsManager::OnItemsRefreshed method) - emit ItemsRefreshed(items_, tabs_, true); + tabs_.clear(); + tab_id_index_.clear(); + + //Get cached tabs (item tabs not search tabs) + for(ItemLocationType type : {ItemLocationType::STASH, ItemLocationType::CHARACTER}){ + std::string tabs = data_.GetTabs(type); + tabs_signature_ = CreateTabsSignatureVector(tabs); + if (tabs.size() != 0) { + rapidjson::Document doc; + if (doc.Parse(tabs.c_str()).HasParseError()) { + QLOG_ERROR() << "Malformed tabs data:" << tabs.c_str() << "The error was" + << rapidjson::GetParseError_En(doc.GetParseError()); + continue; + } + for (auto &tab : doc) { + //constructor values to fill in + int index; + std::string tabUniqueId, name; + int r, g, b; + + if(type == ItemLocationType::STASH){ + if(tab_id_index_.count(tab["id"].GetString())){ + continue; + } + if (!tab.HasMember("n") || !tab["n"].IsString()) { + QLOG_ERROR() << "Malformed tabs data:" << tabs.c_str() << "Tab doesn't contain its name (field 'n')."; + continue; + } + + index = tab["i"].GetInt(); + tabUniqueId = tab["id"].GetString(); + name = tab["n"].GetString(); + r = tab["colour"]["r"].GetInt(); + g = tab["colour"]["g"].GetInt(); + b = tab["colour"]["b"].GetInt(); + } else { + if(tab_id_index_.count(tab["name"].GetString())){ + continue; + } + + if(tab.HasMember("i")) + index = tab["i"].GetInt(); + else + index = tabs_.size(); + + tabUniqueId = tab["name"].GetString(); + name = tab["name"].GetString(); + r = 0; + g = 0; + b = 0; + } + + ItemLocation loc(index, tabUniqueId, name, type, r, g, b); + loc.set_json(tab, doc.GetAllocator()); + tabs_.push_back(loc); + tab_id_index_.insert(loc.get_tab_uniq_id()); + } + } + } + + items_.clear(); + + //Get cached items + for (auto tab : tabs_){ + std::string items = data_.GetItems(tab); + if (items.size() != 0) { + rapidjson::Document doc; + doc.Parse(items.c_str()); + for (auto item = doc.Begin(); item != doc.End(); ++item) + items_.push_back(std::make_shared(*item, tab)); + } + } + + //let ItemManager know that the retrieval of cached items/tabs has been completed (calls ItemsManager::OnItemsRefreshed method) + emit ItemsRefreshed(items_, tabs_, true); } void ItemsManagerWorker::Update(TabSelection::Type type, const std::vector &locations) { - if (updating_) { - QLOG_WARN() << "ItemsManagerWorker::Update called while updating"; - return; - } - - selected_tabs_.clear(); - for (auto const &tab: locations) { - selected_tabs_.insert(tab.get_tab_uniq_id()); - } - - tab_selection_ = type; - - QLOG_DEBUG() << "Updating" << tab_selection_ << "stash tabs"; - updating_ = true; - - cancel_update_ = false; - // remove all mappings (from previous requests) - if (signal_mapper_) - delete signal_mapper_; - signal_mapper_ = new QSignalMapper; - // remove all pending requests - queue_ = std::queue(); - queue_id_ = 0; - replies_.clear(); - items_.clear(); - tabs_as_string_ = ""; - selected_character_ = ""; - - // first, download the main page because it's the only way to know which character is selected - QNetworkReply *main_page = network_manager_.get(Request(QUrl(kMainPage), ItemLocation(), TabCache::Refresh)); - connect(main_page, &QNetworkReply::finished, this, &ItemsManagerWorker::OnMainPageReceived); + if (updating_) { + QLOG_WARN() << "ItemsManagerWorker::Update called while updating"; + return; + } + + selected_tabs_.clear(); + for (auto const &tab: locations) { + selected_tabs_.insert(tab.get_tab_uniq_id()); + } + + tab_selection_ = type; + + QLOG_DEBUG() << "Updating" << tab_selection_ << "stash tabs"; + updating_ = true; + + cancel_update_ = false; + // remove all mappings (from previous requests) + if (signal_mapper_) + delete signal_mapper_; + signal_mapper_ = new QSignalMapper; + // remove all pending requests + queue_ = std::queue(); + queue_id_ = 0; + replies_.clear(); + items_.clear(); + tabs_as_string_ = ""; + selected_character_ = ""; + + // first, download the main page because it's the only way to know which character is selected + QNetworkRequest main_page_request = Request(QUrl(kMainPage), ItemLocation(), TabCache::Refresh); + main_page_request.setHeader(QNetworkRequest::KnownHeaders::UserAgentHeader, "Acquisition"); + QNetworkReply *main_page = network_manager_.get(main_page_request); + connect(main_page, &QNetworkReply::finished, this, &ItemsManagerWorker::OnMainPageReceived); } void ItemsManagerWorker::OnMainPageReceived() { - QNetworkReply *reply = qobject_cast(QObject::sender()); - - if (reply->error()) { - QLOG_WARN() << "Couldn't fetch main page: " << reply->url().toDisplayString() << " due to error: " << reply->errorString(); - } else { - std::string page(reply->readAll().constData()); - - selected_character_ = Util::FindTextBetween(page, "C({\"name\":\"", "\",\"class"); - if (selected_character_.empty()) { - QLOG_WARN() << "Couldn't extract currently selected character name from GGG homepage (maintenence?) Text was: " << page.c_str(); - } - } - - // now get character list - QNetworkReply *characters = network_manager_.get(Request(QUrl(kGetCharactersUrl), ItemLocation(), TabCache::Refresh)); - connect(characters, &QNetworkReply::finished, this, &ItemsManagerWorker::OnCharacterListReceived); - - reply->deleteLater(); + QNetworkReply *reply = qobject_cast(QObject::sender()); + + if (reply->error()) { + QLOG_WARN() << "Couldn't fetch main page: " << reply->url().toDisplayString() << " due to error: " << reply->errorString(); + } else { + std::string page(reply->readAll().constData()); + + selected_character_ = Util::FindTextBetween(page, "C({\"name\":\"", "\",\"class"); + if (selected_character_.empty()) { + QLOG_WARN() << "Couldn't extract currently selected character name from GGG homepage (maintenence?) Text was: " << page.c_str(); + } + } + + // now get character list + QNetworkRequest characters_request = Request(QUrl(kGetCharactersUrl), ItemLocation(), TabCache::Refresh); + characters_request.setHeader(QNetworkRequest::KnownHeaders::UserAgentHeader, "Acquisition"); + QNetworkReply *characters = network_manager_.get(characters_request); + connect(characters, &QNetworkReply::finished, this, &ItemsManagerWorker::OnCharacterListReceived); + + reply->deleteLater(); } void ItemsManagerWorker::OnCharacterListReceived() { - QNetworkReply *reply = qobject_cast(QObject::sender()); - QByteArray bytes = reply->readAll(); - rapidjson::Document doc; - doc.Parse(bytes.constData()); - - if (reply->error()) { - QLOG_WARN() << "Couldn't fetch character list: " << reply->url().toDisplayString() - << " due to error: " << reply->errorString() << " Aborting update."; - updating_ = false; - return; - } else { - if (doc.HasParseError() || !doc.IsArray()) { - QLOG_ERROR() << "Received invalid reply instead of character list. The reply was: " - << bytes.constData(); - if (doc.HasParseError()) { - QLOG_ERROR() << "The error was" << rapidjson::GetParseError_En(doc.GetParseError()); - } - QLOG_ERROR() << ""; - QLOG_ERROR() << "(Maybe you need to log in to the website manually and accept new Terms of Service?)"; - updating_ = false; - return; - } - } - - QLOG_DEBUG() << "Received character list, there are" << doc.Size() << "characters"; - - //clear out ItemLocationType::CHARACTER tabs from tabs_ - std::vector tmpLocs = tabs_; - for(auto &tab : tmpLocs){ - if(tab.get_type() == ItemLocationType::CHARACTER){ - tabs_.erase(std::remove(tabs_.begin(), tabs_.end(), tab), tabs_.end()); - tab_id_index_.erase(tab.get_tab_uniq_id()); - } - } - - auto char_count = 0; - for (auto &character : doc) { - if (!character.HasMember("league") || !character.HasMember("name") || !character["league"].IsString() || !character["name"].IsString()) { - QLOG_ERROR() << "Malformed character entry, the reply is most likely invalid" << bytes.constData(); - continue; - } - if (character["league"].GetString() == league_) { - char_count++; - std::string name = character["name"].GetString(); - ItemLocation location; - location.set_type(ItemLocationType::CHARACTER); - location.set_character(name); - location.set_json(character, doc.GetAllocator()); - location.set_tab_id(tabs_.size()); - tabs_.push_back(location); - //Queue request for items on character in character's stash - QueueRequest(MakeCharacterRequest(name, location), location); - - //Queue request for jewels in character's passive tree - QueueRequest(MakeCharacterPassivesRequest(name, location), location); - } - } - CurrentStatusUpdate status; - status.state = ProgramState::CharactersReceived; - status.total = char_count; - - emit StatusUpdate(status); - - if (char_count == 0) { - updating_ = false; - return; - } - - // Fetch a single tab and also request tabs list. We can fetch any tab here with tabs list - // appended, so prefer one that the user has already 'checked'. Default to index '1' which is - // first user visible tab. - first_fetch_tab_ = ""; - ItemLocation tabToReq; - if (tab_selection_ == TabSelection::Checked) { - for (auto const &tab : tabs_) { - if (bo_manager_.GetRefreshChecked(tab)) { - first_fetch_tab_ = tab.get_tab_uniq_id(); - tabToReq = tab; - break; - } - } - } - // If we're refreshing a manual selection of tabs choose one of them to save a tab fetch - if (tab_selection_ == TabSelection::Selected) { - for (auto const &tab : tabs_) { - if (selected_tabs_.count(tab.get_tab_uniq_id())) { - first_fetch_tab_ = tab.get_tab_uniq_id(); - tabToReq = tab; - break; - } - } - } - - QNetworkReply *first_tab = network_manager_.get(MakeTabRequest(tabToReq.get_tab_id(), ItemLocation(), true, true)); - connect(first_tab, SIGNAL(finished()), this, SLOT(OnFirstTabReceived())); - reply->deleteLater(); + QNetworkReply *reply = qobject_cast(QObject::sender()); + QByteArray bytes = reply->readAll(); + rapidjson::Document doc; + doc.Parse(bytes.constData()); + + if (reply->error()) { + QLOG_WARN() << "Couldn't fetch character list: " << reply->url().toDisplayString() + << " due to error: " << reply->errorString() << " Aborting update."; + updating_ = false; + return; + } else { + if (doc.HasParseError() || !doc.IsArray()) { + QLOG_ERROR() << "Received invalid reply instead of character list. The reply was: " + << bytes.constData(); + if (doc.HasParseError()) { + QLOG_ERROR() << "The error was" << rapidjson::GetParseError_En(doc.GetParseError()); + } + QLOG_ERROR() << ""; + QLOG_ERROR() << "(Maybe you need to log in to the website manually and accept new Terms of Service?)"; + updating_ = false; + return; + } + } + + QLOG_DEBUG() << "Received character list, there are" << doc.Size() << "characters"; + + //clear out ItemLocationType::CHARACTER tabs from tabs_ + std::vector tmpLocs = tabs_; + for(auto &tab : tmpLocs){ + if(tab.get_type() == ItemLocationType::CHARACTER){ + tabs_.erase(std::remove(tabs_.begin(), tabs_.end(), tab), tabs_.end()); + tab_id_index_.erase(tab.get_tab_uniq_id()); + } + } + + auto char_count = 0; + for (auto &character : doc) { + if (!character.HasMember("league") || !character.HasMember("name") || !character["league"].IsString() || !character["name"].IsString()) { + QLOG_ERROR() << "Malformed character entry, the reply is most likely invalid" << bytes.constData(); + continue; + } + if (character["league"].GetString() == league_) { + char_count++; + std::string name = character["name"].GetString(); + ItemLocation location; + location.set_type(ItemLocationType::CHARACTER); + location.set_character(name); + location.set_json(character, doc.GetAllocator()); + location.set_tab_id(tabs_.size()); + tabs_.push_back(location); + //Queue request for items on character in character's stash + QueueRequest(MakeCharacterRequest(name, location), location); + + //Queue request for jewels in character's passive tree + QueueRequest(MakeCharacterPassivesRequest(name, location), location); + } + } + CurrentStatusUpdate status; + status.state = ProgramState::CharactersReceived; + status.total = char_count; + + emit StatusUpdate(status); + + if (char_count == 0) { + updating_ = false; + return; + } + + // Fetch a single tab and also request tabs list. We can fetch any tab here with tabs list + // appended, so prefer one that the user has already 'checked'. Default to index '1' which is + // first user visible tab. + first_fetch_tab_ = ""; + ItemLocation tabToReq; + if (tab_selection_ == TabSelection::Checked) { + for (auto const &tab : tabs_) { + if (bo_manager_.GetRefreshChecked(tab)) { + first_fetch_tab_ = tab.get_tab_uniq_id(); + tabToReq = tab; + break; + } + } + } + // If we're refreshing a manual selection of tabs choose one of them to save a tab fetch + if (tab_selection_ == TabSelection::Selected) { + for (auto const &tab : tabs_) { + if (selected_tabs_.count(tab.get_tab_uniq_id())) { + first_fetch_tab_ = tab.get_tab_uniq_id(); + tabToReq = tab; + break; + } + } + } + + QNetworkReply *first_tab = network_manager_.get(MakeTabRequest(tabToReq.get_tab_id(), ItemLocation(), true, true)); + connect(first_tab, SIGNAL(finished()), this, SLOT(OnFirstTabReceived())); + reply->deleteLater(); } QNetworkRequest ItemsManagerWorker::MakeTabRequest(int tab_index, const ItemLocation &location, bool tabs, bool refresh) { - QUrlQuery query; - query.addQueryItem("league", league_.c_str()); - query.addQueryItem("tabs", tabs ? "1" : "0"); - query.addQueryItem("tabIndex", std::to_string(tab_index).c_str()); - query.addQueryItem("accountName", account_name_.c_str()); + QUrlQuery query; + query.addQueryItem("league", league_.c_str()); + query.addQueryItem("tabs", tabs ? "1" : "0"); + query.addQueryItem("tabIndex", std::to_string(tab_index).c_str()); + query.addQueryItem("accountName", account_name_.c_str()); - QUrl url(kStashItemsUrl); - url.setQuery(query); + QUrl url(kStashItemsUrl); + url.setQuery(query); - // If refresh is explicity request then force unconditionally - TabCache::Flags flags = (refresh) ? TabCache::Refresh : TabCache::None; + // If refresh is explicity request then force unconditionally + TabCache::Flags flags = (refresh) ? TabCache::Refresh : TabCache::None; - return Request(url, location, flags); + QNetworkRequest tab_request = Request(url, location, flags); + tab_request.setHeader(QNetworkRequest::KnownHeaders::UserAgentHeader, "Acquisition"); + return tab_request; } QNetworkRequest ItemsManagerWorker::MakeCharacterRequest(const std::string &name, const ItemLocation &location) { - QUrlQuery query; - query.addQueryItem("character", name.c_str()); - query.addQueryItem("accountName", account_name_.c_str()); + QUrlQuery query; + query.addQueryItem("character", name.c_str()); + query.addQueryItem("accountName", account_name_.c_str()); - QUrl url(kCharacterItemsUrl); - url.setQuery(query); + QUrl url(kCharacterItemsUrl); + url.setQuery(query); - return Request(url, location, TabCache::None); + return Request(url, location, TabCache::None); } QNetworkRequest ItemsManagerWorker::MakeCharacterPassivesRequest(const std::string &name, const ItemLocation &location) { - QUrlQuery query; - query.addQueryItem("character", name.c_str()); - query.addQueryItem("accountName", account_name_.c_str()); + QUrlQuery query; + query.addQueryItem("character", name.c_str()); + query.addQueryItem("accountName", account_name_.c_str()); - QUrl url(kCharacterSocketedJewels); - url.setQuery(query); + QUrl url(kCharacterSocketedJewels); + url.setQuery(query); - return Request(url, location, TabCache::None); + return Request(url, location, TabCache::None); } QNetworkRequest ItemsManagerWorker::Request(QUrl url, const ItemLocation &location, TabCache::Flags flags) { - switch (tab_selection_) { - case TabSelection::All: - flags |= TabCache::Refresh; - break; - case TabSelection::Checked: - if (!location.IsValid() || bo_manager_.GetRefreshChecked(location)) - flags |= TabCache::Refresh; - break; - case TabSelection::Selected: - if (!location.IsValid() || selected_tabs_.count(location.get_tab_uniq_id())) - flags |= TabCache::Refresh; - break; - } - return tab_cache_->Request(url, flags); + switch (tab_selection_) { + case TabSelection::All: + flags |= TabCache::Refresh; + break; + case TabSelection::Checked: + if (!location.IsValid() || bo_manager_.GetRefreshChecked(location)) + flags |= TabCache::Refresh; + break; + case TabSelection::Selected: + if (!location.IsValid() || selected_tabs_.count(location.get_tab_uniq_id())) + flags |= TabCache::Refresh; + break; + } + return tab_cache_->Request(url, flags); } void ItemsManagerWorker::QueueRequest(const QNetworkRequest &request, const ItemLocation &location) { - QLOG_DEBUG() << "Queued (" << queue_id_ + 1 << ") -- " << location.GetHeader().c_str(); - ItemsRequest items_request; - items_request.network_request = request; - items_request.id = queue_id_++; - items_request.location = location; - queue_.push(items_request); + QLOG_DEBUG() << "Queued (" << queue_id_ + 1 << ") -- " << location.GetHeader().c_str(); + ItemsRequest items_request; + items_request.network_request = request; + items_request.id = queue_id_++; + items_request.location = location; + queue_.push(items_request); } void ItemsManagerWorker::FetchItems(int limit) { - std::string tab_titles; - int count = std::min(limit, static_cast(queue_.size())); - for (int i = 0; i < count; ++i) { - ItemsRequest request = queue_.front(); - queue_.pop(); - - QNetworkReply *fetched = network_manager_.get(request.network_request); - signal_mapper_->setMapping(fetched, request.id); - connect(fetched, SIGNAL(finished()), signal_mapper_, SLOT(map())); - - ItemsReply reply; - reply.network_reply = fetched; - reply.request = request; - replies_[request.id] = reply; - - tab_titles += request.location.GetHeader() + " "; - } - QLOG_DEBUG() << "Created" << count << "requests:" << tab_titles.c_str(); - requests_needed_ = count; - requests_completed_ = 0; - cached_requests_completed_ = 0; + std::string tab_titles; + int count = std::min(limit, static_cast(queue_.size())); + for (int i = 0; i < count; ++i) { + ItemsRequest request = queue_.front(); + queue_.pop(); + + QNetworkRequest fetch_request = request.network_request; + fetch_request.setHeader(QNetworkRequest::KnownHeaders::UserAgentHeader, "Acquisition"); + QNetworkReply *fetched = network_manager_.get(fetch_request); + signal_mapper_->setMapping(fetched, request.id); + connect(fetched, SIGNAL(finished()), signal_mapper_, SLOT(map())); + + ItemsReply reply; + reply.network_reply = fetched; + reply.request = request; + replies_[request.id] = reply; + + tab_titles += request.location.GetHeader() + " "; + } + QLOG_DEBUG() << "Created" << count << "requests:" << tab_titles.c_str(); + requests_needed_ = count; + requests_completed_ = 0; + cached_requests_completed_ = 0; } void ItemsManagerWorker::OnFirstTabReceived() { - QNetworkReply *reply = qobject_cast(QObject::sender()); - QByteArray bytes = reply->readAll(); - rapidjson::Document doc; - doc.Parse(bytes.constData()); - - if (!doc.IsObject()) { - QLOG_ERROR() << "Can't even fetch first tab. Failed to update items."; - updating_ = false; - return; - } - - if (doc.HasMember("error")) { - QLOG_ERROR() << "Aborting update since first fetch failed due to 'error': " << Util::RapidjsonSerialize(doc["error"]).c_str(); - updating_ = false; - return; - } - - if (!doc.HasMember("tabs") || doc["tabs"].Size() == 0) { - QLOG_WARN() << "There are no tabs, this should not happen, bailing out."; - updating_ = false; - return; - } - - tabs_as_string_ = Util::RapidjsonSerialize(doc["tabs"]); - tabs_signature_ = CreateTabsSignatureVector(tabs_as_string_); - - QLOG_DEBUG() << "Received tabs list, there are" << doc["tabs"].Size() << "tabs"; - - std::set old_tab_headers; - for (auto const &tab: tabs_) { - // Remember old tab headers before clearing tabs - old_tab_headers.insert(tab.GetHeader()); - } - - //clear out ItemLocationType::STASH tabs from tabs_ - std::vector tmpLocs = tabs_; - for(auto &tab : tmpLocs){ - if(tab.get_type() == ItemLocationType::STASH){ - tabs_.erase(std::remove(tabs_.begin(), tabs_.end(), tab), tabs_.end()); - tab_id_index_.erase(tab.get_tab_uniq_id()); - } - } - - // Create tab location objects - for (auto &tab : doc["tabs"]) { - std::string label = tab["n"].GetString(); - auto index = tab["i"].GetInt(); - // Ignore hidden locations - if (!doc["tabs"][index].HasMember("hidden") || !doc["tabs"][index]["hidden"].GetBool()){ - int r = tab["colour"]["r"].GetInt(); - int g = tab["colour"]["g"].GetInt(); - int b = tab["colour"]["b"].GetInt(); - - ItemLocation loc(index, tab["id"].GetString(), label, ItemLocationType::STASH, r, g, b); - loc.set_json(tab, doc.GetAllocator()); - tabs_.push_back(loc); - tab_id_index_.insert(tab["id"].GetString()); - } - } - - // Queue requests for Stash tabs - for (auto const &tab: tabs_) { - bool refresh = false; - - // Force refreshes for any tabs that were moved or renamed regardless of what user - // requests for refresh. - if (!old_tab_headers.count(tab.GetHeader())) { - QLOG_DEBUG() << "Forcing refresh of moved or renamed tab: " << tab.GetHeader().c_str(); - refresh = true; - } - if(tab.get_type() == ItemLocationType::STASH) - QueueRequest(MakeTabRequest(tab.get_tab_id(), tab, true, refresh), tab); - } - - total_needed_ = queue_.size(); - total_completed_ = 0; - total_cached_ = reply->attribute(QNetworkRequest::SourceIsFromCacheAttribute).toBool() ? 1:0; - - FetchItems(kThrottleRequests - 1); - - connect(signal_mapper_, SIGNAL(mapped(int)), this, SLOT(OnTabReceived(int))); - reply->deleteLater(); + QNetworkReply *reply = qobject_cast(QObject::sender()); + QByteArray bytes = reply->readAll(); + rapidjson::Document doc; + doc.Parse(bytes.constData()); + + if (!doc.IsObject()) { + QLOG_ERROR() << "Can't even fetch first tab. Failed to update items."; + updating_ = false; + return; + } + + if (doc.HasMember("error")) { + QLOG_ERROR() << "Aborting update since first fetch failed due to 'error': " << Util::RapidjsonSerialize(doc["error"]).c_str(); + updating_ = false; + return; + } + + if (!doc.HasMember("tabs") || doc["tabs"].Size() == 0) { + QLOG_WARN() << "There are no tabs, this should not happen, bailing out."; + updating_ = false; + return; + } + + tabs_as_string_ = Util::RapidjsonSerialize(doc["tabs"]); + tabs_signature_ = CreateTabsSignatureVector(tabs_as_string_); + + QLOG_DEBUG() << "Received tabs list, there are" << doc["tabs"].Size() << "tabs"; + + std::set old_tab_headers; + for (auto const &tab: tabs_) { + // Remember old tab headers before clearing tabs + old_tab_headers.insert(tab.GetHeader()); + } + + //clear out ItemLocationType::STASH tabs from tabs_ + std::vector tmpLocs = tabs_; + for(auto &tab : tmpLocs){ + if(tab.get_type() == ItemLocationType::STASH){ + tabs_.erase(std::remove(tabs_.begin(), tabs_.end(), tab), tabs_.end()); + tab_id_index_.erase(tab.get_tab_uniq_id()); + } + } + + // Create tab location objects + for (auto &tab : doc["tabs"]) { + std::string label = tab["n"].GetString(); + auto index = tab["i"].GetInt(); + // Ignore hidden locations + if (!doc["tabs"][index].HasMember("hidden") || !doc["tabs"][index]["hidden"].GetBool()){ + int r = tab["colour"]["r"].GetInt(); + int g = tab["colour"]["g"].GetInt(); + int b = tab["colour"]["b"].GetInt(); + + ItemLocation loc(index, tab["id"].GetString(), label, ItemLocationType::STASH, r, g, b); + loc.set_json(tab, doc.GetAllocator()); + tabs_.push_back(loc); + tab_id_index_.insert(tab["id"].GetString()); + } + } + + // Queue requests for Stash tabs + for (auto const &tab: tabs_) { + bool refresh = false; + + // Force refreshes for any tabs that were moved or renamed regardless of what user + // requests for refresh. + if (!old_tab_headers.count(tab.GetHeader())) { + QLOG_DEBUG() << "Forcing refresh of moved or renamed tab: " << tab.GetHeader().c_str(); + refresh = true; + } + if(tab.get_type() == ItemLocationType::STASH) + QueueRequest(MakeTabRequest(tab.get_tab_id(), tab, true, refresh), tab); + } + + total_needed_ = queue_.size(); + total_completed_ = 0; + total_cached_ = reply->attribute(QNetworkRequest::SourceIsFromCacheAttribute).toBool() ? 1:0; + + FetchItems(kThrottleRequests - 1); + + connect(signal_mapper_, SIGNAL(mapped(int)), this, SLOT(OnTabReceived(int))); + reply->deleteLater(); } void ItemsManagerWorker::ParseItems(rapidjson::Value *value_ptr, ItemLocation base_location, rapidjson_allocator &alloc) { - auto &value = *value_ptr; - - std::string test = Util::RapidjsonSerialize(value); - if(base_location.get_type() == ItemLocationType::CHARACTER){ - // QLOG_DEBUG() << test.c_str(); - } - - for (auto &item : value) { - //ItemLocation location(base_location); - base_location.FromItemJson(item); - base_location.ToItemJson(&item, alloc); - items_.push_back(std::make_shared(item, base_location)); - base_location.set_socketed(true); - if (item.HasMember("socketedItems") && item["socketedItems"].IsArray()){ - ParseItems(&item["socketedItems"], base_location, alloc); - } - } + auto &value = *value_ptr; + + std::string test = Util::RapidjsonSerialize(value); + if(base_location.get_type() == ItemLocationType::CHARACTER){ + // QLOG_DEBUG() << test.c_str(); + } + + for (auto &item : value) { + //ItemLocation location(base_location); + base_location.FromItemJson(item); + base_location.ToItemJson(&item, alloc); + items_.push_back(std::make_shared(item, base_location)); + base_location.set_socketed(true); + if (item.HasMember("socketedItems") && item["socketedItems"].IsArray()){ + ParseItems(&item["socketedItems"], base_location, alloc); + } + } } void ItemsManagerWorker::OnTabReceived(int request_id) { - if (!replies_.count(request_id)) { - QLOG_WARN() << "Received a reply for request" << request_id << "that was not requested."; - return; - } - - ItemsReply reply = replies_[request_id]; - - bool reply_from_cache = reply.network_reply->attribute(QNetworkRequest::SourceIsFromCacheAttribute).toBool(); - - if (reply_from_cache) { - QLOG_DEBUG() << "Received a cached reply for" << reply.request.location.GetHeader().c_str(); - ++cached_requests_completed_; - ++total_cached_; - } else { - QLOG_DEBUG() << "Received a reply for" << reply.request.location.GetHeader().c_str(); - } - - QByteArray bytes = reply.network_reply->readAll(); - rapidjson::Document doc; - doc.Parse(bytes.constData()); - - bool error = false; - if (!doc.IsObject()) { - QLOG_WARN() << request_id << "got a non-object response"; - error = true; - } else if (doc.HasMember("error")) { - // this can happen if user is browsing stash in background and we can't know about it - QLOG_WARN() << request_id << "got 'error' instead of stash tab contents: " << Util::RapidjsonSerialize(doc["error"]).c_str(); - error = true; - } - - // We index expected tabs and their locations as part of the first fetch. It's possible for users - // to move or rename tabs during the update which will result in the item data being out-of-sync with - // expected index/tab name map. We need to detect this case and abort the update. - if (!cancel_update_ && !error && (reply.request.location.get_type() == ItemLocationType::STASH)) { - if (!doc.HasMember("tabs") || doc["tabs"].Size() == 0) { - QLOG_ERROR() << "Full tab information missing from stash tab fetch. Cancelling update. Full fetch URL: " - << reply.request.network_request.url().toDisplayString(); - cancel_update_ = true; - } else { - std::string tabs_as_string = Util::RapidjsonSerialize(doc["tabs"]); - auto tabs_signature_current = CreateTabsSignatureVector(tabs_as_string); - - auto tab_id = reply.request.location.get_tab_id(); - if (tabs_signature_[tab_id] != tabs_signature_current[tab_id]) { - if (reply_from_cache) { - // Here we unexpectedly are seeing a cached document that is out-of-sync with current tab state - // This is not fatal but unexpected as we shouldn't get here if everything else is done right. - // If we do see, set 'error' condition which causes us to flush from catch and re-fetch from server. - QLOG_WARN() << "Unexpected hit on stale cached tab. Flushing and re-fetching request: " - << reply.request.network_request.url().toDisplayString(); - error = true; - // Isn't really cached since we're erroring out and replaying so fix up stats - total_cached_--; - } else { - std::string reason; - if (tabs_signature_current.size() != tabs_signature_.size()) - reason += "[Tab size mismatch:" + std::to_string(tabs_signature_current.size()) + " != " - + std::to_string(tabs_signature_.size()) + "]"; - - auto &x = tabs_signature_current[tab_id]; - auto &y = tabs_signature_[tab_id]; - reason += "[tab_index=" + std::to_string(tab_id) + "/" + std::to_string(tabs_signature_current.size()) + "(#" + std::to_string(tab_id+1) + ")]"; - if (x.first != y.first) - reason += "[name:" + x.first + " != " + y.first + "]"; - if (x.second != y.second) - reason += "[id:" + x.second + " != " + y.second + "]"; - - QLOG_ERROR() << "You renamed or re-ordered tabs in game while acquisition was in the middle of the update," - << " aborting to prevent synchronization problems and pricing data loss. Mismatch reason(s) -> " - << reason.c_str() << ". For request: " << reply.request.network_request.url().toDisplayString(); - cancel_update_ = true; - } - } - } - } - - // re-queue a failed request - if (error) { - // We can 'cache' error response document so make sure we remove it - // before reque - tab_cache_->remove(reply.request.network_request.url()); - QueueRequest(reply.request.network_request, reply.request.location); - } - - ++requests_completed_; - - if (!error) - ++total_completed_; - - bool throttled = false; - - if (requests_completed_ == requests_needed_) { - if (cancel_update_) { - updating_ = false; - } else if (queue_.size() > 0) { - if (cached_requests_completed_ > 0) { - // We basically don't want cached requests to count against throttle limit - // so if we did get any cached requests fetch up to that number without a - // large delay - QTimer::singleShot(1, [&]() { FetchItems(cached_requests_completed_); }); - } else { - throttled = true; - QLOG_DEBUG() << "Sleeping one minute to prevent throttling."; - QTimer::singleShot(kThrottleSleep * 1000, this, SLOT(FetchItems())); - } - } - } - CurrentStatusUpdate status = CurrentStatusUpdate(); - status.state = throttled ? ProgramState::ItemsPaused : ProgramState::ItemsReceive; - status.progress = total_completed_; - status.total = total_needed_; - status.cached = total_cached_; - if (total_completed_ == total_needed_) - status.state = ProgramState::ItemsCompleted; - if (cancel_update_) - status.state = ProgramState::UpdateCancelled; - emit StatusUpdate(status); - - if (error) - return; - - ParseItems(&doc["items"], reply.request.location, doc.GetAllocator()); - - if ((total_completed_ == total_needed_) && !cancel_update_) { - // It's possible that we receive character vs stash tabs out of order, or users - // move items around in a tab and we get them in a different order. For - // consistency we want to present the tab data in a deterministic way to the rest - // of the application. Especially so we don't try to update shop when nothing actually - // changed. So sort items_ here before emitting and then generate - // item list as strings. - - std::sort(begin(items_), end(items_), [](const std::shared_ptr &a, const std::shared_ptr &b){ - return *a < *b; - }); - - std::map tabsPerType; - //categorize tabs by tab type - for(auto const tab : tabs_){ - tabsPerType[tab.get_type()].push_back(tab.get_json().c_str()); - } - - //loop through each item, put it in a set that equals its location - std::map itemsPerLoc; - for (auto const &item: items_) { - itemsPerLoc[item->location()].push_back(item->json().c_str()); - } - - //save tabs - std::map::iterator tabIter; - for ( tabIter = tabsPerType.begin(); tabIter != tabsPerType.end(); tabIter++ ){ - data_.SetTabs(tabIter->first, std::string("[") + tabIter->second.join(",").toStdString() + "]"); - } - - //save items - std::map::iterator itemIter; - for ( itemIter = itemsPerLoc.begin(); itemIter != itemsPerLoc.end(); itemIter++ ) - { - data_.SetItems(itemIter->first, std::string("[") + itemIter->second.join(",").toStdString() + "]"); - } - - // all requests completed - emit ItemsRefreshed(items_, tabs_, false); - - updating_ = false; - QLOG_DEBUG() << "Finished updating stash."; - - // if we're at the verge of getting throttled, sleep so we don't - if (requests_completed_ == kThrottleRequests) - QTimer::singleShot(kThrottleSleep, this, SLOT(PreserveSelectedCharacter())); - else - PreserveSelectedCharacter(); - } - - reply.network_reply->deleteLater(); + if (!replies_.count(request_id)) { + QLOG_WARN() << "Received a reply for request" << request_id << "that was not requested."; + return; + } + + ItemsReply reply = replies_[request_id]; + + bool reply_from_cache = reply.network_reply->attribute(QNetworkRequest::SourceIsFromCacheAttribute).toBool(); + + if (reply_from_cache) { + QLOG_DEBUG() << "Received a cached reply for" << reply.request.location.GetHeader().c_str(); + ++cached_requests_completed_; + ++total_cached_; + } else { + QLOG_DEBUG() << "Received a reply for" << reply.request.location.GetHeader().c_str(); + } + + QByteArray bytes = reply.network_reply->readAll(); + rapidjson::Document doc; + doc.Parse(bytes.constData()); + + bool error = false; + if (!doc.IsObject()) { + QLOG_WARN() << request_id << "got a non-object response"; + error = true; + } else if (doc.HasMember("error")) { + // this can happen if user is browsing stash in background and we can't know about it + QLOG_WARN() << request_id << "got 'error' instead of stash tab contents: " << Util::RapidjsonSerialize(doc["error"]).c_str(); + error = true; + } + + // We index expected tabs and their locations as part of the first fetch. It's possible for users + // to move or rename tabs during the update which will result in the item data being out-of-sync with + // expected index/tab name map. We need to detect this case and abort the update. + if (!cancel_update_ && !error && (reply.request.location.get_type() == ItemLocationType::STASH)) { + if (!doc.HasMember("tabs") || doc["tabs"].Size() == 0) { + QLOG_ERROR() << "Full tab information missing from stash tab fetch. Cancelling update. Full fetch URL: " + << reply.request.network_request.url().toDisplayString(); + cancel_update_ = true; + } else { + std::string tabs_as_string = Util::RapidjsonSerialize(doc["tabs"]); + auto tabs_signature_current = CreateTabsSignatureVector(tabs_as_string); + + auto tab_id = reply.request.location.get_tab_id(); + if (tabs_signature_[tab_id] != tabs_signature_current[tab_id]) { + if (reply_from_cache) { + // Here we unexpectedly are seeing a cached document that is out-of-sync with current tab state + // This is not fatal but unexpected as we shouldn't get here if everything else is done right. + // If we do see, set 'error' condition which causes us to flush from catch and re-fetch from server. + QLOG_WARN() << "Unexpected hit on stale cached tab. Flushing and re-fetching request: " + << reply.request.network_request.url().toDisplayString(); + error = true; + // Isn't really cached since we're erroring out and replaying so fix up stats + total_cached_--; + } else { + std::string reason; + if (tabs_signature_current.size() != tabs_signature_.size()) + reason += "[Tab size mismatch:" + std::to_string(tabs_signature_current.size()) + " != " + + std::to_string(tabs_signature_.size()) + "]"; + + auto &x = tabs_signature_current[tab_id]; + auto &y = tabs_signature_[tab_id]; + reason += "[tab_index=" + std::to_string(tab_id) + "/" + std::to_string(tabs_signature_current.size()) + "(#" + std::to_string(tab_id+1) + ")]"; + if (x.first != y.first) + reason += "[name:" + x.first + " != " + y.first + "]"; + if (x.second != y.second) + reason += "[id:" + x.second + " != " + y.second + "]"; + + QLOG_ERROR() << "You renamed or re-ordered tabs in game while acquisition was in the middle of the update," + << " aborting to prevent synchronization problems and pricing data loss. Mismatch reason(s) -> " + << reason.c_str() << ". For request: " << reply.request.network_request.url().toDisplayString(); + cancel_update_ = true; + } + } + } + } + + // re-queue a failed request + if (error) { + // We can 'cache' error response document so make sure we remove it + // before reque + tab_cache_->remove(reply.request.network_request.url()); + QueueRequest(reply.request.network_request, reply.request.location); + } + + ++requests_completed_; + + if (!error) + ++total_completed_; + + bool throttled = false; + + if (requests_completed_ == requests_needed_) { + if (cancel_update_) { + updating_ = false; + } else if (queue_.size() > 0) { + if (cached_requests_completed_ > 0) { + // We basically don't want cached requests to count against throttle limit + // so if we did get any cached requests fetch up to that number without a + // large delay + QTimer::singleShot(1, [&]() { FetchItems(cached_requests_completed_); }); + } else { + throttled = true; + QLOG_DEBUG() << "Sleeping one minute to prevent throttling."; + QTimer::singleShot(kThrottleSleep * 1000, this, SLOT(FetchItems())); + } + } + } + CurrentStatusUpdate status = CurrentStatusUpdate(); + status.state = throttled ? ProgramState::ItemsPaused : ProgramState::ItemsReceive; + status.progress = total_completed_; + status.total = total_needed_; + status.cached = total_cached_; + if (total_completed_ == total_needed_) + status.state = ProgramState::ItemsCompleted; + if (cancel_update_) + status.state = ProgramState::UpdateCancelled; + emit StatusUpdate(status); + + if (error) + return; + + ParseItems(&doc["items"], reply.request.location, doc.GetAllocator()); + + if ((total_completed_ == total_needed_) && !cancel_update_) { + // It's possible that we receive character vs stash tabs out of order, or users + // move items around in a tab and we get them in a different order. For + // consistency we want to present the tab data in a deterministic way to the rest + // of the application. Especially so we don't try to update shop when nothing actually + // changed. So sort items_ here before emitting and then generate + // item list as strings. + + std::sort(begin(items_), end(items_), [](const std::shared_ptr &a, const std::shared_ptr &b){ + return *a < *b; + }); + + std::map tabsPerType; + //categorize tabs by tab type + for(auto const tab : tabs_){ + tabsPerType[tab.get_type()].push_back(tab.get_json().c_str()); + } + + //loop through each item, put it in a set that equals its location + std::map itemsPerLoc; + for (auto const &item: items_) { + itemsPerLoc[item->location()].push_back(item->json().c_str()); + } + + //save tabs + std::map::iterator tabIter; + for ( tabIter = tabsPerType.begin(); tabIter != tabsPerType.end(); tabIter++ ){ + data_.SetTabs(tabIter->first, std::string("[") + tabIter->second.join(",").toStdString() + "]"); + } + + //save items + std::map::iterator itemIter; + for ( itemIter = itemsPerLoc.begin(); itemIter != itemsPerLoc.end(); itemIter++ ) + { + data_.SetItems(itemIter->first, std::string("[") + itemIter->second.join(",").toStdString() + "]"); + } + + // all requests completed + emit ItemsRefreshed(items_, tabs_, false); + + updating_ = false; + QLOG_DEBUG() << "Finished updating stash."; + + // if we're at the verge of getting throttled, sleep so we don't + if (requests_completed_ == kThrottleRequests) + QTimer::singleShot(kThrottleSleep, this, SLOT(PreserveSelectedCharacter())); + else + PreserveSelectedCharacter(); + } + + reply.network_reply->deleteLater(); } void ItemsManagerWorker::PreserveSelectedCharacter() { - if (selected_character_.empty()) - return; - network_manager_.get(MakeCharacterRequest(selected_character_, ItemLocation())); + if (selected_character_.empty()) + return; + network_manager_.get(MakeCharacterRequest(selected_character_, ItemLocation())); } std::vector > ItemsManagerWorker::CreateTabsSignatureVector(std::string tabs) { - std::vector > tmp; - rapidjson::Document doc; - - if (doc.Parse(tabs.c_str()).HasParseError()) { - QLOG_ERROR() << "Malformed tabs data:" << tabs.c_str() << "The error was" - << rapidjson::GetParseError_En(doc.GetParseError()); - } else { - for (auto &tab : doc) { - std::string name = (tab.HasMember("n") && tab["n"].IsString()) ? tab["n"].GetString(): "UNKNOWN_NAME"; - std::string uid = (tab.HasMember("id") && tab["id"].IsString()) ? tab["id"].GetString(): "UNKNOWN_ID"; - tmp.emplace_back(name,uid); - } - } - return tmp; + std::vector > tmp; + rapidjson::Document doc; + + if (doc.Parse(tabs.c_str()).HasParseError()) { + QLOG_ERROR() << "Malformed tabs data:" << tabs.c_str() << "The error was" + << rapidjson::GetParseError_En(doc.GetParseError()); + } else { + for (auto &tab : doc) { + std::string name = (tab.HasMember("n") && tab["n"].IsString()) ? tab["n"].GetString(): "UNKNOWN_NAME"; + std::string uid = (tab.HasMember("id") && tab["id"].IsString()) ? tab["id"].GetString(): "UNKNOWN_ID"; + tmp.emplace_back(name,uid); + } + } + return tmp; } diff --git a/src/logindialog.cpp b/src/logindialog.cpp index 13ad68eb..d30efbb5 100644 --- a/src/logindialog.cpp +++ b/src/logindialog.cpp @@ -1,20 +1,20 @@ /* - Copyright 2014 Ilya Zhuravlev + Copyright 2014 Ilya Zhuravlev - This file is part of Acquisition. + This file is part of Acquisition. - Acquisition is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. + Acquisition is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. - Acquisition is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. + Acquisition is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. - You should have received a copy of the GNU General Public License - along with Acquisition. If not, see . + You should have received a copy of the GNU General Public License + along with Acquisition. If not, see . */ #include "logindialog.h" @@ -50,7 +50,7 @@ #include "openssl/aes.h" -const char* POE_LEAGUE_LIST_URL = "http://api.pathofexile.com/leagues?type=main&compact=1"; +const char* POE_LEAGUE_LIST_URL = "https://api.pathofexile.com/leagues?type=main&compact=1"; const char* POE_LOGIN_URL = "https://www.pathofexile.com/login"; const char* POE_MAIN_PAGE = "https://www.pathofexile.com/"; const char* POE_MY_ACCOUNT = "https://www.pathofexile.com/my-account"; @@ -60,254 +60,288 @@ const char* POE_COOKIE_NAME = "POESESSID"; const char* LOGIN_CHECK_ERROR = "Failed to log in (invalid password or expired session ID? try re-logging with email/password pair or via steam)"; enum { - LOGIN_PASSWORD, - LOGIN_STEAM, - LOGIN_SESSIONID + LOGIN_PASSWORD, + LOGIN_STEAM, + LOGIN_SESSIONID }; /** * Possible login flows: * * Normal - => Retrieve /login to get csrf token - => OnLoginPageFinished() - => POST email/pw to /login - => OnLoggedIn() - => Retrieve /my-account to get account name - => OnMainPageFinished() - => done + => Retrieve /login to get csrf token + => OnLoginPageFinished() + => POST email/pw to /login + => OnLoggedIn() + => Retrieve /my-account to get account name + => OnMainPageFinished() + => done * Steam - => Run webengine and point it at steam login page - => OnSteamCookieReceived() -> LoginWithCookie() - => Retrieve POE_LOGIN_CHECK_URL - => LoggedInCheck() - => Retrieve /my-account to get account name - => OnMainPageFinished() - => done + => Run webengine and point it at steam login page + => OnSteamCookieReceived() -> LoginWithCookie() + => Retrieve POE_LOGIN_CHECK_URL + => LoggedInCheck() + => Retrieve /my-account to get account name + => OnMainPageFinished() + => done * Session ID - => LoginWithCookie() - => Retrieve POE_LOGIN_CHECK_URL - => LoggedInCheck() - => Retrieve /my-account to get account name - => OnMainPageFinished() - => done + => LoginWithCookie() + => Retrieve POE_LOGIN_CHECK_URL + => LoggedInCheck() + => Retrieve /my-account to get account name + => OnMainPageFinished() + => done */ LoginDialog::LoginDialog(std::unique_ptr app) : - app_(std::move(app)), - ui(new Ui::LoginDialog), - mw(0), - asked_to_update_(false) + app_(std::move(app)), + ui(new Ui::LoginDialog), + mw(0), + asked_to_update_(false) { - ui->setupUi(this); - ui->errorLabel->hide(); - ui->errorLabel->setStyleSheet("QLabel { color : red; }"); - setWindowTitle(QString("Login [") + VERSION_NAME + "]"); + ui->setupUi(this); + ui->errorLabel->hide(); + ui->errorLabel->setStyleSheet("QLabel { color : red; }"); + setWindowTitle(QString("Login [") + VERSION_NAME + "]"); #if defined(Q_OS_LINUX) - setWindowIcon(QIcon(":/icons/assets/icon.svg")); + setWindowIcon(QIcon(":/icons/assets/icon.svg")); #endif - setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); - - settings_path_ = Filesystem::UserDir() + "/settings.ini"; - LoadSettings(); - - login_manager_ = std::make_unique(); - connect(ui->proxyCheckBox, SIGNAL(clicked(bool)), this, SLOT(OnProxyCheckBoxClicked(bool))); - connect(ui->loginButton, SIGNAL(clicked()), this, SLOT(OnLoginButtonClicked())); - connect(&update_checker_, &UpdateChecker::UpdateAvailable, [&](){ - // Only annoy the user once at the login dialog window, even if it's opened for more than an hour - if (asked_to_update_) - return; - asked_to_update_ = true; - UpdateChecker::AskUserToUpdate(this); - }); - - QNetworkReply *leagues_reply = login_manager_->get(QNetworkRequest(QUrl(QString(POE_LEAGUE_LIST_URL)))); - connect(leagues_reply, &QNetworkReply::finished, this, &LoginDialog::OnLeaguesRequestFinished); - new QReplyTimeout(leagues_reply, kPoeApiTimeout); + setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); + + settings_path_ = Filesystem::UserDir() + "/settings.ini"; + LoadSettings(); + + login_manager_ = std::make_unique(); + connect(ui->proxyCheckBox, SIGNAL(clicked(bool)), this, SLOT(OnProxyCheckBoxClicked(bool))); + connect(ui->loginButton, SIGNAL(clicked()), this, SLOT(OnLoginButtonClicked())); + connect(&update_checker_, &UpdateChecker::UpdateAvailable, [&](){ + // Only annoy the user once at the login dialog window, even if it's opened for more than an hour + if (asked_to_update_) + return; + asked_to_update_ = true; + UpdateChecker::AskUserToUpdate(this); + }); + + QNetworkRequest leagues_request = QNetworkRequest(QUrl(QString(POE_LEAGUE_LIST_URL))); + //QSslConfiguration newSslConfig = QSslConfiguration(leagues_request.sslConfiguration()); + //newSslConfig.setProtocol(QSsl::TlsV1_3OrLater); + //leagues_request.setSslConfiguration(newSslConfig); + + leagues_request.setHeader(QNetworkRequest::KnownHeaders::UserAgentHeader, "Acquisition"); + + QNetworkReply *leagues_reply = login_manager_->get(leagues_request); + + /* + QSslConfiguration reply_config = QSslConfiguration(leagues_reply->sslConfiguration()); + reply_config.setProtocol(QSsl::TlsV1_3OrLater); + leagues_reply->setSslConfiguration(reply_config); + QLOG_DEBUG() << "leagues_reply Protocol: " << reply_config.protocol(); + */ + + connect(leagues_reply, &QNetworkReply::errorOccurred, this, &LoginDialog::errorOccurred); + connect(leagues_reply, &QNetworkReply::sslErrors, this, &LoginDialog::sslErrorOccurred); + connect(leagues_reply, &QNetworkReply::finished, this, &LoginDialog::OnLeaguesRequestFinished); + new QReplyTimeout(leagues_reply, kPoeApiTimeout); +} + +void LoginDialog::errorOccurred(){ + QLOG_ERROR() << "League List errorOccured"; +} + +void LoginDialog::sslErrorOccurred(){ + QLOG_ERROR() << "League List sslErrorOccured"; } void LoginDialog::OnLoginButtonClicked() { - ui->loginButton->setEnabled(false); - ui->loginButton->setText("Logging in..."); - - switch (ui->loginTabs->currentIndex()) { - case LOGIN_PASSWORD: { - // Get POE_LOGIN_URL to retrieve the csrf token - QNetworkReply *login_page = login_manager_->get(QNetworkRequest(QUrl(POE_LOGIN_URL))); - connect(login_page, SIGNAL(finished()), this, SLOT(OnLoginPageFinished())); - break; - } - case LOGIN_STEAM: { - if (!steam_login_dialog_) - InitSteamDialog(); - steam_login_dialog_->show(); - steam_login_dialog_->Init(); - break; - } - case LOGIN_SESSIONID: { - LoginWithCookie(ui->sessionIDLineEdit->text()); - break; - } - } + ui->loginButton->setEnabled(false); + ui->loginButton->setText("Logging in..."); + + switch (ui->loginTabs->currentIndex()) { + case LOGIN_PASSWORD: { + // Get POE_LOGIN_URL to retrieve the csrf token + QNetworkReply *login_page = login_manager_->get(QNetworkRequest(QUrl(POE_LOGIN_URL))); + connect(login_page, SIGNAL(finished()), this, SLOT(OnLoginPageFinished())); + break; + } + case LOGIN_STEAM: { + if (!steam_login_dialog_) + InitSteamDialog(); + steam_login_dialog_->show(); + steam_login_dialog_->Init(); + break; + } + case LOGIN_SESSIONID: { + LoginWithCookie(ui->sessionIDLineEdit->text()); + break; + } + } } void LoginDialog::InitSteamDialog() { - steam_login_dialog_ = std::make_unique(); - connect(steam_login_dialog_.get(), SIGNAL(CookieReceived(const QString&)), this, SLOT(OnSteamCookieReceived(const QString&))); - connect(steam_login_dialog_.get(), SIGNAL(Closed()), this, SLOT(OnSteamDialogClosed()), Qt::DirectConnection); + steam_login_dialog_ = std::make_unique(); + connect(steam_login_dialog_.get(), SIGNAL(CookieReceived(const QString&)), this, SLOT(OnSteamCookieReceived(const QString&))); + connect(steam_login_dialog_.get(), SIGNAL(Closed()), this, SLOT(OnSteamDialogClosed()), Qt::DirectConnection); } void LoginDialog::OnSteamDialogClosed() { - DisplayError("Login was not completed"); + DisplayError("Login was not completed"); } void LoginDialog::LeaguesApiError(const QString &error, const QByteArray &reply) { - DisplayError("Leagues API returned malformed data: " + error, true); - QLOG_ERROR() << "Leagues API says: " << reply; + DisplayError("Leagues API returned malformed data: " + error, true); + QLOG_ERROR() << "Leagues API says: " << reply; } void LoginDialog::OnLeaguesRequestFinished() { - SelfDestructingReply reply(qobject_cast(QObject::sender())); - QByteArray bytes = reply->readAll(); - - if (reply->error()) - return LeaguesApiError(reply->errorString(), bytes); - - rapidjson::Document doc; - doc.Parse(bytes.constData()); - - if (doc.HasParseError() || !doc.IsArray()) - return LeaguesApiError("Failed to parse the document", bytes); - - ui->leagueComboBox->clear(); - for (auto &league : doc) { - if (!league.IsObject()) - return LeaguesApiError("Object expected", bytes); - if (!league.HasMember("id")) - return LeaguesApiError("Missing league 'id'", bytes); - if (!league["id"].IsString()) - return LeaguesApiError("String expected", bytes); - ui->leagueComboBox->addItem(league["id"].GetString()); - } - ui->leagueComboBox->setEnabled(true); - - if (saved_league_.size() > 0) - ui->leagueComboBox->setCurrentText(saved_league_); + SelfDestructingReply reply(qobject_cast(QObject::sender())); + QByteArray bytes = reply->readAll(); + + if (reply->error()) + return LeaguesApiError(reply->errorString(), bytes); + + rapidjson::Document doc; + doc.Parse(bytes.constData()); + + if (doc.HasParseError() || !doc.IsArray()) + return LeaguesApiError("Failed to parse the document", bytes); + + ui->leagueComboBox->clear(); + for (auto &league : doc) { + if (!league.IsObject()) + return LeaguesApiError("Object expected", bytes); + if (!league.HasMember("id")) + return LeaguesApiError("Missing league 'id'", bytes); + if (!league["id"].IsString()) + return LeaguesApiError("String expected", bytes); + ui->leagueComboBox->addItem(league["id"].GetString()); + } + ui->leagueComboBox->setEnabled(true); + + if (saved_league_.size() > 0) + ui->leagueComboBox->setCurrentText(saved_league_); } // All characters except + should be handled by QUrlQuery, see http://doc.qt.io/qt-5/qurlquery.html#encoding static QString EncodeSpecialCharacters(QString s) { - s.replace("+", "%2b"); - return s; + s.replace("+", "%2b"); + return s; } void LoginDialog::OnLoginPageFinished() { - QNetworkReply *reply = qobject_cast(QObject::sender()); - if (reply->error()) { - DisplayError("Network error: " + reply->errorString() + "\nTry using another login method."); - return; - } - - QByteArray bytes = reply->readAll(); - std::string page(bytes.constData(), bytes.size()); - std::string hash = Util::GetCsrfToken(page, "hash"); - if (hash.empty()) { - DisplayError("Failed to log in (can't extract form hash from page)"); - return; - } - - QUrlQuery query; - query.addQueryItem("login_email", EncodeSpecialCharacters(ui->emailLineEdit->text())); - query.addQueryItem("login_password", EncodeSpecialCharacters(ui->passwordLineEdit->text())); - query.addQueryItem("hash", QString(hash.c_str())); - query.addQueryItem("login", "Login"); - query.addQueryItem("remember_me", "1"); - - QUrl url(POE_LOGIN_URL); - QByteArray data(query.query().toUtf8()); - QNetworkRequest request(url); - request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded"); - QNetworkReply *logged_in = login_manager_->post(request, data); - connect(logged_in, SIGNAL(finished()), this, SLOT(OnLoggedIn())); + QNetworkReply *reply = qobject_cast(QObject::sender()); + if (reply->error()) { + DisplayError("Network error: " + reply->errorString() + "\nTry using another login method."); + return; + } + + QByteArray bytes = reply->readAll(); + std::string page(bytes.constData(), bytes.size()); + std::string hash = Util::GetCsrfToken(page, "hash"); + if (hash.empty()) { + DisplayError("Failed to log in (can't extract form hash from page)"); + return; + } + + QUrlQuery query; + query.addQueryItem("login_email", EncodeSpecialCharacters(ui->emailLineEdit->text())); + query.addQueryItem("login_password", EncodeSpecialCharacters(ui->passwordLineEdit->text())); + query.addQueryItem("hash", QString(hash.c_str())); + query.addQueryItem("login", "Login"); + query.addQueryItem("remember_me", "1"); + + QUrl url(POE_LOGIN_URL); + QByteArray data(query.query().toUtf8()); + QNetworkRequest request(url); + request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded"); + request.setHeader(QNetworkRequest::KnownHeaders::UserAgentHeader, "Acquisition"); + QNetworkReply *logged_in = login_manager_->post(request, data); + connect(logged_in, SIGNAL(finished()), this, SLOT(OnLoggedIn())); } void LoginDialog::FinishLogin(QNetworkReply *reply) { - QList cookies = reply->manager()->cookieJar()->cookiesForUrl(QUrl(POE_MAIN_PAGE)); - for (QNetworkCookie &cookie : cookies) - if (QString(cookie.name()) == POE_COOKIE_NAME) - session_id_ = cookie.value(); - - // we need one more request to get account name - QNetworkReply *main_page = login_manager_->get(QNetworkRequest(QUrl(POE_MY_ACCOUNT))); - connect(main_page, SIGNAL(finished()), this, SLOT(OnMainPageFinished())); + QList cookies = reply->manager()->cookieJar()->cookiesForUrl(QUrl(POE_MAIN_PAGE)); + for (QNetworkCookie &cookie : cookies) + if (QString(cookie.name()) == POE_COOKIE_NAME) + session_id_ = cookie.value(); + + // we need one more request to get account name + QNetworkRequest main_page_request = QNetworkRequest(QUrl(POE_MY_ACCOUNT)); + main_page_request.setHeader(QNetworkRequest::KnownHeaders::UserAgentHeader, "Acquisition"); + QNetworkReply *main_page = login_manager_->get(main_page_request); + connect(main_page, SIGNAL(finished()), this, SLOT(OnMainPageFinished())); } void LoginDialog::OnLoggedIn() { - QNetworkReply *reply = qobject_cast(QObject::sender()); - QByteArray bytes = reply->readAll(); - int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); - if (status != 302) { - DisplayError(LOGIN_CHECK_ERROR); - return; - } - - FinishLogin(reply); + QNetworkReply *reply = qobject_cast(QObject::sender()); + QByteArray bytes = reply->readAll(); + int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); + if (status != 302) { + DisplayError(LOGIN_CHECK_ERROR); + return; + } + + FinishLogin(reply); } // Need a separate check since it's just the /login URL that's filtered void LoginDialog::LoggedInCheck() { - QNetworkReply *reply = qobject_cast(QObject::sender()); - QByteArray bytes = reply->readAll(); - int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); - if (status == 302) { - DisplayError(LOGIN_CHECK_ERROR); - return; - } - - FinishLogin(reply); + QNetworkReply *reply = qobject_cast(QObject::sender()); + QByteArray bytes = reply->readAll(); + int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); + switch (status) { + case 302: + DisplayError(LOGIN_CHECK_ERROR); + return; + case 401: + DisplayError(LOGIN_CHECK_ERROR); + return; + } + + FinishLogin(reply); } void LoginDialog::OnSteamCookieReceived(const QString &cookie) { - if (cookie.isEmpty()) { - DisplayError("Failed to log in, the received cookie is empty."); - return; - } - LoginWithCookie(cookie); + if (cookie.isEmpty()) { + DisplayError("Failed to log in, the received cookie is empty."); + return; + } + LoginWithCookie(cookie); } void LoginDialog::LoginWithCookie(const QString &cookie) { - QNetworkCookie poeCookie(POE_COOKIE_NAME, cookie.toUtf8()); - poeCookie.setPath("/"); - poeCookie.setDomain(".pathofexile.com"); + QNetworkCookie poeCookie(POE_COOKIE_NAME, cookie.toUtf8()); + poeCookie.setPath("/"); + poeCookie.setDomain(".pathofexile.com"); - login_manager_->cookieJar()->insertCookie(poeCookie); + login_manager_->cookieJar()->insertCookie(poeCookie); - QNetworkReply *login_page = login_manager_->get(QNetworkRequest(QUrl(POE_LOGIN_CHECK_URL))); - connect(login_page, SIGNAL(finished()), this, SLOT(LoggedInCheck())); + QNetworkRequest login_page_request = QNetworkRequest(QUrl(POE_LOGIN_CHECK_URL)); + login_page_request.setHeader(QNetworkRequest::KnownHeaders::UserAgentHeader, "Acquisition"); + QNetworkReply *login_page = login_manager_->get(login_page_request); + connect(login_page, SIGNAL(finished()), this, SLOT(LoggedInCheck())); } void LoginDialog::OnMainPageFinished() { - QNetworkReply *reply = qobject_cast(QObject::sender()); - QString html(reply->readAll()); - QRegExp regexp("/account/view-profile/(.*)\""); - regexp.setMinimal(true); - int pos = regexp.indexIn(html); - if (pos == -1) { - DisplayError("Failed to find account name."); - return; - } - QString account = regexp.cap(1); - QLOG_DEBUG() << "Logged in as:" << account; - - std::string league(ui->leagueComboBox->currentText().toStdString()); - app_->InitLogin(std::move(login_manager_), league, account.toStdString()); - mw = new MainWindow(std::move(app_)); - mw->setWindowTitle(QString("Acquisition - %1").arg(league.c_str())); - mw->show(); - close(); + QNetworkReply *reply = qobject_cast(QObject::sender()); + QString html(reply->readAll()); + QRegExp regexp("/account/view-profile/(.*)\""); + regexp.setMinimal(true); + int pos = regexp.indexIn(html); + if (pos == -1) { + DisplayError("Failed to find account name."); + return; + } + QString account = regexp.cap(1); + QLOG_DEBUG() << "Logged in as:" << account; + + std::string league(ui->leagueComboBox->currentText().toStdString()); + app_->InitLogin(std::move(login_manager_), league, account.toStdString()); + mw = new MainWindow(std::move(app_)); + mw->setWindowTitle(QString("Acquisition - %1").arg(league.c_str())); + mw->show(); + close(); } void LoginDialog::OnProxyCheckBoxClicked(bool checked) { @@ -315,66 +349,66 @@ void LoginDialog::OnProxyCheckBoxClicked(bool checked) { } void LoginDialog::LoadSettings() { - QSettings settings(settings_path_.c_str(), QSettings::IniFormat); - session_id_ = settings.value("session_id", "").toString(); - ui->sessionIDLineEdit->setText(session_id_); - ui->rembmeCheckBox->setChecked(settings.value("remember_me_checked").toBool()); - ui->proxyCheckBox->setChecked(settings.value("use_system_proxy_checked").toBool()); + QSettings settings(settings_path_.c_str(), QSettings::IniFormat); + session_id_ = settings.value("session_id", "").toString(); + ui->sessionIDLineEdit->setText(session_id_); + ui->rembmeCheckBox->setChecked(settings.value("remember_me_checked").toBool()); + ui->proxyCheckBox->setChecked(settings.value("use_system_proxy_checked").toBool()); - if (ui->rembmeCheckBox->isChecked()) - ui->loginTabs->setCurrentIndex(LOGIN_SESSIONID); + if (ui->rembmeCheckBox->isChecked()) + ui->loginTabs->setCurrentIndex(LOGIN_SESSIONID); - saved_league_ = settings.value("league", "").toString(); - if (saved_league_.size() > 0) - ui->leagueComboBox->setCurrentText(saved_league_); + saved_league_ = settings.value("league", "").toString(); + if (saved_league_.size() > 0) + ui->leagueComboBox->setCurrentText(saved_league_); - QNetworkProxyFactory::setUseSystemConfiguration(ui->proxyCheckBox->isChecked()); + QNetworkProxyFactory::setUseSystemConfiguration(ui->proxyCheckBox->isChecked()); } void LoginDialog::SaveSettings() { - QSettings settings(settings_path_.c_str(), QSettings::IniFormat); - if (ui->rembmeCheckBox->isChecked()) { - settings.setValue("session_id", session_id_); - settings.setValue("league", ui->leagueComboBox->currentText()); - } else { - settings.setValue("session_id", ""); - settings.setValue("league", ""); - } - settings.setValue("remember_me_checked", ui->rembmeCheckBox->isChecked() && !session_id_.isEmpty()); - settings.setValue("use_system_proxy_checked", ui->proxyCheckBox->isChecked()); - - // Clear any saved cookies (steamMachineAuth in particular) if user doesn't want - // us to remember login info. - // - // For details see: https://dev.doctormckay.com/topic/365-cookies/ - // - // By default WebEngine stores cookies like a normal browser and steamMachineAuth - // cookie does not naturally expire. Without this cookie the user will be required to - // re-verify access through e-mail. + QSettings settings(settings_path_.c_str(), QSettings::IniFormat); + if (ui->rembmeCheckBox->isChecked()) { + settings.setValue("session_id", session_id_); + settings.setValue("league", ui->leagueComboBox->currentText()); + } else { + settings.setValue("session_id", ""); + settings.setValue("league", ""); + } + settings.setValue("remember_me_checked", ui->rembmeCheckBox->isChecked() && !session_id_.isEmpty()); + settings.setValue("use_system_proxy_checked", ui->proxyCheckBox->isChecked()); + + // Clear any saved cookies (steamMachineAuth in particular) if user doesn't want + // us to remember login info. + // + // For details see: https://dev.doctormckay.com/topic/365-cookies/ + // + // By default WebEngine stores cookies like a normal browser and steamMachineAuth + // cookie does not naturally expire. Without this cookie the user will be required to + // re-verify access through e-mail. #ifndef NO_WEBENGINE - if (!settings.value("remember_me_checked").toBool()) { - QWebEngineProfile::defaultProfile()->cookieStore()->deleteAllCookies(); - } + if (!settings.value("remember_me_checked").toBool()) { + QWebEngineProfile::defaultProfile()->cookieStore()->deleteAllCookies(); + } #endif } void LoginDialog::DisplayError(const QString &error, bool disable_login) { - ui->errorLabel->setText(error); - ui->errorLabel->show(); - ui->loginButton->setEnabled(!disable_login); - ui->loginButton->setText("Login"); + ui->errorLabel->setText(error); + ui->errorLabel->show(); + ui->loginButton->setEnabled(!disable_login); + ui->loginButton->setText("Login"); } LoginDialog::~LoginDialog() { - SaveSettings(); - delete ui; + SaveSettings(); + delete ui; - if (mw) - delete mw; + if (mw) + delete mw; } bool LoginDialog::event(QEvent *e) { - if (e->type() == QEvent::LayoutRequest) - setFixedSize(sizeHint()); - return QDialog::event(e); + if (e->type() == QEvent::LayoutRequest) + setFixedSize(sizeHint()); + return QDialog::event(e); } diff --git a/src/logindialog.h b/src/logindialog.h index acb5b3f9..9721127b 100644 --- a/src/logindialog.h +++ b/src/logindialog.h @@ -1,20 +1,20 @@ /* - Copyright 2014 Ilya Zhuravlev + Copyright 2014 Ilya Zhuravlev - This file is part of Acquisition. + This file is part of Acquisition. - Acquisition is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. + Acquisition is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. - Acquisition is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. + Acquisition is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. - You should have received a copy of the GNU General Public License - along with Acquisition. If not, see . + You should have received a copy of the GNU General Public License + along with Acquisition. If not, see . */ #pragma once @@ -39,40 +39,42 @@ class LoginDialog; } class LoginDialog : public QDialog { - Q_OBJECT + Q_OBJECT public: - explicit LoginDialog(std::unique_ptr app); - ~LoginDialog(); + explicit LoginDialog(std::unique_ptr app); + ~LoginDialog(); public slots: - void OnLeaguesRequestFinished(); - void OnLoginButtonClicked(); - void OnLoginPageFinished(); - void OnLoggedIn(); - void LoggedInCheck(); // checks login is successful - void OnMainPageFinished(); - void OnProxyCheckBoxClicked(bool); - void OnSteamCookieReceived(const QString &cookie); - void OnSteamDialogClosed(); + void OnLeaguesRequestFinished(); + void OnLoginButtonClicked(); + void OnLoginPageFinished(); + void OnLoggedIn(); + void LoggedInCheck(); // checks login is successful + void OnMainPageFinished(); + void OnProxyCheckBoxClicked(bool); + void OnSteamCookieReceived(const QString &cookie); + void OnSteamDialogClosed(); + void errorOccurred(); + void sslErrorOccurred(); protected: - bool event(QEvent *e); + bool event(QEvent *e); private: - void SaveSettings(); - void LoadSettings(); - void DisplayError(const QString &error, bool disable_login = false); - void LoginWithCookie(const QString &cookie); - void InitSteamDialog(); - void LeaguesApiError(const QString &error, const QByteArray &reply); - // Retrieves session cookie for a successful login; proceeds to OnMainPageFinished - void FinishLogin(QNetworkReply *reply); - std::unique_ptr app_; - Ui::LoginDialog *ui; - MainWindow *mw; - std::string settings_path_; - QString saved_league_; - QString session_id_; - std::unique_ptr login_manager_; - std::vector leagues_; - std::unique_ptr steam_login_dialog_; - UpdateChecker update_checker_; - bool asked_to_update_; + void SaveSettings(); + void LoadSettings(); + void DisplayError(const QString &error, bool disable_login = false); + void LoginWithCookie(const QString &cookie); + void InitSteamDialog(); + void LeaguesApiError(const QString &error, const QByteArray &reply); + // Retrieves session cookie for a successful login; proceeds to OnMainPageFinished + void FinishLogin(QNetworkReply *reply); + std::unique_ptr app_; + Ui::LoginDialog *ui; + MainWindow *mw; + std::string settings_path_; + QString saved_league_; + QString session_id_; + std::unique_ptr login_manager_; + std::vector leagues_; + std::unique_ptr steam_login_dialog_; + UpdateChecker update_checker_; + bool asked_to_update_; }; diff --git a/src/version_defines.h b/src/version_defines.h index c6c7fa02..1767ff78 100644 --- a/src/version_defines.h +++ b/src/version_defines.h @@ -1,7 +1,7 @@ #pragma once #define VER_CODE 41 -#define VER_STR "0.8d" +#define VER_STR "0.8e" #define VER_FILEVERSION 0,8,3,0 #define VER_FILEVERSION_STR "0.8.3.0"