QFileDialog "destroys" the name of the files - c++

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*

Related

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);

QT copy to QTemporaryFile

I'd like to make a copy of some/path/myfile in $TMPDIR/myprog-<random-string>.ext, such that I can then pass it on to a 3rd party procedure that chokes on extensionless files.
Here's what I'd like to work:
QString originalPath = "some/path/myfile";
QTemporaryFile f(
QDir::temp().absoluteFilePath("mprog-XXXXXX.ext")
);
// f.open(); ?
QFile(originalPath).copy(f.fileName());
However, I now have a problem - either the file doesn't yet exist, and thus hasn't been assigned a temporary fileName(), or the file name has been assigned but the file itself already exists, preventing the new file being copied on top.
How can I copy a file to a temporary location in QT, and have the temporary copy removed when the destructor of QTemporaryFile is called?
If the file doesn't exist, create the QTemporaryFile object exactly as you have done, open it and then close it immediately. This will generate the random filename and create it on the disk.
When your QTemporaryFile object gets destroyed, the file will be deleted from the disk.
Unfortunately, Qt (5.3) doesn't support copying to an existing file. The only correct, race-free use of QTemporaryFile is to open() it, creating it in the process, and then operate on it.
You'll need to implement the copy yourself, I'm afraid :(
On Windows, if you expect there to be some gain from using CopyFileEx, I have a complete example that wraps it for Qt's perusal, with progress signals.
The real question is: do you really need to create a copy? Wouldn't a hard link do? Since Qt runs, for the most part, on Unices and Windows, you can create a symbolic link wrapper that will wrap POSIX link() and winapi CreateHardLink. If hard link creation fails, or the temporary folder is on a different volume, you can then try CreateSymbolicLink. Of course you'd need to look up CreateSymbolicLinkW using QLibrary if you intend your executable to start un XP at all. If that fails, you're either running on XP or on a FAT partition, and the final fallback is copying.
Would it be out of the question to rename the file, run the 3rd-party application on it, then rename it back?
If you're not going to be actually using the file / stream to the file QTemporaryFile created for you, you're better off using QUuid instead to just generate a guaranteed unique filename. This generates a unique filename, roughly equivalent to QTemporaryFile:
QUuid uuid = QUuid::createUuid();
QString tempFileFullPath = QDir::toNativeSeparators(QDir::tempPath() + "/" + qApp->applicationName().replace(" ", "") + "_" + uuid.toString(QUuid::WithoutBraces) + ".dat");
I like the temporary filename to not contain spaces, so I removed that from the app name used for the filename prefix. (You should call QApplication::setApplicationName in your main() function so this will work.)
Also, you should probably change the .dat extension to something suitable for your file type.

Weird behaviour of system()

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);
}
}

ofstream writing data to file: How do I pass a previously defined string as the filename

I have a program that I have written with C++, OpenCV and Qt, where I am trying to write data to a csv file. In my Qt Widget I have created a QFileDialog that allows me to choose where to save the csv file.
This path is then stored as a QString, and converted to a std::string as follows;
std::string OutputFileName = OutputFile.toUtf8().constData();
I then try to pass this std::string to my ofstream::open function as follows:
ofstream CSVFile;
CSVFile.open(OutputFileName);
And there lies the problem; it refuses to compile, giving the error
no matching function for call to 'std::basic_ofstream >::open(std::string&)'
I'm very new to programming and thus I have no idea what exactly the problem is here. I have tried looking at this, but from what I can tell that is a Windows specific solution, and I am using OSX.
Can anyone tell me how I can successfully pass the filepath stored in the QString to the CSVFile.open() term?
in C++03, ofstream::open takes const char* parameter.
If OutputFileName is std::string.
Try:
CSVFile.open(OutputFileName.c_str());
If outputFileName is Qstring
CSVFile.open(OutputFileName.toStdString().c_str());
See QString::toStdString reference

How to use the bash command 'which' from QProcess

I'm a student programmer using Qt and I seem to have ran into an issue using QProcess to launch the bash command 'which' in an attempt to collect a map of installations of an application. I have the following code and I'm truly lost as to what I might be missing. I have referenced the QProcess documentation and still cant figure out whats wrong.
Every time this code is ran the file is not created in the indicated directory. Without the file constructed the application cannot proceed.
//datatypes
QProcess *findFiles = new QProcess();
QStringList arguments;
QStringList InstallationList;
QString program = "/bin/bash";
QString currentUsersHomeDirectory = QDir::homePath();
QString tmpScriptLocation = currentUsersHomeDirectory;
QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
//generate file with list of files found
tmpScriptLocation += ".whichBAScriptOutput";
arguments << QString(QString("which -a certainFile >> ") += tmpScriptLocation);
findFiles->setProcessEnvironment(env);
findFiles->start(program,arguments);
findFiles->waitForFinished();
which is located on /usr/bin/ so try to change the path..
EDIT:
You need to connect QProcess's signal readyReadStandardOutput() to your slot. Actually if you take a look at the documentation QProcess inherits from QIODevice. This means you can do something like:
while(canReadLine()){
string line = readLine();
...
}
if you have already written a client-server application in Qt, i am sure you reconized the pseudocode..
As you say you want to execute which, but you are lauching bash with a handwritten script. There is a much easier way to do this in a sequential manner:
//preparing the job,
QProcess process;
QString processName = "which"; //or absoute path if not in path
QStringList arguments = QStringList() << "-a"
<< "certainFile.txt";
// process.setWorkingDirectory() //if you want it to execute in a specific directory
//start the process
process.start(processName, arguments );
//sit back and wait
process.waitForStarted(); //blocking, return bool
process.waitForFinished(); //blocking, return bool
if(process.exitCode() != 0){
//Something went wrong
}
//return a byte array containing what the command "which" print in console
QByteArray processOutput = process.readAll();