/* * Copyright (C) 2004-2012 Geometer Plus * * This program 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 2 of the License, or * (at your option) any later version. * * This program 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 this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ #include #include #include "../authentication/NetworkAuthenticationManager.h" #include "NetworkCatalogUtil.h" #include "../../networkActions/NetworkOperationRunnable.h" #include "../NetworkErrors.h" #include "NetworkTreeFactory.h" #include "../../networkActions/AuthenticationDialogManager.h" #include "NetworkTreeNodes.h" const ZLTypeId NetworkCatalogTree::TYPE_ID(NetworkTree::TYPE_ID); const ZLTypeId &NetworkCatalogTree::typeId() const { return TYPE_ID; } NetworkCatalogTree::NetworkCatalogTree(RootTree *parent, shared_ptr item, std::size_t position) : NetworkTree(parent, position), myItem(item) { } NetworkCatalogTree::NetworkCatalogTree(NetworkCatalogTree *parent, shared_ptr item, std::size_t position) : NetworkTree(parent, position), myItem(item) { init(); } void NetworkCatalogTree::init() { // if (!item().URLByType[NetworkItem::URL_CATALOG].empty()) { // registerAction(new ExpandCatalogAction(*this)); // } // const std::string htmlUrl = // item().URLByType[NetworkItem::URL_HTML_PAGE]; // if (!htmlUrl.empty()) { // registerAction(new OpenInBrowserAction(htmlUrl)); // } //registerAction(new ReloadAction(*this)); } std::string NetworkCatalogTree::title() const { return myItem->Title; } std::string NetworkCatalogTree::subtitle() const { return ((const NetworkCatalogItem&)*myItem).Summary; } shared_ptr NetworkCatalogTree::image() const { const std::string &url = myItem->URLByType[NetworkItem::URL_COVER]; if (url.empty()) { if (ZLTreeTitledNode* node = zlobject_cast(parent())) { return node->image(); } } if (myImage.isNull()) { myImage = NetworkCatalogUtil::getAndDownloadImageByUrl(url, this); } return (!myImage.isNull() && myImage->good()) ? myImage : FBTree::defaultCoverImage("booktree-catalog.png"); } class AsyncLoadSubCatalogRunnable : public ZLNetworkRequest::Listener { public: AsyncLoadSubCatalogRunnable(NetworkCatalogTree *tree, bool resumeMode) : myTree(tree), myResumeMode(resumeMode) { myTree->notifyDownloadStarted(); if (myResumeMode) { myTree->item().resumeLoading(myChildrens, this); } else { myTree->item().loadChildren(myChildrens, this); } } void finished(const std::string &error) { myTree->notifyDownloadStopped(); myTree->onChildrenReceived(myChildrens, error); } void setUIStatus(bool enabled) { if (enabled) { myTree->notifyDownloadStarted(); } else { myTree->notifyDownloadStopped(); } } private: NetworkCatalogTree *myTree; NetworkItem::List myChildrens; bool myResumeMode; }; //class NetworkCatalogTreeAuthScope : public ZLUserData { //public: // shared_ptr listener; //}; class NetworkCatalogTreeAuthListener : public ZLNetworkRequest::Listener { public: NetworkCatalogTreeAuthListener(NetworkCatalogTree *tree) : myTree(tree) { } void finished(const std::string &error) { myTree->onAuthCheck(error); } void setUIStatus(bool enabled) { if (enabled) { myTree->notifyDownloadStarted(); } else { myTree->notifyDownloadStopped(); } } private: NetworkCatalogTree *myTree; }; void NetworkCatalogTree::requestChildren(shared_ptr listener) { myListeners.push_back(listener); if (myListeners.size() > 1) { return; } const NetworkLink &link = item().Link; shared_ptr manager = link.authenticationManager(); if (item().getVisibility() == B3_UNDEFINED && !manager.isNull()) { AuthenticationDialogManager::authAndInitAsync(*manager, new NetworkCatalogTreeAuthListener(this)); return; } if (!manager.isNull() && manager->isAuthorised(0).Status == B3_TRUE) { AuthenticationDialogManager::athoriseIfCan(*manager, new NetworkCatalogTreeAuthListener(this)); return; } onAuthCheck(std::string()); } void NetworkCatalogTree::onAuthCheck(const std::string &error) { if (!error.empty()) { notifyListeners(error); return; } if (!myChildrenItems.empty()) { notifyDownloadStopped(); notifyListeners(std::string()); //TODO maybe not be silent about auth error here return; } new AsyncLoadSubCatalogRunnable(this, false); } void NetworkCatalogTree::requestMoreChildren(shared_ptr listener) { //TODO does double requesting is processed correct? if (!item().supportsResumeLoading()) { listener->finished(); return; } myListeners.push_back(listener); if (myListeners.size() == 1) { new AsyncLoadSubCatalogRunnable(this, true); } } void NetworkCatalogTree::onChildrenReceived(NetworkItem::List &childrens, const std::string &error) { if (!error.empty()) { //special case for authenticationFailed after 'cancel' button pressed in AuthDialog? //TODO maybe it'll be work wrong at some cases? maybe we should have another error this case? if (error != NetworkErrors::errorMessage(NetworkErrors::ERROR_AUTHENTICATION_FAILED)) { NetworkErrors::showErrorMessage(error); } notifyListeners(error); return; } myChildrenItems.insert(myChildrenItems.end(), childrens.begin(), childrens.end()); if (myChildrenItems.empty()) { ZLDialogManager::Instance().informationBox(ZLResourceKey("emptyCatalogBox")); notifyListeners(error); return; } bool hasSubcatalogs = false; for (NetworkItem::List::iterator it = myChildrenItems.begin(); it != myChildrenItems.end(); ++it) { if ((*it)->typeId() == NetworkCatalogItem::TYPE_ID) { hasSubcatalogs = true; break; } } //TODO rewrite this method if (hasSubcatalogs) { for (NetworkItem::List::iterator it = childrens.begin(); it != childrens.end(); ++it) { NetworkTreeFactory::createNetworkTree(this, *it); } } else { NetworkTreeFactory::fillAuthorTree(this, childrens); } notifyListeners(error); this->updated(); } void NetworkCatalogTree::notifyListeners(const std::string &error) { for (std::size_t i = 0; i < myListeners.size(); ++i) { if (!myListeners.at(i).isNull()) myListeners.at(i)->finished(error); } myListeners.clear(); } NetworkCatalogItem &NetworkCatalogTree::item() { return (NetworkCatalogItem&)*myItem; } void NetworkCatalogTree::updateVisibility() { //adding to remove list and clearing all existed nodes List toRemove; NetworkItem::List itemsWithNodes; //used in loop for creating new nodes (for these items new nodes won't be created) for (size_t i = 0; i < children().size(); ++i) { ZLTreeNode* tree = children().at(i); if (!tree->isInstanceOf(NetworkCatalogTree::TYPE_ID)) { continue; } NetworkCatalogTree *child = (NetworkCatalogTree*)tree; itemsWithNodes.push_back(child->myItem); switch (child->item().getVisibility()) { case B3_TRUE: child->updateVisibility(); break; case B3_FALSE: toRemove.push_back(child); break; case B3_UNDEFINED: child->clearCatalog(); break; } } //creating new nodes (if necessary) for (size_t i = 0; i < myChildrenItems.size(); ++i) { shared_ptr item = myChildrenItems.at(i); if (!item->isInstanceOf(NetworkCatalogItem::TYPE_ID)) { continue; } if (std::find(itemsWithNodes.begin(), itemsWithNodes.end(), item) != itemsWithNodes.end()) { continue; } NetworkCatalogItem *catalogItem = (NetworkCatalogItem*)(&*item); if (catalogItem->getVisibility() != B3_FALSE) { NetworkTreeFactory::createNetworkTree(this, item, i); } } for (size_t i = 0; i < toRemove.size(); ++i) { ZLTreeNode* tree = toRemove.at(i); remove(tree); } } void NetworkCatalogTree::clearCatalog() { myChildrenItems.clear(); clear(); } const ZLResource &NetworkCatalogTree::resource() const { return ZLResource::resource("networkView")["libraryItemNode"]; }