File indexing completed on 2024-04-28 15:39:42

0001 // SPDX-FileCopyrightText: 2014-2022 Jesper K. Pedersen <blackie@kde.org>
0002 //
0003 // SPDX-License-Identifier: GPL-2.0-or-later
0004 
0005 #include "RemoteInterface.h"
0006 
0007 #include "Action.h"
0008 #include "Client.h"
0009 #include "ImageDetails.h"
0010 #include "ImageStore.h"
0011 #include "RemoteCommand.h"
0012 #include "ScreenInfo.h"
0013 #include "Settings.h"
0014 
0015 #include <QBuffer>
0016 #include <QCoreApplication>
0017 #include <QDataStream>
0018 #include <QHostInfo>
0019 #include <QLabel>
0020 #include <QNetworkInterface>
0021 #include <QTcpSocket>
0022 #include <qimage.h>
0023 
0024 #include <memory>
0025 
0026 using namespace RemoteControl;
0027 
0028 RemoteInterface::RemoteInterface()
0029     : m_categories(new CategoryModel(this))
0030     , m_categoryItems(new ThumbnailModel(this))
0031     , m_thumbnailModel(new ThumbnailModel(this))
0032     , m_discoveryModel(new DiscoveryModel(this))
0033 {
0034     m_connection = new Client;
0035     connect(m_connection, SIGNAL(gotCommand(RemoteCommand)), this, SLOT(handleCommand(RemoteCommand)));
0036     connect(m_connection, &Client::gotConnected, this, &RemoteInterface::connectionChanged);
0037     connect(m_connection, &Client::gotConnected, this, &RemoteInterface::requestInitialData);
0038     connect(m_connection, &Client::disconnected, this, &RemoteInterface::gotDisconnected);
0039     connect(m_connection, &Client::disconnected, this, &RemoteInterface::connectionChanged);
0040     qRegisterMetaType<RemoteControl::CategoryModel *>("RemoteControl::CategoryModel*");
0041     qRegisterMetaType<RemoteControl::ThumbnailModel *>("ThumbnailModel*");
0042     qRegisterMetaType<RemoteControl::DiscoveryModel *>("DiscoveryModel*");
0043 
0044     QTimer::singleShot(1000, this, SLOT(pushAwayFromStartupState()));
0045 }
0046 
0047 void RemoteInterface::setCurrentPage(Page page)
0048 {
0049     if (m_currentPage != page) {
0050         m_currentPage = page;
0051         Q_EMIT currentPageChanged();
0052     }
0053 }
0054 
0055 void RemoteInterface::setListCategoryValues(const QStringList &values)
0056 {
0057     if (m_listCategoryValues != values) {
0058         m_listCategoryValues = values;
0059         Q_EMIT listCategoryValuesChanged();
0060     }
0061 }
0062 
0063 void RemoteInterface::requestHomePageImages()
0064 {
0065     m_connection->sendCommand(StaticImageRequest(ScreenInfo::instance().overviewIconSize()));
0066 }
0067 
0068 void RemoteInterface::gotDisconnected()
0069 {
0070     setCurrentPage(Page::UnconnectedPage);
0071 }
0072 
0073 void RemoteInterface::setHomePageImages(const StaticImageResult &command)
0074 {
0075     m_homeImage = command.homeIcon;
0076     Q_EMIT homeImageChanged();
0077 
0078     m_kphotoalbumImage = command.kphotoalbumIcon;
0079     Q_EMIT kphotoalbumImageChange();
0080 
0081     m_discoveryImage = command.discoverIcon;
0082     Q_EMIT discoveryImageChanged();
0083 }
0084 
0085 RemoteInterface &RemoteInterface::instance()
0086 {
0087     static RemoteInterface interface;
0088     return interface;
0089 }
0090 
0091 bool RemoteInterface::isConnected() const
0092 {
0093     return m_connection->isConnected();
0094 }
0095 
0096 void RemoteInterface::sendCommand(const RemoteCommand &command)
0097 {
0098     m_connection->sendCommand(command);
0099 }
0100 
0101 QString RemoteInterface::currentCategory() const
0102 {
0103     return m_search.currentCategory();
0104 }
0105 
0106 QImage RemoteInterface::discoveryImage() const
0107 {
0108     return m_discoveryImage;
0109 }
0110 
0111 void RemoteInterface::setActiveThumbnailModel(RemoteInterface::ModelType type)
0112 {
0113     ThumbnailModel *newModel = (type == ModelType::Thumbnail ? m_thumbnailModel : m_discoveryModel);
0114     if (newModel != m_activeThumbnailModel) {
0115         m_activeThumbnailModel = newModel;
0116         activeThumbnailModelChanged();
0117     }
0118     m_activeThumbnailModel->setImages({});
0119 }
0120 
0121 void RemoteInterface::goHome()
0122 {
0123     requestInitialData();
0124 }
0125 
0126 void RemoteInterface::goBack()
0127 {
0128     if (m_history.canGoBack())
0129         m_history.goBackward();
0130     else
0131         qApp->quit();
0132 }
0133 
0134 void RemoteInterface::goForward()
0135 {
0136     if (m_history.canGoForward())
0137         m_history.goForward();
0138 }
0139 
0140 void RemoteInterface::selectCategory(const QString &category, int type)
0141 {
0142     m_search.addCategory(category);
0143     m_history.push(std::unique_ptr<Action>(new ShowCategoryValueAction(m_search, static_cast<CategoryViewType>(type))));
0144 }
0145 
0146 void RemoteInterface::selectCategoryValue(const QString &value)
0147 {
0148     m_search.addValue(value);
0149     m_history.push(std::unique_ptr<Action>(new ShowThumbnailsAction(m_search)));
0150 }
0151 
0152 void RemoteInterface::showThumbnails()
0153 {
0154     m_history.push(std::unique_ptr<Action>(new ShowThumbnailsAction(m_search)));
0155 }
0156 
0157 void RemoteInterface::showImage(int imageId)
0158 {
0159     m_history.push(std::unique_ptr<Action>(new ShowImagesAction(imageId, m_search)));
0160 }
0161 
0162 void RemoteInterface::requestDetails(int imageId)
0163 {
0164     m_connection->sendCommand(ImageDetailsRequest(imageId));
0165 }
0166 
0167 void RemoteInterface::activateSearch(const QString &search)
0168 {
0169     QStringList list = search.split(";;;");
0170     QString category = list[0];
0171     QString item = list[1];
0172     SearchInfo result;
0173     result.addCategory(category);
0174     result.addValue(item);
0175     m_history.push(std::unique_ptr<Action>(new ShowThumbnailsAction(result)));
0176 }
0177 
0178 void RemoteInterface::doDiscovery()
0179 {
0180     m_history.push(std::unique_ptr<Action>(new DiscoverAction(m_search, m_discoveryModel)));
0181 }
0182 
0183 void RemoteInterface::showOverviewPage()
0184 {
0185     m_history.push(std::unique_ptr<Action>(new ShowOverviewAction(m_search)));
0186 }
0187 
0188 void RemoteInterface::setToken(int imageId, const QString &token)
0189 {
0190     sendCommand(ToggleTokenRequest(imageId, token, ToggleTokenRequest::On));
0191 }
0192 
0193 void RemoteInterface::removeToken(int imageId, const QString &token)
0194 {
0195     sendCommand(ToggleTokenRequest(imageId, token, ToggleTokenRequest::Off));
0196 }
0197 
0198 void RemoteInterface::rerequestOverviewPageData()
0199 {
0200     requestHomePageImages();
0201     m_history.rerunTopItem();
0202 }
0203 
0204 void RemoteInterface::pushAwayFromStartupState()
0205 {
0206     // Avoid that the "not connected page" show for a few milliseconds while the connection is being set up.
0207     if (!isConnected() && m_currentPage == Types::Startup)
0208         setCurrentPage(Types::UnconnectedPage);
0209 }
0210 
0211 void RemoteInterface::setCurrentView(int imageId)
0212 {
0213     Q_EMIT jumpToImage(m_activeThumbnailModel->indexOf(imageId));
0214 }
0215 
0216 QString RemoteInterface::networkAddress() const
0217 {
0218     QStringList result;
0219     for (const QHostAddress &address : QNetworkInterface::allAddresses()) {
0220         if (address.isLoopback() || address.toIPv4Address() == 0)
0221             continue;
0222         result.append(address.toString());
0223     }
0224     return result.join(QStringLiteral(", "));
0225 }
0226 
0227 QStringList RemoteInterface::tokens() const
0228 {
0229     // FIXME: in KPA the tokens category is now retrieved using categoryForSpecial
0230     return ImageDetails::instance().itemsOfCategory(QStringLiteral("Tokens"));
0231 }
0232 
0233 void RemoteInterface::requestInitialData()
0234 {
0235     requestHomePageImages();
0236     m_history.push(std::unique_ptr<Action>(new ShowOverviewAction({})));
0237 }
0238 
0239 void RemoteInterface::handleCommand(const RemoteCommand &command)
0240 {
0241     if (command.commandType() == CommandType::ThumbnailResult)
0242         updateImage(static_cast<const ThumbnailResult &>(command));
0243     else if (command.commandType() == CommandType::CategoryListResult)
0244         updateCategoryList(static_cast<const CategoryListResult &>(command));
0245     else if (command.commandType() == CommandType::SearchResult)
0246         gotSearchResult(static_cast<const SearchResult &>(command));
0247     else if (command.commandType() == CommandType::TimeCommand)
0248         ; // Used for debugging, it will print time stamp when decoded
0249     else if (command.commandType() == CommandType::ImageDetailsResult) {
0250         ImageDetails::instance().setData(static_cast<const ImageDetailsResult &>(command));
0251         Q_EMIT tokensChanged();
0252     } else if (command.commandType() == CommandType::CategoryItemsResult)
0253         setListCategoryValues(static_cast<const CategoryItemsResult &>(command).items);
0254     else if (command.commandType() == CommandType::StaticImageResult)
0255         setHomePageImages(static_cast<const StaticImageResult &>(command));
0256     else
0257         qFatal("Unhandled command");
0258 }
0259 
0260 void RemoteInterface::updateImage(const ThumbnailResult &command)
0261 {
0262     ImageStore::instance().updateImage(command.imageId, command.image, command.label, command.type);
0263 }
0264 
0265 void RemoteInterface::updateCategoryList(const CategoryListResult &command)
0266 {
0267     ScreenInfo::instance().setCategoryCount(command.categories.count());
0268     m_categories->setCategories(command.categories);
0269 }
0270 
0271 void RemoteInterface::gotSearchResult(const SearchResult &result)
0272 {
0273     if (result.type == SearchType::Images) {
0274         m_activeThumbnailModel->setImages(result.result);
0275     } else if (result.type == SearchType::CategoryItems) {
0276         m_categoryItems->setImages(result.result);
0277     }
0278 }
0279 
0280 #include "moc_RemoteInterface.cpp"