Add NetImageManager and NetImageTracker classes from BlackBerry

This commit is contained in:
Morgan McMillian 2017-11-16 08:37:13 -08:00
parent e525492bc6
commit f954e15fb6
5 changed files with 572 additions and 0 deletions

View file

@ -18,6 +18,8 @@
#include "Pnut.h"
#include "WebImageView.h"
#include "ActiveFrameQML.h"
#include "netimagemanager.h"
#include "netimagetracker.h"
#include <bb/cascades/Application>
#include <bb/cascades/QmlDocument>
@ -56,6 +58,8 @@ ApplicationUI::ApplicationUI() :
qmlRegisterType<Pnut>("com.monkeystew.pnut", 1, 0, "Pnut");
qmlRegisterType<QTimer> ("com.monkeystew.qtimer", 1, 0, "QTimer");
qmlRegisterType<WebImageView>("org.labsquare", 1, 0, "WebImageView");
qmlRegisterType<NetImageTracker>("com.netimage", 1, 0, "NetImageTracker");
qmlRegisterType<NetImageManager>("com.netimage", 1, 0, "NetImageManager");
m_appSettings = new QSettings("Morgan McMillian", "Goober");

199
src/netimagemanager.cpp Normal file
View file

@ -0,0 +1,199 @@
/* Copyright (c) 2012 Research In Motion Limited.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "netimagemanager.h"
#include <QtNetwork/QNetworkAccessManager>
#include <QtNetwork/QNetworkRequest>
#include <QDir>
using namespace bb::cascades;
const char* const NetImageManager::mDefaultId = "netimagemanager";
NetImageManager::NetImageManager(QObject *parent) :
QObject(parent) {
mCacheId = mDefaultId;
mCacheSize = 125;
QString diskPath = QDir::homePath() + "/" + mCacheId;
if (!QDir(diskPath).exists()) {
QDir().mkdir(diskPath);
}
// Connect to the sslErrors signal to the onSslErrors() function. This will help us see what errors
// we get when connecting to the address given by mWeatherAdress.
connect(&mAccessManager,
SIGNAL(sslErrors ( QNetworkReply * , const QList<QSslError> & )),
this,
SLOT(onSslErrors ( QNetworkReply * , const QList<QSslError> & )));
// Connect to the reply finished signal to httpFinsihed() Slot function.
connect(&mAccessManager, SIGNAL(finished(QNetworkReply *)), this,
SLOT(httpFinished(QNetworkReply *)));
}
NetImageManager::~NetImageManager() {
}
void NetImageManager::lookUpImage(const QString imageName) {
QUrl url = QUrl(imageName);
// Check if image is stored on disc
// The qHash is a bucket type hash so the doubling is to remove possible collisions.
QString diskPath = QDir::homePath() + "/" + mCacheId + "/"
+ QString::number(qHash(url.host())) + "_"
+ QString::number(qHash(url.path())) + ".JPG";
QFile imageFile(diskPath);
// If the file exists, send a signal the image is ready
if (imageFile.exists()) {
emit imageReady(diskPath, url.toString());
} else {
// otherwise let's download the file, but first we show a loading image
emit imageReady(imageName, "loading");
QNetworkRequest request(url);
if (mQueue.isEmpty()) {
mAccessManager.get(request);
}
mQueue.append(request);
}
}
void NetImageManager::setCacheId(QString cacheId) {
if (mCacheId != cacheId) {
mCacheId = cacheId;
QString diskPath = QDir::homePath() + "/" + mCacheId;
if (!QDir(diskPath).exists()) {
QDir().mkdir(diskPath);
}
emit cacheIdChanged(mCacheId);
}
houseKeep();
}
QString NetImageManager::cacheId() {
return mCacheId;
}
void NetImageManager::setCacheSize(int cacheSize) {
if (mCacheSize != cacheSize) {
mCacheSize = cacheSize;
emit cacheSizeChanged(mCacheSize);
}
houseKeep();
}
int NetImageManager::cacheSize() {
return mCacheSize;
}
void NetImageManager::houseKeep() {
QString diskPath = QDir::homePath() + "/" + mCacheId + "/";
QDir directory(diskPath);
if (directory.count() > (uint) mCacheSize) {
//Find the oldest file and delete it.
QFileInfoList list = directory.entryInfoList(QDir::Files, QDir::Time);
QFile::remove(list.at(list.size() - 1).absoluteFilePath());
//maybe there are more then the permitted amount of files here, let's call housekeeping again
houseKeep();
}
}
void NetImageManager::httpFinished(QNetworkReply * reply) {
if (reply->error() == QNetworkReply::NoError) {
QImage qImage;
qImage.loadFromData(reply->readAll());
if (qImage.isNull()) {
return;
}
// When the download is finished we make a hash-tag for the image out of it's url so we can find it again,
// then we save it as a .JPG. The qHash is a bucket type hash so the doubling is to remove possible collisions.
QString diskPath = QDir::homePath() + "/" + mCacheId + "/"
+ QString::number(qHash(reply->url().host())) + "_"
+ QString::number(qHash(reply->url().path())) + ".JPG";
if (qImage.save(diskPath)) {
// houseKeep() is called to see that we don't save more then we are allowed in the cache
houseKeep();
emit imageReady(diskPath, reply->url().toString());
}
//we remove the first item in the download queue
if (!mQueue.isEmpty()) {
mQueue.removeFirst();
if (!mQueue.isEmpty()) {
QNetworkRequest request = mQueue.first();
mAccessManager.get(request);
}
}
} else {
//Handle error
qDebug() << "Could Not access image" << reply->url().toString();
}
reply->deleteLater();
}
void NetImageManager::onDialogFinished(bb::system::SystemUiResult::Type type)
{
exit(0);
}
void NetImageManager::onSslErrors(QNetworkReply * reply,
const QList<QSslError> & errors) {
foreach (QSslError e, errors)
qDebug() << "SSL error: " << e;
SystemDialog *dialog = new SystemDialog("OK");
dialog->setTitle(tr("SSL errors received"));
dialog->setBody(tr("We have received information about a security breach in the protocol. Press \"OK\" to terminate the application"));
// Connect your functions to handle the predefined signals for the buttons.
// The slot will check the SystemUiResult to see which button was clicked.
bool success = connect(dialog,
SIGNAL(finished(bb::system::SystemUiResult::Type)),
this,
SLOT(onDialogFinished(bb::system::SystemUiResult::Type)));
if (success) {
// Signal was successfully connected.
// Now show the dialog box in your UI
dialog->show();
} else {
// Failed to connect to signal.
dialog->deleteLater();
}
}

146
src/netimagemanager.h Normal file
View file

@ -0,0 +1,146 @@
/* Copyright (c) 2012 Research In Motion Limited.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef _NETIMAGECACHE_H_
#define _NETIMAGECACHE_H_
#include <bb/cascades/Image>
#include <bb/system/SystemDialog>
#include <QtNetwork/QNetworkRequest>
#include <QObject>
#include <QtGui/QImage>
using namespace bb::cascades;
using namespace bb::system;
/**
* NetImageManager is a cache service for our Internet downloaded images.
* You can set the size of the cache and an id for the cache.
* If you want to reuse the cache between different pages it's possible.
*/
class NetImageManager: public QObject
{
Q_OBJECT
/**
* This property sets the name of the image cache, if none is set we will use it to the
* default "netimagemanager".
*/
Q_PROPERTY(QString cacheId READ cacheId WRITE setCacheId NOTIFY cacheIdChanged)
/**
* Sets the size of the cache in number of files in the directory, if not set, it defaults
* to 125 files.
*/
Q_PROPERTY(int cacheSize READ cacheSize WRITE setCacheSize NOTIFY cacheSizeChanged)
public:
/**
* This is our constructor which initializes the member variables.
* @param parent The parent QObject, if not specified, 0 is used.
*/
NetImageManager(QObject *parent = 0);
~NetImageManager();
/**
* This function sets the cacheId property.
*
* @param cacheId The cacheId used for storing downloaded in a folder.
*/
void setCacheId(QString cacheId);
/**
* This function return the chacheId, that is the location of the folder where images
* are stored for the cache object.
*
* @return The cacheId
*/
QString cacheId();
/**
* This function sets the cacheSize property.
*
* @param cacheId The cacheSize used for cleaning the cache folder.
*/
void setCacheSize(int cacheSize);
/**
* This function return the chacheSize.
*
* @return The cacheId
*/
int cacheSize();
/**
* Check if the image exists in cache
*
* @return the full path to the image if it exists otherwise 0
*/
QString getNetImage(QString imageName);
void lookUpImage(const QString imageName);
/**
* Check if the cache is full and if so deletes the oldest
*/
void houseKeep();
public slots:
/**
* Slot called for by the dialog that you get with SSL-errors
*/
void onDialogFinished(bb::system::SystemUiResult::Type type);
signals:
/**
* This signal is emitted when a new cacheId has been set
*/
void cacheIdChanged(QString cacheId);
void cacheSizeChanged(int cacheSize);
void imageReady(const QString filePath, const QString imageName);
private slots:
/**
* This Slot function is called when the network request is complete.
*/
void httpFinished( QNetworkReply * reply );
/**
* This Slot function is connected to the mAccessManager sslErrors signal. This function
* allows us to see what errors we get when connecting to the address given by mWeatherAdress.
*
* @param reply The network reply
* @param errors SSL Error List
*/
void onSslErrors(QNetworkReply * reply, const QList<QSslError> & errors);
private:
// Property variables
QString mCacheId;
int mCacheSize;
// String constant for the default id of the image cache
static const char* const mDefaultId;
// The network parameters; used for accessing a file from the Internet
QNetworkAccessManager mAccessManager;
QList<QNetworkRequest> mQueue;
};
#endif // _NETIMAGECACHE_H_

108
src/netimagetracker.cpp Normal file
View file

@ -0,0 +1,108 @@
/* Copyright (c) 2012 Research In Motion Limited.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "netimagetracker.h"
#include <bb/cascades/ImageTracker>
using namespace bb;
using namespace bb::cascades;
NetImageTracker::NetImageTracker(QObject *parent) :
ImageTracker(parent), mManager(0)
{
mIsCreated = false;
connect(this, SIGNAL(creationCompleted()), this, SLOT(onCreationCompleted()));
}
void NetImageTracker::onCreationCompleted()
{
mIsCreated = true;
if (!mSource.isEmpty() && mManager) {
// Once creation of the tracker has completed, the lookup of the image is ready to
// be executed. If the tracker is used within a list item this lookup is not needed
// since the update of list item data will enforce a refresh of the imageSource that
// will perform the lookup. But for the tracker to work in ImageViews that are not
// part of a list item we need this here.
mManager->lookUpImage(mSource);
}
}
void NetImageTracker::onImageReady(const QString filePath, const QString imageName)
{
// The NetImageManager will emit a signal to all NetImageTrackers, make sure the
// image that is ready belongs to this tracker.
if (imageName.compare(mSource) == 0) {
if (imageName.compare("loading") == 0) {
// If we don't have an image to display, let's display a loading image
QUrl url = QUrl("asset:///images/ca_rss_unread.png");
setImageSource(url);
} else {
// Set the path to the image that is now downloaded and cached in the data folder on the device.
QUrl url = QUrl(filePath);
setImageSource(url);
}
}
}
void NetImageTracker::setSource(const QString source)
{
if (!source.isEmpty() && mSource.compare(source) != 0) {
mSource = source;
if (mManager) {
// If a manger has been set make a request to look up the image. Otherwise
// the request is delayed to onCreationCompleted or at the next time a call
// to set the source is made.
mManager->lookUpImage(mSource);
} else {
qWarning()
<< "This NetImageTracker does not have any NetImageManager, set up one as an attached object and add it to the property.";
}
emit sourceChanged(mSource);
}
}
QString NetImageTracker::source()
{
return mSource;
}
void NetImageTracker::setManager(NetImageManager *manager)
{
if (mManager != manager) {
// Change the manager that is used for the tracker.
if (mManager) {
disconnect(mManager, SIGNAL(imageReady(const QString , const QString )), this,
SLOT(onImageReady( const QString , const QString )));
delete (mManager);
}
mManager = manager;
emit managerChanged(mManager);
connect(mManager, SIGNAL(imageReady(const QString , const QString )), this,
SLOT(onImageReady( const QString , const QString )));
}
}
NetImageManager *NetImageTracker::manager()
{
return mManager;
}

115
src/netimagetracker.h Normal file
View file

@ -0,0 +1,115 @@
/* Copyright (c) 2012 Research In Motion Limited.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef _NETIMAGETRACKER_H_
#define _NETIMAGETRACKER_H_
#include "netimagemanager.h"
#include <bb/cascades/ImageTracker>
using namespace bb::cascades;
/**
* The NetImageTracker is used so that Cascades can be informed when an image is downloaded
* via a NetImageManager.
*/
class NetImageTracker: public bb::cascades::ImageTracker
{
Q_OBJECT
/**
* The NetImageManager property points to a manager that is used for downloading and caching
* images.
*/
Q_PROPERTY(NetImageManager *manager READ manager WRITE setManager NOTIFY managerChanged)
/**
* Sets the NetImageTracker source, the remote networked url that points to the image.
* You need to set one as an attached object in your QML files.
*/
Q_PROPERTY(QString source READ source WRITE setSource NOTIFY sourceChanged)
public:
/**
* Constructor; Sets up the net image view
* @param parent The parent Container.
*/
NetImageTracker(QObject *parent = 0);
public slots:
/**
* Setter function for setting the trackers net image manager
*
* @param manager in manager that we're going to use.
*/
void setManager(NetImageManager *manager);
/**
* Getter for Trackers Manager object
* @return
*/
NetImageManager *manager();
/**
* Setter for the source object.
*
* @param source in string with path to the source.
*/
void setSource(const QString source);
/**
* Getter for source
* @return a string of the source
*/
QString source();
signals:
/**
* Signal that emits when the source have changed, wont happen automatically
*
* @param source the new source
*/
void sourceChanged(QString source);
/**
* signal that is emitted if the manager is changed, will not happen automatically.
*
* @param imageCache the new NetImageManager we want to have .
*/
void managerChanged(NetImageManager *imageCache);
private slots:
/**
* Emitted when we are done with the setup of this class
*/
void onCreationCompleted();
/**
* Emitted when we have a image that is ready for consumption
*
* @param filePath the path to the image that we can do what we want with
* @param imageName the actual name of the file, useful!
*/
void onImageReady(const QString filePath, const QString imageName);
private:
QString mSource;
NetImageManager *mManager;
bool mIsCreated;
};
#endif // ifndef _NETIMAGETRACKER_H_