Qt Installer Framework - Prevent installation in non-empty folder - qt

I use Qt Installer Framework.
I want to know how to prevent installation in a non-empty folder?
In addition, how can I make the uninstaller remove only the files and folders it has installed, and not all the contents of its folder?
Thank you in advance

Due to the Qt Documentation you have access to the QDesktopServices inside the Scripting API, which contains the function findFiles(string path,string pattern), which should return none in your case, where path is your target directory for installation.
In the TargetDirectory Installer Installer Page you have access to the set TargetDirectory via Installer Page, which can be connected to if there is some edit.
It took me some hard time to figure out the following solution, which I have to admit is not the way I wanted to have it beforehand.
First of all you need a control script, that needs to be set inside your config.xml. It is called controlScript.js and resides in the same directory as your config.xml.
config.xml
<?xml version="1.0" encoding="UTF-8"?>
<Installer>
<Name>Your application</Name>
<Version>1.0.0</Version>
<Title>Your application Installer</Title>
<Publisher>Your vendor</Publisher>
<StartMenuDir>Super App</StartMenuDir>
<TargetDir>#HomeDir#/InstallationDirectory</TargetDir>
<ControlScript>controlScript.js</ControlScript>
</Installer>
Now, the only solution that I brought to work is the following:
controlScript.js
function Controller()
{
console.log("Control script");
}
Controller.prototype.ComponentSelectionPageCallback = function() {
var widget = gui.currentPageWidget();
widget.title="Select empty directory!";
var targetDirWidget = gui.pageById(QInstaller.TargetDirectory);
var targetDir=targetDirWidget.TargetDirectoryLineEdit.text;
var files=QDesktopServices.findFiles(targetDir, "*.*");
if (files.length!=0) {
var result = QMessageBox.warning("quit.question", "You selected a non-empty directory!", targetDir,QMessageBox.Ok);
gui.clickButton(buttons.BackButton);
}
}
Basically, the user enters a target directory and presses the BackButton. In case the target directory is non-empty a message box is displayed and the BackButton in the Component Selection is pressed.
My desired solution was beforehand to deactivate the NextButton in the TargetDirectory Page, but all my attempts were futile. Even though the following disabling of the NextButton should work, as shown in this answer.

Related

How to translate Next, Cancel, Quit Buttons ? (Qt Installer Framework based)

I would like to translate my installer wizard (Qt Installer Framework based) in English or French (OS language depends).
I added those lines in the "installscript.qs" file :
Component.prototype.retranslateUi = function()
{
component.languageChanged();
}
and I added those in "config.xml" file :
<Installer>
...
<Translations>
<Translation>fr.qm</Translation>
</Translations>
</Installer>
But everything is ok (all long texts are translated) (in French) but the buttons like "Next", "Cancel", "Quit" are not translated (see the screenshot) :
ps: I don't want to use C++ code. (only Script or Xml)
You need to load the Qt translation file in addition to your own .qm file(s). The file is located in the translation sub-folder of your Qt installation folder (e.g. ./usr/share/qt5/translations/). For some languages it seems sufficient to load qt_xx (where XX should be replaced with your locale), but for German I had to load "qtbase_XX" to translate the Next and Cancel buttons. In example for the fr locale they are named qt_fr.qm and qtbase_fr.qm.
EDIT:
Because of the comment of John Smith I checked the Installer framework source and the framework is not capable loading more than one translation file:
See installer-framework/src/libs/installer/component.cpp
/*!
Loads the translations matching the name filters \a qms inside \a directory. Only translations
with a base name matching the current locale's name are loaded. For more information, see
\l{Translating Pages}.
*/
void Component::loadTranslations(const QDir &directory, const QStringList &qms)
So my original answer above (which would lead to a translated QWizard::CancelButton) is not working.
I got the Quit button of the Installer Frameworks translation example translated to German by correcting the de.ts file provided within the framworks source in installer-framework/src/sdk/translations
The original translation coming with the feramework is missing an &:
So, changing:
<context>
<name>QInstaller::IntroductionPage</name>
...
<message>
<source>Quit</source>
<translation>Beenden</translation>
</message>
to
<context>
<name>QInstaller::IntroductionPage</name>
...
<message>
<source>&Quit</source>
<translation>Beenden</translation>
</message>
and recompiling the Framework leads to a translated Quit button (Beenden) within the framework.
I did not tried, but studying /installer-framework/src/libs/installer/packagemanagergui.cpp should enable you to translate the Next button, too.
Adding a context may help:
function Component()
{
qsTranslate("QInstaller::IntroductionPage", "&Quit");
}
It woked after Next and Back, but could not find where to write the qsTranslate().

Laravel/blade caching css files

I am working on Nginx server, with PHP-FPM. I installed Laravel 4.1 and bootstrap v3.1.1., and here is the problem. For the last 30 minutes, I have been trying to change a css rule that I first declared to check boostrap.
.jumbotron{
background: red;
}
The first time it worked. The jumbotron container was red. So, I removed that css value and started working, but still no matter which browse I use, the container is red. I even checked the css file through the Google Chromes inspection tool, and it is showing me that first value when jumbotron had a background:red. I deleted the css file and renamed it and add new styles, I configured chrome not to cache pages. But Still the same value. I'm convinced now, that Laravel has kept a cache of the first style declaration.
Is there any way to disable this at all?
General explanation
When you access a Laravel Blade view, it will generate it to a temporary file so it doesn't have to process the Blade syntax every time you access to a view. These files are stored in app/storage/view with a filename that is the MD5 hash of the file path.
Usually when you change a view, Laravel regenerate these files automatically at the next view access and everything goes on. This is done by comparing the modification times of the generated file and the view's source file through the filemtime() function. Probably in your case there was a problem and the temporary file wasn't regenerated. In this case, you have to delete these files, so they can be regenerated. It doesn't harm anything, because they are autogenerated from your views and can be regenerated anytime. They are only for cache purposes.
Normally, they should be refreshed automatically, but you can delete these files anytime if they get stuck and you have problems like these, but as I said these should be just rare exceptions.
Code break down
All the following codes are from laravel/framerok/src/Illuminate/View/. I added some extra comments to the originals.
Get view
Starting from Engines/CompilerEngine.php we have the main code we need to understand the mechanics.
public function get($path, array $data = array())
{
// Push the path to the stack of the last compiled templates.
$this->lastCompiled[] = $path;
// If this given view has expired, which means it has simply been edited since
// it was last compiled, we will re-compile the views so we can evaluate a
// fresh copy of the view. We'll pass the compiler the path of the view.
if ($this->compiler->isExpired($path))
{
$this->compiler->compile($path);
}
// Return the MD5 hash of the path concatenated
// to the app's view storage folder path.
$compiled = $this->compiler->getCompiledPath($path);
// Once we have the path to the compiled file, we will evaluate the paths with
// typical PHP just like any other templates. We also keep a stack of views
// which have been rendered for right exception messages to be generated.
$results = $this->evaluatePath($compiled, $data);
// Remove last compiled path.
array_pop($this->lastCompiled);
return $results;
}
Check if regeneration required
This will be done in Compilers/Compiler.php. This is an important function. Depending on the result it will be decided whether the view should be recompiled. If this returns false instead of true that can be a reason for views not being regenerated.
public function isExpired($path)
{
$compiled = $this->getCompiledPath($path);
// If the compiled file doesn't exist we will indicate that the view is expired
// so that it can be re-compiled. Else, we will verify the last modification
// of the views is less than the modification times of the compiled views.
if ( ! $this->cachePath || ! $this->files->exists($compiled))
{
return true;
}
$lastModified = $this->files->lastModified($path);
return $lastModified >= $this->files->lastModified($compiled);
}
Regenerate view
If the view is expired it will be regenerated. In Compilers\BladeCompiler.php we see that the compiler will loop through all Blade keywords and finally give back a string that contains the compiled PHP code. Then it will check if the view storage path is set and save the file there with a filename that is the MD5 hash of the view's filename.
public function compile($path)
{
$contents = $this->compileString($this->files->get($path));
if ( ! is_null($this->cachePath))
{
$this->files->put($this->getCompiledPath($path), $contents);
}
}
Evaluate
Finally in Engines/PhpEngine.php the view is evaluated. It imports the data passed to the view with extract() and include the file with the passed path in a try and catch all exceptions with handleViewException() that throws the exception again. There are some output buffering too.
Same issue here. I am using VirtualBox with Shared Folders pointing to my document root.
This pointed me in the right direction:
https://stackoverflow.com/a/26583609/1036602
Which led me to this:
http://www.danhart.co.uk/blog/vagrant-virtualbox-modified-files-not-updating-via-nginx-apache
and this:
https://forums.virtualbox.org/viewtopic.php?f=1&t=24905
If you're mounting your local dev root via vboxsf Shared Folders, set EnableSendFile Off in your apache2.conf (or sendfile off if using Nginx).
For what it's worth and because this answer came up first in my google search...
I had the same problem. The CSS and JS files wouldn't update. Deleting the cache files didn't work. The timestamps were not the problem. The only way I could update them was to change the filename, load it directly to get the 404 error, and then change the name back to the original name.
In the end the problem was not related to Laravel or the browser cache at all. The problem was due to NginX using sendfile which doesn't work with remote file systems. In my case, I was using VirtualBox for the OS and the remote file system was vboxsf through Guest Additions.
I hope this saves someone else some time.
In Laravel 5.8+ you can use so:
The version method will automatically append a unique hash to the filenames of all compiled files, allowing for more convenient cache busting:
mix.js('resources/js/app.js', 'public/js').version();
After generating the versioned file, you won't know the exact file name. So, you should use Laravel's global mix function within your views to load the appropriately hashed asset. The mix function will automatically determine the current name of the hashed file:
<script src="{{ mix('/js/app.js') }}"></script>
full document: https://laravel.com/docs/5.8/mix

Load Animated gif file using QMovie in Ubuntu

I am new to Ubuntu & Qt. I need to show busy status for other long operations. So, I was just trying to use waiting animation gif files to load instead using Progress bars.
I am using Eclipse Editor for Qt project.
Trolltech/../imageformat folder contains libqgif.so and libqgif.so.debug. I have copied these files in my debug folder too.
loader.gif is added in qrc file and kept in /Resources folder
IN MainWindow class I have added label and after setupUi(this) been called I call my ShowMovie() function as below:
ShowMovie() {
QMovie *movie = NULL;
movie = new QMovie(":/Resources/loader.gif");
if(movie->isValid()) {
ui.label_3->setMovie(movie);
movie->start();
}
else
qDebug()<<"Movie is Invalid";
qDebug()<<QImageReader::supportedImageFormats ();
}
Always isValid() function returns false & I got message that Movie is Invalid.
Last qDebug() returns
("bmp", "gif", "ico", "jpeg", "jpg", "mng", "pbm", "pgm", "png", "ppm",
"svg", "svgz", "tif", "tiff", "xbm", "xpm")
i.e means gif support is available.
I have tried to call ShowMovie() function before loading Main UI and/or on button clicked. Both fails.
Provide help on what is to be corrected.
Thank you.
you don't need to copy librairies files *.so.
Try creating the movie object with the full path to loader.gif. Does it work?
Then you have not setup correctly your resource system.
Either you have a syntax mistake in the qrc file which need to be fixed or you forgot to add it as a resource in the project file (.pro) using
RESOURCES = myqresource.qrc

Qt Installer framework component installation location

I've created an installer package based on the Qt installer framework with multiple components.
I needed to install each component in the appropriate directory.
Is it possible to specify the target directory for the individual component? I am referring to something like this:
var appData = installer.environmentVariable("AppData");
if (appData != "")
component.setValue("TargetDir", appData+ "/MyComponent");
Thank you in advance.
This question has already been answered, but I thought I would add a more detailed answer.
The documentation states that "for each component, you can specify one script that prepares the operations to be performed by the installer."
The Qt installer framework QtIFW comes with a set of examples, one of which is called modifyextract. Using this, I modified my package.xml file to include the line
<Script>installscript.qs</Script>
I then added a file installscript.qs to my package meta directory with the following content
function Component()
{
}
Component.prototype.createOperationsForArchive = function(archive)
{
// don't use the default operation
// component.createOperationsForArchive(archive);
// add an extract operation with a modified path
component.addOperation("Extract", archive, "#TargetDir#/SubDirectoryName");
}
The files in the package data folder were then installed in the subfolder SubDirectoryName
You need this based on the documentation:
Extract "Extract" archive target directory Extracts archive to target directory.
In my case, the component.addOperation("Extract", ... line resulted in extracting to #TargetDir#.
Instead, use one of the 'Operations> options in the Package.xml file.

InDesign CS5 Script: How can you display a directory?

I have a script that:
creates a new folder
scans an InDesign document for images
formats the images and copies them to the new folder
When the script is done doing all of this I want it to bring to focus the new folder directory (in Windows).
As of now I am displaying the folder-path in an alert window, but I would rather it open the directory (if it isn't already) so the user can see the new files.
I wish I could just call one of these:
myNewFolder.bringToFront() : works only on program focus, i.e. -- BridgeTalk.bringToFront("photoshop")
myNewFolder.open() : seems to apply only to file I/O operations
myNewFolder.show() : seems to apply only to the Window object
...but none of these work.
EDIT: new ActiveXObject("Scripting.FileSystemObject") does not work either...
You have to use the execute method.
myFolder.execute();

Resources