Qt check for valid URL - c++

I am trying to create a Qt application which checks if a URL entered by the user into a text edit is valid.
This is what I have so far but it only ever says the URL entered is valid, even when I enter one which is not.
bool checkUrl(const QUrl &url) {
if (!url.isValid()) {
//qDebug(QString("Invalid URL: %1").arg(url.toString()));
return false;
}
return true;
}
void MainWindow::on_pushButton_clicked()
{
QString usertext = ui->plainTextEdit->toPlainText();
QUrl url = QUrl::fromUserInput(usertext);
if (checkUrl(url))
ui->textEdit->setPlainText("Valid URL.");
else
ui->textEdit->setPlainText("Invalid URL.");
}
Also on the qDebug line there is an error:
/home/user/HTML/mainwindow.cpp:32: error: no matching function for call to ‘qDebug(QString)’
Does anyone know what the problem is as it keeps returning true?

You should use qDebug like this:
qDebug() << QString("Invalid URL: %1").arg(url.toString());
also note that QUrl::isValid() does not check syntax of url. You may want to use regular expressions to validate urls.

QUrl::isValid() only basically checks if the character encoding is right. What are you considering a wrong url?
Re qDebug, the form you use basically encapsulates printf, so it doesn't work with QString. You want to do:
qDebug() << QString("Invalid URL: %1").arg(url.toString());

Related

How do I get the value of text inside of the file using Qt?

The data of my file.txt is as below:
Student_ID=0001
Student_Name=joseph
Student_GradeLevel=2
How do I get the value, let say I want to get the Student_ID using Qt.
Thanks.
Take a look at this function, it can be used to find any value you want in your input file, where all lines are in the format you've posted above (key=value). If the key is not found, it returns an empty QString() object.
QString findValueInFile(QString key, QString filename) {
QFile file(filename);
if(file.open(QIODevice::ReadOnly)) {
QTextStream txtStr(&file);
QStringList fileContent = txtStr.readAll().split('\n');
for(auto &&line : fileContent) {
if(line.contains(key)) return line.split(QChar('='))[1];
}
file.close();
}
return QString(); // not found
}
Now you call it somewhere, e.g.:
qDebug() << findValueInFile("Student_ID", "file.txt");
qDebug() << findValueInFile("Student_Name", "file.txt");
This function can be easily modified if you replace your = sign with other delimiter e.g. => or sth else. However for key=value format there is a special QSettings class (mentioned by sebastian) that can allow you to read those values even easier:
QSettings file("file.txt", QSettings::IniFormat);
qDebug() << file.value("Student_Name").toString(); // et voila!
You can probably also use QSettings, as they are able to read ini files.
There are some caveats though regarding backslashes which might be important to you (though they aren't for the example you posted): http://doc.qt.io/qt-4.8/qsettings.html#Format-enum
QSettings iniFile("myfile.txt", QSettings::IniFormat);
// now get the values by their key
auto studentId = iniFile.value("Student_ID").toString().toInt();
I'm more of a PyQt user, so: apologies if I got some C++ specifics wrong...

Creating a QVariantMap in Qt with strings

Apologies for asking something this trivial but I just can't seem to get it right so I guess I've completely misunderstood everything I thought I knew about memory management.
I have a function that parses a network reply for some data and it looks like this:
// Call from another function
QVariantMap *mappedResult = handleReply(reply);
...
// Function
QVariantMap *handleReply(QNetworkReply *reply) {
QVariantMap *result = new QVariantMap;
QVariant testvalue = new QVariant("testvalue");
result->insert("testkey", testvalue);
if (reply->error() > 0) {
qDebug() << "Error number = " + reply->errorString();
QVariant variant = QVariant.fromValue(reply->errorString());
result->insert("error", variant);
} else {
QJsonDocument jsonResponse = QJsonDocument::fromJson(jsonString.toUtf8());
QJsonObject jsonResponseObject = jsonResponse.object();
*result = jsonResponseObject.toVariantMap();
}
return result;
}
If there is no error, the result is parsed fine by the built in toVariantMap function. When there is an error however, I would like to create an entry in the result that is sent back from the function. As you can see in the function, I'm trying to create QVariants from Strings in two different ways.
The first approach gives an error like this:
C:\Qt\5.2.0\mingw48_32\include\QtCore\qvariant.h:466: error: 'QVariant::QVariant(void*)' is private inline QVariant(void *) Q_DECL_EQ_DELETE;
^
The second approach like this:
[PATH] error: expected primary-expression before '.' token QVariant variant = QVariant.fromValue(reply->errorString());
I've also tried setting the values like this:
result->insert("testkey", "testvalue");
result->insert("error", reply->errorString());
The last approach doesn't give compile errors but the result variable in the return statement cannot be inspected in the debugger and as soon as the return statement is executed the application crashes with memory problems indicating I'm not using "new" properly.
"Error accessing memory address 0x...".
If someone with at least a little knowledge could help me sort out how to perform this simple task, I would be very greatful. How can I return a QVariantMap from my function with custom strings as key/value pairs?
Cheers.
I would write your function in the following way (with fixes):
QVariantMap *handleReply(QNetworkReply *reply) {
QVariantMap *result = new QVariantMap;
QVariant testvalue("testvalue"); // <- fixed here
result->insert("testkey", testvalue);
if (reply->error() > 0) {
qDebug() << "Error number = " + reply->errorString();
QVariant variant(reply->errorString()); // <- fixed here
result->insert("error", variant);
} else {
QJsonDocument jsonResponse = QJsonDocument::fromJson(jsonString.toUtf8());
QJsonObject jsonResponseObject = jsonResponse.object();
*result = jsonResponseObject.toVariantMap();
}
return result;
}
However it is still unclear, why do you need to work with a pointer to the variant map instread of passing it by value?

Check if two consts are empty

I'm kind of new to the C++ scene so I'm wondering how I'd verify both fields have some text entered, here's the current code which is only verifying one field
void App::requestLogin(const QString &email, const QString &password) {
if (m_active)
return;
//how can I do both password and email here????
const QStringList list = email.split(QRegExp("\\s+"), QString::SkipEmptyParts);
if (list.isEmpty()) {
m_errorMessage = "please complete both fields";
m_error = true;
emit statusChanged();
return;
}
}
It is hard to understand what you mean, but this is my wild guess based on your error message. You do not even need a regex for this. Even if you needed, you should use QRegularExpression rather than the much slower QRegExp.
void App::requestLogin(const QString &email, const QString &password) {
if (m_active)
return;
...
if (email.isEmpty() || password.isEmpty()) {
m_errorMessage = "please complete both fields";
m_error = true;
emit statusChanged();
return;
}
}
This operation is also more logical than && as you wrote in your comment because usually you need to supply both email and password. Basically the condition will meet if either of those meets. That means if any of the input fields kept empty, you will raise the error which seems a reasonable behavior.
Something along these lines:
if (list.isEmpty() && password.isEmpty())
I'm not sure why you are "splitting" the email. If it's just an email address used for login purposes, you should be able to do email.isEmpty() rather than using the regexp splitting.

How to use Google Translate API With c++

I'm a beginner in C++ and using Google task API.
How do I write a C++ program that accepts a word, then invokes Google Translate to translate it from English to French, then saves the resulted page to a local file?
For example, if the user inputs "river", the program should invoke Google Translate to translate into French, the resulting page is:
http://translate.google.com/#en|fr|River%0A
This page should be saved.
I read the official documentation through fully: http://code.google.com/apis/language/translate/v2/getting_started.html
but I couldn't understand how to using REST and I'm not familiar with JSON or AJAX.
You cannot use JSON objects straight in C++.
JSON = JavaScript Object Notation
You need to spawn/create something which can parse such objects. For example I've used QNetworkManager in Qt (in C++) to send build javascript and send requests to google APIs. The result would be a JSON object which I had to parse and either display in a browser (which I made in c++) or parse the results into a c++ class and process it differently (do some calculations with it).
If you just need the data, you can request XML instead of JSON and then you can use a standard XML parser to extract the translated word.
EDIT 1:
Google in their example uses:
https://www.googleapis.com/language/translate/v2?key=YOUR-API-KEY&source=en&target=de&q=words+to+translate
This translate from english (en) to german (de). The words to translate are: "words to translate".
Now build an HTTP request in C++ with this URL as the data. Send that with some network manager or sockets and wait for a reply back. Google will give you back data.
I seen this codes below somewhere but I don't remember where, anyway try this:
QString YourClass::translate(QString keyword, QString from, QString to)
{
//Translate URL
QString url = QString("http://translate.google.com/translate_a/t?client=t&text=%0&hl=%1&sl=%2&tl=%1&multires=1&prev=enter&oc=2&ssel=0&tsel=0&uptl=%1&sc=1").arg(keyword).arg(to).arg(from);
QNetworkAccessManager manager;
QNetworkRequest request(url);
QNetworkReply *reply = manager.get(request);
//Get reply from Google
do {
QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
} while(!reply->isFinished());
//Convert to string
QString translation(reply->readAll());
reply->close();
//Free memory
delete reply;
//Remove [[[" from the beginning
translation = translation.replace("[[[\"", "");
//Extract final translated string
translation = translation.mid(0, translation.indexOf(",\"") - 1);
return translation;
}
someone advise me to use libcurl, I will try and see.
You need some kind of HTTP library. I second most of what Adrian said, but here's some (incomplete) Qt code which should give you an idea.
namespace {
const QString API_KEY = /* TODO */;
}
MyQObject :: MyQbject ()
: m_manager (new QNetworkAccessManager (this))
{
connect(manager, SIGNAL (finished (QNetworkReply *)),
this, SLOT (reply_finished (QNetworkReply *)));
}
void MyQObject :: fetch_translation (
QString words,
void (*on_receive)(const QString &))
{
// Let's assume asynchronous but non-concurrent requests.
m_on_receive = on_receive;
QString request =
"https://www.googleapis.com/language/translate/v2"
"?key=%1&source=en&target=de&q=%2";
// May want to url-encode 'words' first.
m_manager -> get (QUrl (request .arg (API_KEY) .arg (words));
}
void MyQObject :: reply_finished (QNetworkReply * reply)
{
m_on_receive (reply -> readAll ());
}
// ...
{
my_q_object -> translate ("hello, world", [](const QString & s) {
qWarning () << "translation is: " << s;
});
}

How do I read headers from a QNetworkReply

How can one read headers for example a cookie out of a QNetworkReply?
I just thought to add to the above answer concerning rawHeader
QList<QByteArray> headerList = reply->rawHeaderList();
foreach(QByteArray head, headerList) {
qDebug() << head << ":" << reply->rawHeader(head);
}
Consulting the documentation, there are a few methods related to reading headers: header, rawHeader, rawHeaderList, and rawHeaderPairs. For the specific case of getting a cookie, you can use the header method. It would look something like this:
QNetworkReply *reply;
// somehow give reply a value
QVariant cookieVar = reply.header(QNetworkRequest::CookieHeader);
if (cookieVar.isValid()) {
QList<QNetworkCookie> cookies = cookieVar.value<QList<QNetworkCookie> >();
foreach (QNetworkCookie cookie, cookies) {
// do whatever you want here
}
}
The header method only works for certain HTTP headers, though. In the general case, if there is no QNetworkRequest::KnownHeaders value for the header you want, the rawHeader method is probably the way to go.
I have tried the answer of Evan Shaw, but there is a little mistake.
The QNetworkRequest::CookieHeader need change to QNetworkRequest::SetCookieHeader. Because I found it is Set-Cookie in the header of QNetworkReply other than Cookie.
QNetworkReply *reply;
// somehow give reply a value
QVariant cookieVar = reply.header(QNetworkRequest::SetCookieHeader);
if (cookieVar.isValid()) {
QList<QNetworkCookie> cookies = cookieVar.value<QList<QNetworkCookie> >();
foreach (QNetworkCookie cookie, cookies) {
// do whatever you want here
}
}