When does `QKeySequence::match()` return `QKeySequence::PartialMatch`? - qt

What sequences partially match?
I thought 1 partially matches Ctrl+1, but it doesn't.

Taken from the source code,
QKeySequence::SequenceMatch QKeySequence::matches(const QKeySequence &seq) const {
uint userN = count(),
seqN = seq.count();
if (userN > seqN)
return NoMatch;
// If equal in length, we have a potential ExactMatch sequence,
// else we already know it can only be partial.
SequenceMatch match = (userN == seqN ? ExactMatch : PartialMatch);
for (uint i = 0; i < userN; ++i) {
QKeyCombination userKey = (*this)[i],
sequenceKey = seq[i];
if (userKey != sequenceKey)
return NoMatch;
}
return match;
}
It seems that,
The compared sequence has to be longer than the source
The compared sequence has to start with the source
So if you have,
#include "mainwindow.h"
#include <QApplication>
#include <QDebug>
#include <QKeySequence>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QKeySequence ks_1{Qt::CTRL, Qt::Key_X, Qt::Key_Y};
QKeySequence ks_2{Qt::CTRL};
QKeySequence ks_3{Qt::CTRL, Qt::Key_X};
QKeySequence ks_4{Qt::CTRL, Qt::Key_X, Qt::Key_Y};
QKeySequence ks_5{Qt::CTRL, Qt::Key_X, Qt::Key_Y, Qt::Key_Z};
qDebug() << ks_1.count() << ks_2.count() << ks_1.matches(ks_2);
qDebug() << ks_1.count() << ks_3.count() << ks_1.matches(ks_3);
qDebug() << ks_1.count() << ks_4.count() << ks_1.matches(ks_4);
qDebug() << ks_1.count() << ks_5.count() << ks_1.matches(ks_5);
return a.exec();
}
ks_4 would be an exact match, and ks_5 would be a partial match.
Note that the length is acquired using count(), which from the source is:
int QKeySequence::count() const
{
return int(std::distance(d->key, std::find(d->key, d->key + QKeySequencePrivate::MaxKeyCount, 0)));
}
So if the previous example is declared as:
QKeySequence ks_1{Qt::CTRL + Qt::Key_X + Qt::Key_Y};
QKeySequence ks_2{Qt::CTRL};
QKeySequence ks_3{Qt::CTRL + Qt::Key_X};
QKeySequence ks_4{Qt::CTRL + Qt::Key_X + Qt::Key_Y};
QKeySequence ks_5{Qt::CTRL + Qt::Key_X + Qt::Key_Y + Qt::Key_Z};
All will be no match, since count() returns 1 for all cases above.

Related

Converting std::vector from BYTE to int

Code:
using ColumnIndexVector = std::vector<int>;
using ByteVector = std::vector<BYTE>;
void CCreateReportDlg::GetColumnIndexesToExclude()
{
const CString strSection = theApp.GetActiveScheduleSection(_T("Options"));
ByteVector vData = theApp.GetProfileVector(strSection, _T("AssignStatesEx"));
ColumnIndexVector vTemp(vData.begin(), vData.end()); // This converts BYTE to int
m_vColumnIndexesToExclude = vTemp;
}
Is there any way to avoid the requirement for vTemp without manually iterating vData and casting from BYTE to int?
Yes, just use assign(). IDK if you need to use clear() as well, but probably not. Just step through the runtime code the first time to know.
m_vColumnIndexesToExclude.assign(vData.begin(), vData.end());
Here's a test program:
#include <windows.h>
#include <iostream>
#include <vector>
using namespace std;
using ColumnIndexVector = std::vector<int>;
using ByteVector = std::vector<BYTE>;
int main(int argc, char* argv[])
{
cout << "Test" << endl;
ByteVector bytes = {'A', 'B', 'C', 'D'};
ColumnIndexVector colVector;
for ( auto _val: bytes)
{
cout << _val << endl;
}
colVector.assign(bytes.begin(), bytes.end());
for ( auto _val : colVector)
{
cout << _val << endl;
}
return 0;
}

Equality operator for QFlags with scoped enum

I have some flags defined as follows, using a scoped enum:
enum class Capability : int
{
NoCapabilities = 0,
SomethingCool = 1,
UberCool = 1 << 1,
EvenCooler = 1 << 2,
};
Q_DECLARE_FLAGS( Capabilities, Capability )
Now, I am trying to use the equality operator:
Capabilities(DataCapability::NoCapabilities) == Capability::NoCapabilities
I cannot use testFlag in the current example, since NoCapabilities = 0. This works if the enum is not scoped (removing class keyword).
Apparently, casting to int (static_cast<int>(NoCapabilities)) works, but it's really ugly.
What is the approach to solve this?
Is it a bad practice to have a 0 zero value and test it?
You can overload equality operator for your combination of data types. However cast ist still necessary but hidden by operator.
#include <QCoreApplication>
#include <QFlags>
#include <iostream>
enum class Capability : int
{
NoCapabilities = 0,
SomethingCool = 1,
UberCool = (1 << 1),
EvenCooler = (1 << 2),
};
Q_DECLARE_FLAGS(Capabilities, Capability)
template <typename T>
bool operator==(const QFlags<T> lhs, const Capability rhs)
{
return (QFlags<T>::Int(lhs) == static_cast<int>(rhs));
}
int main(int argc, char *argv[])
{
Q_UNUSED(argc);
Q_UNUSED(argv);
if (Capabilities(Capability::NoCapabilities) == Capability::NoCapabilities)
{
std::cout << "true" << std::endl;
}
else
{
std::cout << "false" << std::endl;
}
if (Capabilities(Capability::EvenCooler) == Capability::NoCapabilities)
{
std::cout << "true" << std::endl;
}
else
{
std::cout << "false" << std::endl;
}
return 0;
}

Qt5: compile error while QSharedPointer<const T>::create()

Is it "expected" for QSharedPointer::create() not to work or is it a bug? I get an error:
/usr/include/qt5/QtCore/qsharedpointer_impl.h:439:9: error:
invalid conversion from ‘const void*’ to ‘void*’ [-fpermissive]
new (result.data()) T(std::forward<Args>(arguments)...);
casting from nonconst shared pointer and constructor from raw const pointer work.
I got this for Qt5.7.0 and Qt5.10.0.
Here is a minimal example:
#include <QSharedPointer>
struct A {};
int main(int argc, char *argv[])
{
auto ca = QSharedPointer<const A>::create();
return 0;
}
Here is one file (not minimal) example but with few working cases, 2 not working and a debug. Commented defines are for "not compiling" parts.
#include <QSharedPointer>
#include <QDebug>
#define FROM_PTR
//#define CONST_CREATE
#define FROM_RAW_PTR
#define PERFECT_FORWARD_CREATE
//#define PERFECT_FORWARD_CREATE_CONST
#define BUILTIN_CAST
class A
{
public:
A() = default;
A(int i) : _i{i} {}
void foo() const { qDebug() << "const foo" << _i; }
void foo() { qDebug() << "foo" << ++_i; }
private:
int _i{0};
};
using ASPtr = QSharedPointer<A>;
using ASCPtr = QSharedPointer<const A>;
int main(int argc, char *argv[])
{
Q_UNUSED(argc)
Q_UNUSED(argv)
#ifdef FROM_PTR
qDebug() << "FROM_PTR";
auto a1 = ASPtr::create();
a1->foo();
auto ca1 = static_cast<ASCPtr>(a1);
ca1->foo();
qDebug() << "\n";
#endif // FROM_PTR
#ifdef CONST_CREATE
qDebug() << "CONST_CREATE";
auto ca2 = ASCPtr::create();
ca2->foo();
qDebug() << "\n";
#endif // CONST_CREATE
#ifdef FROM_RAW_PTR
qDebug() << "FROM_RAW_PTR";
auto ca3 = ASCPtr(new const A);
ca3->foo();
qDebug() << "\n";
#endif // FROM_RAW_PTR
#ifdef PERFECT_FORWARD_CREATE
qDebug() << "PERFECT_FORWARD_CREATE";
auto a2 = ASPtr::create(10);
a2->foo();
qDebug() << "\n";
#endif // PERFECT_FORWARD_CREATE
#ifdef PERFECT_FORWARD_CREATE_CONST
qDebug() << "PERFECT_FORWARD_CREATE_CONST";
auto ca4 = ASCPtr::create(20);
ca4->foo();
qDebug() << "\n";
#endif // PERFECT_FORWARD_CREATE
#ifdef BUILTIN_CAST
qDebug() << "BUILTIN_CAST";
QSharedPointer<A> a3 = ASPtr::create();
a3->foo();
auto ca4 = a3.constCast<const A>();
ca4->foo();
qDebug() << "\n";
#endif // BUILTIN_CAST
return 0;
}
That is a known Qt bug (QTBUG-49748). Although it is marked as resolved in Qt 5.6.0, the bug is still present as pointed out in the comments.
Why is this happening?
Look at the implmentation of the class QSharedPointer qsharedpointer_impl.h.
In particular the line:
new (result.data()) T(std::forward<Args>(arguments)...);
uses the result.data() as the new expression placement params. Unfortunately, one can not use a const pointer as a placement param (have a look at this question here on SO for more details).
Hence, there's not much you can do except reporting this to Qt developers via the official bug tracker.
You may have a look at the smart pointers provided by the standard library (e.g. std::shared_ptr) if you are not forced to use Qt ones.
UPDATE
As reported in Qt bug tracker, this bug was fixed in version 5.11 (here is the related commit). Basically, they used std::remove_cv to remove the topmost const from the type specified.

QVariant with custom class pointer does not return same address

I need to assign a pointer to a custom class in qml using QQmlContext::setContextProperty(). Another qml object has Q_PROPERTY of the same type to retrieve it again.
A simple test showed me that the conversion does not work like i thought.
#include <QCoreApplication>
#include <QDebug>
#include <QMetaType>
class TestClass
{
public: TestClass() { qDebug() << "TestClass()::TestClass()"; }
};
Q_DECLARE_METATYPE(TestClass*)
int main(int argc, char *argv[])
{
QCoreApplication app(argc, argv);
qDebug() << "metaTypeId =" << qMetaTypeId<TestClass*>();
auto testObject = new TestClass;
QVariant variant(qMetaTypeId<TestClass*>(), testObject);
auto test = variant.value<TestClass*>();
qDebug() << testObject << variant << test;
return 0;
}
This tiny test application gives me an output like this:
metaTypeId = 1024
TestClass::TestClass()
0x1b801e0 QVariant(TestClass*, ) 0x0
I would really like to get the same pointer out again after converting it down to a QVariant. Later I will assign it to a qml context and then the conversation must work correctly.
This works for me using Qt 5.9:
#include <QVariant>
#include <QDebug>
class CustomClass
{
public:
CustomClass()
{
}
};
Q_DECLARE_METATYPE(CustomClass*)
class OtherClass
{
public:
OtherClass()
{
}
};
Q_DECLARE_METATYPE(OtherClass*)
int main()
{
CustomClass *c = new CustomClass;
OtherClass *o = new OtherClass;
QVariant v;
v.setValue(c);
QVariant v2;
v2.setValue(o);
qDebug() << v.userType() << qMetaTypeId<CustomClass*>() << v2.userType() << qMetaTypeId<OtherClass*>();
qDebug() << v.value<CustomClass*>() << c << v2.value<OtherClass*>() << o;
return 0;
}
And the output i got:
1024 1024 1025 1025
0x81fca50 0x81fca50 0x81fca60 0x81fca60
As #thuga mentioned in the comments, you need to use void* and static_cast along with QVariant::fromValue.
#include <QCoreApplication>
#include <QDebug>
#include <QMetaType>
class TestClass
{
public: TestClass() { qDebug() << "TestClass()::TestClass()"; }
};
Q_DECLARE_METATYPE(TestClass*)
int main(int argc, char *argv[])
{
QCoreApplication app(argc, argv);
qDebug() << "metaTypeId =" << qMetaTypeId<TestClass*>();
auto testObject = new TestClass;
QVariant variant(QVariant::fromValue(static_cast<void*>(testObject)));
auto test = static_cast<TestClass*>(variant.value<void*>());
qDebug() << testObject << variant << test;
return 0;
}

QT QString from QDataStream

I'm working with a buffer and I'm trying to get a string from it, but isnt working...
Example:
*void myFunc(QDataStream& in)
{
quint8 v;
in >> v;
// Ok, I caught v value successfuly
QString s;
in >> s;
// Didnt work :<
}*
The string lenght is stored on 2 first bytes...
Thanks
If the string was not written as a QString, you need to read its length and content separately.
quint8 v;
in >> v;
quint16 length = 0;
in >> length;
// the string is probably utf8 or latin
QByteArray buffer(length, Qt::Uninitialized);
in.readRawData(buffer.data(), length);
QString string(buffer);
You might have to change the endianness of the QDataStream with QDataStream::setByteOrder before reading the 16-bit length.
We should really see the writing code and how you create the QDataStream. I tried with the following sample, and in this case your function works very well:
#include <QCoreApplication>
#include <QDebug>
#include <QDataStream>
#include <QBuffer>
void myFunc(QDataStream& in)
{
quint8 v;
in >> v;
qDebug() << v;
// Ok, I caught v value successfuly
QString s;
in >> s;
qDebug() << s;
// Didnt work :<
}
int main(int argc, char ** argv) {
QCoreApplication a(argc, argv);
QBuffer buffer;
buffer.open(QBuffer::ReadWrite);
// write test data into the buffer
QDataStream out(&buffer);
quint8 ival = 42;
QString sval = "Qt";
out << ival;
out << sval;
// read back data
buffer.seek(0);
myFunc(out);
return a.exec();
}
Output when executed:
$ ./App
42
"Qt"

Resources