QML Textinput inputmask with multiple mask guards - qt

Is there a way to make TextInput inputMask guard multiple conditions? For example:
inputMask: ("9999" || "9999-9999") // syntax probably wrong
Accepted inputs:
1234
1234-3456
Edit: the right hand side input (xxxx-rhs) would also have to be greater than the left hand side.

The validate implementation is probably not the most efficient or readable, but it does the job. Have a look at this GitHub repository custom validator.
QValidator::State SpecialValidator::validate(QString &input, int &pos) const
{
if (input.isEmpty())
return QValidator::Acceptable;
static QRegularExpression expression("^\\d{0,4}$");
QRegularExpressionMatch expressionMatch = expression.match(input);
if (expressionMatch.hasMatch()) {
if (expressionMatch.captured(0).size() != 4)
return QValidator::Intermediate;
return QValidator::Acceptable;
}
static QRegularExpression advancedExpression("^(\\d{4})-(\\d{0,4})$");
QRegularExpressionMatch advancedExpressionMatch = advancedExpression.match(input);
if (advancedExpressionMatch.hasMatch()) {
QString lhs = advancedExpressionMatch.captured(1);
const QString rhs = advancedExpressionMatch.captured(2);
if (rhs.isEmpty())
return QValidator::Intermediate;
if (rhs.size() == 4)
return lhs.toInt() < rhs.toInt() ? QValidator::Acceptable : QValidator::Invalid;
lhs.truncate(rhs.size());
return lhs.toInt() <= rhs.toInt() ? QValidator::Intermediate : QValidator::Invalid;
}
return QValidator::Invalid;
}

Related

Overloading == and !== when object is a pointer

I am new to writing operators (in this case == and !=). I have done a bit of research and so far came up with:
bool operator==(const SPECIAL_EVENT_S &rsEvent)
{
bool bSame = false;
if (rsEvent.datEvent == m_datSpecialEvent &&
rsEvent.strEvent == m_strNotes &&
rsEvent.strLocation == m_strLocation &&
rsEvent.datEventStartTime == m_datEventStartTime &&
rsEvent.datEventFinishTime == m_datEventFinishTime &&
gsl::narrow<bool>(rsEvent.bEventAllDay) == m_bEventAllDay &&
gsl::narrow<bool>(rsEvent.bSetReminder) == m_bSetReminder &&
rsEvent.iReminderUnitType == m_iReminderUnitType &&
rsEvent.iReminderInterval == m_iReminderInterval &&
rsEvent.iImageWidthPercent == m_wImageWidthPercent &&
rsEvent.strImagePath == m_strImagePath &&
rsEvent.strTextBeforeImage == m_strTextBeforeImage &&
rsEvent.strTextAfterImage == m_strTextAfterImage &&
rsEvent.eType == m_eVideoconfType &&
rsEvent.sBSSTI == m_sBSSTI)
{
// The fundamental information is unchanged
bSame = true;
}
// Now compare the MWB Event Type
if (bSame)
{
switch (rsEvent.eMWBEventType)
{
case EventTypeMWB::MWBBethelSpeakerServiceTalk:
return m_bSpecialEventBethelServiceTalk;
case EventTypeMWB::MWBVideoconferenceAssembly:
return m_bSpecialEventVideoconf && m_eVideoconfType == VideoConferenceEventType::Live;
case EventTypeMWB::MWBVideoconferenceConvention:
return m_bSpecialEventVideoconf && m_eVideoconfType == VideoConferenceEventType::Recorded;
case EventTypeMWB::MWBSpecialEvent:
return m_bSpecialEvent;
case EventTypeMWB::MWBMemorial:
return m_bEventMemorial;
case EventTypeMWB::MWBCircuitOverseerMeeting:
return m_bCircuitVisit || m_bCircuitVisitGroup;
case EventTypeMWB::MWBMeeting:
return !m_bNoMeeting;
default:
bSame = false;
}
}
return bSame;
}
bool operator!=(const SPECIAL_EVENT_S& rsEvent)
{
return !(rsEvent == *this);
}
What surprised me what when I then tried to use these operators:
if (pEntry != sEvent)
{
AfxMessageBox(_T("The special event information has changed"));
}
It does not like pEntry being a pointer. In the end I did this:
if (*pEntry != sEvent)
{
AfxMessageBox(_T("The special event information has changed"));
}
Why was this an issue in the first place? I ask that because if this was a standard function it would not matter if the object was a pointer or not.
What is the correct way to cater for this scenario?
For example:
object->Function(value)
object.Function(value)
Function can be used both by the object when it is / is not a pointer. So why not with an operator?
Function can be used both by the object when it is / is not a pointer.
Actually, no it can't. In a statement/expression like object->Function(value) the -> (member access) and () (function call) operators have the same precedence and left-to-right associativity. So, the -> is applied first and that automatically dereferences the pointer. So, the effect is the same as (*object).Function(value) – and Function is still being called on an object, rather than on a pointer.
So why not with an operator?
The syntax for calling an operator function is (or can be) rather different: because it is defined as an operator, you can call it using the operator token (between the two operands) rather than by using an explicit function call. But then, you have to pass objects, as that's what the operands are defined to be.
However, should you really want to, you can still call an operator override using explicit function-call syntax; and, in that case, you can use the -> on a pointer; like this (where operator== is effectively the 'name' of the function):
if (!pEntry->operator==(sEvent))
{
AfxMessageBox(_T("The special event information has changed"));
}
However, this seems like a lot of hard work and your *pEntry != sEvent is actually the 'correct' way to use the override.
PS: As bonus, if you're using a compiler that supports the C++20 (or later) Standard, you can add a "defaulted" operator== to your structures/classes, which would save you explicitly comparing each individual data member:
struct foo {
int a;
double b;
bool operator==(const foo&) const = default; // Compares "a" and "b"
};
struct bar {
foo f;
int c;
int d;
bool operator==(const bar&) const = default; // Compares "c", "d" and "f"
};

How can I determine if an Array is readonly using TS compiler-api?

I'd like to determine if an array type is readonly. This includes ReadonlyArray and readonly prefixed.
Examples:
type a = ReadonlyArray<string>
type b = readonly string[]
The relevant non-exposed TypeChecker code is:
let globalReadonlyArrayType = <GenericType>getGlobalTypeOrUndefined("ReadonlyArray" as __String, /*arity*/ 1) || globalArrayType;
function isReadonlyArrayType(type: Type): boolean {
return !!(getObjectFlags(type) & ObjectFlags.Reference) && (<TypeReference>type).target === globalReadonlyArrayType;
}
function getGlobalTypeOrUndefined(name: __String, arity = 0): ObjectType | undefined {
const symbol = getGlobalSymbol(name, SymbolFlags.Type, /*diagnostic*/ undefined);
return symbol && <GenericType>getTypeOfGlobalSymbol(symbol, arity);
}
function getTypeOfGlobalSymbol(symbol: Symbol | undefined, arity: number): ObjectType {
function getTypeDeclaration(symbol: Symbol): Declaration | undefined {
const declarations = symbol.declarations;
for (const declaration of declarations) {
switch (declaration.kind) {
case SyntaxKind.ClassDeclaration:
case SyntaxKind.InterfaceDeclaration:
case SyntaxKind.EnumDeclaration:
return declaration;
}
}
}
if (!symbol) {
return arity ? emptyGenericType : emptyObjectType;
}
const type = getDeclaredTypeOfSymbol(symbol);
if (!(type.flags & TypeFlags.Object)) {
error(getTypeDeclaration(symbol), Diagnostics.Global_type_0_must_be_a_class_or_interface_type, symbolName(symbol));
return arity ? emptyGenericType : emptyObjectType;
}
if (length((<InterfaceType>type).typeParameters) !== arity) {
error(getTypeDeclaration(symbol), Diagnostics.Global_type_0_must_have_1_type_parameter_s, symbolName(symbol), arity);
return arity ? emptyGenericType : emptyObjectType;
}
return <ObjectType>type;
}
TypeChecker Method
cspotcode pointed out that you can get IndexInfo via the TypeChecker.
const isReadonlyArrayType = (type: Type) =>
type.checker.isArrayLikeType(type) &&
!!type.checker.getIndexInfoOfType(type, IndexKind.Number)?.isReadonly
TS Compiler Method
The following matches the compiler's logic.
let globalReadonlyArrayType: Type;
export const isReadonlyArrayType = (type: Type): boolean => {
const { checker } = type;
if (!globalReadonlyArrayType) {
const symbol =
checker.resolveName('ReadonlyArray', /* location */ void 0, SymbolFlags.Type, /* excludeGlobals */ false)!;
globalReadonlyArrayType = checker.getDeclaredTypeOfSymbol(symbol);
}
return !!((type as ObjectType).objectFlags & ObjectFlags.Reference) &&
((<TypeReference>type).target === globalReadonlyArrayType);
};
Notes
It appears that there may be no immediate advantage of the TypeChecker method over using the Compiler method. The one concern that I had was that comparing target equality may fail if ReadonlyArray was extended, but it appears that this is currently not possible with TypeScript (v3.9.3)
Logic-wise, if performing isArrayLikeType first, the TypeChecker method would be performing a little more work, but likely not enough to worry about in terms of performance.
With that said, it seems that there may be advantage in the TypeChecker method over the second in the event that TS changes its readonly logic, allows extension of ReadonlyArray, etc.
For that reason, I'd recommend using the TypeChecker method.
If you're not using byots, you could probably replace the call to isArrayLikeType with !!((type as ObjectType).objectFlags & ObjectFlags.Reference)
Caveat: My understanding of ReadonlyArray is at a basic level, as of writing this, so if I'm wrong on any of this, please let me know!

What tools in Qt are there to decode HTML 4 entities?

I have an input QString that has HTML 4 entities, like õ that I’d like to decode. But I can’t find any facilities in Qt to do so. Is there a way to do so in Qt? If possible I’d like to avoid QTextDocument so I don’t have to bring in QtGui.
The HTML 4 entities are listed in this link:
https://www.w3schools.com/charsets/ref_html_entities_4.asp
Out of curiosity, I have looked a bit around.
I found this SO: How can i convert entity character(Escape character) to HTML in QT?. However, it uses QTextDocument (which is part of GUI) what OP wants to prevent.
The doc. of QTextDocument::setHtml() doesn't mention anything specific whether something is used which could be accessed directly (and is even part of the Qt core). Hence, I had a look into source code. I started with QTextDocument::setHtml() on woboq.org and followed the bread crumbs.
Finally, I ended up in qtbase/src/gui/text/qtexthtmlparser.cpp:
QString QTextHtmlParser::parseEntity()
{
const int recover = pos;
int entityLen = 0;
QStringRef entity;
while (pos < len) {
QChar c = txt.at(pos++);
if (c.isSpace() || pos - recover > 9) {
goto error;
}
if (c == QLatin1Char(';'))
break;
++entityLen;
}
if (entityLen) {
entity = QStringRef(&txt, recover, entityLen);
QChar resolved = resolveEntity(entity);
if (!resolved.isNull())
return QString(resolved);
if (entityLen > 1 && entity.at(0) == QLatin1Char('#')) {
entity = entity.mid(1); // removing leading #
int base = 10;
bool ok = false;
if (entity.at(0).toLower() == QLatin1Char('x')) { // hex entity?
entity = entity.mid(1);
base = 16;
}
uint uc = entity.toUInt(&ok, base);
if (ok) {
if (uc >= 0x80 && uc < 0x80 + (sizeof(windowsLatin1ExtendedCharacters)/sizeof(windowsLatin1ExtendedCharacters[0])))
uc = windowsLatin1ExtendedCharacters[uc - 0x80];
QString str;
if (QChar::requiresSurrogates(uc)) {
str += QChar(QChar::highSurrogate(uc));
str += QChar(QChar::lowSurrogate(uc));
} else {
str = QChar(uc);
}
return str;
}
}
}
error:
pos = recover;
return QLatin1String("&");
}
A table of named entities can be found in the same source file:
static const struct QTextHtmlEntity { const char name[9]; quint16 code; } entities[]= {
{ "AElig", 0x00c6 },
{ "AMP", 38 },
...
{ "zwj", 0x200d },
{ "zwnj", 0x200c }
};
Q_STATIC_ASSERT(MAX_ENTITY == sizeof entities / sizeof *entities);
These are bad news for OP:
The API of the QTextHtmlParser is private:
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists purely as an
// implementation detail. This header file may change from version to
// version without notice, or even be removed.
//
// We mean it.
//
and it's part of Qt GUI.
If OP insists to prevent GUI dependencies, the only other chance I see is to duplicate the code (or just to re-implement it from scratch).

Find greater and lower keys in a BTreeSet in a single search

I would like to be able to find keys in a Rust BTreeSet that are strictly lower and greater than a specified key.
For example, given the set { "1", "3" }, and the search key is "2" then the answer should be ("1", "3"). In the cases either where either lower or greater value does not exist None should be returned.
I can achieve the result that I am looking for by calling the range() method on the BTreeSet twice.
Is there is a way to do this using a single search, like there is in C++? C++'s std::set has a bi-directional iterator:
// $CXX -std=c++17 less-than.c++ -o less-than && ./less-than
#include <cassert>
#include <optional>
#include <set>
#include <string>
#include <iostream>
using std::optional;
using std::pair;
using std::set;
using std::string;
pair<optional<string>, optional<string>> bounding_box(
const set<string>& space,
const string& point)
{
if (space.empty()) { return {}; }
optional<string> gt_bound;
optional<string> lt_bound;
const auto ge_bound_it = space.lower_bound(point);
if (ge_bound_it != space.end()) {
if (*ge_bound_it == point) {
// lower_bound returned an equal point, use the next one
// if it exists
const auto gt_bound_it = std::next(ge_bound_it, 1);
if (gt_bound_it != space.end()) {
gt_bound = *gt_bound_it;
}
} else {
gt_bound = *ge_bound_it;
}
}
if (ge_bound_it != space.begin()) {
lt_bound = *std::next(ge_bound_it, -1);
}
return {lt_bound, gt_bound};
}
int main() {
{
const auto box = bounding_box({"1", "3"}, "2");
assert(box.first);
assert(*box.first == "1");
assert(box.second);
assert(*box.second == "3");
}
{
const auto box = bounding_box({"1", "3"}, "4");
assert(box.first);
assert(*box.first == "3");
assert(!box.second);
}
{
const auto box = bounding_box({"1", "3"}, "0");
assert(!box.first);
assert(box.second);
assert(*box.second == "1");
}
{
const auto box = bounding_box({"3", "3"}, "3");
assert(!box.first);
assert(!box.second);
}
{
const auto box = bounding_box({"3", "4"}, "3");
assert(!box.first);
assert(box.second);
assert(*box.second == "4");
}
{
const auto box = bounding_box({}, "3");
assert(!box.first);
assert(!box.second);
}
}
The search method is a bit of a hot spot and I wonder if there is an idiomatic way to do this in Rust.
No, there is no way to do this in a single search; you need to call range twice.
There have been discussions about enhancing BTreeMap / BTreeSet to have a "cursor" API. Recently, a pull request was opened to do so, but it was closed because it was deemed that there should be more discussion about how such an API should look and work.
Perhaps you will be the one to spearhead the discussion about such an API?
See also:
How to get the lower bound and upper bound of an element in Rust BTreeSet?
There is not a cursor API in Rust, as said in Shepmaster's answer. You can sometimes simulate it when your iterator implements DoubleEndedIterator with next() and next_back().
However, if I understand well what you are trying to do, you do not need this stuff because a set is ordered. You can write your code by going through each pair and stop when the second item is greater than your "point":
use std::collections::BTreeSet;
fn find_bounds<'a>(set: &'a BTreeSet<&str>, point: &str) -> (Option<&'a str>, Option<&'a str>) {
let mut it = set.iter();
let mut lower = match it.next() {
None => return (None, None),
Some(s) if *s > point => return (None, Some(s)),
Some(s) => s,
};
while let Some(upper) = it.next() {
if *upper > point {
return (Some(lower), Some(*upper));
}
lower = upper;
}
(Some(lower), None)
}
#[test]
fn tests() {
let mut s = BTreeSet::new();
s.insert("a");
s.insert("c");
s.insert("t");
s.insert("g");
assert_eq!(find_bounds(&s, "f"), (Some("c"), Some("g")));
assert_eq!(find_bounds(&s, "z"), (Some("t"), None));
assert_eq!(find_bounds(&s, " "), (None, Some("a")));
}
The code is not well written, but it works.

How to ignore key press events that don't output characters

I'm developing a virtual musical keyboard that allows you to press keys on your keyboard and have it play notes. So in my MainWindow class I have reimplemented keyPressEvent. I would like to ignore events generated by modifiers (Control, Alt, Shift, etc.), as well as events generated by other non-character keys such as Tab, Backspace, and Enter. Something like this would be ideal:
void MainWindow::keyPressEvent(QKeyEvent *event)
{
if (!event->key().isCharacter()))
{
event->ignore();
return;
}
// handle the event
}
Is there a way to do something like that (short of testing every possible non-character key individually)? If not, is there at least a way to easily ignore the event if it is a modifier?
Looks like you want QKeyEvent::text().
The accepted answer is unfortunately incomplete. If you press Ctrl+C, then QKeyEvent::text() will return "\x03" (^C "End of Text").
That is not an empty string.
I decided to look inside the Qt source code, since they need to handle this problem for QLineEdit as well:
In QLineEdit::keyPressEvent:
d->control->processKeyEvent(event);
src/widgets/widgets/qlineedit.cpp:1742
In QWidgetLineControl::processKeyEvent:
if (unknown
&& !isReadOnly()
&& isAcceptableInput(event)) {
insert(event->text());
src/widgets/widgets/qwidgetlinecontrol.cpp:1912
In QInputControl::isAcceptableInput:
bool QInputControl::isAcceptableInput(const QKeyEvent *event) const
{
const QString text = event->text();
if (text.isEmpty())
return false;
const QChar c = text.at(0);
// Formatting characters such as ZWNJ, ZWJ, RLM, etc. This needs to go before the
// next test, since CTRL+SHIFT is sometimes used to input it on Windows.
if (c.category() == QChar::Other_Format)
return true;
// QTBUG-35734: ignore Ctrl/Ctrl+Shift; accept only AltGr (Alt+Ctrl) on German keyboards
if (event->modifiers() == Qt::ControlModifier
|| event->modifiers() == (Qt::ShiftModifier | Qt::ControlModifier)) {
return false;
}
if (c.isPrint())
return true;
if (c.category() == QChar::Other_PrivateUse)
return true;
if (c.isHighSurrogate() && text.size() > 1 && text.at(1).isLowSurrogate())
return true;
if (m_type == TextEdit && c == u'\t')
return true;
return false;
}
src/gui/text/qinputcontrol.cpp:21
This is exactly what you need but you may want to change the check for \t and ignore that as well.

Resources