Using QTWebKit to display a website stored in memory - qt

Currently I have my HTML, JS, CSS, graphics, etc stored locally on hard disk and access them using QWebFrame::SetUrl( QUrl::fromLocalFile( "appFolder\html\index.html" )). At some point I am going to need to encrypt the locally stored files so I'm looking for a way to either decrypt them as they're requested or to decrypt them all into memory and access them that way.
I know I can use QWebFrame::setContent( htmlData ) to load the HTML from memory so I can load the encrypted HTML file, decrypt it in memory and then display it that way, but how would I go about the other data (JS, CSS, graphics, etc) which is currently stored in subfolders?
Alternatively, is there a way I can intercept requests for access to all the HTML, JS, CSS, etc files and decrypt them as they're loaded?
By using my own NetworkAccessManager I can intercept calls to createRequest so I can see when each file is being loaded, but I can't see how to use this to decrypt the data on the fly. I can also connect a slot function to the finished(QNetworkReply*) signal, but at that point the data has already been read - the QIODevice's current position is pointing to the end of the file.
I'd be very grateful for any advice or pointers in the right direction.

I think in your case the best solution is to inherit QNetworkReply class and use this new class in reimplemented QNetworkAccessManager::createRequest() function.
In general, you should reimplement next virtual functions of QNetworkReply:
bytesAvailable(), readData(char *data, qint64 maxSize), close(), abort().
For example, readData should be the folowing:
qint64 NetworkReplyEx::readData(char *data, qint64 maxSize)
{
return m_buffer.read(data, maxSize);
}
where m_buffer is already decrypted data.
Also you need to add all necessary logic in this class to get encrypted data, decrypt this data...
In the end you should manually emit finished() signal inside new class, so QWebView or other related class will get decrypted html.

Related

How should a Qt-based preferences panel broadcast that a pref has changed?

I am trying to design a preferences panel for my multidocument app. When a given pref changes – font size, say – all of the document windows should immediately update to reflect the new pref value. I don't want to construct the preferences panel up front, for all the document windows to connect to, because it contains a QFontComboBox that takes more than a second to set itself up (ouch); that's not a price I want to pay at startup. So then, my question is: what is an elegant design for the prefs panel to let all the document windows know about the change? In Cocoa, which I'm more used to, I'd use NSNotification to broadcast a notification from the prefs panel that all the document windows could observe; that provides the loose coupling required (since objects can add themselves as observers before the broadcaster exists).
Two approaches occur to me so far:
Loop through topLevelWidgets, do a dynamic cast to my document window class, and for all the document windows I thereby find, just call a hard-coded method on them directly.
Make a second class, PreferencesNotifier, that is separate from the UI object that takes so long to load, and construct a singleton object of this class at startup that all of the document windows can connect themselves to. When the preferences panel eventually gets created, it can send signals to slots in PreferencesNotifier, which will then call its own signals to notify the connected document windows.
Neither seems quite as elegant as NSNotification, and I'm wondering if I'm missing something. Thanks for any tips.
First thing, do not try to copy patterns, like Cocoa's NSNotification/NotificationCenter, to other frameworks (or languages, or...). There are various ways to send messages and generally each framework has picked one. Trying to use the one method that was picked by the framework you are using will lead to the most elegant solutions.
If you really want to, you could implement your own set of classes that will do exactly what NSNotification does. It will feel more elegant to you, but only because you are used to using Cocoa. It will feel odd to every other Qt developer. Also, this solution will require you to write a lot of code as you will not be able to leverage all the features of Qt.
The first solution you are suggesting is a bit ugly and looks more like a hack than anything.
What I do, when I have to handle preferences in a program, is something similar to your solution 2. I create a class that is responsible for handling all settings: read/write setting file, change setting, set default values, etc. Generally this class is a singleton. This class has very limited access to other parts of the program, and generally no access at all to the UI. Each components that needs to access the preferences will use this class. If you do it properly (e.g. use Q_PROPERTY), this class can even be accessed by QML, if you ever need to use Qt Quick.
class Settings: public QObject {
Q_OBJECT
Q_PROERTY(bool showX READ showX WRITE setShowX NOTIFY showXChanged)
public:
bool showX() const { return m_showX; }
void setShowX(bool show) {
if (show == m_showX)
return;
m_showX = show;
emit showXChanged(m_showX);
}
signals:
void showXChanged(bool);
public slots:
void save() const; // Save to disk
void load(); // Load from disk
private:
QSettings m_settings; // Handle load/save from/to disk
bool m_showX;
};
class Window {
Window() {
...
m_widgetX->setVisible(settings->showX());
connect(settings, &Settings::showXChanged,
this, [this](bool show) { m_widgetX->setVisible(show); }
);
...
}
};
class PrefWindow {
PrefWindow () {
...
ui->checkBoxShowX->setChecked(settings->showX());
...
}
private slots:
void on_saveButton_clicked() {
settings->setShowX(ui->checkBoxShowX->checked()):
settings->save();
}
};

Qt: How to lock/prevent a file from being read while it is written?

I am using Qt5 on Windows 7.
In my current project I open a binary file in order to populate it with data coming from a TCP socket.
Normally, after the file is populated, I close it and another application will read this binary file for further processing.
Well, the problem is: The writing operation takes about 4-5 seconds (or even more) so I need to find a way to prevent the other application from reading from the binary file until the file is completely populated...
Here below is the code (yet I suppose it won't help much):
int error = 0;
unsigned long dataLength;
char dataBuffer[1500];
QFile localFile("datafile.bin");
//
localFile.open(QIODevice::WriteOnly);
while(error == 0)
{
error = readSocket(dataBuffer, &dataLength);
if(error == 0)
{
localFile.write(dataBuffer, dataLength);
}
else
{
error = -1;
}
}
localFile.close();
I am thinking about using a temporary file and rename it after the write operation is complete.
But maybe there is another better/smarter idea? Some kind of "lock file for reading" maybe...?
If you have the source to both applications, then the one writing the file can signal the other application by one of many IPC mechanisms (e.g. local sockets) that it has finished writing.
Alternatively, write to a file with a different filename and then rename / copy the file to the location expected by the reading application, when the write has finished.
However, it is advisable to use QSaveFile, rather than QFile when writing out files. As the documentation states: -
While writing, the contents will be written to a temporary file, and if no error happened, commit() will move it to the final file
So this will likely solve the problem for you.
I know maybe it's a little bit too late, but I recently found an interesting solution, i.e. a component named "Locked File":
The QtLockedFile class extends QFile with advisory locking functions.
This class extends the QFile class with inter-process file locking
capabilities. If an application requires that several processes should
access the same file, QtLockedFile can be used to easily ensure that
only one process at a time is writing to the file, and that no process
is writing to it while others are reading it.
class QtLockedFile : public QFile
{
public:
enum LockMode { NoLock = 0, ReadLock, WriteLock };
QtLockedFile();
QtLockedFile(const QString &name);
~QtLockedFile();
bool open(OpenMode mode);
bool lock(LockMode mode, bool block = true);
bool unlock();
bool isLocked() const;
LockMode lockMode() const;
private:
LockMode m_lock_mode;
};
This link will lead you to the right place, where the QLockedFile class implementation is:
https://github.com/kbinani/qt-solutions/tree/master/qtlockedfile
** So, I decided to share this info, maybe other Qt-users are interested! **

Qt Signals and Slots with Boost::smart_ptr

So what I am trying to do is use Qt signals and slots to pass around an image through a smart_ptr so that it will delete itself when everything that needs to use the data is done accessing it.
Here is the code I have:
Class A, inherits QObject:
signals:
void newImageSent(boost::shared_ptr<namespace::ImageData> &image);
Class B, inherits QObject:
public slots:
void newImageRecieved(boost::shared_ptr<namespace::ImageData> &image)
{
// Manipulate Image
}
Connection Code:
QObject::connect(classAPtr.get(),
SIGNAL(newImageSent(boost::shared_ptr<namespace::ImageData>)),
classBPtr.get(),
SLOT(newImageRecieved(boost::shared_ptr<namespace::ImageData>)),
Qt::QueuedConnection);
When I try to do the connection is always returns false though, so is there something I am missing?
In a queued connection the signal is queued in the event loop and its parameters are copied.
Therefore the slot is not directly executed.
To make copying possible you have to register the type via qRegisterMetaType, see also here.
Since you are using shared pointers easiest solution would be to transmit them by value, then you would not have to bother with the references as Frank Osterfeld pointed out.
The way you create the connection is string based and as result is easy to get wrong, especially when namespaces are involved.
Using typedef would ease the pain a little and make it easier to spot errors.
For example you could do
typedef boost::shared_ptr<namespace::ImageData> ImageDataPtr;
and use ImageDataPtr from then on.
Especially on registering the type as meta type which you have to do since you are using a queued connection.
If you are using Qt5 then you can rely on the new connection syntax which ensures correctness during compilation as it does not rely on string comparisons:
QObject::connect(classAPtr.get(), &A::newImageSent,
classBPtr.get(), &B::newImageRecieved,
Qt::QueuedConnection);

Is it possible to control download speed using QNetworkAccessManager

Can we restrict QNetworkAccessManager from consuming whole bandwidth, by restricting the download speed, as we do see such options available with almost every download manager?
This is not possible out of the box. But have a look at the Qt Torrent Example, especially the class RateController (ratecontroller.h | ratecontroller.cpp). This class does almost what you want by controlling not only one but a set of connections.
However, this rate controller is operating on QTcpSockets (to be exact on PeerWireClients), so you need to change the type of the "peers" to be QIODevice, which I hope isn't that hard, since PeerWireClient inherits from QTcpSocket, which itself inherits from QIODevice:
// old
void addSocket(PeerWireClient *socket);
// new
void addDevice(QIODevice *device);
(Note that the RateController from the Torrent example controlls both upload and download, but you only need to control the download rate. So you can remove unnecessary code.)
Then you need to make requests made by your QNetworkAccessManager use this rate controller. This can be done by reimplementing QNetworkAccessManager and overwriting (extending) the method QNetworkAccessManager::createRequest, which will be called whenever a new request gets created. This method returns the QNetworkReply* (which inherits from QIODevice*) where the download will be read from, so telling the rate controller to control this device will limit the download rate:
QNetworkReply *MyNetworkAccessManager::createRequest(
QNetworkAccessManager::Operation op,
const QNetworkRequest &req,
QIODevice *outgoingData)
{
// original call to QNetworkAccessManager in order to get the reply
QNetworkReply *reply = QNetworkAccessManager::createRequest(op, req, outgoingData);
// add this reply (which is a QIODevice*) to the rate controller
rateController.addDevice(reply);
return reply;
}
You will not have to subclass QNetworkAccessManager if you already know the pieces of code where you actually perform requests. The methods get() and post() return a QNetworkReply* which you can also just add to the rate controller. (But this way, you manually do this outside of the manager, which is doesn't fulfill the concept of information/implementation hiding, in this case the fact that downloads are rate-controlled.)

FileReference.save() duplicates ByteArray

I've encountered a memory problem using FileReference.save(). My Flash application generates of a lot of data in real-time and needs to save this data to a local file. As I understand, Flash 10 (as opposed to AIR) does not support streaming to a file. But, what's even worse is that FileReference.save() duplicates all the data before saving it. I was looking for a workaround to this doubled memory usage and thought about the following approach:
What if I pass a custom subclass of ByteArray as an argument to FileReference.save(), where this ByteArray subclass would override all read*() methods. The overridden read*() methods would wait for a piece of data to be generated by my application, return this piece of data and immediately remove it from the memory. I know how much data will be generated, so I could also override length/bytesAvailable methods.
Would it be possible? Could you give me some hint how to do it? I've created a subclass of ByteArray, registered an alias for it, passed an instance of this subclass to FileReference.save(), but somehow FileReference.save() seems to treat it just as it was a ByteArray instance and doesn't call any of my overridden methods...
Thanks a lot for any help!
It's not something I've tried before, but can you try sending the data out to a php application that would handle saving the ByteArray to the server, much like saving an image to the server, so then you'd use URLLoader.data instead, using something like this:
http://www.zedia.net/2008/sending-bytearray-and-variables-to-server-side-script-at-the-same-time/
It's an interesting idea. Perhaps to start you should just add traces in your extended ByteArray to see how the FileReference#save() functions internally.
If it has some kind of
while( originalByteArray.bytesAvailable )
writeToSaveBuffer( originalByteArray.readByte() );
functionality the overrides could just truncate the original buffer on every read like you say, something like:
override function readByte() : uint {
var b : uint = super.readByte();
// Truncate the bytes (assuming bytesAvailable = length - removedBytes)
length = length - bytesAvailable;
return b;
}
On the other hand, if this now works I guess the original byte array would not be available afterwards in the application anymore.
(i havn't tested this myself, truncating might require more work than the example)

Resources