Can QML FileDialog Be Used to Select Upload File from Web Browser? - qt

I am trying to create a pop-up dialog in my browser-based Qt/QML application in order to select a file on my workstation to upload to the unit running the web server. I am unsure what "context" the FileDialog is operating in when invoked via button click in the browser. Is it local to the unit that's running the server and hosting the page or is it local to the workstation running the browser?
I've got the following code in QML, taken from an example in the FileDialog documentation:
FileDialog {
id: fileDialog
title: "Please choose a file"
folder: shortcuts.home
onAccepted: {
console.log("You chose: " + fileDialog.fileUrls)
//Do the data_client stuff and get the file moving
client.getUploadFile(fileUrls)
}
onRejected: {
console.log("Canceled")
}
}
This dialog is displayed with the following:
Button {
id: uploadButton
x: 224
y: 14
text: qsTr("Upload")
onClicked: {
fileDialog.open()
}
}
The problem I'm seeing currently is that, when opened, the dialog gives me some filesystem "space" that I have no idea about. Regardless of whether I'm running on a Windows or Linux machine, I get the following dialog, in the "/home/web_user" directory:
To my layman's brain, this would seem to indicate that the dialog is local to the unit hosting the server(linux-based, where my workstation is USUALLY Windows-based), but I can't find that directory structure anywhere on that unit. Is it some special context that exists in the web server (lighttpd)? Is this some userspace in the context of the browser? Is there something I need to do to "point" the FileDialog at the local filesystem on the workstation I want to upload the file from?
I'm not well-versed in web development lingo/tools, hence my attempt to use Qt/WebAssembly to create a web-based GUI, so please forgive my using terms that may not be technically correct...

I'm incredibly angry with myself for not having read the documentation closely enough.
I had to change from the QGuiApplication to a QApplication in order to use widgets, add "widgets" to my project "QT +=" line, change the QML to call the backend instead of trying to invoke the FileDialog directly there in the QML, and call the appropriate function, as specified in the QFileDialog documentation...
The QML is now:
Button {
id: uploadButton
x: 224
y: 14
text: qsTr("Upload")
onClicked: {
client.getUploadFile();
}
}
In the backend C++:
auto fileContentReady = [](const QString &fileName, const QByteArray &fileContent) {
if (fileName.isEmpty()) {
// No file was selected
} else {
qDebug() << "File name: " + fileName;
}
};
void Data_Client::getUploadFile()
{
QFileDialog::getOpenFileContent("Images (*.png *.xpm *.jpg)", fileContentReady);
//...
}
It's all pretty clearly defined in the documentation for getOpenFileContent(), but I had to understand so much about emscripten, browser sand-boxes, and web stuff, just to realize what I wasn't seeing... Hope this helps people having a similar problem...

Related

QT creator python stream video using opencv

I've been at it from quite some days, searched the docs online but have not been able to find any example :/.
I want to stream video on a page using opencv.Im using QtCreator and on a QtQuick application, that is with qml files.
MediaPlayer {
id: mediaplayer
source: "videoplayback.mp4"
}
VideoOutput {
anchors.fill: parent
source: mediaplayer
}
MouseArea {
id: playArea
anchors.fill: parent
onPressed: mediaplayer.play();
}
Which shows this:
Now i can play the video.
But i rather want the source to be coming from my backend main.py file so i can work upon it.
The main.py file as of now is:
'''
class MainWindow(QObject):
def __init__(self):
QObject.__init__(self)
#QTimer
self.timer = QTimer()
self.timer.timeout.connect(lambda: self.setTime())
self.timer.start(1000)
def setTime(self):
now = datetime.datetime.now()
formatDate = now.strftime("Time: %H:%M:%S %p of %Y/%m/%d")
#print(formatDate)
self.printTime.emit(formatDate)
if __name__ == "__main__":
app = QGuiApplication(sys.argv)
engine = QQmlApplicationEngine()
#Get Context
main = MainWindow()
engine.rootContext().setContextProperty("backend", main)
engine.load(os.fspath(Path(__file__).resolve().parent / "qml/main.qml"))
if not engine.rootObjects():
sys.exit(-1)
sys.exit(app.exec_())
In the above code, basically this line:
engine.rootContext().setContextProperty("backend", main)
Is the one for connection with the qml files using
Connections{
target: backend
function onPrintTime(time){
labelDate.text = time
}
}
So in context i want to ouput video on my page using source as being from opencv. Basically it's a surviellance system app, so i want to show multiple feeds, but if someone could help me with just one from webcam, as in how to stream it to the mediaplayer i'll be really really grateful.
Note: Im working with qml files inside the QT Creator application. There are a number of ways to do this with UI files but that doens't help me :/

NSFileProtectionComplete doesn't encrypt the core data file

I am using Xcode 7.3 for iOS 9.3 to try and encrypt a Core Data file. I am trying to use NSPersistentStoreFileProtectionKey and set it to NSFileProtectionComplete to enable the encryption. It is not working for some reason and I can always see the .sqlite file generated by the app and browse through the content in sqlitebrowser or iexplorer. Here is my code :
lazy var persistentStoreCoordinator: NSPersistentStoreCoordinator = {
// The persistent store coordinator for the application. This implementation creates and returns a coordinator, having added the store for the application to it. This property is optional since there are legitimate error conditions that could cause the creation of the store to fail.
// Create the coordinator and store
let coordinator = NSPersistentStoreCoordinator(managedObjectModel: self.managedObjectModel)
let url = self.applicationDocumentsDirectory.URLByAppendingPathComponent("SingleViewCoreData.sqlite")
var failureReason = "There was an error creating or loading the application's saved data."
let dict: [NSObject : AnyObject] = [
NSPersistentStoreFileProtectionKey : NSFileProtectionComplete
]
do {
try coordinator.addPersistentStoreWithType(NSSQLiteStoreType, configuration: nil, URL: url, options: dict)
} catch {
// Report any error we got.
var dict = [String: AnyObject]()
dict[NSLocalizedDescriptionKey] = "Failed to initialize the application's saved data"
dict[NSLocalizedFailureReasonErrorKey] = failureReason
dict[NSUnderlyingErrorKey] = error as NSError
let wrappedError = NSError(domain: "YOUR_ERROR_DOMAIN", code: 9999, userInfo: dict)
// Replace this with code to handle the error appropriately.
// abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
NSLog("Unresolved error \(wrappedError), \(wrappedError.userInfo)")
abort()
}
do {
let url = self.applicationDocumentsDirectory.URLByAppendingPathComponent("SingleViewCoreData.sqlite")
try NSFileManager.defaultManager().setAttributes([NSFileProtectionKey : NSFileProtectionComplete], ofItemAtPath: url.path!)
} catch {
}
do {
let url = self.applicationDocumentsDirectory.URLByAppendingPathComponent("SingleViewCoreData.sqlite-wal")
try NSFileManager.defaultManager().setAttributes([NSFileProtectionKey : NSFileProtectionComplete], ofItemAtPath: url.path!)
// try print(NSFileManager.defaultManager().attributesOfFileSystemForPath(String(url)))
} catch {
}
do {
let url = self.applicationDocumentsDirectory.URLByAppendingPathComponent("SingleViewCoreData.sqlite-shm")
try NSFileManager.defaultManager().setAttributes([NSFileProtectionKey : NSFileProtectionComplete], ofItemAtPath: url.path!)
// try print(NSFileManager.defaultManager().attributesOfFileSystemForPath(String(url)))
} catch {
}
return coordinator
}()
I have also enabled Data Protection for my target in the "Capabilities". I have regenerated the provisioning profile from the Apple Developer portal and am using that with Enabled Data Protection.
I am also using the following code to check the file attributes of .sqlite , .sqlite-wal and .sqlite-shm files. NSFileProtectionKey is correctly set for all 3 of them.
func checkProtectionForLocalDb(atDir : String){
let fileManager = NSFileManager.defaultManager()
let enumerator: NSDirectoryEnumerator = fileManager.enumeratorAtPath(atDir)!
for path in enumerator {
let attr : NSDictionary = enumerator.fileAttributes!
print(attr)
}
}
I also tried disabling the Journal mode to prevent -wal and -shm files from being created. But I can still read the .sqlite file. Even though the attributes read NSFileProtectionComplete.
As described in the Apple Documentation at Apple Docs under "Protecting Data using On Disk Encryption", I tried to check whether the value of variable protectedDataAvailable changes as shown in the code below
public func applicationDidEnterBackground(application: UIApplication) {
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
NSThread.sleepForTimeInterval(10)
sleep(10)
let dataAvailable : Bool = UIApplication.sharedApplication().protectedDataAvailable
print("Protected Data Available : " + String(dataAvailable))
}
If I check the value without the delay it's set to true but after adding the delay it's set to false. This is kind of encouraging, however, right after, when I download the container, to show the content, it still has .sqlite file that still shows the content when opened in sqlitebrowser.
Ok, I finally understand this.
Using Xcode 7.3.1
Enabling File Protection
Enable File Protection using the Capabilities tab on your app target
If you do not want the default NSFileProtectionComplete, change this setting in the developer portal under your app id
Make sure Xcode has the new provisioning profile this creates.
For protecting files your app creates, that's it.
To protect Core Data, you need to add the NSPersistentStoreFileProtectionKey: NSFileProtectionComplete option to your persistent store.
Example:
var options: [NSObject : AnyObject] = [NSMigratePersistentStoresAutomaticallyOption: true,
NSPersistentStoreFileProtectionKey: NSFileProtectionComplete,
NSInferMappingModelAutomaticallyOption: true]
do {
try coordinator!.addPersistentStoreWithType(NSSQLiteStoreType, configuration: nil, URL: url, options: options)
Testing File Protection
I am not able to test this using a non-jailbroken device connected to a computer. Every attempt to access the device this way requires that I "trust" the computer and I believe that trusted computers are always able to read the phone's data ("Trusted computers can sync with your iOS device, create backups, and access your device's photos, videos, contacts, and other content" - https://support.apple.com/en-us/HT202778). I think the other answers on SO referencing this technique are no longer valid with more recent versions of iOS. Indeed, I am always able to download the container using XCode and view the app's data using iPhone Explorer. So how to test...
1 - Create an archive and ensure that it is has the proper entitlements by running the following on the .app file from the command line:
codesign -d --entitlements :- <path_to_app_binary>
You should see a key/value pair that represents your Data Protection level. In this example, NSFileProtectionComplete:
<key>com.apple.developer.default-data-protection</key>
<string>NSFileProtectionComplete</string>
In addition, I used the following two techniques to satisfy myself that the data protection is indeed working. They both require code changes.
2 - Add some code to verify that the proper NSFileProtectionKey is being set on your files and/or core data store:
NSFileManager.defaultManager().attributesOfItemAtPath(dbPath.path!)
If I print this out on one of my files I get:
["NSFileCreationDate": 2016-10-14 02:06:39 +0000, "NSFileGroupOwnerAccountName": mobile, "NSFileType": NSFileTypeRegular, "NSFileSystemNumber": 16777218, "NSFileOwnerAccountName": mobile, "NSFileReferenceCount": 1, "NSFileModificationDate": 2016-10-14 02:06:39 +0000, "NSFileExtensionHidden": 0, "NSFileSize": 81920, "NSFileGroupOwnerAccountID": 501, "NSFileOwnerAccountID": 501, "NSFilePosixPermissions": 420, "NSFileProtectionKey": NSFileProtectionComplete, "NSFileSystemFileNumber": 270902]
Note the "NSFileProtectionKey": "NSFileProtectionComplete" pair.
3 - Modify the following code and hook it up to some button in your app.
#IBAction func settingButtonTouch(sender: AnyObject) {
updateTimer = NSTimer.scheduledTimerWithTimeInterval(0.5, target: self,
selector: #selector(TabbedOverviewViewController.runTest), userInfo: nil, repeats: true)
registerBackgroundTask()
}
var backgroundTask: UIBackgroundTaskIdentifier = UIBackgroundTaskInvalid
var updateTimer: NSTimer?
func registerBackgroundTask() {
backgroundTask = UIApplication.sharedApplication().beginBackgroundTaskWithExpirationHandler {
[unowned self] in
self.endBackgroundTask()
}
assert(backgroundTask != UIBackgroundTaskInvalid)
}
func endBackgroundTask() {
NSLog("Background task ended.")
UIApplication.sharedApplication().endBackgroundTask(backgroundTask)
backgroundTask = UIBackgroundTaskInvalid
}
func runTest() {
switch UIApplication.sharedApplication().applicationState {
case .Active:
NSLog("App is active.")
checkFiles()
case .Background:
NSLog("App is backgrounded.")
checkFiles()
case .Inactive:
break
}
}
func checkFiles() {
// attempt to access a protected resource, i.e. a core data store or file
}
When you tap the button this code begins executing the checkFiles method every .5 seconds. This should run indefinitely with the app in the foreground or background - until you lock your phone. At that point it should reliably fail after roughly 10 seconds - exactly as described in the description of NSFileProtectionComplete.
We need to understand how Data Protection works.
Actually, you don't even need to enable it. Starting with iOS7, the default protection level is “File Protection Complete until first user authentication.”
This means that the files are not accessible until the user unlocks the device for the first time. After that, the files remain accessible even when the device is locked and until it shuts down or reboots.
The other thing is that you're going to see the app's data on a trusted computer always - regardless of the Data Protection level setting.
However, the data can’t be accessed if somebody tries to read them from the flash drive directly. The purpose of Data Protection is to ensure that sensitive data can’t be extracted from a password-protected device’s storage.
After running this code, I could still access and read the contents written to protectedFileURL, even after locking the device.
do {
try data.write(to: protectedFileURL, options: .completeFileProtectionUnlessOpen)
} catch {
print(error)
}
But that's normal since I ran iExplorer on a trusted computer.
And for the same reason, it's fine if you see your sqlite file.
The situation is different if your device gets lost or stolen. A hacker won't be able to read the sqlite file since it's encrypted. Well, unless he guesses your passcode somehow.
Swift 5.0 & Xcode 11:
Enable "Data Protection" in "Capabilities".
Use the following code to protect a file or folder at a specific path:
// Protects a file or folder + excludes it from backup.
// - parameter path: Path component of the file.
// - parameter fileProtectionType: `FileProtectionType`.
// - returns: True, when protected successful.
static func protectFileOrFolderAtPath(_ path: String, fileProtectionType: FileProtectionType) -> Bool {
guard FileManager.default.fileExists(atPath: path) else { return false }
let fileProtectionAttrs = [FileAttributeKey.protectionKey: fileProtectionType]
do {
try FileManager.default.setAttributes(fileProtectionAttrs, ofItemAtPath: path)
return true
} catch {
assertionFailure("Failed protecting path with error: \(error).")
return false
}
}
(Optional) Use the following code to check whether the file or folder at the specific path is protected (note: This only works on physical devices):
/// Returns true, when the file at the provided path is protected.
/// - parameter path: Path of the file to check.
/// - note: Returns true, for simulators. Simulators do not have hardware file encryption. This feature is only available for real devices.
static func isFileProtectedAtPath(_ path: String) -> Bool {
guard !Environment.isSimulator else { return true } // file protection does not work on simulator!
do {
let attributes = try FileManager.default.attributesOfItem(atPath: path)
if attributes.contains(where: { $0.key == .protectionKey }) {
return true
} else {
return false
}
} catch {
assertionFailure(String(describing: error))
return false
}
}
Rather than encrypt a file at the local level I set NSFileProtectionComplete for the app as a whole.
Create the file 'entitlements.plist' in your apps root folder with the following content.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>DataProtectionClass</key>
<string>NSFileProtectionComplete</string>
</dict>
</plist>
Then if you haven't already done so already (this could be the problem with your file level encryption) enable Data Protection in your apps capabilities.

qt translator doesn't show translated text in program

I use qt linguist to translate my program in different languages but it doesn't show he translated text in the program.
I set proper fonts and add .ts file to TRANSLATIONS.
I use lupdate and lrelease commands.
how can i create .ts file also? (I create text file and change the format to .ts is it correct way?)
Revie Qt Translation.
To translate the app dynamically:
1 - Open Qt command terminal and go to your project folder.
2 - Get all the translatable string from your project
lupdate -pro Example.pro -ts example.ts
3 - Translate all the string to the language you want using QLinguist
4 - Generate the .qm file with all translation executing:
lrelease example.ts
5 - Add this file, example.qm, as a resource to your project to include it with the executable file. Resource System
6 - Now, use QTranslator to translate the app:
QTranslator* translator = new QTranslator;
if(translator->load(":/"+example.qm)){
qApp->removeTranslator(translator); // Remove the translator if was used before
qApp->installTranslator(translator); // Install again the translator to force a new translation.
qDebug() << "Translation success!" ;
}else{
qDebug() << "Error file not found!";
}
7 - You can handle the translation event using changeEvent:
void MainWindow::changeEvent(QEvent* event)
{
if (event) {
switch(event->type()) {
// When the translator is loaded this event is send.
case QEvent::LanguageChange:
break;
// Whem the system language changes this event is send.
case QEvent::LocaleChange:
//retranslate the ui.
break;
default:
break;
}
}
QMainWindow::changeEvent(event);
}
That's all folks!

Using QNetworkAccessManager across dll

I have a Qt5 application which uses QNetworkAccessManager for network requests which is accessible via a singleton and QPluginLoader to load extensions which add the functionality to the program. Currently I'm using static linking for plugins and everything works just fine.
However I want to switch to using dynamic libraries to separate the core functionality from other parts of the app. I've added the necessary declspec's via macro, and made necessary adjustments in my .pro files.
The problem is that very often (like, 3 of 4 starts) QNetworkAccessManager when used from dlls just returns an empty request or a null pointer. No data, no error string, no headers.
This is the code I'm using for loading plugins:
template <typename PluginType>
static QList<PluginType*> loadModules() {
QList<PluginType*> loadedModules;
foreach (QObject* instance, QPluginLoader::staticInstances()) {
PluginType* plugin = qobject_cast<PluginType*>(instance);
if (plugin) {
loadedModules << plugin;
}
}
QDir modulesDir(qApp->applicationDirPath() + "/modules");
foreach (QString fileName, modulesDir.entryList(QDir::Files)) {
QPluginLoader loader(modulesDir.absoluteFilePath(fileName));
QObject *instance = loader.instance();
PluginType* plugin = qobject_cast<PluginType*>(instance);
if (plugin) {
loadedModules << plugin;
}
}
return loadedModules;
}
Which is used in this non-static non-template overload called during the startup:
bool AppController::loadModules() {
m_window = new AppWindow();
/* some unimportant connection and splashscreen updating */
QList <ModuleInterface*> loadedModules = loadModules<ModuleInterface>();
foreach (ModuleInterface* module, loadedModules) {
m_splash->showMessage(tr("Initializing module: %1").arg(module->getModuleName()),
Qt::AlignBottom | Qt::AlignRight, Qt::white);
module->preinit();
QApplication::processEvents();
// [1]
ControllerInterface *controller = module->getMainController();
m_window->addModule(module->getModuleName(),
QIcon(module->getIconPath()),
controller->primaryWidget(),
controller->settingsWidget());
m_moduleControllers << controller;
}
m_window->addGeneralSettings((new GeneralSettingsController(m_window))->settingsWidget());
m_window->enableSettings();
/* restoring window geometry & showing it */
return true;
}
However, if I insert QThread::sleep(1); into the line marked 1, it works okay, but the loading slows down and I highly doubt it is a stable solution that will work everywhere.
Also, the site I'm sending requests to is MyAnimeList.
All right, now I have finally debugged it. Turned out I deleted internal QNetworkAccessManager in one of the classes that needed unsync access. That, and updating to Qt5.3 seem to have solved my problem.

Qt: How to use an accesspoint throughout the application?

I'm developing an application for Symbian S60 phones using the Qt Nokia SDK, which sends requests and receives responses from a webservice in every view i have.
The problem with this, is that it always asks the user to choose a accesspoint.
So what i want is to choose an accesspoint when the application starts, and use that throughout the application.
So i found this example: http://wiki.forum.nokia.com/index.php/How_to_set_default_access_point_using_Qt_Mobility_APIs
but i got following error:
undefined reference to 'QtMobility::QNetworkConfigurationManager::QNetworkConfigurationManager(QObject*)
i'm also getting more of these errors from other classes from QMobillity, like:
undefined reference to 'QtMobility::QNetworkSession::open()
.pro file:
CONFIG += mobility
MOBILITY += bearer
header:
#include <qmobilityglobal.h>
#include <QtNetwork>
#include <QNetworkSession>
#include <QNetworkConfigurationManager>
QTM_USE_NAMESPACE;
cpp file:
QNetworkConfigurationManager manager;
const bool selectIap = (manager.capabilities()& QNetworkConfigurationManager::CanStartAndStopInterfaces);
QNetworkConfiguration defaultIap = manager.defaultConfiguration();
if(!defaultIap.isValid() && (!selectIap && defaultIap.state() != QNetworkConfiguration::Active))
{
qDebug() << "Network access point NOT found";
// let the user know that there is no access point available
msgBox->setText(tr("Error"));
msgBox->setInformativeText(tr("No default access point available"));
msgBox->setStandardButtons(QMessageBox::Ok);
msgBox->setDefaultButton(QMessageBox::Ok);
msgBox->topLevelWidget();
msgBox->exec();
}
else
{
qDebug() << "Network access point found and chosen";
}
session = new QNetworkSession(defaultIap,this);
session->open();
Anyone got an idea of what could be wrong?
Have you tried adding this to the .PRO file?
CONFIG += network

Resources