Re: Ip Address Validation
I realize this wins me necro-poster of the year, but I felt that this information would be beneficial to a lot of people.
The IP Address Validation (by Regex) and Mask issue was a tough cookie to crack. Setting one without the other usually worked but was flawed. I'd either not get the visual effect of having dots in the box or the user could enter invalid addresses (octets with values >255). Setting them together made it impossible to enter any value.
I found that the Class provided by Wysota solved the problem, but there was another limitation: it required you to use blanks as 0's, when I would prefer to use spaces.
Side-Note: I know a lot of people are looking for a good IP Address RegEx and here's the best one I've found so far:
Code:
\b(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\b
What I ended up doing was expanding the code that Wysota provided to allow for spaces. Here is the excerpt:
Code:
if (slist[i].isEmpty() || slist[i] == " ") {
emptyGroup = true;
continue;
}
Now that fully works with a Mask of "000.000.000.000; " and your users cannot physically enter an invalid address.
Yay! That is settled. Now for my next problem. My specific programming needs also include being able to enter in a CIDR, which has a Mask of "009.009.009.009\/09". The first part of that works just like IP Addresses and the last part is limited to integers of 0-32.
To accomplish this, I duplicated Wysota's IP Address class to CIDRValidator. Here is the full code (tested and works):
Code:
public:
void fixup
(QString &/*input*/) const { } State validate
(QString &input,
int &/*pos*/) const { if(input.isEmpty()) { return Acceptable; }
int s = slist.size();
if (s > 4) { return Invalid; }
bool emptyGroup = false;
for (int i=0; i<s; i++) {
bool ok, ok2 = true;
if (slist[i].isEmpty()
|| slist[i] == " "
|| ssplit.count() > 1 && (ssplit[0] == " " || ssplit[1] == " "))
{
emptyGroup = true;
continue;
}
int val = (ssplit.count() > 1 ? ssplit[0].toInt(&ok) : slist[i].toInt(&ok));
int cidval = (ssplit.count() > 1 ? ssplit[1].toInt(&ok2) : -1);
if((!ok || val<0 || val>255) || (ssplit.count() > 1 && (!ok2 || cidval<0 || cidval>32))) { return Invalid; }
}
if(s<4 || emptyGroup) return Intermediate;
return Acceptable;
}
};
I hope this information helps future searchers with setting up their own IP Address and CIDR Address boxes.
Re: Ip Address Validation
With * support class C and D
class IPV4Validator : public QValidator {
public:
IPV4Validator(QObject *parent=0) : QValidator(parent){}
State validate ( QString & input, int & pos ) const {
if(input.isEmpty()) return Intermediate;
QStringList sections = input.split(".");
if(sections.count()>4)
return Invalid;
int newPos = pos;
int grp = 0;
bool isEmpty = false;
while(grp<sections.count()){
QString txt = sections[grp];
if(txt.count()>3){
if(sections.count()==4) return Invalid;
sections[grp] = txt.left(3);
sections.insert(grp+1, txt.mid(3));
newPos++;
} else if(txt.count()==0){
isEmpty = true;
grp++;
continue;
}
txt = sections[grp];
if(txt[0]=='0' && txt[1]=='0'){
sections[grp] = '0';
if(sections.count()<4){
sections.insert(grp+1, sections[grp]);
newPos++;
}
} else if(txt[0]=='0' && txt.count()>1){
sections[grp] = txt.mid(1);
newPos--;
}
bool ok;
int val = txt.toInt(&ok);
if(!ok)
{
if(grp < 2)
return Invalid;
if(txt != "*")
return Invalid;
}
if(val>255 && sections.count()<4){
sections[grp] = txt.left(2);
sections.insert(grp+1, txt.mid(2));
val = txt.left(2).toInt();
newPos++;
}
if(val>255||val<0) return Invalid;
grp++;
}
input = sections.join(".");
// if(newPos==input.count() && sections.count()<4 && input[input.count()-1]!='.' && sections.last().count()==3){
// newPos++;
// input += ".";
// }
pos = newPos;
if(sections.count()==4 && !isEmpty) return Acceptable;
return Intermediate;
}
};
Re: Ip Address Validation
Hey everyone,
Thanks for all the great help.
I've written some code based on Wysota's work in the previous post. I am implementing the QValidator::fixup() to do some simple alignment and checking of integer checking (The only case when a non integer can be entered is such as "a b", this must be intermediate). The problem is that fixup gets called twice if I press <Enter> to commit the changes to the QLineEdit - displaying two error pop ups. It gets called through two separate events, a keyPressEvent and a focusOutEvent. fixup() is called the second time before it has finished running the first time.
Code:
void IP4Validator
::fixup(QString &input
) const {
bool intOk;
bool nonIntFound = false;
int s = slist.size();
for(int i=0;i<s;i++){
slist[i].toInt(&intOk);
if(!intOk){
// replace non-integers with a zero value
slist[i] = " 0";
nonIntFound = true;
}
else {
// force right align
slist[i].remove(" ");
slist[i] = slist[i].rightJustified(3,' ');
}
}
input = slist.join(".");
if(nonIntFound){
msgBox.setText("Error: The IPv4 address entered is incorrect");
msgBox.setInformativeText("At least one byte of the address was non-integer, it has now been set to 0. Please check the address");
msgBox.exec();
}
}
IP4Validator
::State IP4Validator
::validate(QString &input,
int &/*pos*/) const { if(input.isEmpty()) return Acceptable;
int s = slist.size();
if(s>4) return Invalid;
bool emptyGroup = false;
bool ok;
for(int i=0;i<s;i++){
// This cannot be true with the inputMask set, as there will be space characters
if(slist[i].isEmpty()){
emptyGroup = true;
continue;
}
int val = slist[i].toInt(&ok);
if(!ok)
return Intermediate;
else
if(val<0 || val>255)
return Invalid;
}
if(s<4 || emptyGroup) return Intermediate;
input = slist.join(".");
return Acceptable;
}
I considered accessing the type() of the event which called fixup() to filter it but I'm not sure if this is the best way to get around this. Is there something more fundamental with my logic that I have missed here?
What is the best way to handle this?
Thanks in advance for your help!
- Cotlone
Re: Ip Address Validation
IMO fixup() should not display any pop-ups. It should convert an invalid entry to a valid one. If you want to display a popup, you can handle focusOut()/returnPressed()/whatever, call the validator from there manually and display a popup if the validator claims the entry to be invalid.
Re: Ip Address Validation
I agree, actually, I was thinking that earlier today.
What do you think about fixup() emitting a signal which can be handled elsewhere? Thanks for your help.
Re: Ip Address Validation
Quote:
Originally Posted by
Cotlone
What do you think about fixup() emitting a signal which can be handled elsewhere?
Bad idea. You never know when fixup() might be called and if it started emitting signals in arbitrary moments, it might not be what your users expect.
Re: Ip Address Validation
Ok, good. It did seem a little like bad practise to me.
Looks like I'll be learning about events now then :)