Can I use applicationDirPath() to access resources at a higher directory level? - c++

In the application that I am developing (using C++ and Qt), I am using QApplication::applicationDirPath() to access some resources, with respect of the application's path.
As an example, since I want to open a HTML manual from the application, I act this way:
void MainWindow::on_actionHelp_triggered()
{
QString link = QApplication::applicationDirPath() + "/Guide/guide.html";
bool r = QDesktopServices::openUrl(QUrl::fromLocalFile(link));
}
This snippet works if the project's structure presents the path "ProjectName/bin/Release/Guide/guide.html" (since the .exe file is in "ProjectName/bin/Release/AppName.exe").
But what can I do to refer to a higher-directory-level resource? As an example, I wish my HTML file to be in "ProjectName/data/Guide/guide.html". But this way, it seems not possible to compose the path in the way I'm acting.
EDIT: After #olive's comment, I wish to clarify a thing:
"Why am I not using '../'?"
Because it won't work from Visual Studio, where I am massively launch the application to test it. From VS, in fact, I shall use "../data/Guide/guide.html", when "from the outside", I'd have to do "../../data/Guide/guide.html".
That's why (I think) QApplication::applicationDirPath() exists. However, I am not an expert, so don't blame me and correct any eventual mistake of mine, please!

Just use ... QApplication::applicationDirPath() + "/../../data/Guide/guide.html" is perfectly valid path!
Of course there is another problem. When the application is installed, the relative path will probably be different again. You either need to configure the paths in visual studio so that the relative path works both during development and after deployment, or you need to detect the layout.

Related

How to specify a remote preprocessor include path like 192.0.2.17://usr/include

Is it possible to specify a C/C++ include path to a remote preprocessor server?
The point here is to have once central location for header files. This makes upgrades, version consistency, and a host of other things much better than people running all willy-nilly including different versions of things.
Minimal, Complete, and Verifiable Example
Typical include. On Linux, would default to /usr/include/ or the like; in Windows VS, to a location specified in the $(IncludePath) variable.
#include <iostream>
int main() {
std::cout << "hello, world" << std::endl;
return 0;
}
Now imagine that we set our include path as follows:
C_INCLUDE_PATH=192.0.2.17://usr/include;/usr/include;
The above would first check the remote server at 192.0.2.17 to see if the iostream library existed. Failing this, /usr/include would be checked.
This is a bit of a stretch to illustrate the point:
#include <192.0.2.17://iostream>
int main() {
std::cout << "hello, world" << std::endl;
}
Thanks, Keith :^)
Since you want version control anyway you could just use git (like thousands of other projects). So each user has a local clone of anything needed.
To answer the original question: No. I'm not aware of any preprocessor supporting such an include scheme.
I'm not aware of any compiler that retrieves include files or libraries remotely, so this is not something you can do directly.
The best you can do is have these dependencies on an NFS share that you can mount and then add that path to your include path.
I wouldn't put references to this in the code like that, and as dbush said, you'd have to enhance the preprocessor.
But there might be cute ways to do this within the Make system. That is, if you're using Make (for instance), you could add steps to the Makefile that force a refresh of data.
However, I would suggest this is WRONG because it's not just the include files that need to be fresh. If an include has changed, the related code has probably also changed, and you would need those changes, too. Your magic #include stuff isn't going to do a thing to make sure people have the right code / libraries that the includes are for.
I'm not sure why proper use of source code repositories don't already handle this for you.

Qt QDir::current()

I had some code like this:
void MainWindow::saveData()
{
QDir oldDir=QDir::current();//this should return the main executable directory.Since there is no other place in my hole code where i temper with QDir.
QDir sess("Sessions");
if(!oldDir.exists("Sessions"))//if "Sessions" Dir doesn't exist
oldDir.mkdir("Sessions");//create it.
QDir::setCurrent(sess.absolutePath());
//some virtual code inside current Dir, which i didn't implement yet.
QDir::setCurrent(oldDir.absolutePath());//restore old dir
}
When I run my app firstly the code works perfectly.but in the second run, the first call to QDir::current(); returns the "Sessions" Dir and not the main executable Dir as it should be restored in the first run.actually i did manage to overcome this by adding one line at the biginning of the code, the following :
QDir::setCurrent(QCoreApplication::applicationDirPath());
Still I want to know why the first code didn't work.already checked for the documentation of the functions and found nothing.
QDir::current();//this should return the main executable directory
No it should not! Not unless you change it to point there first.
I'm dead serious when I'll say this: Yours is a myth, fantasy, whatever you call it, I have no idea what gave you the idea. Point me to a spec that says so. Oh, you can't, because there's no such spec, no such requirement. It's someone's twilight hour mirage that seems to perpetuate itself endlessly. If you heard it from someone, you have every right to be angry at them this very moment, for they did you a big disservice.
Generally speaking, for applications that are not normally started from the command line, the initial working directory can be anything and it will be platform- and session/system configuration dependent. For a typical GUI application, assuming any particular initial working directory is a fool's errand and completely misguided.
Once you change it to where you want it to point to, you of course have full control over it, but the initial working directory must be assumed to be random and out of your control.
For example, on Windows I can start your application through an Explorer shortcut where I can specify whatever startup folder I desire, and you have zero control over it. On OS X, Finder sets the working directory to something or another, IIRC to the folder where the app bundle resides. Again, you as a developer have no control over it unless there's some setting in the bundle that you could add to that effect, but that is platform-specific and will be ignored if your application is not started through Finder or bundle API mechanisms (they probably are called something else). And so on. It's completely arbitrary and it's pointless to depend on its initial value.
If you want to refer to the application's installation directory or executable directory, do so explicitly. Do not assume anything about the initial working directory of a GUI application.
I tried with the below code and it works fine for several runs.
The version details of Qt and OS may help.
Qt creator 3.3.2 (open source). Qt lib 5.4.1.Os windows 8.1
#include <QCoreApplication>
#include "QDir"
#include "qDebug"
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QDir oldDir=QDir::current();
qDebug()<<QDir::current().absolutePath();
QDir sess("H:\\cuteapps\\session");
if(!oldDir.exists("H:\\cuteapps\\session"))//if "Sessions" Dir doesn't exist
oldDir.mkdir("H:\\cuteapps\\session");//create it.
QDir::setCurrent(sess.absolutePath());
qDebug()<<QDir::current().absolutePath();
return a.exec();
}
output 1:
"H:/cuteapps/build-untitled2-Desktop_Qt_5_4_1_MSVC2012_OpenGL_32bit-Debug"
"H:/cuteapps/session"
output 2:
"H:/cuteapps/build-untitled2-Desktop_Qt_5_4_1_MSVC2012_OpenGL_32bit-Debug"
"H:/cuteapps/session"
output 3:
"H:/cuteapps/build-untitled2-Desktop_Qt_5_4_1_MSVC2012_OpenGL_32bit-Debug"
"H:/cuteapps/session"

How to use Qt/C++ to create/read/write files and store settings local with the program

I'm an unfortunate beginner at C++ and using the Qt GUI designer program seemed perfect for my needs, except I'm having problems trying to write out the code necessary for this. I could use the QSettings string to store local settings on the hard drive, but I personally hate it when programs do the %HOME_LOCAL%\APPS_SETTINGS bull that some do. I need to save a text file for both settings and a local\host database, within the program directory, to remember strings to read from later.
What is the line of code I need to make use of a local host text database or is there a better option? And how can I store that with the local program inside its directory?
You can use QSettings with any file, with constructor QSettings::QSettings ( const QString & fileName, Format format, QObject * parent = 0 ).
To get the program directory, you can use QCoreApplication::applicationDirPath().
So, answer to your question, statement to put after creation of QApplication instance:
QSettings *settings = new QSettings(
QCoreApplication::applicationDirPath() + "/settings.ini",
QSettings::IniFormat,
qApp);
But, as noted in the comments under question, if you're making your program for general distribution, you should use the OS default. Examine all the constructors of QSettings to see what it can do. User does not often have write permission in the application directory. Note that you can also store settings to Windows registry with QSettings::NativeFormat.

Visual C++ - Throwing unhandled exception from setting forms icon?

I can compile the solution with no errors, but when I'll try to run it, I get a crash window:
An unhandled exception of type
'System.Resources.MissingManifestResourceException' occurred in mscorlib.dll
Additional information: Could not find any resources appropriate for the specified culture or the neutral culture. Make sure "<myformname>.resources" was corerctly embedded or linked into assembly "<myprojectname>" at compile time, or that all the satellite assemblies required are loaded and fully signed.
And after I press Break it throws me to the line:
this->Icon = (cli::safe_cast<System::Drawing::Icon^ >(resources->GetObject(L"$this.Icon")));
If I comment this line out, everything works just fine, but my program doesn't have icon.
Anyone else had this problem? Found a solution? I couldn't find anything clear enough for me to understand, problem is really annoying me, only solution I found was to declare my form class before any other classes, but I don't even have any other classes in my solution?
I also have only one project in this solution, ms support said something about having multiple projects, which I don't have, so it was no use either.
Take a look here :
http://www.mztools.com/articles/2005/MZ2005007.aspx
The exception is thrown because your icon cannot be located. You will probably need to compiles your resources under one .dll and put this under en-US subfolder on your project output. It did the trick for me at least. There are probably other solutions to your problem too.
Do not panic like I did. The root cause of the problem is that the compiled resource file is different from the one that is asked to load at runtime. This happens because the underlying build-script cannot detect the filename or namespace changes made after the form is created.
For example, At first we started a project named x . And our $(RootNamespace) becomes x. And we created a form named y. So our XML resource file y.resx gets compiled into x.y.resource . At this point the icon change works.
Now somehow we changed the project name or the namespace to z. But our $(RootNamespace) remains the x. While at compile-time it wrongly generates old x.y.resource, but at links-time it links z.y.resource. And at this point the icon change does not work.
It can also happen if the form is under some nested namespace which is not known in the project file.
It can be fixed by changing the compilation output of the y.resx file . It can be done by right-clicking the resource and changing the Resource Logical Name to $(RootNamespace).%(Filename).resources .
I will also make sure that ProjectName,AssemblyName and RootNamespace are the same in the .vcxproj file. Somehow if the form is declared under a nested namespace like RootNamespace.gui , then the output file of the resource should be $(RootNamespace).gui.%(Filename).resources .

Qt4.4 how to get the user settings path

linux: $HOME/.config
windows: %APPDATA%
mac os: $HOME/.config
It can be set using http://qt-project.org/doc/qt-4.8/qsettings.html#setPath, but it seems as I am not able to retrieve it.
http://qt-project.org/doc/qt-4.8/qlibraryinfo.html#location QLibraryInfo::LibrariesPath returns the system wide settings dir, which is not what I want.
Any ideas, or do I have to code it separately for each platform?
€: I want to create a sub directory, and store files into it. (You may punish me if this is a bad idea)
This might not answer your question directly: if you want to store per-user persistent data, shouldn't you use QDesktopServices::storageLocation(QDesktopServices::DataLocation) instead?
This is a nasty workaround. First you create QSettings, then get its location.
QSettings cfg(QSettings::IniFormat, QSettings::UserScope,
"organization", "application");
QString config_dir = QFileInfo(cfg.fileName()).absolutePath() + "/";
Credits go to the Qt Centre forum.
QSettings stores the default config in the user AppData directory. See documentation for QSettings. Also this code instructs to store the config in the Ini file format.
this works on both qt 4 and qt 5
QApplication::setApplicationName("MyApp");
QApplication::setOrganizationName("Me");
QString homePath;
#if QT_VERSION >= 0x050000
homePath = QStandardPaths::writableLocation(QStandardPaths::DataLocation);
#else
homePath = QDesktopServices::storageLocation(QDesktopServices::DataLocation);
#endif
Why do you need to know the settings path? If you are going to put settings in it, you could use QSettings. I could see making a subdirectory to hold various settings, but it seems like the easiest way would be to use QSettings directly.
As far as I can tell, you can't retrieve the path. In the Qt source, src/corelib/io/qsettings.cpp, there is a function to get the path:
static QString getPath(QSettings::Format format, QSettings::Scope scope)
{
...
but it's not accessible from code using Qt. You can't copy it and use it either, because it uses internal Qt globals to store the path...
EDIT: A solution was posted, using QDesktopServices.storageLocation(QDesktopServices.DataLocation) but it doesn't do exactly what the question was asking for, i.e. if I set a custom path using QSettings.setPath() it doesn't reflect the change.
What platform are you at?
Might be related or not but in windows, the default is to write QSettings to the registry.
I read more into the question than there was as it was originally posted. It is clearer after the edits. Ok, so can't you use..
QString QSettings::fileName () const
Returns the path where settings are written to using this QSettings object are stored.
On Windows, if the format is QSettings::NativeFormat, the return value is a system registry path, not a file path.