I'm trying to read and edit a Desktop Entry .desktop file using Qt QSettings. The problem is that these files contain keys with multiple values separated by semicolon ;. I tried reading these as QStringList but no luck. I only get the first value. For example:
Keywords=disc;cdrom;dvd;burn;audio;video;
Categories=GTK;GNOME;AudioVideo;Audio;Video;DiscBurning;
MimeType=application/x-cd-image;application/x-cdrdao-toc;application/x-cue;application/x-toc;audio/x-scpls;audio/x-ms-asx;audio/x-mp3-playlist;audio/x-mpegurl;application/x-brasero;x-content/audio-cdda;x-content/video-dvd;x-content/video-vcd;x-content/video-svcd;x-content/image-picturecd;
Getting the values with:
settings.value("Desktop Entry/MimeType").toStringList();
settings.value("Desktop Entry/MimeType").toString();
returns only the first value (in my example: disc, GTK or application/x-cd-image).
How to I return the full value from those keys? And how do I write it back using QSettings?
Update (first attempt was completely useless)
Variant 1
QMap<QString, QString> settings;
QFile inFile("<input filename.ini>");
if(inFile.open(QIODevice::ReadOnly))
{
QTextStream in(&inFile);
while (!in.atEnd())
{
QString line = in.readLine();
QStringList linelist = line.split("=");
settings[linelist[0]] = linelist[1];
}
}
Variant 2
use QSettings::registerFormat().
This is probably the only "clean" way to do it with QSettings. The advantage is that you can register it with the .desktop extension. You'll have to write a pair of ReadFunc() and WriteFunc() functions.
I think you can't do it. QSettings has certain interpretation of .ini file format, which is very close to Windows interpretation, and is not meant for generic parsing. Semicolon starts a comment, and apparently QSettings allows comment after value until end of line, and AFAIK there's no way around it.
You need to find a different library to handle .desktop files, or implement one yourself.
Related
I have a Qt program which was developed on Linux. In it are some user settings which are parsed from a config file. Of course, the users don't tend to have that config file during the first launch and we want things to work even if it isn't present, so a copy of the sensible defaults is stored in a resource text file, which is in the same format as the on-disk version would be.
I've run into an annoyance when running on windows...
The resources have had their "\n" line endings all converted to "\r\n" somewhere along the line! I'd really prefer to not have to alter the parsers to optionally accept more than one type of newline.
Is there a way to tell cmake to tell the Qt resource compiler to not do the conversion by passing a flag or similar?
EDIT: To clarify what's going on, I'll explain all of the little details of why I think qrc is adding the newlines...
First, I have a .qrc file which looks roughly like this:
<RCC>
<qresource prefix="/">
<file>res/DefaultSettings.txt</file>
</qresource>
</RCC>
It is added to the executable via cmake using code like this:
qt5_add_resources(QRC_SOURCES
resource.qrc
)
and
add_executable(my_project
resource.qrc
main.cpp
)
finally, it is being loaded with code like this:
QByteArray loadResource(const QString &resource) {
QResource res(resource);
if(!res.isValid()) {
qFatal("Failed to load internal resource");
}
// don't copy the data, if it's uncompressed, we can deal with it in place
auto defaults = QByteArray::fromRawData(reinterpret_cast<const char *>(res.data()), res.size());
if(res.isCompressed()) {
defaults = qUncompress(defaults);
}
// NOTE: at this point, using a debugger, I observe
// "\r\n" newlines in the defaults byte array
return defaults;
}
If by "resource" text file you mean a binary resource stored in the executable via qrc, then no: qrc will never alter the files - it doesn't discriminate between binary and text resources, it's all binary as far as it's concerned. Version control systems such as git may do that on checkin/checkout, though. You may also be reading the file using APIs that convert line endings. You'd ideally want to have a reproducer that outputs the file, and then another one that uses qrc to embed the file and then demonstrate the changed line endings.
I have a Qt program that processes stdin data like this:
QTextStream qtin(stdin);
QString stdindata = qtin.readAll();
QByteArray ba;
ba = stdindata.toUtf8();
QJsonDocument exJSONDoc(QJsonDocument::fromJson(ba));
QJsonObject extRoot;
extRoot = exJSONDoc.object();
QStringList keys;
keys = extRoot.keys();
for (int n=0; n <= keys.count()-1; n++)
{
qDebug() << extRoot.value(keys[n]).toString();
}
It works when I call my program like this:
myprogram < ./data.json
But if I call it without any "<" it hangs in qtin.readAll().
How can I check with Qt if the stdin is empty?
(I am assuming a Linux -or at least POSIX- operating system)
QTextStream qtin(stdin);
QString stdindata = qtin.readAll();
This would read stdin till end-of-file is reached. So works with a redirected input like
myprogram < ./data.json
But if I call it without any "<" it hangs ...
But then (that is, if you run myprogram alone) stdin is not empty. It is the same as your shell's stdin. and your program, being the foreground job, is waiting for input on the terminal you are typing (see also tty(4)). Try (in that case) typing some input on the terminal (which you could end with Ctrl D to make an end-of-file condition). Read about job control and the tty demystified and see also termios(3).
Perhaps you could detect that situation with e.g. isatty(3) on STDIN_FILENO. But that won't detect a pipe(7) like
tail -55 somefile | myprogram
You need to define what an empty stdin is for you. I have no idea what that means to you, and I would instead think of myprogram < /dev/null (see null(4)) as the way to get an empty stdin.
Perhaps you should design myprogram so that some program
option (perhaps --ignore-stdin) is avoiding any read from stdin.
Problem here is readAll. See documentation:
Reads the entire content of the stream, and returns it as a QString.
Avoid this function when working on large files, as it will consume a
significant amount of memory.
So it reads stdin until it encounters end of file and since stdin is associated with console you have to signal end of file. Usually it is Ctrl-D and press enter.
It is more probable you what to read stdin line by line.
To alow user text editing console transfers data to standard input of the application only line by line. This was designed like this ages ago when computer had only a printer as user interface (no screen).
Now question is how to read JSon form stdin console connected with console without end of file information?
I would use some SAX parser, but this would be to complicated for you.
So is there another way to detect end of JSon?
You can try this approach (this is basic idea, not final solution, so it has couple shortcomings):
QFile file(stdin);
QByteArray data = file.peak(largeNumber);
QJsonParseError error;
QJSonDocument doc = QJSonDocument::fromJson(data, &error);
while (!doc.isValid() && JSonNotTerminatedError(error.error))
{
// TODO: wait for new data - it would be best to use readyRead signal
doc = QJSonDocument::fromJson(data, &error);
}
Where JSonNotTerminatedError returns true for respective QJsonParseError::ParseError values (see linked documentation) which are related with unterminated JSon data.
Now I see QFile doesn't have required constructor, but main concept should be clear. Read data from stdin and check if it is a valid JSon document.
I have some pictures in the resource file and their file names correspond to their staffIds. this is how I set the picture into my QLabel but nothing is shown.
QString staffId;
staffId=ui->lineEdit_staffID->text();
QPixmap managerPic(":/staff/\'"+staffId+"\'.jpg");
managerInterface.ui->label_mpic->setScaledContents(true);
managerInterface.ui->label_mpic->setPixmap(managerPic);
I'm with #Mike here, most probably the single quotes aren't part of your filenames. You can use the debugger to see what is passed to the QPixmap constructor, or put the name into a separate QString variable and write it to qDebug() to see what it contains.
In general you better use QString::arg() to build strings instead of concatenation; usually it's easier to read and understand:
QPixmap managerPic(QString(":/staff/\'%1\'.jpg").arg(staffId));
QPixmap managerPic(QString(":/staff/%1.jpg").arg(staffId));
QString fe = "C:\\Program Files\\Autodesk\\Maya2008\\bin\\imconvert.exe ";
This line gives a problem because of space between Program and Files. How is it possible to decode it so that it is treated as one complete string
Brgds,
kNish
You can use a QFileInfo object to store it. This object accepts all path even if they have spaces. In addition you have some functions to do all checks you need before using it.
Use QUrl::toPercentEncoding static method
In windows you would do:
QString fe = "\"C:\\Program Files\\Autodesk\\Maya2008\\bin\\imconvert.exe\"";
I am writing a qt application, with the goal of it being portable to the 3 major operating systems.
I am using QFileDialog to select a folder, and then adding it to a QListWidget. However the folder name is being returned as E:/media even though I am on Windows. I would want it to return E:\media
I could use a simple string replace, but then on Linux/Mac it would look weird to have \home\user\Documents
My code if it helps:
void LibrariesForm::on_addButton_clicked()
{
QString dir = QFileDialog::getExistingDirectory(this, tr("Select Folder"), "/", QFileDialog::ShowDirsOnly);
if (dir.isNull() == true)
{
return;
}
ui->librariesList->addItem(new QListWidgetItem(dir, ui->librariesList, 0));
}
I guess you are looking for QDir::toNativeSeparators().
If you use the string just internally, you don't need to convert slashes to backslashes. Qt's classes work with linux-style pathes, too. If you want a "pretty printed" string, take Jérôme's answer. :)