Last active
March 24, 2017 01:35
-
-
Save Mononofu/5155614 to your computer and use it in GitHub Desktop.
Auto reloader for .qml files. If you change one of your .qml files, the View will automagically refresh to reflect the change. Note: Right now, the watch is not recursive, so only changes in top level files will cause a refresh. For a usage sample, check below.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
int main() { | |
QApplication a(argc, argv); | |
QMainWindow *window = new QMainWindow(); | |
QDeclarativeView *view = new QDeclarativeView(window); | |
FileWatcher watcher; | |
// assuming all .qml files are in ./ui | |
watcher.addWatch(view, "./ui/ui.qml"); | |
watcher.start("./ui"); | |
view->setResizeMode(QDeclarativeView::SizeRootObjectToView); | |
view->setSource(QUrl("./ui/ui.qml")); | |
window->setGeometry(100, 100, 800, 220); | |
window->setCentralWidget(view); | |
window->show(); | |
return a.exec(); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "FileWatcher.h" | |
#include <sys/inotify.h> | |
#include <iostream> | |
#include <unistd.h> | |
#include <QtConcurrentRun> | |
#include <QtDeclarative/QDeclarativeEngine> | |
#define EVENT_SIZE ( sizeof (struct inotify_event) ) | |
#define BUF_LEN ( 1024 * ( EVENT_SIZE + 16 ) ) | |
void FileWatcher::watch(string dir) { | |
qRegisterMetaType<QDeclarativeView*>("QDeclarativeView*"); | |
int fd = inotify_init(); | |
if(fd < 0) | |
throw WatchException("failed to init inotify"); | |
int wd = inotify_add_watch( fd, dir.c_str(), | |
IN_MODIFY | IN_CREATE | IN_DELETE ); | |
char buffer[BUF_LEN]; | |
while(running) { | |
fd_set descriptors; | |
FD_ZERO( &descriptors); | |
FD_SET( pipe.receiverFd(), &descriptors); // pipe to signal end of execution | |
FD_SET( fd, &descriptors); // fd from inotify | |
int nfds = max(fd, pipe.receiverFd()) + 1; | |
int retval = select ( nfds, &descriptors, NULL, NULL, NULL); | |
if(retval == -1) { | |
throw WatchException("select failed"); | |
} else if(retval) { | |
if(FD_ISSET ( pipe.receiverFd(), &descriptors)) { | |
// signal to stop watching | |
break; | |
} else if(FD_ISSET ( fd, &descriptors)) { | |
int length = read( fd, buffer, BUF_LEN ); | |
if(length < 0) { | |
throw WatchException("failed to read() events"); | |
} else { | |
// refresh all views | |
QMapIterator<QString, QDeclarativeView *> i(views); | |
while(i.hasNext()) { | |
i.next(); | |
QMetaObject::invokeMethod(this, "refreshView", Qt::QueuedConnection, | |
Q_ARG(QDeclarativeView*, i.value()), | |
Q_ARG(QUrl, QUrl(i.key()))); | |
} | |
} | |
} else { | |
throw WatchException("unexpected fd"); | |
} | |
} else { // timeout | |
throw WatchException("select should never timeout"); | |
} | |
} | |
// cleanup | |
inotify_rm_watch(fd, wd); | |
close(fd); | |
} | |
void FileWatcher::start(string dir) { | |
running = true; | |
future = QtConcurrent::run(this, &FileWatcher::watch, dir); | |
} | |
void FileWatcher::stop() { | |
running = false; | |
pipe.notify(); | |
future.waitForFinished(); | |
} | |
void FileWatcher::refreshView(QDeclarativeView* view, const QUrl &url) { | |
// important: .qml is only reloaded if the cache is cleared first | |
view->engine()->clearComponentCache(); | |
view->setSource(url); | |
view->show(); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <string> | |
#include <QtDeclarative/QDeclarativeView> | |
#include <QObject> | |
#include "NotifyPipe.h" | |
#include <QFuture> | |
using namespace std; | |
class FileWatcher : public QObject { | |
Q_OBJECT | |
public: | |
~FileWatcher() { | |
stop(); | |
} | |
void addWatch(QDeclarativeView *view, QString layout) { | |
views[layout] = view; | |
} | |
void watch(string dir); | |
void start(string dir); | |
void stop(); | |
public slots: | |
void refreshView(QDeclarativeView* view, const QUrl &url); | |
private: | |
QMap<QString, QDeclarativeView*> views; | |
NotifyPipe pipe; | |
QFuture<void> future; | |
bool running; | |
}; | |
class WatchException : exception { | |
public: | |
WatchException(string reason) : reason(reason) { } | |
const char* what() const throw() { | |
return reason.c_str(); | |
} | |
~WatchException() throw() { } | |
private: | |
string reason; | |
}; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// from http://stackoverflow.com/questions/2486335/wake-up-thread-blocked-on-accept-cal | |
#include "NotifyPipe.h" | |
#include <unistd.h> | |
#include <assert.h> | |
#include <fcntl.h> | |
NotifyPipe::NotifyPipe() | |
{ | |
int pipefd[2]; | |
int ret = pipe(pipefd); | |
assert(ret == 0); | |
m_receiveFd = pipefd[0]; | |
m_sendFd = pipefd[1]; | |
} | |
NotifyPipe::~NotifyPipe() | |
{ | |
close(m_sendFd); | |
close(m_receiveFd); | |
} | |
int NotifyPipe::receiverFd() | |
{ | |
return m_receiveFd; | |
} | |
void NotifyPipe::notify() | |
{ | |
write(m_sendFd,"1",1); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// from http://stackoverflow.com/questions/2486335/wake-up-thread-blocked-on-accept-call | |
#ifndef NOTIFYPIPE_H_INCLUDED | |
#define NOTIFYPIPE_H_INCLUDED | |
class NotifyPipe | |
{ | |
int m_receiveFd; | |
int m_sendFd; | |
public: | |
NotifyPipe(); | |
virtual ~NotifyPipe(); | |
int receiverFd(); | |
void notify(); | |
}; | |
#endif // NOTIFYPIPE_H_INCLUDED |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment