QString doSanitizeKeyword(const QString &keyword) { QString allowed = QString(ALLOWED_SYMBOLS); int start = 0; int length = keyword.length(); QChar c; while (start < length) { c = keyword.at(start); if (c.isLetterOrNumber() || allowed.contains(c) || c.category() == QChar::Symbol_Currency) { break; } else { start++; } } int end = length - 1; while (end >= 0) { c = keyword.at(end); if (c.isLetterOrNumber() || allowed.contains(c) || c.category() == QChar::Symbol_Currency) { break; } else { end--; } } QString result; if (start <= end) { result = keyword.mid(start, end - start + 1).simplified(); } return result; }
Word Filter::nextWord() const { QChar currentChar = skipToLetter( m_currentPosition ); if ( m_currentPosition >= m_buffer.length() ) { return Filter::end(); } bool allUppercase = currentChar.category() & QChar::Letter_Uppercase; bool runTogether = false; QString foundWord; int start = m_currentPosition; while ( currentChar.isLetter() ) { if ( currentChar.category() & QChar::Letter_Lowercase ) allUppercase = false; /* FIXME: this does not work for Hebrew for example //we consider run-together words as mixed-case words if ( !allUppercase && currentChar.category() & QChar::Letter_Uppercase ) runTogether = true; */ foundWord += currentChar; ++m_currentPosition; currentChar = m_buffer[ m_currentPosition ]; } if ( shouldBeSkipped( allUppercase, runTogether, foundWord ) ) return nextWord(); return Word( foundWord, start ); }
static bool isIdentifierPart(QChar ch) { // fast path for ascii if ((ch.unicode() >= 'a' && ch.unicode() <= 'z') || (ch.unicode() >= 'A' && ch.unicode() <= 'Z') || (ch.unicode() >= '0' && ch.unicode() <= '9') || ch == '$' || ch == '_' || ch.unicode() == 0x200c /* ZWNJ */ || ch.unicode() == 0x200d /* ZWJ */) return true; switch (ch.category()) { case QChar::Mark_NonSpacing: case QChar::Mark_SpacingCombining: case QChar::Number_DecimalDigit: case QChar::Number_Letter: case QChar::Letter_Uppercase: case QChar::Letter_Lowercase: case QChar::Letter_Titlecase: case QChar::Letter_Modifier: case QChar::Letter_Other: case QChar::Punctuation_Connector: return true; default: break; } return false; }
void searchTargetFromScreen(QEditor *editor, const QChar &target) { m_targetPos.clear(); if (editor == NULL) { return; } m_currentGroup = 0; m_targetChar = target; QTextDocument *doc = editor->document(); int cursorPos = editor->textCursor().position(); QPair<int, int> visibleRange = getFirstAndLastVisiblePosition(editor); int firstPos = visibleRange.first; int lastPos = visibleRange.second; bool notCaseSensative = target.category() != QChar::Letter_Uppercase; for (int offset = 1; cursorPos - offset >= firstPos || cursorPos + offset <= lastPos; offset++) { if (cursorPos + offset <= lastPos) { QChar c = doc->characterAt(cursorPos + offset); if (notCaseSensative) { c = c.toLower(); } if (c == target) { m_targetPos << (cursorPos + offset); } } if (cursorPos - offset >= firstPos) { QChar c = doc->characterAt(cursorPos - offset); if (notCaseSensative) { c = c.toLower(); } if (c == target) { m_targetPos << (cursorPos - offset); } } } }
int KNewPasswordWidget::KNewPasswordWidgetPrivate::effectivePasswordLength(const QString &password) { enum Category { Digit, Upper, Vowel, Consonant, Special }; Category previousCategory = Vowel; QString vowels(QStringLiteral("aeiou")); int count = 0; for (int i = 0; i < password.length(); ++i) { QChar currentChar = password.at(i); if (!password.leftRef(i).contains(currentChar)) { Category currentCategory; switch (currentChar.category()) { case QChar::Letter_Uppercase: currentCategory = Upper; break; case QChar::Letter_Lowercase: if (vowels.contains(currentChar)) { currentCategory = Vowel; } else { currentCategory = Consonant; } break; case QChar::Number_DecimalDigit: currentCategory = Digit; break; default: currentCategory = Special; break; } switch (currentCategory) { case Vowel: if (previousCategory != Consonant) { ++count; } break; case Consonant: if (previousCategory != Vowel) { ++count; } break; default: if (previousCategory != currentCategory) { ++count; } break; } previousCategory = currentCategory; } } return count; }
static void formatCharacter(QTextStream &str, const QChar &qc, FormattingContext &context) { const ushort unicode = qc.unicode(); str << "U+" << qSetFieldWidth(4) << qSetPadChar('0') << uppercasedigits << hex << unicode << dec << qSetFieldWidth(0) << ' '; const EnumLookup *specialChar = enumLookup(unicode, specialCharactersEnumLookup, sizeof(specialCharactersEnumLookup) / sizeof(EnumLookup)); if (specialChar) str << specialChar->description; else str << "'" << qc << '\''; const int category = qc.category(); if (category != context.category) { str << " category=" << enumName(category, categoryEnumLookup, sizeof(categoryEnumLookup) / sizeof(EnumLookup)); context.category = category; } #if QT_VERSION >= 0x050100 const int script = qc.script(); if (script != context.script) { str << " script=" << enumName(script, scriptEnumLookup, sizeof(scriptEnumLookup) / sizeof(EnumLookup)) << '(' << script << ')'; context.script = script; } #endif // Qt 5 const int direction = qc.direction(); if (direction != context.direction) { str << " direction=" << enumName(direction, directionEnumLookup, sizeof(directionEnumLookup) / sizeof(EnumLookup)); context.direction = direction; } #if QT_VERSION >= 0x050000 const int joiningType = qc.joiningType(); if (joiningType != context.joiningType) { str << " joiningType=" << enumName(joiningType, joiningTypeEnumLookup, sizeof(joiningTypeEnumLookup) / sizeof(EnumLookup)); context.joiningType = joiningType; } #endif // Qt 5QWidget const int decompositionTag = qc.decompositionTag(); if (decompositionTag != context.decompositionTag) { str << " decomposition=" << enumName(decompositionTag, decompositionEnumLookup, sizeof(decompositionEnumLookup) / sizeof(EnumLookup)); context.decompositionTag = decompositionTag; } const int unicodeVersion = qc.unicodeVersion(); if (unicodeVersion != context.unicodeVersion) { str << " version=" << enumName(unicodeVersion, unicodeVersionEnumLookup, sizeof(unicodeVersionEnumLookup) / sizeof(EnumLookup)); context.unicodeVersion = unicodeVersion; } }
QString Private::Converter::toPortablePath(const QString &path) const { if (path.isEmpty() || m_baseDir.path().isEmpty()) return path; #ifdef Q_OS_WIN if (QDir::isAbsolutePath(path)) { QChar driveLeter = path[0].toUpper(); QChar baseDriveLetter = m_baseDir.path()[0].toUpper(); bool onSameDrive = (driveLeter.category() == QChar::Letter_Uppercase) && (driveLeter == baseDriveLetter); if (!onSameDrive) return path; } #endif return m_baseDir.relativeFilePath(path); }
bool isValidKeyword(const QString &keyword) { bool isValid = false; int length = keyword.length(); if (2 <= length && length < 30) { isValid = true; } if (length == 1) { QChar symbol = keyword.at(0); if (symbol.isLetterOrNumber() || QString(ALLOWED_SYMBOLS).contains(symbol) || symbol.category() == QChar::Symbol_Currency) { isValid = true; } } return isValid; }
static inline bool isIdentifierStart(QChar ch) { // fast path for ascii if ((ch.unicode() >= 'a' && ch.unicode() <= 'z') || (ch.unicode() >= 'A' && ch.unicode() <= 'Z') || ch == '$' || ch == '_') return true; switch (ch.category()) { case QChar::Number_Letter: case QChar::Letter_Uppercase: case QChar::Letter_Lowercase: case QChar::Letter_Titlecase: case QChar::Letter_Modifier: case QChar::Letter_Other: return true; default: break; } return false; }
Token* Tokenizer::getToken() { int startRow = row; int startCol = col; QChar c = getChar(); // get and store the next character from the string // catch the end of the input string if (atEnd) return new Token(Token::EndOfInput, "END", row, col, row, col); int cType = translator->look2type(c); // since we need to know it often we store it // catch spaces if (isSpace(c)) { QString look; do { look += (isTab(c) ? " " : " "); c = getChar(); } while (isSpace(c) && !atEnd); ungetChar(); return new Token(Token::WhiteSpace, look, startRow, startCol, row, col); } // catch EndOfLine's if (isBreak(c)) { return new Token(Token::EndOfLine, "\\n", startRow, startCol, startRow+1, 1); } // catch comments if (cType == Token::Comment) { QString look; do { look += c; c = getChar(); } while (!isBreak(c) && !atEnd); ungetChar(); return new Token(Token::Comment, look, startRow, startCol, row, col); } // catch strings if (cType == Token::StringDelimiter) { QString look = QString(c); do { c = getChar(); look += c; } while (!(translator->look2type(c) == Token::StringDelimiter && look.right(2) != "\\\"") && !isBreak(c) && !atEnd); return new Token(Token::String, look, startRow, startCol, row, col); } // catch variables if (cType == Token::VariablePrefix) { QString look; do { look += c; c = getChar(); } while (isWordChar(c) || c.category() == QChar::Number_DecimalDigit || c == '_'); ungetChar(); return new Token(Token::Variable, look, startRow, startCol, row, col); } // catch words (known commands or function calls) if (isWordChar(c)) { // first char has to be a letter QString look; do { look += c; c = getChar(); } while (isWordChar(c) || c.isDigit() || c == '_'); // next chars ungetChar(); int type = translator->look2type(look); if (type == Token::Unknown) type = Token::FunctionCall; return new Token(type, look, startRow, startCol, row, col); } // catch numbers if (c.isDigit() || cType == Token::DecimalSeparator) { bool hasDot = false; int localType = cType; QString look; do { if (localType == Token::DecimalSeparator) hasDot = true; look += c; c = getChar(); localType = translator->look2type(c); } while (c.isDigit() || (localType == Token::DecimalSeparator && !hasDot)); ungetChar(); // if all we got is a dot then this is not a number, so return an Error token here if (translator->look2type(look) == Token::DecimalSeparator) return new Token(Token::Error, look, startRow, startCol, row, col); return new Token(Token::Number, look, startRow, startCol, row, col); } // catch previously uncatched 'double charactered tokens' (tokens that ar not in letters, like: == != >= <=) { QString look = QString(c).append(getChar()); int type = translator->look2type(look); if (type != Token::Unknown) return new Token(type, look, startRow, startCol, row, col); ungetChar(); } // catch known tokens of a single character (as last...) if (cType != Token::Unknown) return new Token(cType, static_cast<QString>(c), startRow, startCol, row, col); // this does not neglect calls to functions with a name of length one (checked it) return new Token(Token::Error, static_cast<QString>(c), startRow, startCol, row, col); }
bool Tokenizer::isSpace(const QChar& c) { return (c.category() == QChar::Separator_Space || c == ' ' || isTab(c)); }
/** * \sa format() * \sa setFormat(const QString&) */ QString AbstractStringAppender::formattedString(const QDateTime& timeStamp, Logger::LogLevel logLevel, const char* file, int line, const char* function, const QString& category, const QString& message) const { QString f = format(); const int size = f.size(); QString result; int i = 0; while (i < f.size()) { QChar c = f.at(i); // We will silently ignore the broken % marker at the end of string if (c != QLatin1Char(formattingMarker) || (i + 2) >= size) { result.append(c); } else { i += 2; QChar currentChar = f.at(i); QString command; int fieldWidth = 0; if (currentChar.isLetter()) { command.append(currentChar); int j = 1; while ((i + j) < size && f.at(i + j).isLetter()) { command.append(f.at(i+j)); j++; } i+=j; currentChar = f.at(i); // Check for the padding instruction if (currentChar == QLatin1Char(':')) { currentChar = f.at(++i); if (currentChar.isDigit() || currentChar.category() == QChar::Punctuation_Dash) { int j = 1; while ((i + j) < size && f.at(i + j).isDigit()) j++; fieldWidth = f.mid(i, j).toInt(); i += j; } } } // Log record chunk to insert instead of formatting instruction QString chunk; // Time stamp if (command == QLatin1String("time")) { if (f.at(i + 1) == QLatin1Char('{')) { int j = 1; while ((i + 2 + j) < size && f.at(i + 2 + j) != QLatin1Char('}')) j++; if ((i + 2 + j) < size) { chunk = timeStamp.toString(f.mid(i + 2, j)); i += j; i += 2; } } if (chunk.isNull()) chunk = timeStamp.toString(QLatin1String("HH:mm:ss.zzz")); } // Log level else if (command == QLatin1String("type")) chunk = Logger::levelToString(logLevel); // Uppercased log level else if (command == QLatin1String("Type")) chunk = Logger::levelToString(logLevel).toUpper(); // One letter log level else if (command == QLatin1String("typeOne")) chunk = Logger::levelToString(logLevel).left(1).toLower(); // One uppercase letter log level else if (command == QLatin1String("TypeOne")) chunk = Logger::levelToString(logLevel).left(1).toUpper(); // Filename else if (command == QLatin1String("File")) chunk = QLatin1String(file); // Filename without a path else if (command == QLatin1String("file")) chunk = QString(QLatin1String(file)).section('/', -1); // Source line number else if (command == QLatin1String("line")) chunk = QString::number(line); // Function name, as returned by Q_FUNC_INFO else if (command == QLatin1String("Function")) chunk = QString::fromLatin1(function); // Stripped function name else if (command == QLatin1String("function")) chunk = stripFunctionName(function); // Log message else if (command == QLatin1String("message")) chunk = message; else if (command == QLatin1String("category")) chunk = category; // Application pid else if (command == QLatin1String("pid")) chunk = QString::number(QCoreApplication::applicationPid()); // Appplication name else if (command == QLatin1String("appname")) chunk = QCoreApplication::applicationName(); // Thread ID (duplicates Qt5 threadid debbuging way) else if (command == QLatin1String("threadid")) chunk = QLatin1String("0x") + QString::number(qlonglong(QThread::currentThread()->currentThread()), 16); // We simply replace the double formatting marker (%) with one else if (command == QString(formattingMarker)) chunk = QLatin1Char(formattingMarker); // Do not process any unknown commands else { chunk = QString(formattingMarker); chunk.append(command); } result.append(QString(QLatin1String("%1")).arg(chunk, fieldWidth)); } ++i; } return result; }
void Font::drawText(QPainter *p, int x, int y, QChar *str, int slen, int pos, int len, int toAdd, QPainter::TextDirection d, int from, int to, QColor bg, int uy, int h, int deco) const { if(!str) return; QConstString cstr = QConstString(str, slen); QString qstr = cstr.string(); // ### fixme for RTL if(!scFont && !letterSpacing && !wordSpacing && !toAdd && from == -1) { // simply draw it // Due to some unfounded cause QPainter::drawText traverses the // *whole* string when painting, not only the specified // [pos, pos + len) segment. This makes painting *extremely* slow for // long render texts (in the order of several megabytes). // Hence, only hand over the piece of text of the actual inline text box QConstString cstr = QConstString(str + pos, len); p->drawText(x, y, cstr.string(), 0, len, d); } else { if(from < 0) from = 0; if(to < 0) to = len; int numSpaces = 0; if(toAdd) { for(int i = 0; i < len; ++i) if(str[i + pos].category() == QChar::Separator_Space) ++numSpaces; } const int totWidth = width(str, slen, pos, len); if(d == QPainter::RTL) { x += totWidth + toAdd; } QString upper = qstr; QFontMetrics sc_fm = fm; if(scFont) { // draw in small caps upper = qstr.upper(); sc_fm = QFontMetrics(*scFont); } // ### sc could be optimized by only painting uppercase letters extra, // and treat the rest WordWise, but I think it's not worth it. // Somebody else may volunteer, and implement this ;-) (LS) // The mode determines whether the text is displayed character by // character, word by word, or as a whole enum { CharacterWise, WordWise, Whole } mode = Whole; if(!letterSpacing && !scFont && (wordSpacing || toAdd > 0)) mode = WordWise; else if(letterSpacing || scFont) mode = CharacterWise; if(mode == Whole) { // most likely variant is treated extra if(to < 0) to = len; const QConstString cstr(str + pos, len); const QConstString segStr(str + pos + from, to - from); const int preSegmentWidth = fm.width(cstr.string(), from); const int segmentWidth = fm.width(segStr.string()); const int eff_x = d == QPainter::RTL ? x - preSegmentWidth - segmentWidth : x + preSegmentWidth; // draw whole string segment, with optional background if(bg.isValid()) p->fillRect(eff_x, uy, segmentWidth, h, bg); p->drawText(eff_x, y, segStr.string(), -1, d); if(deco) drawDecoration(p, eff_x, uy, y - uy, segmentWidth - 1, h, deco); return; } // We are using two passes. In the first pass, the widths are collected, // and stored. In the second, the actual characters are drawn. // For each letter in the text box, save the width of the character. // When word-wise, only the first letter contains the width, but of the // whole word. short *const widthList = (short *)alloca(to * sizeof(short)); // First pass: gather widths int preSegmentWidth = 0; int segmentWidth = 0; int lastWordBegin = 0; bool onSegment = from == 0; for(int i = 0; i < to; ++i) { if(i == from) { // Also close words on visibility boundary if(mode == WordWise) { const int width = closeWordAndGetWidth(fm, str, pos, lastWordBegin, i); if(lastWordBegin < i) { widthList[lastWordBegin] = (short)width; lastWordBegin = i; preSegmentWidth += width; } } onSegment = true; } const QChar ch = str[pos + i]; bool lowercase = (ch.category() == QChar::Letter_Lowercase); bool is_space = (ch.category() == QChar::Separator_Space); int chw = 0; if(letterSpacing) chw += letterSpacing; if((wordSpacing || toAdd) && is_space) { if(mode == WordWise) { const int width = closeWordAndGetWidth(fm, str, pos, lastWordBegin, i); if(lastWordBegin < i) { widthList[lastWordBegin] = (short)width; lastWordBegin = i; (onSegment ? segmentWidth : preSegmentWidth) += width; } ++lastWordBegin; // ignore this space } chw += wordSpacing; if(numSpaces) { const int a = toAdd / numSpaces; chw += a; toAdd -= a; --numSpaces; } } if(is_space || mode == CharacterWise) { chw += lowercase ? sc_fm.charWidth(upper, pos + i) : fm.charWidth(qstr, pos + i); widthList[i] = (short)chw; (onSegment ? segmentWidth : preSegmentWidth) += chw; } } // close last word Q_ASSERT(onSegment); if(mode == WordWise) { const int width = closeWordAndGetWidth(fm, str, pos, lastWordBegin, to); segmentWidth += width; widthList[lastWordBegin] = (short)width; } if(d == QPainter::RTL) x -= preSegmentWidth; else x += preSegmentWidth; const int startx = d == QPainter::RTL ? x - segmentWidth : x; // optionally draw background if(bg.isValid()) p->fillRect(startx, uy, segmentWidth, h, bg); // second pass: do the actual drawing lastWordBegin = from; for(int i = from; i < to; ++i) { const QChar ch = str[pos + i]; bool lowercase = (ch.category() == QChar::Letter_Lowercase); bool is_space = ch.category() == QChar::Separator_Space; if(is_space) { if(mode == WordWise) { closeAndDrawWord(p, d, x, y, widthList, str, pos, lastWordBegin, i); ++lastWordBegin; // jump over space } } if(is_space || mode == CharacterWise) { const int chw = widthList[i]; if(d == QPainter::RTL) x -= chw; if(scFont) p->setFont(lowercase ? *scFont : f); p->drawText(x, y, (lowercase ? upper : qstr), pos + i, 1, d); if(d != QPainter::RTL) x += chw; } } // don't forget to draw last word if(mode == WordWise) { closeAndDrawWord(p, d, x, y, widthList, str, pos, lastWordBegin, to); } if(deco) drawDecoration(p, startx, uy, y - uy, segmentWidth - 1, h, deco); if(scFont) p->setFont(f); } }
static bool isEndOfWordChar(const QChar &c) { return !c.isLetterOrNumber() && c.category() != QChar::Punctuation_Connector; }
void Main_GUI::check_number_set() { QString text = snapping_line->text(); QString qs; // construct ASCII string from arbitrary Unicode data; // the idea is to accept, say, CJK fullwidth digits also for (int i = 0; i < text.size(); i++) { QChar c = text.at(i); int digit = c.digitValue(); if (digit >= 0) qs += QString::number(digit); else if (c.isSpace()) qs += ' '; // U+30FC KATAGANA-HIRAGANA PROLONGED SOUND MARK is assigned // to the `-' key in some Japanese input methods else if (c.category() == QChar::Punctuation_Dash || c == QChar(0x30FC)) qs += '-'; // various Unicode COMMA characters, // including representation forms else if (c == QChar(',') || c == QChar(0x055D) || c == QChar(0x060C) || c == QChar(0x07F8) || c == QChar(0x1363) || c == QChar(0x1802) || c == QChar(0x1808) || c == QChar(0x3001) || c == QChar(0xA4FE) || c == QChar(0xA60D) || c == QChar(0xA6F5) || c == QChar(0xFE10) || c == QChar(0xFE11) || c == QChar(0xFE50) || c == QChar(0xFE51) || c == QChar(0xFF0C) || c == QChar(0xFF64)) qs += ','; else qs += c; // we do error handling below } if (x_height_snapping_exceptions) number_set_free(x_height_snapping_exceptions); QByteArray str = qs.toLocal8Bit(); const char* s = number_set_parse(str.constData(), &x_height_snapping_exceptions, 6, 0x7FFF); if (s && *s) { statusBar()->setStyleSheet("color: red;"); if (x_height_snapping_exceptions == NUMBERSET_ALLOCATION_ERROR) statusBar()->showMessage( tr("allocation error")); else if (x_height_snapping_exceptions == NUMBERSET_INVALID_CHARACTER) statusBar()->showMessage( tr("invalid character (use digits, dashes, commas, and spaces)")); else if (x_height_snapping_exceptions == NUMBERSET_OVERFLOW) statusBar()->showMessage( tr("overflow")); else if (x_height_snapping_exceptions == NUMBERSET_INVALID_RANGE) statusBar()->showMessage( tr("invalid range (minimum is 6, maximum is 32767)")); else if (x_height_snapping_exceptions == NUMBERSET_OVERLAPPING_RANGES) statusBar()->showMessage( tr("overlapping ranges")); else if (x_height_snapping_exceptions == NUMBERSET_NOT_ASCENDING) statusBar()->showMessage( tr("values und ranges must be specified in ascending order")); snapping_line->setText(qs); snapping_line->setFocus(Qt::OtherFocusReason); snapping_line->setCursorPosition(s - str.constData()); x_height_snapping_exceptions = NULL; } else { // normalize if there is no error char* new_str = number_set_show(x_height_snapping_exceptions, 6, 0x7FFF); snapping_line->setText(new_str); free(new_str); } }
static inline bool isSentenceSeparator(const QChar &character) { return character.isMark() || character.isPunct() || character.category() == QChar::Separator_Paragraph; }