Weird behaviour of system() - c++

I'm a beginner in all this stuff. I'm trying to make a function that opens files (using Qt in windows), I tried some functions from QProcess library but they are unable to fit in my needs.So, I decided to use system() function to execute files.The problem is system function only opening .exe files and other files from my system drive and is not opening any file from
any other drive.Is there a built-in function in Qt that I can use to open any file with default program assigned for that file type. Why is this happening.What am I doing wrong?
My code:
QString FilePath = openFileDialog.getOpenFileName(this, tr("Open File"),"/home",tr("All Files"));
ui->Label_7->setText("Choose file to open.");
const char *file;
QByteArray bArray;
bArray = FilePath.toLatin1();
file = bArray.data();
system(file);

You can use the QDesktopServices::openUrl function to open local files with a suitable application.
Try this:
void Widget::open()
{
QString filename = QFileDialog::getOpenFileName();
if (!filename.isEmpty())
{
QUrl url = QUrl::fromLocalFile(filename);
QDesktopServices::openUrl(url);
}
}

Related

How to specify which types of files you can open

I am currently starting to develop a QT desktop application, to edit the scripting language "Lua". The implementation should be pretty basic, opening Lua extension files, saving and editing them. The problem that i have stumbled upon is that I want to be able to open/save/edit just Lua files. While reading a QT documentation i stumbled upon an explanation of how you can open files for a so called "notepad" editor. They have provided the following example code:
QString fileName = QFileDialog::getOpenFileName(this, "Open the file");
QFile file(fileName);
currentFile = fileName;
if (!file.open(QIODevice::ReadOnly | QFile::Text)) {
QMessageBox::warning(this, "Warning", "Cannot open file: " + file.errorString());
return;
}
setWindowTitle(fileName);
QTextStream in(&file);
QString text = in.readAll();
ui->textEdit->setText(text);
file.close();
So here they basically add a condition where the file was unable to open, (it was in this line of code if (!file.open(QIODevice::ReadOnly | QFile::Text))) but they don't specify what the condition should look like if I only want to be able to open certain types of files (in my case, lua files). The same goes for the "save" option that they have displayed.. So my question is, how should I extend this condition, to check if the files has the given extension type for Lua ? Thanks in advance.
getOpenFileName can take more arguments (has default values for some of the arguments), see the documentation here.
So your code will be something like:
QString fileName = QFileDialog::getOpenFileName(this, tr("Open File"),
"", //default path here
tr("Lua files (*.lua)"));
You could try this:
void QFileDialog::setNameFilter(const QString &filter)
Sets the filter used in the file dialog to the given filter.
/* If filter contains a pair of parentheses containing one or
more filename-wildcard patterns, separated by spaces, then
only the text contained in the parentheses is used as the filter.
This means that these calls are all equivalent: */
dialog.setNameFilter("All Lua files (*.lua)");
Taken from the docs:
https://doc.qt.io/qt-5/qfiledialog.html#setNameFilter

Running a Bash Script with arguments as a Qt resource

Qt newbie here :).
I'm currently executing a bash script in Qt using the popen function to redirect the output to a textBrowser in my application. When I add the script to my project as a resource it does not seem to execute anymore? I use the :/myScript.sh syntax and then try to add my arguments as QStrings.
Any advice will be appreciated!
FILE *in;
char buff[512];
QString args = ":/myScript.sh" + <arguments>;
QByteArray ba = args.toLatin1();
char *temp = ba.data();
if(!(in = popen(temp , "r")))
{
exit(1);
}
while(fgets(buff, sizeof(buff), in)!=NULL)
{
ui->txtConsole->append(buff);
}
ui->progressBar->setValue(50); pclose(in);
Invoking popen with the Qt resource path format will not do what you expect.
You are effectively trying to invoke is this:
popen(":/myScript.sh args", "r");
The popen function doesn't know anything about the Qt resource system nor the :/ syntax. It expects the first parameter to a path on disk that the operating system understands.
Two choices:
Just ship the myScript.sh file as a separate file and execute it directly. (What you observed as working before you tried to make the script a resource). If you aren't using compiled resources, chances are it already is a disk file. Just invoke popen on the absolute path to the file instead of with the :/ syntax.
Write code to extract the myScript.sh text file from the resources and save it locally to disk. Then invoke popen on that saved file.
Its running script file as a qt resource. You add arguments maybe this run.
QStringList arg("-c");
QFile file(":/scriptFile.sh");
arg << file.readAll();
process->start("sh", arg);

C++ char* relative file path? (Qt)

I am trying to play a .mod audio file in an executable. I am using the 3rd party BASSMOD .dll. I can get the audio file to play when I provide the full path to the file, but I cannot get it to play when providing a relative path. Here are some snippets.
main.cpp
#include <QCoreApplication>
#include "bassmod.h"
// define file location
const char* file = "C:/Users/Downloads/test4/console/music.mod";
void startMusic() {
BASSMOD_Init(-1, 44100, 0);
BASSMOD_MusicLoad(FALSE,(void*)file,0,0,BASS_MUSIC_RAMPS);
BASSMOD_MusicPlayEx(0,-1,TRUE);
}
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
startMusic();
return a.exec();
}
bassmod.h (relevant snippet)
BOOL BASSDEF(BASSMOD_MusicLoad)(BOOL mem, void* file, DWORD offset, DWORD length, DWORD flags);
The function I'm concerned about is BASSMOD_MusicLoad. As this project stands, the .mod file will play no problem. However, when I try to change the absolute path of the .mod file to a relative path ("music.mod"), the file fails to play. Why is that? I have the .mod file in the same directory as the executable as well as in the directory containing the .pro file -- that didn't seem to be the issue.
Also, maybe I'm missing something related to how files are opened in C++. It looks like the MusicLoad function requires that the second parameter be of type void*. I'm sure there are many different things I could be doing better here. Ideally, I'd like to be able to have file store the relative path to the .mod file and have it play that way so I don't have to hard code an absolute path. In a perfect world, I would like to supply file with a path to the .mod file in my resources.qrc, but then I would have to use QFile, I believe, which won't work because I need the type to be void*.
Any help for a beginner would be much appreciated.
EDIT 01: Thank you all for your help! I got it to work (using relative file path, at least). There are two ways to do this. Here's what I did and how I tested it:
The first case makes the assumption that BASSMOD (or whatever external dll you're using) does not handle relative paths.
const char* file = "C:/debug/music.mod"; // same dir as .exe
QFileInfo info("music.mod");
QString path = info.absoluteFilePath();
const string& tmp = path.toStdString();
const char* raw = tmp.data();
Those are the test items I set up. When I run BASSMOD_MusicLoad(FALSE,(void*)file,0,0,BASS_MUSIC_RAMPS);, it works as expected. That's when I hard-code the full absolute path.
When I ran BASSMOD_MusicLoad(FALSE,(void*)raw,0,0,BASS_MUSIC_RAMPS);, it didn't work. So I decided to print out the values for everything to see where it's messing up:
cout << "Qstring path: ";
qDebug() << path;
cout << "string& tmp: ";
cout << tmp << endl;
cout << "raw: ";
cout << raw << endl;
cout << "full char* file: ";
cout << file;
startMusic();
...returns this:
Qstring path:
"C:/myApp/build-Debug/music.mod"
string& tmp:
C:/myApp/build-Debug/music.mod
raw:
C:/myApp/build-Debug/music.mod
full char* file:
C:/myApp/build-Debug/debug/music.mod
Note the difference? When I hard-code the full path to the file, I found that (thanks to #FrankOsterfeld and #JasonC) the current working directory was actually not where the .exe (/debug) or .pro files were located. It was actually in the same directory as the Makefile.
So I just changed it to this: QFileInfo info("./debug/x.m"); and it worked.
Even though the problem wound up being me not knowing where the current working directory was, the solutions by #Radek, #SaZ, and #JasonC helped to find another way to solve this (plus it showed me how to get the working dirs and convert between types). This is a good reference for people who would want to use QFileInfo to determine where you actually are in the filesystem. I would have used this solution if the dll I was using did not handle relative paths well. However...
I wondered if I could apply the same solution to my original code (without using QFileInfo and converting types, etc). I assumed that BASSMOD did not handle relative paths out of the box. I was wrong. I changed the file variable to const char* file = "./debug/x.m"; It worked!
Thanks for the help, everyone!
However, I would still like to get this to work using music.mod from a Qt resources file. Based on the replies, though, it doesn't look like that's possible unless the 3rd party library you're using supports the Qt resource system.
I have the .mod file in the same directory as the executable.
In Qt Creator the default initial working directory is the directory that the .pro file is in, not the directory that the .exe ends up in.
Either put your file in that directory (the one that probably has all the source files and such in it as well, if you used the typical setup), or change the startup directory to the directory the .exe file is in (in the Run Settings area).
Although, based on your new comment below, I guess the problem is deeper than that... I can't really tell you why BASS doesn't like relative filenames but you can convert a relative path to an absolute one before passing it to BASS. There's a lot of ways to do that; using Qt's API you could:
#include <QFileInfo>
...
const char* file = "music.mod"; // Your relative path.
...
BASSMOD_MusicLoad(...,
(void*)QFileInfo(file).absoluteFilePath().toAscii().data(),
...);
In a perfect world, I would like to supply file with a path to the .mod file in my resources.qrc
You won't be able to do that because loading resources from .qrc files is a Qt thing and BASS presumably does not use Qt internally (just like e.g. you could not open a resource with fopen), and doesn't understand how to load resources embedded by Qt. I am not familiar with BASS but a cursory glance at this documentation shows that it also has the ability to play data from an in-memory buffer. So one approach would be to use Qt to load the resource into accessible memory and pass that buffer instead.
In a perfect world, I would like to supply file with a path to the .mod file in my resources.qrc, but then I would have to use QFile, I believe, which won't work because I need the type to be void*.
Why do you only belive? Read Qt Doc. It will work. Don't use class QFile but QFileInfo.
QFileInfo info(:/resourcePrefix/name);
QString path = info.absoluteFilePath();
void* rawPtr = (void*)path.toStdString().c_str();

qt check if file exists in a directory, if it doesn't prompt the user for its location, then copy the file to the program working directory

I have a program who's working directory is ~/Library/Application Support/MyApp, it looks here for the config.cfg and log files. The program needs a map file called MP512-Map.map. It looks in this directory to load it.
When the program is first run on a new machine its likely the file is not in this location, but on the users desktop or within the .dmg that the executable is distributed in. I want a file dialog to pop up and get the location of the .map file (if its not already present in the working directory) and then I want the program to copy the file from that location to the working directory so that next time the program is run the .map file can be loaded right away from there.
I have the following code:
QString path = QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation);
QString desktop = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation);
QDir dir(path);
if (!dir.exists()) {
dir.mkpath(".");
}
QString MapPath = path+"/MP512-Map.map";
QFile file(MapPath);
QFile tempfile;
if(file.exists()!=true){
qDebug()<<"MAP FILE NOT FOUND.";
QString temppath = QFileDialog::getOpenFileName(this,tr("Find Location of MP512-Map file:"),desktop,tr("Map Files (*.map)"));
tempfile.copy(temppath,path);
qDebug() << "location" << temppath;
qDebug() << "destination: " << path;
}
After this the read in of the map file occurs. The issue is with the copy.
The file does not successfully get copied over.
The console output is showing the correct directories:
location "/Users/Mitch/Desktop/MP512-Map.map"
destination: "/Users/Mitch/Library/Application Support/AFE-MP-512"
Am I implementing the copy function correctly?
Yes this function implementation is correct. But there is few moments
if(!QFile::copy(temppath, file.fileName()))
qDebug() << file.errorString();
Copy function(same as exists) is static and you don`t need temp object - tempfile
There is good practice to check if copy/read/write functions is successful

QFileDialog "destroys" the name of the files

Right now I'm working on a GUI for a suite of console applications used for bioinformatics and I'm doing my first tests as its my first project using Qt. I'm using QtDesigner for making the GUI and everything works perfectly except that QFileDialog converts the end of the file name into a strange character, although I'm not really sure if it is QFileDialog, or the conversion from QString into const char.
Here is my code:
QString file=QFileDialog::getOpenFileName(this, tr("Open File"),"/home/",tr("Any file (*.*)"));
QString fastqdumpDir = "/home/nsg/Downloads/sratoolkit.2.1.16-centos_linux32/bin/"
fastqdumpDir=fastqdumpDir+"./fastq-dump ";
QString cmdStr =fastqdumpDir + file;
const char* command = cmdStr.toStdString().c_str();
system(command);
The fastq-dump program ends because it says that the filename is not correct, and after debugging, I see that the file name goes from /home/nsg/Downloads/SRR502947.sra into /home/nsg/Downloads/SRR502947.sra[] and sometimes even /home/nsg/Downloads/SRR5029[]
Any ideas why is this happening or how to fix it?
Your problem is that you are calling QString::toStdString(), which returns a temporary object, and trying to get a pointer it's contents. The memory pointed to becomes invalid as the std::string is destroyed. You don't need to the intermediate std::string at all. This should work:
QString cmdStr =fastqdumpDir + file;
system( qPrintable(cmdStr) );
Rather than using the system command to run the external program, you can use Qt's QProcess: -
QString cmdStr = fastqdumpDir + file;
QProcess::execute(cmdStr);
or
QProcess::startDetached(cmdStr)
if you don't want to wait for the process to finish. Since the functions take a QString, there's no need for the conversion to a const char*