From 22ff3df15cc3143e6410b02f39b967d1d76cf2d6 Mon Sep 17 00:00:00 2001 From: Alan Alpert Date: Tue, 7 Jul 2009 17:37:43 +1000 Subject: Manual cherrypick of QLineControl from kinetic-declarativeui-qfxlineedit Splits out the control logic of QLineEdit into QLineControl, which is somewhat similar to QTextEdit. This was originally worked on in the ianws-qt-lineedit-textedit-research repository, and then further developed in kinetic in the kinetic-declarativeui-qfxlineedit branch. Note that this also includes a tiny change to qvalidator.h which allows validators to be used in qml. --- src/gui/widgets/qlinecontrol.cpp | 1707 ++++++++++++++++++++++++++++++++ src/gui/widgets/qlinecontrol_p.h | 715 ++++++++++++++ src/gui/widgets/qlinecontrol_p_p.h | 105 ++ src/gui/widgets/qlineedit.cpp | 1885 ++++-------------------------------- src/gui/widgets/qlineedit.h | 2 + src/gui/widgets/qlineedit_p.cpp | 253 +++++ src/gui/widgets/qlineedit_p.h | 174 +--- src/gui/widgets/qvalidator.h | 6 +- src/gui/widgets/widgets.pri | 3 + 9 files changed, 3010 insertions(+), 1840 deletions(-) create mode 100644 src/gui/widgets/qlinecontrol.cpp create mode 100644 src/gui/widgets/qlinecontrol_p.h create mode 100644 src/gui/widgets/qlinecontrol_p_p.h create mode 100644 src/gui/widgets/qlineedit_p.cpp diff --git a/src/gui/widgets/qlinecontrol.cpp b/src/gui/widgets/qlinecontrol.cpp new file mode 100644 index 0000000..b762a00 --- /dev/null +++ b/src/gui/widgets/qlinecontrol.cpp @@ -0,0 +1,1707 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qlinecontrol_p.h" + +#ifndef QT_NO_LINEEDIT + +#include "qabstractitemview.h" +#include "qclipboard.h" +#ifndef QT_NO_ACCESSIBILITY +#include "qaccessible.h" +#endif +#ifndef QT_NO_IM +#include "qinputcontext.h" +#include "qlist.h" +#endif +#include "qapplication.h" +#ifndef QT_NO_GRAPHICSVIEW +#include "qgraphicssceneevent.h" +#endif + +QT_BEGIN_NAMESPACE + +/* + Updates the display text based of the current edit text + If the text has changed will emit displayTextChanged() +*/ +void QLineControl::updateDisplayText() +{ + QString orig = textLayout.text(); + QString str; + if (m_echoMode == QLineEdit::NoEcho) + str = QString::fromLatin1(""); + else + str = m_text; + + if (m_echoMode == QLineEdit::Password || (m_echoMode == QLineEdit::PasswordEchoOnEdit + && !m_passwordEchoEditing)) + str.fill(m_passwordCharacter); + + // replace certain non-printable characters with spaces (to avoid + // drawing boxes when using fonts that don't have glyphs for such + // characters) + QChar* uc = str.data(); + for (int i = 0; i < (int)str.length(); ++i) { + if ((uc[i] < 0x20 && uc[i] != 0x09) + || uc[i] == QChar::LineSeparator + || uc[i] == QChar::ParagraphSeparator + || uc[i] == QChar::ObjectReplacementCharacter) + uc[i] = QChar(0x0020); + } + + textLayout.setText(str); + + QTextOption option; + option.setTextDirection(m_layoutDirection); + option.setFlags(QTextOption::IncludeTrailingSpaces); + textLayout.setTextOption(option); + + textLayout.beginLayout(); + QTextLine l = textLayout.createLine(); + textLayout.endLayout(); + m_ascent = qRound(l.ascent()); + + if (str != orig) + emit displayTextChanged(str); +} + +#ifndef QT_NO_CLIPBOARD +/* + Copies the currently selected text into the clipboard using the given + \a mode. + + \note If the echo mode is set to a mode other than Normal then copy + will not work. This is to prevent using copy as a method of bypassing + password features of the line control. +*/ +void QLineControl::copy(QClipboard::Mode mode) const +{ + QString t = selectedText(); + if (!t.isEmpty() && m_echoMode == QLineEdit::Normal) { + disconnect(QApplication::clipboard(), SIGNAL(selectionChanged()), this, 0); + QApplication::clipboard()->setText(t, mode); + connect(QApplication::clipboard(), SIGNAL(selectionChanged()), + this, SLOT(_q_clipboardChanged())); + } +} + +/* + Inserts the text stored in the application clipboard into the line + control. + + \sa insert() +*/ +void QLineControl::paste() +{ + insert(QApplication::clipboard()->text(QClipboard::Clipboard)); +} + +#endif // !QT_NO_CLIPBOARD + +/* + Handles the behavior for the backspace key or function. + Removes the current selection if there is a selection, otherwise + removes the character prior to the cursor position. + + \sa del() +*/ +void QLineControl::backspace() +{ + int priorState = undoState; + if (hasSelectedText()) { + removeSelectedText(); + } else if (m_cursor) { + --m_cursor; + if (maskData) + m_cursor = prevMaskBlank(m_cursor); + QChar uc = m_text.at(m_cursor); + if (m_cursor > 0 && uc.unicode() >= 0xdc00 && uc.unicode() < 0xe000) { + // second half of a surrogate, check if we have the first half as well, + // if yes delete both at once + uc = m_text.at(m_cursor - 1); + if (uc.unicode() >= 0xd800 && uc.unicode() < 0xdc00) { + p_del(true); + --m_cursor; + } + } + p_del(true); + } + finishChange(priorState); +} + +/* + Handles the behavior for the delete key or function. + Removes the current selection if there is a selection, otherwise + removes the character after the cursor position. + + \sa del() +*/ +void QLineControl::del() +{ + int priorState = undoState; + if (hasSelectedText()) { + removeSelectedText(); + } else { + int n = textLayout.nextCursorPosition(m_cursor) - m_cursor; + while (n--) + p_del(); + } + finishChange(priorState); +} + +/* + Inserts the given \a newText at the current cursor position. + If there is any selected text it is removed prior to insertion of + the new text. +*/ +void QLineControl::insert(const QString &newText) +{ + int priorState = undoState; + removeSelectedText(); + p_insert(newText); + finishChange(priorState); +} + +/* + Clears the line control text. +*/ +void QLineControl::clear() +{ + int priorState = undoState; + selstart = 0; + selend = m_text.length(); + removeSelectedText(); + separate(); + finishChange(priorState, /*update*/false, /*edited*/false); +} + +/* + Sets \a length characters from the given \a start position as selected. + The given \a start position must be within the current text for + the line control. If \a length characters cannot be selected, then + the selection will extend to the end of the current text. +*/ +void QLineControl::setSelection(int start, int length) +{ + Q_ASSERT_X(start >= 0 && start <= (int)m_text.length(), + "QLineControl::setSelection", "Invalid start position"); + + if (length > 0) { + selstart = start; + selend = qMin(start + length, (int)m_text.length()); + m_cursor = selend; + } else { + selstart = qMax(start + length, 0); + selend = start; + m_cursor = selstart; + } +} + +void QLineControl::_q_clipboardChanged() +{ +} + +void QLineControl::_q_deleteSelected() +{ + if (!hasSelectedText()) + return; + + int priorState = undoState; + emit resetInputContext(); + removeSelectedText(); + separate(); + finishChange(priorState); +} + +/* + Initializes the line control with a starting text value of \a txt. +*/ +void QLineControl::init(const QString& txt) +{ + m_text = txt; + updateDisplayText(); + m_cursor = m_text.length(); +} + +/* + Sets the password echo editing to \a editing. If password echo editing + is true, then the text of the password is displayed even if the echo + mode is set to QLineEdit::PasswordEchoOnEdit. Password echoing editing + does not affect other echo modes. +*/ +void QLineControl::updatePasswordEchoEditing(bool editing) +{ + m_passwordEchoEditing = editing; + updateDisplayText(); +} + +/* + Returns the cursor position of the given \a x pixel value in relation + to the displayed text. The given \a betweenOrOn specified what kind + of cursor position is requested. +*/ +int QLineControl::xToPos(int x, QTextLine::CursorPosition betweenOrOn) const +{ + return textLayout.lineAt(0).xToCursor(x, betweenOrOn); +} + +/* + Returns the bounds of the current cursor, as defined as a + between characters cursor. +*/ +QRect QLineControl::cursorRect() const +{ + QTextLine l = textLayout.lineAt(0); + int c = m_cursor; + if (m_preeditCursor != -1) + c += m_preeditCursor; + int cix = qRound(l.cursorToX(c)); + int w = m_cursorWidth; + int ch = l.height() + 1; + + return QRect(cix-5, 0, w+9, ch); +} + +/* + Fixes the current text so that it is valid given any set validators. + + Returns true if the text was changed. Otherwise returns false. +*/ +bool QLineControl::fixup() // this function assumes that validate currently returns != Acceptable +{ +#ifndef QT_NO_VALIDATOR + if (m_validator) { + QString textCopy = m_text; + int cursorCopy = m_cursor; + m_validator->fixup(textCopy); + if (m_validator->validate(textCopy, cursorCopy) == QValidator::Acceptable) { + if (textCopy != m_text || cursorCopy != m_cursor) + p_setText(textCopy, cursorCopy); + return true; + } + } +#endif + return false; +} + +/* + Moves the cursor to the given position \a pos. If \a mark is true will + adjust the currently selected text. +*/ +void QLineControl::moveCursor(int pos, bool mark) +{ + if (pos != m_cursor) { + separate(); + if (maskData) + pos = pos > m_cursor ? nextMaskBlank(pos) : prevMaskBlank(pos); + } + if (mark) { + int anchor; + if (selend > selstart && m_cursor == selstart) + anchor = selend; + else if (selend > selstart && m_cursor == selend) + anchor = selstart; + else + anchor = m_cursor; + selstart = qMin(anchor, pos); + selend = qMax(anchor, pos); + updateDisplayText(); + } else { + p_deselect(); + } + m_cursor = pos; + if (mark || selDirty) { + selDirty = false; + emit selectionChanged(); + } + emitCursorPositionChanged(); +} + +/* + Applies the given input method event \a event to the text of the line + control +*/ +void QLineControl::processInputMethodEvent(QInputMethodEvent *event) +{ + int priorState = undoState; + removeSelectedText(); + + int c = m_cursor; // cursor position after insertion of commit string + if (event->replacementStart() <= 0) + c += event->commitString().length() + qMin(-event->replacementStart(), event->replacementLength()); + + m_cursor += event->replacementStart(); + + // insert commit string + if (event->replacementLength()) { + selstart = m_cursor; + selend = selstart + event->replacementLength(); + removeSelectedText(); + } + if (!event->commitString().isEmpty()) + insert(event->commitString()); + + m_cursor = qMin(c, m_text.length()); + + setPreeditArea(m_cursor, event->preeditString()); + m_preeditCursor = event->preeditString().length(); + hideCursor = false; + QList formats; + for (int i = 0; i < event->attributes().size(); ++i) { + const QInputMethodEvent::Attribute &a = event->attributes().at(i); + if (a.type == QInputMethodEvent::Cursor) { + m_preeditCursor = a.start; + hideCursor = !a.length; + } else if (a.type == QInputMethodEvent::TextFormat) { + QTextCharFormat f = qvariant_cast(a.value).toCharFormat(); + if (f.isValid()) { + QTextLayout::FormatRange o; + o.start = a.start + m_cursor; + o.length = a.length; + o.format = f; + formats.append(o); + } + } + } + textLayout.setAdditionalFormats(formats); + updateDisplayText(); + if (!event->commitString().isEmpty()) + emitCursorPositionChanged(); + finishChange(priorState); +} + +/* + Draws the display text for the line control using the given + \a painter, \a clip, and \a offset. Which aspects of the display text + are drawn is specified by the given \a flags. + + If the flags contain DrawSelections, then the selection or input mask + backgrounds and foregrounds will be applied before drawing the text. + + If the flags contain DrawCursor a cursor of the current cursorWidth() + will be drawn after drawing the text. + + The display text will only be drawn if the flags contain DrawText +*/ +void QLineControl::draw(QPainter *painter, const QPoint &offset, const QRect &clip, int flags) +{ + QVector selections; + if (flags & DrawSelections) { + QTextLayout::FormatRange o; + if (selstart < selend) { + o.start = selstart; + o.length = selend - selstart; + o.format.setBackground(m_palette.brush(QPalette::Highlight)); + o.format.setForeground(m_palette.brush(QPalette::HighlightedText)); + } else { + // mask selection + o.start = m_cursor; + o.length = 1; + o.format.setBackground(m_palette.brush(QPalette::Text)); + o.format.setForeground(m_palette.brush(QPalette::Window)); + } + selections.append(o); + } + + if (flags & DrawText) + textLayout.draw(painter, offset, selections, clip); + + if (flags & DrawCursor){ + if(!m_blinkPeriod || m_blinkStatus) + textLayout.drawCursor(painter, offset, m_cursor, m_cursorWidth); + } +} + +/* + Sets the selection to cover the word at the given cursor position. + The word boundries is defined by the behavior of QTextLayout::SkipWords + cursor mode. +*/ +void QLineControl::selectWordAtPos(int cursor) +{ + int c = textLayout.previousCursorPosition(cursor, QTextLayout::SkipWords); + moveCursor(c, false); + // ## text layout should support end of words. + int end = textLayout.nextCursorPosition(cursor, QTextLayout::SkipWords); + while (end > cursor && m_text[end-1].isSpace()) + --end; + moveCursor(end, true); +} + +/* + Completes a change to the line control text. If the change is not valid + will undo the line control state back to the given \a validateFromState. + + If \a edited is true and the change is valid, will emit textEdited() in + addition to textChanged(). Otherwise only emits textChanged() on a valid + change. + + The \a update value is currently unused. +*/ + +bool QLineControl::finishChange(int validateFromState, bool update, bool edited) +{ + Q_UNUSED(update) + bool lineDirty = selDirty; + if (textDirty) { + // do validation + bool wasValidInput = validInput; + validInput = true; +#ifndef QT_NO_VALIDATOR + if (m_validator) { + validInput = false; + QString textCopy = m_text; + int cursorCopy = m_cursor; + validInput = (m_validator->validate(textCopy, cursorCopy) != QValidator::Invalid); + if (validInput) { + if (m_text != textCopy) { + p_setText(textCopy, cursorCopy); + return true; + } + m_cursor = cursorCopy; + } + } +#endif + if (validateFromState >= 0 && wasValidInput && !validInput) { + if (transactions.count()) + return false; + p_undo(validateFromState); + history.resize(undoState); + if (modifiedState > undoState) + modifiedState = -1; + validInput = true; + textDirty = false; + } + updateDisplayText(); + lineDirty |= textDirty; + if (textDirty) { + textDirty = false; + QString actualText = text(); + if (edited) + emit textEdited(actualText); + emit textChanged(actualText); + } + } + if (selDirty) { + selDirty = false; + emit selectionChanged(); + } + emitCursorPositionChanged(); + return true; +} + +/* + An internal function for setting the text of the line control. +*/ +void QLineControl::p_setText(const QString& txt, int pos, bool edited) +{ + p_deselect(); + emit resetInputContext(); + QString oldText = m_text; + if (maskData) { + m_text = maskString(0, txt, true); + m_text += clearString(m_text.length(), m_maxLength - m_text.length()); + } else { + m_text = txt.isEmpty() ? txt : txt.left(m_maxLength); + } + history.clear(); + modifiedState = undoState = 0; + m_cursor = (pos < 0 || pos > m_text.length()) ? m_text.length() : pos; + textDirty = (oldText != m_text); + finishChange(-1, true, edited); +} + + +/* + Adds the given \a command to the undo history + of the line control. Does not apply the command. +*/ +void QLineControl::addCommand(const Command& cmd) +{ + if (separator && undoState && history[undoState-1].type != Separator) { + history.resize(undoState + 2); + history[undoState++] = Command(Separator, m_cursor, 0, selstart, selend); + } else { + history.resize(undoState + 1); + } + separator = false; + history[undoState++] = cmd; +} + +/* + Inserts the given string \a s into the line + control. + + Also adds the appropriate commands into the undo history. + This function does not call finishChange(), and may leave the text + in an invalid state. +*/ +void QLineControl::p_insert(const QString& s) +{ + if (hasSelectedText()) + addCommand(Command(SetSelection, m_cursor, 0, selstart, selend)); + if (maskData) { + QString ms = maskString(m_cursor, s); + for (int i = 0; i < (int) ms.length(); ++i) { + addCommand (Command(DeleteSelection, m_cursor+i, m_text.at(m_cursor+i), -1, -1)); + addCommand(Command(Insert, m_cursor+i, ms.at(i), -1, -1)); + } + m_text.replace(m_cursor, ms.length(), ms); + m_cursor += ms.length(); + m_cursor = nextMaskBlank(m_cursor); + textDirty = true; + } else { + int remaining = m_maxLength - m_text.length(); + if (remaining != 0) { + m_text.insert(m_cursor, s.left(remaining)); + for (int i = 0; i < (int) s.left(remaining).length(); ++i) + addCommand(Command(Insert, m_cursor++, s.at(i), -1, -1)); + textDirty = true; + } + } +} + +/* + \internal + deletes a single character from the current text. If \a wasBackspace, + the character prior to the cursor is removed. Otherwise the character + after the cursor is removed. + + Also adds the appropriate commands into the undo history. + This function does not call finishChange(), and may leave the text + in an invalid state. +*/ +void QLineControl::p_del(bool wasBackspace) +{ + if (m_cursor < (int) m_text.length()) { + if (hasSelectedText()) + addCommand(Command(SetSelection, m_cursor, 0, selstart, selend)); + addCommand (Command((CommandType)((maskData?2:0)+(wasBackspace?Remove:Delete)), m_cursor, m_text.at(m_cursor), -1, -1)); + if (maskData) { + m_text.replace(m_cursor, 1, clearString(m_cursor, 1)); + addCommand(Command(Insert, m_cursor, m_text.at(m_cursor), -1, -1)); + } else { + m_text.remove(m_cursor, 1); + } + textDirty = true; + } +} + +/* + \internal + removes the currently selected text from the line control. + + Also adds the appropriate commands into the undo history. + This function does not call finishChange(), and may leave the text + in an invalid state. +*/ +void QLineControl::removeSelectedText() +{ + if (selstart < selend && selend <= (int) m_text.length()) { + separate(); + int i ; + addCommand(Command(SetSelection, m_cursor, 0, selstart, selend)); + if (selstart <= m_cursor && m_cursor < selend) { + // cursor is within the selection. Split up the commands + // to be able to restore the correct cursor position + for (i = m_cursor; i >= selstart; --i) + addCommand (Command(DeleteSelection, i, m_text.at(i), -1, 1)); + for (i = selend - 1; i > m_cursor; --i) + addCommand (Command(DeleteSelection, i - m_cursor + selstart - 1, m_text.at(i), -1, -1)); + } else { + for (i = selend-1; i >= selstart; --i) + addCommand (Command(RemoveSelection, i, m_text.at(i), -1, -1)); + } + if (maskData) { + m_text.replace(selstart, selend - selstart, clearString(selstart, selend - selstart)); + for (int i = 0; i < selend - selstart; ++i) + addCommand(Command(Insert, selstart + i, m_text.at(selstart + i), -1, -1)); + } else { + m_text.remove(selstart, selend - selstart); + } + if (m_cursor > selstart) + m_cursor -= qMin(m_cursor, selend) - selstart; + p_deselect(); + textDirty = true; + } +} + +/* + Parses the input mask specified by \a maskFields to generate + the mask data used to handle input masks. +*/ +void QLineControl::parseInputMask(const QString &maskFields) +{ + int delimiter = maskFields.indexOf(QLatin1Char(';')); + if (maskFields.isEmpty() || delimiter == 0) { + if (maskData) { + delete [] maskData; + maskData = 0; + m_maxLength = 32767; + p_setText(QString()); + } + return; + } + + if (delimiter == -1) { + blank = QLatin1Char(' '); + m_inputMask = maskFields; + } else { + m_inputMask = maskFields.left(delimiter); + blank = (delimiter + 1 < maskFields.length()) ? maskFields[delimiter + 1] : QLatin1Char(' '); + } + + // calculate m_maxLength / maskData length + m_maxLength = 0; + QChar c = 0; + for (int i=0; i 0 && m_inputMask.at(i-1) == QLatin1Char('\\')) { + m_maxLength++; + continue; + } + if (c != QLatin1Char('\\') && c != QLatin1Char('!') && + c != QLatin1Char('<') && c != QLatin1Char('>') && + c != QLatin1Char('{') && c != QLatin1Char('}') && + c != QLatin1Char('[') && c != QLatin1Char(']')) + m_maxLength++; + } + + delete [] maskData; + maskData = new MaskInputData[m_maxLength]; + + MaskInputData::Casemode m = MaskInputData::NoCaseMode; + c = 0; + bool s; + bool escape = false; + int index = 0; + for (int i = 0; i < m_inputMask.length(); i++) { + c = m_inputMask.at(i); + if (escape) { + s = true; + maskData[index].maskChar = c; + maskData[index].separator = s; + maskData[index].caseMode = m; + index++; + escape = false; + } else if (c == QLatin1Char('<')) { + m = MaskInputData::Lower; + } else if (c == QLatin1Char('>')) { + m = MaskInputData::Upper; + } else if (c == QLatin1Char('!')) { + m = MaskInputData::NoCaseMode; + } else if (c != QLatin1Char('{') && c != QLatin1Char('}') && c != QLatin1Char('[') && c != QLatin1Char(']')) { + switch (c.unicode()) { + case 'A': + case 'a': + case 'N': + case 'n': + case 'X': + case 'x': + case '9': + case '0': + case 'D': + case 'd': + case '#': + case 'H': + case 'h': + case 'B': + case 'b': + s = false; + break; + case '\\': + escape = true; + default: + s = true; + break; + } + + if (!escape) { + maskData[index].maskChar = c; + maskData[index].separator = s; + maskData[index].caseMode = m; + index++; + } + } + } + p_setText(m_text); +} + + +/* checks if the key is valid compared to the inputMask */ +bool QLineControl::isValidInput(QChar key, QChar mask) const +{ + switch (mask.unicode()) { + case 'A': + if (key.isLetter()) + return true; + break; + case 'a': + if (key.isLetter() || key == blank) + return true; + break; + case 'N': + if (key.isLetterOrNumber()) + return true; + break; + case 'n': + if (key.isLetterOrNumber() || key == blank) + return true; + break; + case 'X': + if (key.isPrint()) + return true; + break; + case 'x': + if (key.isPrint() || key == blank) + return true; + break; + case '9': + if (key.isNumber()) + return true; + break; + case '0': + if (key.isNumber() || key == blank) + return true; + break; + case 'D': + if (key.isNumber() && key.digitValue() > 0) + return true; + break; + case 'd': + if ((key.isNumber() && key.digitValue() > 0) || key == blank) + return true; + break; + case '#': + if (key.isNumber() || key == QLatin1Char('+') || key == QLatin1Char('-') || key == blank) + return true; + break; + case 'B': + if (key == QLatin1Char('0') || key == QLatin1Char('1')) + return true; + break; + case 'b': + if (key == QLatin1Char('0') || key == QLatin1Char('1') || key == blank) + return true; + break; + case 'H': + if (key.isNumber() || (key >= QLatin1Char('a') && key <= QLatin1Char('f')) || (key >= QLatin1Char('A') && key <= QLatin1Char('F'))) + return true; + break; + case 'h': + if (key.isNumber() || (key >= QLatin1Char('a') && key <= QLatin1Char('f')) || (key >= QLatin1Char('A') && key <= QLatin1Char('F')) || key == blank) + return true; + break; + default: + break; + } + return false; +} + +/* + Returns true if the given text \a str is valid for any + validator or input mask set for the line control. + + Otherwise returns false +*/ +bool QLineControl::hasAcceptableInput(const QString &str) const +{ +#ifndef QT_NO_VALIDATOR + QString textCopy = str; + int cursorCopy = m_cursor; + if (m_validator && m_validator->validate(textCopy, cursorCopy) + != QValidator::Acceptable) + return false; +#endif + + if (!maskData) + return true; + + if (str.length() != m_maxLength) + return false; + + for (int i=0; i < m_maxLength; ++i) { + if (maskData[i].separator) { + if (str.at(i) != maskData[i].maskChar) + return false; + } else { + if (!isValidInput(str.at(i), maskData[i].maskChar)) + return false; + } + } + return true; +} + +/* + Applies the inputMask on \a str starting from position \a pos in the mask. \a clear + specifies from where characters should be gotten when a separator is met in \a str - true means + that blanks will be used, false that previous input is used. + Calling this when no inputMask is set is undefined. +*/ +QString QLineControl::maskString(uint pos, const QString &str, bool clear) const +{ + if (pos >= (uint)m_maxLength) + return QString::fromLatin1(""); + + QString fill; + fill = clear ? clearString(0, m_maxLength) : m_text; + + int strIndex = 0; + QString s = QString::fromLatin1(""); + int i = pos; + while (i < m_maxLength) { + if (strIndex < str.length()) { + if (maskData[i].separator) { + s += maskData[i].maskChar; + if (str[(int)strIndex] == maskData[i].maskChar) + strIndex++; + ++i; + } else { + if (isValidInput(str[(int)strIndex], maskData[i].maskChar)) { + switch (maskData[i].caseMode) { + case MaskInputData::Upper: + s += str[(int)strIndex].toUpper(); + break; + case MaskInputData::Lower: + s += str[(int)strIndex].toLower(); + break; + default: + s += str[(int)strIndex]; + } + ++i; + } else { + // search for separator first + int n = findInMask(i, true, true, str[(int)strIndex]); + if (n != -1) { + if (str.length() != 1 || i == 0 || (i > 0 && (!maskData[i-1].separator || maskData[i-1].maskChar != str[(int)strIndex]))) { + s += fill.mid(i, n-i+1); + i = n + 1; // update i to find + 1 + } + } else { + // search for valid blank if not + n = findInMask(i, true, false, str[(int)strIndex]); + if (n != -1) { + s += fill.mid(i, n-i); + switch (maskData[n].caseMode) { + case MaskInputData::Upper: + s += str[(int)strIndex].toUpper(); + break; + case MaskInputData::Lower: + s += str[(int)strIndex].toLower(); + break; + default: + s += str[(int)strIndex]; + } + i = n + 1; // updates i to find + 1 + } + } + } + strIndex++; + } + } else + break; + } + + return s; +} + + + +/* + Returns a "cleared" string with only separators and blank chars. + Calling this when no inputMask is set is undefined. +*/ +QString QLineControl::clearString(uint pos, uint len) const +{ + if (pos >= (uint)m_maxLength) + return QString(); + + QString s; + int end = qMin((uint)m_maxLength, pos + len); + for (int i=pos; i= m_maxLength || pos < 0) + return -1; + + int end = forward ? m_maxLength : -1; + int step = forward ? 1 : -1; + int i = pos; + + while (i != end) { + if (findSeparator) { + if (maskData[i].separator && maskData[i].maskChar == searchChar) + return i; + } else { + if (!maskData[i].separator) { + if (searchChar.isNull()) + return i; + else if (isValidInput(searchChar, maskData[i].maskChar)) + return i; + } + } + i += step; + } + return -1; +} + +void QLineControl::p_undo(int until) +{ + if (!isUndoAvailable()) + return; + p_deselect(); + while (undoState && undoState > until) { + Command& cmd = history[--undoState]; + switch (cmd.type) { + case Insert: + m_text.remove(cmd.pos, 1); + m_cursor = cmd.pos; + break; + case SetSelection: + selstart = cmd.selStart; + selend = cmd.selEnd; + m_cursor = cmd.pos; + break; + case Remove: + case RemoveSelection: + m_text.insert(cmd.pos, cmd.uc); + m_cursor = cmd.pos + 1; + break; + case Delete: + case DeleteSelection: + m_text.insert(cmd.pos, cmd.uc); + m_cursor = cmd.pos; + break; + case Separator: + continue; + } + if (until < 0 && undoState) { + Command& next = history[undoState-1]; + if (next.type != cmd.type && next.type < RemoveSelection + && (cmd.type < RemoveSelection || next.type == Separator)) + break; + } + } + textDirty = true; + emitCursorPositionChanged(); +} + +void QLineControl::p_redo() { + if (!isRedoAvailable()) + return; + p_deselect(); + while (undoState < (int)history.size()) { + Command& cmd = history[undoState++]; + switch (cmd.type) { + case Insert: + m_text.insert(cmd.pos, cmd.uc); + m_cursor = cmd.pos + 1; + break; + case SetSelection: + selstart = cmd.selStart; + selend = cmd.selEnd; + m_cursor = cmd.pos; + break; + case Remove: + case Delete: + case RemoveSelection: + case DeleteSelection: + m_text.remove(cmd.pos, 1); + selstart = cmd.selStart; + selend = cmd.selEnd; + m_cursor = cmd.pos; + break; + case Separator: + selstart = cmd.selStart; + selend = cmd.selEnd; + m_cursor = cmd.pos; + break; + } + if (undoState < (int)history.size()) { + Command& next = history[undoState]; + if (next.type != cmd.type && cmd.type < RemoveSelection && next.type != Separator + && (next.type < RemoveSelection || cmd.type == Separator)) + break; + } + } + textDirty = true; + emitCursorPositionChanged(); +} + +/* + If the current cursor position differs from the last emited cursor + position, emits cursorPositionChanged(). +*/ +void QLineControl::emitCursorPositionChanged() +{ + if (m_cursor != lastCursorPos) { + const int oldLast = lastCursorPos; + lastCursorPos = m_cursor; + cursorPositionChanged(oldLast, m_cursor); + } +} + +#ifndef QT_NO_COMPLETER +// iterating forward(dir=1)/backward(dir=-1) from the +// current row based. dir=0 indicates a new completion prefix was set. +bool QLineControl::advanceToEnabledItem(int dir) +{ + int start = m_completer->currentRow(); + if (start == -1) + return false; + int i = start + dir; + if (dir == 0) dir = 1; + do { + if (!m_completer->setCurrentRow(i)) { + if (!m_completer->wrapAround()) + break; + i = i > 0 ? 0 : m_completer->completionCount() - 1; + } else { + QModelIndex currentIndex = m_completer->currentIndex(); + if (m_completer->completionModel()->flags(currentIndex) & Qt::ItemIsEnabled) + return true; + i += dir; + } + } while (i != start); + + m_completer->setCurrentRow(start); // restore + return false; +} + +void QLineControl::complete(int key) +{ + if (!m_completer || isReadOnly() || echoMode() != QLineEdit::Normal) + return; + + QString text = this->text(); + if (m_completer->completionMode() == QCompleter::InlineCompletion) { + if (key == Qt::Key_Backspace) + return; + int n = 0; + if (key == Qt::Key_Up || key == Qt::Key_Down) { + if (textAfterSelection().length()) + return; + QString prefix = hasSelectedText() ? textBeforeSelection() + : text; + if (text.compare(m_completer->currentCompletion(), m_completer->caseSensitivity()) != 0 + || prefix.compare(m_completer->completionPrefix(), m_completer->caseSensitivity()) != 0) { + m_completer->setCompletionPrefix(prefix); + } else { + n = (key == Qt::Key_Up) ? -1 : +1; + } + } else { + m_completer->setCompletionPrefix(text); + } + if (!advanceToEnabledItem(n)) + return; + } else { +#ifndef QT_KEYPAD_NAVIGATION + if (text.isEmpty()) { + m_completer->popup()->hide(); + return; + } +#endif + m_completer->setCompletionPrefix(text); + } + + m_completer->complete(); +} +#endif + +void QLineControl::setCursorBlinkPeriod(int msec) +{ + if(msec == m_blinkPeriod) + return; + if(m_blinkTimer){ + killTimer(m_blinkTimer); + } + if(msec){ + m_blinkTimer = startTimer(msec/2); + m_blinkStatus = 1; + }else{ + m_blinkTimer = 0; + if(m_blinkStatus == 0) + emit updateNeeded(inputMask().isEmpty()?cursorRect():QRect()); + } + m_blinkPeriod = msec; +} + +void QLineControl::timerEvent ( QTimerEvent * event ) +{ + if(event->timerId() == m_blinkTimer) { + m_blinkStatus = !m_blinkStatus; + emit updateNeeded(inputMask().isEmpty()?cursorRect():QRect()); + }else if(event->timerId() == m_deleteAllTimer){ + killTimer(m_deleteAllTimer); + m_deleteAllTimer = 0; + clear(); + }else if(event->timerId() == m_tripleClickTimer){ + killTimer(m_tripleClickTimer); + m_tripleClickTimer = 0; + } +} + +bool QLineControl::processEvent(QEvent* ev) +{ +#ifdef QT_KEYPAD_NAVIGATION + if (QApplication::keypadNavigationEnabled()) { + if ((ev->type() == QEvent::KeyPress) || (ev->type() == QEvent::KeyRelease)) { + QKeyEvent *ke = (QKeyEvent *)ev; + if (ke->key() == Qt::Key_Back) { + if (ke->isAutoRepeat()) { + // Swallow it. We don't want back keys running amok. + ke->accept(); + return true; + } + if ((ev->type() == QEvent::KeyRelease) + && !isReadOnly() + && deleteAllTimer) { + killTimer(m_deleteAllTimer); + m_deleteAllTimer = 0; + backspace(); + ke->accept(); + return true; + } + } + //TODO: Needs a call to processKeyEvent? + } else if (e->type() == QEvent::EnterEditFocus) { + end(false); + int cft = QApplication::cursorFlashTime(); + control->setCursorBlinkPeriod(cft/2); + } else if (e->type() == QEvent::LeaveEditFocus) { + d->setCursorVisible(false);//!!! + control->setCursorBlinkPeriod(0); + if (!m_emitingEditingFinished) { + if (hasAcceptableInput() || fixup()) { + m_emitingEditingFinished = true; + emit editingFinished(); + m_emitingEditingFinished = false; + } + } + } + return; + } +#endif + switch(ev->type()){ +#ifndef QT_NO_GRAPHICSVIEW + case QEvent::GraphicsSceneMouseMove: + case QEvent::GraphicsSceneMouseRelease: + case QEvent::GraphicsSceneMousePress:{ + QGraphicsSceneMouseEvent *gvEv = static_cast(ev); + QMouseEvent* mouse = new QMouseEvent(ev->type(), + gvEv->pos().toPoint(), gvEv->button(), gvEv->buttons(), gvEv->modifiers()); + processMouseEvent(mouse); break; + } +#endif + case QEvent::MouseButtonPress: + case QEvent::MouseButtonRelease: + case QEvent::MouseButtonDblClick: + case QEvent::MouseMove: + processMouseEvent(static_cast(ev)); break; + case QEvent::KeyPress: + case QEvent::KeyRelease: + processKeyEvent(static_cast(ev)); break; + case QEvent::InputMethod: + processInputMethodEvent(static_cast(ev)); break; +#ifndef QT_NO_SHORTCUT + case QEvent::ShortcutOverride:{ + QKeyEvent* ke = static_cast(ev); + if (ke == QKeySequence::Copy + || ke == QKeySequence::Paste + || ke == QKeySequence::Cut + || ke == QKeySequence::Redo + || ke == QKeySequence::Undo + || ke == QKeySequence::MoveToNextWord + || ke == QKeySequence::MoveToPreviousWord + || ke == QKeySequence::MoveToStartOfDocument + || ke == QKeySequence::MoveToEndOfDocument + || ke == QKeySequence::SelectNextWord + || ke == QKeySequence::SelectPreviousWord + || ke == QKeySequence::SelectStartOfLine + || ke == QKeySequence::SelectEndOfLine + || ke == QKeySequence::SelectStartOfBlock + || ke == QKeySequence::SelectEndOfBlock + || ke == QKeySequence::SelectStartOfDocument + || ke == QKeySequence::SelectAll + || ke == QKeySequence::SelectEndOfDocument) { + ke->accept(); + } else if (ke->modifiers() == Qt::NoModifier || ke->modifiers() == Qt::ShiftModifier + || ke->modifiers() == Qt::KeypadModifier) { + if (ke->key() < Qt::Key_Escape) { + ke->accept(); + } else { + switch (ke->key()) { + case Qt::Key_Delete: + case Qt::Key_Home: + case Qt::Key_End: + case Qt::Key_Backspace: + case Qt::Key_Left: + case Qt::Key_Right: + ke->accept(); + default: + break; + } + } + } + } +#endif + default: + return false; + } + return true; +} + +void QLineControl::processMouseEvent(QMouseEvent* ev) +{ + + switch (ev->type()){ + case QEvent::GraphicsSceneMousePress: + case QEvent::MouseButtonPress:{ + if (m_tripleClickTimer && (ev->pos() - m_tripleClick).manhattanLength() < + QApplication::startDragDistance()) { + selectAll(); + return; + } + if (ev->button() == Qt::RightButton) + return; +#ifdef QT_KEYPAD_NAVIGATION + if (QApplication::keypadNavigationEnabled() && !hasEditFocus()) { + setEditFocus(true); + // Get the completion list to pop up. + if (m_completer) + m_completer->complete(); + } +#endif + + bool mark = ev->modifiers() & Qt::ShiftModifier; + int cursor = xToPos(ev->pos().x()); + moveCursor(cursor, mark); + break; + } + case QEvent::MouseButtonDblClick: + if (ev->button() == Qt::LeftButton) { + selectWordAtPos(xToPos(ev->pos().x())); + if(m_tripleClickTimer) + killTimer(m_tripleClickTimer); + m_tripleClickTimer = startTimer(QApplication::doubleClickInterval()); + m_tripleClick = ev->pos(); + } + break; + case QEvent::GraphicsSceneMouseRelease: + case QEvent::MouseButtonRelease: +#ifndef QT_NO_CLIPBOARD + if (QApplication::clipboard()->supportsSelection()) { + if (ev->button() == Qt::LeftButton) { + copy(QClipboard::Selection); + } else if (!isReadOnly() && ev->button() == Qt::MidButton) { + deselect(); + insert(QApplication::clipboard()->text(QClipboard::Selection)); + } + } +#endif + break; + case QEvent::GraphicsSceneMouseMove: + case QEvent::MouseMove: + if (ev->buttons() & Qt::LeftButton) { + moveCursor(xToPos(ev->pos().x()), true); + } + break; + default: + break; + } +} + +void QLineControl::processKeyEvent(QKeyEvent* event) +{ + + bool inlineCompletionAccepted = false; + +#ifndef QT_NO_COMPLETER + if (m_completer) { + QCompleter::CompletionMode completionMode = m_completer->completionMode(); + if ((completionMode == QCompleter::PopupCompletion + || completionMode == QCompleter::UnfilteredPopupCompletion) + && m_completer->popup() + && m_completer->popup()->isVisible()) { + // The following keys are forwarded by the completer to the widget + // Ignoring the events lets the completer provide suitable default behavior + switch (event->key()) { + case Qt::Key_Escape: + event->ignore(); + return; + case Qt::Key_Enter: + case Qt::Key_Return: + case Qt::Key_F4: +#ifdef QT_KEYPAD_NAVIGATION + case Qt::Key_Select: + if (!QApplication::keypadNavigationEnabled()) + break; +#endif + m_completer->popup()->hide(); // just hide. will end up propagating to parent + default: + break; // normal key processing + } + } else if (completionMode == QCompleter::InlineCompletion) { + switch (event->key()) { + case Qt::Key_Enter: + case Qt::Key_Return: + case Qt::Key_F4: +#ifdef QT_KEYPAD_NAVIGATION + case Qt::Key_Select: + if (!QApplication::keypadNavigationEnabled()) + break; +#endif + if (!m_completer->currentCompletion().isEmpty() && hasSelectedText() + && textAfterSelection().isEmpty()) { + setText(m_completer->currentCompletion()); + inlineCompletionAccepted = true; + } + default: + break; // normal key processing + } + } + } +#endif // QT_NO_COMPLETER + + + + if (echoMode() == QLineEdit::PasswordEchoOnEdit + && !passwordEchoEditing() + && !isReadOnly() + && !event->text().isEmpty() +#ifdef QT_KEYPAD_NAVIGATION + && event->key() != Qt::Key_Select + && event->key() != Qt::Key_Up + && event->key() != Qt::Key_Down + && event->key() != Qt::Key_Back +#endif + && !(event->modifiers() & Qt::ControlModifier)) { + // Clear the edit and reset to normal echo mode while editing; the + // echo mode switches back when the edit loses focus + // ### resets current content. dubious code; you can + // navigate with keys up, down, back, and select(?), but if you press + // "left" or "right" it clears? + updatePasswordEchoEditing(true);//TODO: used to set a WA too + clear(); + } + + //setCursorVisible(true);TODO: Who handles this? + if (event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return) { + if (hasAcceptableInput() || fixup()) { + emit accepted(); + emitingEditingFinished = true; + emit editingFinished(); + emitingEditingFinished = false; + } + if (inlineCompletionAccepted) + event->accept(); + else + event->ignore(); + return; + } + bool unknown = false; + + if (false) { + } +#ifndef QT_NO_SHORTCUT + else if (event == QKeySequence::Undo) { + if (!isReadOnly()) + undo(); + } + else if (event == QKeySequence::Redo) { + if (!isReadOnly()) + redo(); + } + else if (event == QKeySequence::SelectAll) { + selectAll(); + } +#ifndef QT_NO_CLIPBOARD + else if (event == QKeySequence::Copy) { + copy(); + } + else if (event == QKeySequence::Paste) { + if (!isReadOnly()) + paste(); + } + else if (event == QKeySequence::Cut) { + if (!isReadOnly()) { + copy(); + del(); + } + } + else if (event == QKeySequence::DeleteEndOfLine) { + if (!isReadOnly()) { + setSelection(cursor(), end()); + copy(); + del(); + } + } +#endif //QT_NO_CLIPBOARD + else if (event == QKeySequence::MoveToStartOfLine) { + home(0); + } + else if (event == QKeySequence::MoveToEndOfLine) { + end(0); + } + else if (event == QKeySequence::SelectStartOfLine) { + home(1); + } + else if (event == QKeySequence::SelectEndOfLine) { + end(1); + } + else if (event == QKeySequence::MoveToNextChar) { +#if !defined(Q_WS_WIN) || defined(QT_NO_COMPLETER) + if (hasSelectedText()) { +#else + if (hasSelectedText() && m_completer + && m_completer->completionMode() == QCompleter::InlineCompletion) { +#endif + moveCursor(selectionEnd(), false); + } else { + cursorForward(0, layoutDirection() == Qt::LeftToRight ? 1 : -1); + } + } + else if (event == QKeySequence::SelectNextChar) { + cursorForward(1, layoutDirection() == Qt::LeftToRight ? 1 : -1); + } + else if (event == QKeySequence::MoveToPreviousChar) { +#if !defined(Q_WS_WIN) || defined(QT_NO_COMPLETER) + if (hasSelectedText()) { +#else + if (hasSelectedText() && m_completer + && m_completer->completionMode() == QCompleter::InlineCompletion) { +#endif + moveCursor(selectionStart(), false); + } else { + cursorForward(0, layoutDirection() == Qt::LeftToRight ? -1 : 1); + } + } + else if (event == QKeySequence::SelectPreviousChar) { + cursorForward(1, layoutDirection() == Qt::LeftToRight ? -1 : 1); + } + else if (event == QKeySequence::MoveToNextWord) { + if (echoMode() == QLineEdit::Normal) + layoutDirection() == Qt::LeftToRight ? cursorWordForward(0) : cursorWordBackward(0); + else + layoutDirection() == Qt::LeftToRight ? end(0) : home(0); + } + else if (event == QKeySequence::MoveToPreviousWord) { + if (echoMode() == QLineEdit::Normal) + layoutDirection() == Qt::LeftToRight ? cursorWordBackward(0) : cursorWordForward(0); + else if (!isReadOnly()) { + layoutDirection() == Qt::LeftToRight ? home(0) : end(0); + } + } + else if (event == QKeySequence::SelectNextWord) { + if (echoMode() == QLineEdit::Normal) + layoutDirection() == Qt::LeftToRight ? cursorWordForward(1) : cursorWordBackward(1); + else + layoutDirection() == Qt::LeftToRight ? end(1) : home(1); + } + else if (event == QKeySequence::SelectPreviousWord) { + if (echoMode() == QLineEdit::Normal) + layoutDirection() == Qt::LeftToRight ? cursorWordBackward(1) : cursorWordForward(1); + else + layoutDirection() == Qt::LeftToRight ? home(1) : end(1); + } + else if (event == QKeySequence::Delete) { + if (!isReadOnly()) + del(); + } + else if (event == QKeySequence::DeleteEndOfWord) { + if (!isReadOnly()) { + cursorWordForward(true); + del(); + } + } + else if (event == QKeySequence::DeleteStartOfWord) { + if (!isReadOnly()) { + cursorWordBackward(true); + del(); + } + } +#endif // QT_NO_SHORTCUT + else { +#ifdef Q_WS_MAC + if (event->key() == Qt::Key_Up || event->key() == Qt::Key_Down) { + Qt::KeyboardModifiers myModifiers = (event->modifiers() & ~Qt::KeypadModifier); + if (myModifiers & Qt::ShiftModifier) { + if (myModifiers == (Qt::ControlModifier|Qt::ShiftModifier) + || myModifiers == (Qt::AltModifier|Qt::ShiftModifier) + || myModifiers == Qt::ShiftModifier) { + + event->key() == Qt::Key_Up ? home(1) : end(1); + } + } else { + if ((myModifiers == Qt::ControlModifier + || myModifiers == Qt::AltModifier + || myModifiers == Qt::NoModifier)) { + event->key() == Qt::Key_Up ? home(0) : end(0); + } + } + } +#endif + if (event->modifiers() & Qt::ControlModifier) { + switch (event->key()) { + case Qt::Key_Backspace: + if (!isReadOnly()) { + cursorWordBackward(true); + del(); + } + break; +#ifndef QT_NO_COMPLETER + case Qt::Key_Up: + case Qt::Key_Down: + complete(event->key()); + break; +#endif +#if defined(Q_WS_X11) + case Qt::Key_E: + end(0); + break; + + case Qt::Key_U: + if (!isReadOnly()) { + setSelection(0, text().size()); +#ifndef QT_NO_CLIPBOARD + copy(); +#endif + del(); + } + break; +#endif + default: + unknown = true; + } + } else { // ### check for *no* modifier + switch (event->key()) { + case Qt::Key_Backspace: + if (!isReadOnly()) { + backspace(); +#ifndef QT_NO_COMPLETER + complete(Qt::Key_Backspace); +#endif + } + break; +#ifdef QT_KEYPAD_NAVIGATION//TODO: This section + case Qt::Key_Back: + if (QApplication::keypadNavigationEnabled() && !event->isAutoRepeat() + && !isReadOnly()) { + if (text().length() == 0) { + setText(d->origText); + + if (d->passwordEchoEditing) + d->updatePasswordEchoEditing(false); + + setEditFocus(false); + } else if (!d->deleteAllTimer.isActive()) { + d->deleteAllTimer.start(750, this); + } + } else { + unknown = true; + } + break; +#endif + + default: + unknown = true; + } + } + } + + if (event->key() == Qt::Key_Direction_L || event->key() == Qt::Key_Direction_R) { + setLayoutDirection((event->key() == Qt::Key_Direction_L) ? Qt::LeftToRight : Qt::RightToLeft); + unknown = false; + } + + if (unknown && !isReadOnly()) { + QString t = event->text(); + if (!t.isEmpty() && t.at(0).isPrint()) { + insert(t); +#ifndef QT_NO_COMPLETER + complete(event->key()); +#endif + event->accept(); + return; + } + } + + if (unknown) + event->ignore(); + else + event->accept(); +} + + +QT_END_NAMESPACE + +#endif diff --git a/src/gui/widgets/qlinecontrol_p.h b/src/gui/widgets/qlinecontrol_p.h new file mode 100644 index 0000000..bb27778 --- /dev/null +++ b/src/gui/widgets/qlinecontrol_p.h @@ -0,0 +1,715 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QLINECONTROL_P_H +#define QLINECONTROL_P_H + +// +// 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. +// + +#include "QtCore/qglobal.h" + +#ifndef QT_NO_LINEEDIT +#include "private/qwidget_p.h" +#include "QtGui/qlineedit.h" +#include "QtGui/qtextlayout.h" +#include "QtGui/qstyleoption.h" +#include "QtCore/qpointer.h" +#include "QtGui/qlineedit.h" +#include "QtGui/qclipboard.h" +#include "QtCore/qpoint.h" +#include "QtGui/qcompleter.h" + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Gui) + +class Q_GUI_EXPORT QLineControl : public QObject +{ + Q_OBJECT +public: + + QLineControl(const QString &txt = QString()) + : emitingEditingFinished(0), + m_cursor(0), m_preeditCursor(0), m_layoutDirection(Qt::LeftToRight), + hideCursor(false), separator(0), readOnly(0), + dragEnabled(0), m_echoMode(0), textDirty(0), selDirty(0), + validInput(1), m_blinkPeriod(0), m_blinkTimer(0), m_deleteAllTimer(0), + m_ascent(0), m_maxLength(32767), lastCursorPos(-1), + m_tripleClickTimer(0), maskData(0), modifiedState(0), undoState(0), + selstart(0), selend(0), m_passwordEchoEditing(false) + { + init(txt); + } + + ~QLineControl() + { + delete [] maskData; + } + + int nextMaskBlank(int pos); + int prevMaskBlank(int pos); + + bool isUndoAvailable() const; + bool isRedoAvailable() const; + void clearUndo(); + bool isModified() const; + void setModified(bool modified); + + bool allSelected() const; + bool hasSelectedText() const; + + int width() const; + int height() const; + int ascent() const; + + void setSelection(int start, int length); + + QString selectedText() const; + QString textBeforeSelection() const; + QString textAfterSelection() const; + + int selectionStart() const; + int selectionEnd() const; + bool inSelection(int x) const; + + void removeSelection(); + + int start() const; + int end() const; + +#ifndef QT_NO_CLIPBOARD + void copy(QClipboard::Mode mode = QClipboard::Clipboard) const; + void paste(); +#endif + + int cursor() const; + int preeditCursor() const; + + int cursorWidth() const; + void setCursorWidth(int value); + + void moveCursor(int pos, bool mark = false); + void cursorForward(bool mark, int steps); + void cursorWordForward(bool mark); + void cursorWordBackward(bool mark); + void home(bool mark); + void end(bool mark); + + int xToPos(int x, QTextLine::CursorPosition = QTextLine::CursorBetweenCharacters) const; + QRect cursorRect() const; + + qreal cursorToX(int cursor) const; + qreal cursorToX() const; + + bool isReadOnly() const; + void setReadOnly(bool enable); + + QString text() const; + void setText(const QString &); + + QString displayText() const; + + void backspace(); + void del(); + void deselect(); + void selectAll(); + void insert(const QString &); + void clear(); + void undo(); + void redo(); + void selectWordAtPos(int); + + uint echoMode() const; + void setEchoMode(uint mode); + + void setMaxLength(int maxLength); + int maxLength() const; + + const QValidator *validator() const; + void setValidator(const QValidator *); + +#ifndef QT_NO_COMPLETER + QCompleter *completer() const; + void setCompleter(const QCompleter*); + void complete(int key); +#endif + + void setCursorPosition(int pos); + int cursorPosition() const; + + bool hasAcceptableInput() const; + bool fixup(); + + QString inputMask() const; + void setInputMask(const QString &mask); + + // input methods +#ifndef QT_NO_IM + bool composeMode() const; + void setPreeditArea(int cursor, const QString &text); +#endif + + QString preeditAreaText() const; + + void updatePasswordEchoEditing(bool editing); + bool passwordEchoEditing() const; + + QChar passwordCharacter() const; + void setPasswordCharacter(const QChar &character); + + Qt::LayoutDirection layoutDirection() const; + void setLayoutDirection(Qt::LayoutDirection direction); + void setFont(const QFont &font); + + void processInputMethodEvent(QInputMethodEvent *event); + void processMouseEvent(QMouseEvent* ev); + void processKeyEvent(QKeyEvent* ev); + + int cursorBlinkPeriod() const; + void setCursorBlinkPeriod(int msec); + + enum DrawFlags { + DrawText = 0x01, + DrawSelections = 0x02, + DrawCursor = 0x04, + DrawAll = DrawText | DrawSelections | DrawCursor + }; + void draw(QPainter *, const QPoint &, const QRect &, int flags = DrawAll); + + bool processEvent(QEvent* ev); + + bool emitingEditingFinished;//Needed in QLineEdit FocusOut event +private: + void init(const QString&); + void removeSelectedText(); + void p_setText(const QString& txt, int pos = -1, bool edited = true); + void updateDisplayText(); + + void p_insert(const QString& s); + void p_del(bool wasBackspace = false); + void p_remove(int pos); + inline void p_deselect() { selDirty |= (selend > selstart); selstart = selend = 0; } + void p_undo(int until = -1); + void p_redo(); + + QString m_text; + QPalette m_palette; + int m_cursor; + int m_preeditCursor; + int m_cursorWidth; + Qt::LayoutDirection m_layoutDirection; + uint hideCursor : 1; // used to hide the m_cursor inside preedit areas + uint separator : 1; + uint readOnly : 1; + uint dragEnabled : 1; + uint m_echoMode : 2; + uint textDirty : 1; + uint selDirty : 1; + uint validInput : 1; + int m_blinkPeriod; // 0 for non-blinking cursor + int m_blinkTimer; + int m_deleteAllTimer; + int m_blinkStatus; + int m_ascent; + int m_maxLength; + int lastCursorPos; + QList transactions; + QPoint m_tripleClick; + int m_tripleClickTimer; + + void emitCursorPositionChanged(); + + bool finishChange(int validateFromState = -1, bool update = false, bool edited = true); + + QPointer m_validator; + QPointer m_completer; +#ifndef QT_NO_COMPLETER + bool advanceToEnabledItem(int dir); +#endif + + struct MaskInputData { + enum Casemode { NoCaseMode, Upper, Lower }; + QChar maskChar; // either the separator char or the inputmask + bool separator; + Casemode caseMode; + }; + QString m_inputMask; + QChar blank; + MaskInputData *maskData; + + + // undo/redo handling + enum CommandType { Separator, Insert, Remove, Delete, RemoveSelection, DeleteSelection, SetSelection }; + struct Command { + inline Command() {} + inline Command(CommandType t, int p, QChar c, int ss, int se) : type(t),uc(c),pos(p),selStart(ss),selEnd(se) {} + uint type : 4; + QChar uc; + int pos, selStart, selEnd; + }; + int modifiedState; + int undoState; + QVector history; + void addCommand(const Command& cmd); + + inline void separate() { separator = true; } + + // selection + int selstart, selend; + + // masking + void parseInputMask(const QString &maskFields); + bool isValidInput(QChar key, QChar mask) const; + bool hasAcceptableInput(const QString &text) const; + QString maskString(uint pos, const QString &str, bool clear = false) const; + QString clearString(uint pos, uint len) const; + QString stripString(const QString &str) const; + int findInMask(int pos, bool forward, bool findSeparator, QChar searchChar = QChar()) const; + + + // complex text layout + QTextLayout textLayout; + + bool m_passwordEchoEditing; + QChar m_passwordCharacter; + +Q_SIGNALS: + void cursorPositionChanged(int, int); + void selectionChanged(); + + void displayTextChanged(const QString &); + void textChanged(const QString &); + void textEdited(const QString &); + + void resetInputContext(); + + void accepted(); + void editingFinished(); + void updateNeeded(const QRect &); +protected: + virtual void timerEvent ( QTimerEvent * event ); +private slots: + void _q_clipboardChanged(); + void _q_deleteSelected(); + +}; + +inline int QLineControl::nextMaskBlank(int pos) +{ + int c = findInMask(pos, true, false); + separator |= (c != pos); + return (c != -1 ? c : m_maxLength); +} + +inline int QLineControl::prevMaskBlank(int pos) +{ + int c = findInMask(pos, false, false); + separator |= (c != pos); + return (c != -1 ? c : 0); +} + +inline bool QLineControl::isUndoAvailable() const +{ + return !readOnly && undoState; +} + +inline bool QLineControl::isRedoAvailable() const +{ + return !readOnly && undoState < (int)history.size(); +} + +inline void QLineControl::clearUndo() +{ + history.clear(); + modifiedState = undoState = 0; +} + +inline bool QLineControl::isModified() const +{ + return modifiedState != undoState; +} + +inline void QLineControl::setModified(bool modified) +{ + modifiedState = modified ? -1 : undoState; +} + +inline bool QLineControl::allSelected() const +{ + return !m_text.isEmpty() && selstart == 0 && selend == (int)m_text.length(); +} + +inline bool QLineControl::hasSelectedText() const +{ + return !m_text.isEmpty() && selend > selstart; +} + +inline int QLineControl::width() const +{ + return qRound(textLayout.lineAt(0).width()) + 1; +} + +inline int QLineControl::height() const +{ + return qRound(textLayout.lineAt(0).height()) + 1; +} + +inline int QLineControl::ascent() const +{ + return m_ascent; +} + +inline QString QLineControl::selectedText() const +{ + if (hasSelectedText()) + return m_text.mid(selstart, selend - selstart); + return QString(); +} + +inline QString QLineControl::textBeforeSelection() const +{ + if (hasSelectedText()) + return m_text.left(selstart); + return QString(); +} + +inline QString QLineControl::textAfterSelection() const +{ + if (hasSelectedText()) + return m_text.mid(selend); + return QString(); +} + +inline int QLineControl::selectionStart() const +{ + return hasSelectedText() ? selstart : -1; +} + +inline int QLineControl::selectionEnd() const +{ + return hasSelectedText() ? selend : -1; +} + +inline int QLineControl::start() const +{ + return 0; +} + +inline int QLineControl::end() const +{ + return m_text.length(); +} + +inline void QLineControl::removeSelection() +{ + int priorState = undoState; + removeSelectedText(); + finishChange(priorState); +} + +inline bool QLineControl::inSelection(int x) const +{ + if (selstart >= selend) return false; + int pos = xToPos(x, QTextLine::CursorOnCharacter); return pos >= selstart && pos < selend; +} + +inline int QLineControl::cursor() const +{ + return m_cursor; +} + +inline int QLineControl::preeditCursor() const +{ + return m_preeditCursor; +} + +inline int QLineControl::cursorWidth() const +{ + return m_cursorWidth; +} + +inline void QLineControl::setCursorWidth(int value) +{ + m_cursorWidth = value; +} + +inline void QLineControl::cursorForward(bool mark, int steps) +{ + int c = m_cursor; + if (steps > 0) { + while(steps--) + c = textLayout.nextCursorPosition(c); + } else if (steps < 0) { + while (steps++) + c = textLayout.previousCursorPosition(c); + } + moveCursor(c, mark); +} + +inline void QLineControl::cursorWordForward(bool mark) +{ + moveCursor(textLayout.nextCursorPosition(m_cursor, QTextLayout::SkipWords), mark); +} + +inline void QLineControl::home(bool mark) +{ + moveCursor(0, mark); +} + +inline void QLineControl::end(bool mark) +{ + moveCursor(text().length(), mark); +} + +inline void QLineControl::cursorWordBackward(bool mark) +{ + moveCursor(textLayout.previousCursorPosition(m_cursor, QTextLayout::SkipWords), mark); +} + +inline qreal QLineControl::cursorToX(int cursor) const +{ + return textLayout.lineAt(0).cursorToX(cursor); +} + +inline qreal QLineControl::cursorToX() const +{ + return cursorToX(m_cursor); +} + +inline bool QLineControl::isReadOnly() const +{ + return readOnly; +} + +inline void QLineControl::setReadOnly(bool enable) +{ + readOnly = enable; +} + +inline QString QLineControl::text() const +{ + QString res = maskData ? stripString(m_text) : m_text; + return (res.isNull() ? QString::fromLatin1("") : res); +} + +inline void QLineControl::setText(const QString &txt) +{ + p_setText(txt, -1, false); +} + +inline QString QLineControl::displayText() const +{ + return textLayout.text(); +} + +inline void QLineControl::deselect() +{ + p_deselect(); finishChange(); +} + +inline void QLineControl::selectAll() +{ + selstart = selend = m_cursor = 0; moveCursor(m_text.length(), true); +} + +inline void QLineControl::undo() +{ + p_undo(), finishChange(-1, true); +} + +inline void QLineControl::redo() +{ + p_redo(), finishChange(); +} + +inline uint QLineControl::echoMode() const +{ + return m_echoMode; +} + +inline void QLineControl::setEchoMode(uint mode) +{ + m_echoMode = mode; + m_passwordEchoEditing = false; + updateDisplayText(); +} + +inline void QLineControl::setMaxLength(int maxLength) +{ + if (maskData) + return; + m_maxLength = maxLength; + setText(m_text); +} + +inline int QLineControl::maxLength() const +{ + return m_maxLength; +} + +inline const QValidator *QLineControl::validator() const +{ + return m_validator; +} + +inline void QLineControl::setValidator(const QValidator *v) +{ + m_validator = const_cast(v); +} + +#ifndef QT_NO_COMPLETER +inline QCompleter *QLineControl::completer() const +{ + return m_completer; +} + +/* Note that you must set the widget for the completer seperately */ +inline void QLineControl::setCompleter(const QCompleter* c) +{ + m_completer = const_cast(c); +} +#endif + +inline void QLineControl::setCursorPosition(int pos) +{ + if (pos < 0) pos = 0; + if (pos < m_text.length()) + moveCursor(pos); +} + +inline int QLineControl::cursorPosition() const +{ + return m_cursor; +} + +inline bool QLineControl::hasAcceptableInput() const +{ + return hasAcceptableInput(m_text); +} + +inline QString QLineControl::inputMask() const +{ + return maskData ? m_inputMask + QLatin1Char(';') + blank : QString(); +} + +inline void QLineControl::setInputMask(const QString &mask) +{ + parseInputMask(mask); + if (maskData) + moveCursor(nextMaskBlank(0)); +} + +// input methods +#ifndef QT_NO_IM +inline bool QLineControl::composeMode() const +{ + return !textLayout.preeditAreaText().isEmpty(); +} + +inline void QLineControl::setPreeditArea(int cursor, const QString &text) +{ + textLayout.setPreeditArea(cursor, text); +} +#endif + +inline QString QLineControl::preeditAreaText() const +{ + return textLayout.preeditAreaText(); +} + +inline bool QLineControl::passwordEchoEditing() const +{ + return m_passwordEchoEditing; +} + +inline QChar QLineControl::passwordCharacter() const +{ + return m_passwordCharacter; +} + +inline void QLineControl::setPasswordCharacter(const QChar &character) +{ + m_passwordCharacter = character; + updateDisplayText(); +} + +inline Qt::LayoutDirection QLineControl::layoutDirection() const +{ + return m_layoutDirection; +} + +inline void QLineControl::setLayoutDirection(Qt::LayoutDirection direction) +{ + if (direction != m_layoutDirection) { + m_layoutDirection = direction; + updateDisplayText(); + } +} + +inline void QLineControl::setFont(const QFont &font) +{ + textLayout.setFont(font); + updateDisplayText(); +} + +inline int QLineControl::cursorBlinkPeriod() const +{ + return m_blinkPeriod; +} + +QT_END_NAMESPACE + +QT_END_HEADER +#endif // QT_NO_LINEEDIT + + +#endif // QLINECONTROL_P_H diff --git a/src/gui/widgets/qlinecontrol_p_p.h b/src/gui/widgets/qlinecontrol_p_p.h new file mode 100644 index 0000000..e76794b --- /dev/null +++ b/src/gui/widgets/qlinecontrol_p_p.h @@ -0,0 +1,105 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QLINECONTROL_P_P_H +#define QLINECONTROL_P_P_H + +// +// 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. +// + +#include "private/qobject_p.h" +#include "QtGui/qtextlayout.h" + +QT_BEGIN_NAMESPACE + +class QMimeData; +class QAbstractScrollArea; +class QInputContext; + +class QLineControlPrivate : public QObjectPrivate +{ + Q_DECLARE_PUBLIC(QLineControl) +public: + QLineControlPrivate() + : cursor(0), preeditCursor(0), cursorWidth(1), cursorTimer(0), + maxLength(32767), modifiedState(0), undoState(0), + selStart(0), selEnd(0), textInteractionFlags(0), + cursorVisible(0), hideCursor(0), echoMode(0) + {} + + QPalette palette; + QVector history; + QTextLayout textLayout; // display text + QString text; + + int cursor; + int preeditCursor; + int lastCursorPos; + int cursorWidth; + int cursorTimer; + + int maxLength; + + int modifiedState; + int undoState; + + int selStart, selEnd; + + Qt::TextInteractionFlags textInteractionFlags; + + // keep together and at end + uint cursorVisible : 1; + uint hideCursor : 1; // used to hide the cursor inside preedit areas + uint echoMode : 2; +}; + +QT_END_NAMESPACE + +#endif // QLINECONTROL_P_H + diff --git a/src/gui/widgets/qlineedit.cpp b/src/gui/widgets/qlineedit.cpp index d1067a8..baaad32 100644 --- a/src/gui/widgets/qlineedit.cpp +++ b/src/gui/widgets/qlineedit.cpp @@ -86,21 +86,12 @@ #include -#define verticalMargin 1 -#define horizontalMargin 2 - QT_BEGIN_NAMESPACE #ifdef Q_WS_MAC extern void qt_mac_secure_keyboard(bool); //qapplication_mac.cpp #endif -static inline bool shouldEnableInputMethod(QLineEdit *lineedit) -{ - const QLineEdit::EchoMode mode = lineedit->echoMode(); - return !lineedit->isReadOnly() && (mode == QLineEdit::Normal || mode == QLineEdit::PasswordEchoOnEdit); -} - /*! Initialize \a option with the values from this QLineEdit. This method is useful for subclasses when they need a QStyleOptionFrame or QStyleOptionFrameV2, but don't want @@ -122,7 +113,7 @@ void QLineEdit::initStyleOption(QStyleOptionFrame *option) const : 0; option->midLineWidth = 0; option->state |= QStyle::State_Sunken; - if (d->readOnly) + if (d->control->isReadOnly()) option->state |= QStyle::State_ReadOnly; #ifdef QT_KEYPAD_NAVIGATION if (hasEditFocus()) @@ -350,14 +341,14 @@ QLineEdit::QLineEdit(const QString& contents, const QString &inputMask, QWidget* { Q_D(QLineEdit); setObjectName(QString::fromAscii(name)); - d->parseInputMask(inputMask); - if (d->maskData) { - QString ms = d->maskString(0, contents); - d->init(ms + d->clearString(ms.length(), d->maxLength - ms.length())); - d->cursor = d->nextMaskBlank(ms.length()); - } else { + //d->control->parseInputMask(inputMask); + //if (d->control->maskData) { + // QString ms = d->control->maskString(0, contents); + // d->init(ms + d->control->clearString(ms.length(), d->control->maxLength() - ms.length())); + // d->control->moveCursor(d->control->nextMaskBlank(ms.length())); + // } else { d->init(contents); - } + // } } #endif @@ -388,19 +379,13 @@ QLineEdit::~QLineEdit() QString QLineEdit::text() const { Q_D(const QLineEdit); - QString res = d->text; - if (d->maskData) - res = d->stripString(d->text); - return (res.isNull() ? QString::fromLatin1("") : res); + return d->control->text(); } void QLineEdit::setText(const QString& text) { Q_D(QLineEdit); - d->setText(text, -1, false); -#ifdef QT_KEYPAD_NAVIGATION - d->origText = d->text; -#endif + d->control->setText(text); } @@ -421,17 +406,7 @@ void QLineEdit::setText(const QString& text) QString QLineEdit::displayText() const { Q_D(const QLineEdit); - if (d->echoMode == NoEcho) - return QString::fromLatin1(""); - QString res = d->text; - - if (d->echoMode == Password || (d->echoMode == PasswordEchoOnEdit - && !d->passwordEchoEditing)) { - QStyleOptionFrameV2 opt; - initStyleOption(&opt); - res.fill(style()->styleHint(QStyle::SH_LineEdit_PasswordCharacter, &opt, this)); - } - return (res.isNull() ? QString::fromLatin1("") : res); + return d->control->displayText(); } @@ -456,20 +431,15 @@ QString QLineEdit::displayText() const int QLineEdit::maxLength() const { Q_D(const QLineEdit); - return d->maxLength; + return d->control->maxLength(); } void QLineEdit::setMaxLength(int maxLength) { Q_D(QLineEdit); - if (d->maskData) - return; - d->maxLength = maxLength; - setText(d->text); + d->control->setMaxLength(maxLength); } - - /*! \property QLineEdit::frame \brief whether the line edit draws itself with a frame @@ -536,22 +506,20 @@ void QLineEdit::setFrame(bool enable) QLineEdit::EchoMode QLineEdit::echoMode() const { Q_D(const QLineEdit); - return (EchoMode) d->echoMode; + return (EchoMode) d->control->echoMode(); } void QLineEdit::setEchoMode(EchoMode mode) { Q_D(QLineEdit); - if (mode == (EchoMode)d->echoMode) + if (mode == (EchoMode)d->control->echoMode()) return; - setAttribute(Qt::WA_InputMethodEnabled, shouldEnableInputMethod(this)); - d->echoMode = mode; - d->passwordEchoEditing = false; - d->updateTextLayout(); + setAttribute(Qt::WA_InputMethodEnabled, d->shouldEnableInputMethod()); + d->control->setEchoMode(mode); update(); #ifdef Q_WS_MAC if (hasFocus()) - qt_mac_secure_keyboard(d->echoMode == Password || d->echoMode == NoEcho); + qt_mac_secure_keyboard(mode == Password || mode == NoEcho); #endif } @@ -567,7 +535,7 @@ void QLineEdit::setEchoMode(EchoMode mode) const QValidator * QLineEdit::validator() const { Q_D(const QLineEdit); - return d->validator; + return d->control->validator(); } /*! @@ -585,7 +553,7 @@ const QValidator * QLineEdit::validator() const void QLineEdit::setValidator(const QValidator *v) { Q_D(QLineEdit); - d->validator = const_cast(v); + d->control->setValidator(v); } #endif // QT_NO_VALIDATOR @@ -609,23 +577,23 @@ void QLineEdit::setValidator(const QValidator *v) void QLineEdit::setCompleter(QCompleter *c) { Q_D(QLineEdit); - if (c == d->completer) + if (c == d->control->completer()) return; - if (d->completer) { - disconnect(d->completer, 0, this, 0); - d->completer->setWidget(0); - if (d->completer->parent() == this) - delete d->completer; + if (d->control->completer()) { + disconnect(d->control->completer(), 0, this, 0); + d->control->completer()->setWidget(0); + if (d->control->completer()->parent() == this) + delete d->control->completer(); } - d->completer = c; + d->control->setCompleter(c); if (!c) return; if (c->widget() == 0) c->setWidget(this); if (hasFocus()) { - QObject::connect(d->completer, SIGNAL(activated(QString)), + QObject::connect(d->control->completer(), SIGNAL(activated(QString)), this, SLOT(setText(QString))); - QObject::connect(d->completer, SIGNAL(highlighted(QString)), + QObject::connect(d->control->completer(), SIGNAL(highlighted(QString)), this, SLOT(_q_completionHighlighted(QString))); } } @@ -638,83 +606,9 @@ void QLineEdit::setCompleter(QCompleter *c) QCompleter *QLineEdit::completer() const { Q_D(const QLineEdit); - return d->completer; -} - -// looks for an enabled item iterating forward(dir=1)/backward(dir=-1) from the -// current row based. dir=0 indicates a new completion prefix was set. -bool QLineEditPrivate::advanceToEnabledItem(int dir) -{ - int start = completer->currentRow(); - if (start == -1) - return false; - int i = start + dir; - if (dir == 0) dir = 1; - do { - if (!completer->setCurrentRow(i)) { - if (!completer->wrapAround()) - break; - i = i > 0 ? 0 : completer->completionCount() - 1; - } else { - QModelIndex currentIndex = completer->currentIndex(); - if (completer->completionModel()->flags(currentIndex) & Qt::ItemIsEnabled) - return true; - i += dir; - } - } while (i != start); - - completer->setCurrentRow(start); // restore - return false; -} - -void QLineEditPrivate::complete(int key) -{ - if (!completer || readOnly || echoMode != QLineEdit::Normal) - return; - - if (completer->completionMode() == QCompleter::InlineCompletion) { - if (key == Qt::Key_Backspace) - return; - int n = 0; - if (key == Qt::Key_Up || key == Qt::Key_Down) { - if (selend != 0 && selend != text.length()) - return; - QString prefix = hasSelectedText() ? text.left(selstart) : text; - if (text.compare(completer->currentCompletion(), completer->caseSensitivity()) != 0 - || prefix.compare(completer->completionPrefix(), completer->caseSensitivity()) != 0) { - completer->setCompletionPrefix(prefix); - } else { - n = (key == Qt::Key_Up) ? -1 : +1; - } - } else { - completer->setCompletionPrefix(text); - } - if (!advanceToEnabledItem(n)) - return; - } else { -#ifndef QT_KEYPAD_NAVIGATION - if (text.isEmpty()) { - completer->popup()->hide(); - return; - } -#endif - completer->setCompletionPrefix(text); - } - - completer->complete(); + return d->control->completer(); } -void QLineEditPrivate::_q_completionHighlighted(QString newText) -{ - Q_Q(QLineEdit); - if (completer->completionMode() != QCompleter::InlineCompletion) - q->setText(newText); - else { - int c = cursor; - q->setText(text.left(c) + newText.mid(c)); - q->setSelection(text.length(), c - newText.length()); - } -} #endif // QT_NO_COMPLETER /*! @@ -729,10 +623,10 @@ QSize QLineEdit::sizeHint() const Q_D(const QLineEdit); ensurePolished(); QFontMetrics fm(font()); - int h = qMax(fm.lineSpacing(), 14) + 2*verticalMargin + int h = qMax(fm.lineSpacing(), 14) + 2*d->verticalMargin + d->topTextMargin + d->bottomTextMargin + d->topmargin + d->bottommargin; - int w = fm.width(QLatin1Char('x')) * 17 + 2*horizontalMargin + int w = fm.width(QLatin1Char('x')) * 17 + 2*d->horizontalMargin + d->leftTextMargin + d->rightTextMargin + d->leftmargin + d->rightmargin; // "some" QStyleOptionFrameV2 opt; @@ -753,7 +647,7 @@ QSize QLineEdit::minimumSizeHint() const Q_D(const QLineEdit); ensurePolished(); QFontMetrics fm = fontMetrics(); - int h = fm.height() + qMax(2*verticalMargin, fm.leading()) + int h = fm.height() + qMax(2*d->verticalMargin, fm.leading()) + d->topmargin + d->bottommargin; int w = fm.maxWidth() + d->leftmargin + d->rightmargin; QStyleOptionFrameV2 opt; @@ -775,17 +669,13 @@ QSize QLineEdit::minimumSizeHint() const int QLineEdit::cursorPosition() const { Q_D(const QLineEdit); - return d->cursor; + return d->control->cursorPosition(); } void QLineEdit::setCursorPosition(int pos) { Q_D(QLineEdit); - if (pos < 0) - pos = 0; - - if (pos <= d->text.length()) - d->moveCursor(pos); + d->control->setCursorPosition(pos); } /*! @@ -807,22 +697,12 @@ int QLineEdit::cursorPositionAt(const QPoint &pos) bool QLineEdit::validateAndSet(const QString &newText, int newPos, int newMarkAnchor, int newMarkDrag) { - Q_D(QLineEdit); - int priorState = d->undoState; - d->selstart = 0; - d->selend = d->text.length(); - d->removeSelectedText(); - d->insert(newText); - d->finishChange(priorState); - if (d->undoState > priorState) { - d->cursor = newPos; - d->selstart = qMin(newMarkAnchor, newMarkDrag); - d->selend = qMax(newMarkAnchor, newMarkDrag); - update(); - d->emitCursorPositionChanged(); - return true; - } - return false; + // Note, this doesn't validate', but then neither + // does the suggested functions above in the docs. + setText(newText); + setCursorPosition(newPos); + setSelection(qMin(newMarkAnchor, newMarkDrag), qAbs(newMarkAnchor - newMarkDrag)); + return true; } #endif //QT3_SUPPORT @@ -863,15 +743,7 @@ void QLineEdit::setAlignment(Qt::Alignment alignment) void QLineEdit::cursorForward(bool mark, int steps) { Q_D(QLineEdit); - int cursor = d->cursor; - if (steps > 0) { - while(steps--) - cursor = d->textLayout.nextCursorPosition(cursor); - } else if (steps < 0) { - while (steps++) - cursor = d->textLayout.previousCursorPosition(cursor); - } - d->moveCursor(cursor, mark); + d->control->cursorForward(mark, steps); } @@ -896,7 +768,7 @@ void QLineEdit::cursorBackward(bool mark, int steps) void QLineEdit::cursorWordForward(bool mark) { Q_D(QLineEdit); - d->moveCursor(d->textLayout.nextCursorPosition(d->cursor, QTextLayout::SkipWords), mark); + d->control->cursorWordForward(mark); } /*! @@ -909,7 +781,7 @@ void QLineEdit::cursorWordForward(bool mark) void QLineEdit::cursorWordBackward(bool mark) { Q_D(QLineEdit); - d->moveCursor(d->textLayout.previousCursorPosition(d->cursor, QTextLayout::SkipWords), mark); + d->control->cursorWordBackward(mark); } @@ -924,26 +796,7 @@ void QLineEdit::cursorWordBackward(bool mark) void QLineEdit::backspace() { Q_D(QLineEdit); - int priorState = d->undoState; - if (d->hasSelectedText()) { - d->removeSelectedText(); - } else if (d->cursor) { - --d->cursor; - if (d->maskData) - d->cursor = d->prevMaskBlank(d->cursor); - QChar uc = d->text.at(d->cursor); - if (d->cursor > 0 && uc.unicode() >= 0xdc00 && uc.unicode() < 0xe000) { - // second half of a surrogate, check if we have the first half as well, - // if yes delete both at once - uc = d->text.at(d->cursor - 1); - if (uc.unicode() >= 0xd800 && uc.unicode() < 0xdc00) { - d->del(true); - --d->cursor; - } - } - d->del(true); - } - d->finishChange(priorState); + d->control->backspace(); } /*! @@ -957,15 +810,7 @@ void QLineEdit::backspace() void QLineEdit::del() { Q_D(QLineEdit); - int priorState = d->undoState; - if (d->hasSelectedText()) { - d->removeSelectedText(); - } else { - int n = d->textLayout.nextCursorPosition(d->cursor) - d->cursor; - while (n--) - d->del(); - } - d->finishChange(priorState); + d->control->del(); } /*! @@ -980,7 +825,7 @@ void QLineEdit::del() void QLineEdit::home(bool mark) { Q_D(QLineEdit); - d->moveCursor(0, mark); + d->control->home(mark); } /*! @@ -995,7 +840,7 @@ void QLineEdit::home(bool mark) void QLineEdit::end(bool mark) { Q_D(QLineEdit); - d->moveCursor(d->text.length(), mark); + d->control->end(mark); } @@ -1020,16 +865,13 @@ void QLineEdit::end(bool mark) bool QLineEdit::isModified() const { Q_D(const QLineEdit); - return d->modifiedState != d->undoState; + return d->control->isModified(); } void QLineEdit::setModified(bool modified) { Q_D(QLineEdit); - if (modified) - d->modifiedState = -1; - else - d->modifiedState = d->undoState; + d->control->setModified(modified); } @@ -1057,7 +899,7 @@ Use setModified(false) instead. bool QLineEdit::hasSelectedText() const { Q_D(const QLineEdit); - return d->hasSelectedText(); + return d->control->hasSelectedText(); } /*! @@ -1075,9 +917,7 @@ bool QLineEdit::hasSelectedText() const QString QLineEdit::selectedText() const { Q_D(const QLineEdit); - if (d->hasSelectedText()) - return d->text.mid(d->selstart, d->selend - d->selstart); - return QString(); + return d->control->selectedText(); } /*! @@ -1090,7 +930,7 @@ QString QLineEdit::selectedText() const int QLineEdit::selectionStart() const { Q_D(const QLineEdit); - return d->hasSelectedText() ? d->selstart : -1; + return d->control->selectionStart(); } @@ -1120,9 +960,10 @@ void QLineEdit::setEdited(bool on) { setModified(on); } int QLineEdit::characterAt(int xpos, QChar *chr) const { Q_D(const QLineEdit); - int pos = d->xToPos(xpos + contentsRect().x() - d->hscroll + horizontalMargin); - if (chr && pos < (int) d->text.length()) - *chr = d->text.at(pos); + int pos = d->xToPos(xpos + contentsRect().x() - d->hscroll + d->horizontalMargin); + QString txt = d->control->text(); + if (chr && pos < (int) txt.length()) + *chr = txt.at(pos); return pos; } @@ -1133,9 +974,9 @@ int QLineEdit::characterAt(int xpos, QChar *chr) const bool QLineEdit::getSelection(int *start, int *end) { Q_D(QLineEdit); - if (d->hasSelectedText() && start && end) { - *start = d->selstart; - *end = d->selend; + if (d->control->hasSelectedText() && start && end) { + *start = selectionStart(); + *end = *start + selectedText().length(); return true; } return false; @@ -1153,30 +994,19 @@ bool QLineEdit::getSelection(int *start, int *end) void QLineEdit::setSelection(int start, int length) { Q_D(QLineEdit); - if (start < 0 || start > (int)d->text.length()) { + if (start < 0 || start > (int)d->control->text().length()) { qWarning("QLineEdit::setSelection: Invalid start position (%d)", start); return; - } else { - if (length > 0) { - d->selstart = start; - d->selend = qMin(start + length, (int)d->text.length()); - d->cursor = d->selend; - } else { - d->selstart = qMax(start + length, 0); - d->selend = start; - d->cursor = d->selstart; - } } - if (d->hasSelectedText()){ + d->control->setSelection(start, length); + + if (d->control->hasSelectedText()){ QStyleOptionFrameV2 opt; initStyleOption(&opt); if (!style()->styleHint(QStyle::SH_BlinkCursorWhenTextSelected, &opt, this)) d->setCursorVisible(false); } - - update(); - d->emitCursorPositionChanged(); } @@ -1192,7 +1022,7 @@ void QLineEdit::setSelection(int start, int length) bool QLineEdit::isUndoAvailable() const { Q_D(const QLineEdit); - return d->isUndoAvailable(); + return d->control->isUndoAvailable(); } /*! @@ -1208,7 +1038,7 @@ bool QLineEdit::isUndoAvailable() const bool QLineEdit::isRedoAvailable() const { Q_D(const QLineEdit); - return d->isRedoAvailable(); + return d->control->isRedoAvailable(); } /*! @@ -1244,7 +1074,7 @@ void QLineEdit::setDragEnabled(bool b) bool QLineEdit::hasAcceptableInput() const { Q_D(const QLineEdit); - return d->hasAcceptableInput(d->text); + return d->control->hasAcceptableInput(); } /*! @@ -1350,15 +1180,13 @@ void QLineEdit::getTextMargins(int *left, int *top, int *right, int *bottom) con QString QLineEdit::inputMask() const { Q_D(const QLineEdit); - return (d->maskData ? d->inputMask + QLatin1Char(';') + d->blank : QString()); + return d->control->inputMask(); } void QLineEdit::setInputMask(const QString &inputMask) { Q_D(QLineEdit); - d->parseInputMask(inputMask); - if (d->maskData) - d->moveCursor(d->nextMaskBlank(0)); + d->control->setInputMask(inputMask); } /*! @@ -1373,8 +1201,7 @@ void QLineEdit::setInputMask(const QString &inputMask) void QLineEdit::selectAll() { Q_D(QLineEdit); - d->selstart = d->selend = d->cursor = 0; - d->moveCursor(d->text.length(), true); + d->control->selectAll(); } /*! @@ -1386,8 +1213,7 @@ void QLineEdit::selectAll() void QLineEdit::deselect() { Q_D(QLineEdit); - d->deselect(); - d->finishChange(); + d->control->deselect(); } @@ -1402,10 +1228,7 @@ void QLineEdit::insert(const QString &newText) { // q->resetInputContext(); //#### FIX ME IN QT Q_D(QLineEdit); - int priorState = d->undoState; - d->removeSelectedText(); - d->insert(newText); - d->finishChange(priorState); + d->control->insert(newText); } /*! @@ -1416,13 +1239,8 @@ void QLineEdit::insert(const QString &newText) void QLineEdit::clear() { Q_D(QLineEdit); - int priorState = d->undoState; resetInputContext(); - d->selstart = 0; - d->selend = d->text.length(); - d->removeSelectedText(); - d->separate(); - d->finishChange(priorState, /*update*/false, /*edited*/false); + d->control->clear(); } /*! @@ -1435,8 +1253,7 @@ void QLineEdit::undo() { Q_D(QLineEdit); resetInputContext(); - d->undo(); - d->finishChange(-1, true); + d->control->undo(); } /*! @@ -1447,8 +1264,7 @@ void QLineEdit::redo() { Q_D(QLineEdit); resetInputContext(); - d->redo(); - d->finishChange(); + d->control->redo(); } @@ -1470,16 +1286,16 @@ void QLineEdit::redo() bool QLineEdit::isReadOnly() const { Q_D(const QLineEdit); - return d->readOnly; + return d->control->isReadOnly(); } void QLineEdit::setReadOnly(bool enable) { Q_D(QLineEdit); - if (d->readOnly != enable) { - d->readOnly = enable; - setAttribute(Qt::WA_MacShowFocusRect, !d->readOnly); - setAttribute(Qt::WA_InputMethodEnabled, shouldEnableInputMethod(this)); + if (d->control->isReadOnly() != enable) { + d->control->setReadOnly(enable); + setAttribute(Qt::WA_MacShowFocusRect, !enable); + setAttribute(Qt::WA_InputMethodEnabled, d->shouldEnableInputMethod()); #ifndef QT_NO_CURSOR setCursor(enable ? Qt::ArrowCursor : Qt::IBeamCursor); #endif @@ -1518,7 +1334,7 @@ void QLineEdit::cut() void QLineEdit::copy() const { Q_D(const QLineEdit); - d->copy(); + d->control->copy(); } /*! @@ -1535,23 +1351,7 @@ void QLineEdit::copy() const void QLineEdit::paste() { Q_D(QLineEdit); - if (echoMode() == PasswordEchoOnEdit && !d->passwordEchoEditing) { - // Clear the edit and reset to normal echo mode when pasting; the echo - // mode switches back when the edit loses focus. ### changes a public - // property, resets current content - d->updatePasswordEchoEditing(true); - clear(); - } - insert(QApplication::clipboard()->text(QClipboard::Clipboard)); -} - -void QLineEditPrivate::copy(bool clipboard) const -{ - Q_Q(const QLineEdit); - QString t = q->selectedText(); - if (!t.isEmpty() && echoMode == QLineEdit::Normal) { - QApplication::clipboard()->setText(t, clipboard ? QClipboard::Clipboard : QClipboard::Selection); - } + d->control->paste(); } #endif // !QT_NO_CLIPBOARD @@ -1561,57 +1361,10 @@ void QLineEditPrivate::copy(bool clipboard) const bool QLineEdit::event(QEvent * e) { Q_D(QLineEdit); -#ifndef QT_NO_SHORTCUT - if (e->type() == QEvent::ShortcutOverride && !d->readOnly) { - QKeyEvent* ke = (QKeyEvent*) e; - if (ke == QKeySequence::Copy - || ke == QKeySequence::Paste - || ke == QKeySequence::Cut - || ke == QKeySequence::Redo - || ke == QKeySequence::Undo - || ke == QKeySequence::MoveToNextWord - || ke == QKeySequence::MoveToPreviousWord - || ke == QKeySequence::MoveToStartOfDocument - || ke == QKeySequence::MoveToEndOfDocument - || ke == QKeySequence::SelectNextWord - || ke == QKeySequence::SelectPreviousWord - || ke == QKeySequence::SelectStartOfLine - || ke == QKeySequence::SelectEndOfLine - || ke == QKeySequence::SelectStartOfBlock - || ke == QKeySequence::SelectEndOfBlock - || ke == QKeySequence::SelectStartOfDocument - || ke == QKeySequence::SelectAll - || ke == QKeySequence::SelectEndOfDocument) { - ke->accept(); - } else if (ke->modifiers() == Qt::NoModifier || ke->modifiers() == Qt::ShiftModifier - || ke->modifiers() == Qt::KeypadModifier) { - if (ke->key() < Qt::Key_Escape) { - ke->accept(); - } else { - switch (ke->key()) { - case Qt::Key_Delete: - case Qt::Key_Home: - case Qt::Key_End: - case Qt::Key_Backspace: - case Qt::Key_Left: - case Qt::Key_Right: - ke->accept(); - default: - break; - } - } - } - } else -#endif if (e->type() == QEvent::Timer) { // should be timerEvent, is here for binary compatibility int timerId = ((QTimerEvent*)e)->timerId(); - if (timerId == d->cursorTimer) { - QStyleOptionFrameV2 opt; - initStyleOption(&opt); - if(!hasSelectedText() - || style()->styleHint(QStyle::SH_BlinkCursorWhenTextSelected, &opt, this)) - d->setCursorVisible(!d->cursorVisible); + if (false) { #ifndef QT_NO_DRAGANDDROP } else if (timerId == d->dndTimer.timerId()) { d->drag(); @@ -1619,62 +1372,20 @@ bool QLineEdit::event(QEvent * e) } else if (timerId == d->tripleClickTimer.timerId()) d->tripleClickTimer.stop(); -#ifdef QT_KEYPAD_NAVIGATION - else if (timerId == d->deleteAllTimer.timerId()) { - d->deleteAllTimer.stop(); - clear(); - } -#endif } else if (e->type() == QEvent::ContextMenu) { #ifndef QT_NO_IM - if (d->composeMode()) + if (d->control->composeMode()) return true; #endif - d->separate(); + //d->separate(); } else if (e->type() == QEvent::WindowActivate) { QTimer::singleShot(0, this, SLOT(_q_handleWindowActivate())); + }else if(e->type() == QEvent::ShortcutOverride){ + d->control->processEvent(e); + }else if(e->type() == QEvent::LayoutDirectionChange){ + d->control->setLayoutDirection((layoutDirection())); } -#ifdef QT_KEYPAD_NAVIGATION - if (QApplication::keypadNavigationEnabled()) { - if ((e->type() == QEvent::KeyPress) || (e->type() == QEvent::KeyRelease)) { - QKeyEvent *ke = (QKeyEvent *)e; - if (ke->key() == Qt::Key_Back) { - if (ke->isAutoRepeat()) { - // Swallow it. We don't want back keys running amok. - ke->accept(); - return true; - } - if ((e->type() == QEvent::KeyRelease) - && !isReadOnly() - && d->deleteAllTimer.isActive()) { - d->deleteAllTimer.stop(); - backspace(); - ke->accept(); - return true; - } - } - } else if (e->type() == QEvent::EnterEditFocus) { - end(false); - if (!d->cursorTimer) { - int cft = QApplication::cursorFlashTime(); - d->cursorTimer = cft ? startTimer(cft/2) : -1; - } - } else if (e->type() == QEvent::LeaveEditFocus) { - d->setCursorVisible(false); - if (d->cursorTimer > 0) - killTimer(d->cursorTimer); - d->cursorTimer = 0; - - if (!d->emitingEditingFinished) { - if (hasAcceptableInput() || d->fixup()) { - d->emitingEditingFinished = true; - emit editingFinished(); - d->emitingEditingFinished = false; - } - } - } - } -#endif + return QWidget::event(e); } @@ -1684,37 +1395,35 @@ void QLineEdit::mousePressEvent(QMouseEvent* e) { Q_D(QLineEdit); if (d->sendMouseEventToInputContext(e)) - return; + return; if (e->button() == Qt::RightButton) return; #ifdef QT_KEYPAD_NAVIGATION if (QApplication::keypadNavigationEnabled() && !hasEditFocus()) { setEditFocus(true); // Get the completion list to pop up. - if (d->completer) - d->completer->complete(); + if (d->control->completer()) + d->control->completer()->complete(); } #endif if (d->tripleClickTimer.isActive() && (e->pos() - d->tripleClick).manhattanLength() < QApplication::startDragDistance()) { selectAll(); - return; + return; } bool mark = e->modifiers() & Qt::ShiftModifier; int cursor = d->xToPos(e->pos().x()); #ifndef QT_NO_DRAGANDDROP - if (!mark && d->dragEnabled && d->echoMode == Normal && - e->button() == Qt::LeftButton && d->inSelection(e->pos().x())) { - d->cursor = cursor; - update(); + if (!mark && d->dragEnabled && d->control->echoMode() == Normal && + e->button() == Qt::LeftButton && d->control->inSelection(e->pos().x())) { + d->control->moveCursor(cursor); d->dndPos = e->pos(); if (!d->dndTimer.isActive()) d->dndTimer.start(QApplication::startDragTime(), this); - d->emitCursorPositionChanged(); } else #endif { - d->moveCursor(cursor, mark); + d->control->moveCursor(cursor, mark); } } @@ -1724,7 +1433,7 @@ void QLineEdit::mouseMoveEvent(QMouseEvent * e) { Q_D(QLineEdit); if (d->sendMouseEventToInputContext(e)) - return; + return; if (e->buttons() & Qt::LeftButton) { #ifndef QT_NO_DRAGANDDROP @@ -1734,7 +1443,7 @@ void QLineEdit::mouseMoveEvent(QMouseEvent * e) } else #endif { - d->moveCursor(d->xToPos(e->pos().x()), true); + d->control->moveCursor(d->xToPos(e->pos().x()), true); } } } @@ -1745,26 +1454,19 @@ void QLineEdit::mouseReleaseEvent(QMouseEvent* e) { Q_D(QLineEdit); if (d->sendMouseEventToInputContext(e)) - return; + return; + + if (e->buttons() & Qt::LeftButton) { #ifndef QT_NO_DRAGANDDROP - if (e->button() == Qt::LeftButton) { if (d->dndTimer.isActive()) { - d->dndTimer.stop(); - deselect(); - return; - } - } + if ((d->dndPos - e->pos()).manhattanLength() > QApplication::startDragDistance()) + d->drag(); + } else #endif -#ifndef QT_NO_CLIPBOARD - if (QApplication::clipboard()->supportsSelection()) { - if (e->button() == Qt::LeftButton) { - d->copy(false); - } else if (!d->readOnly && e->button() == Qt::MidButton) { - d->deselect(); - insert(QApplication::clipboard()->text(QClipboard::Selection)); + { + d->control->moveCursor(d->xToPos(e->pos().x()), true); } } -#endif } /*! \reimp @@ -1773,16 +1475,9 @@ void QLineEdit::mouseDoubleClickEvent(QMouseEvent* e) { Q_D(QLineEdit); if (d->sendMouseEventToInputContext(e)) - return; + return; if (e->button() == Qt::LeftButton) { - deselect(); - d->cursor = d->xToPos(e->pos().x()); - d->cursor = d->textLayout.previousCursorPosition(d->cursor, QTextLayout::SkipWords); - // ## text layout should support end of words. - int end = d->textLayout.nextCursorPosition(d->cursor, QTextLayout::SkipWords); - while (end > d->cursor && d->text[end-1].isSpace()) - --end; - d->moveCursor(end, true); + d->control->selectWordAtPos(d->xToPos(e->pos().x())); d->tripleClickTimer.start(QApplication::doubleClickInterval(), this); d->tripleClick = e->pos(); } @@ -1822,65 +1517,15 @@ void QLineEdit::mouseDoubleClickEvent(QMouseEvent* e) void QLineEdit::keyPressEvent(QKeyEvent *event) { Q_D(QLineEdit); - - bool inlineCompletionAccepted = false; - -#ifndef QT_NO_COMPLETER - if (d->completer) { - QCompleter::CompletionMode completionMode = d->completer->completionMode(); - if ((completionMode == QCompleter::PopupCompletion - || completionMode == QCompleter::UnfilteredPopupCompletion) - &&d->completer->popup() - && d->completer->popup()->isVisible()) { - // The following keys are forwarded by the completer to the widget - // Ignoring the events lets the completer provide suitable default behavior - switch (event->key()) { - case Qt::Key_Escape: - event->ignore(); - return; - case Qt::Key_Enter: - case Qt::Key_Return: - case Qt::Key_F4: -#ifdef QT_KEYPAD_NAVIGATION - case Qt::Key_Select: - if (!QApplication::keypadNavigationEnabled()) - break; -#endif - d->completer->popup()->hide(); // just hide. will end up propagating to parent - default: - break; // normal key processing - } - } else if (completionMode == QCompleter::InlineCompletion) { - switch (event->key()) { - case Qt::Key_Enter: - case Qt::Key_Return: - case Qt::Key_F4: -#ifdef QT_KEYPAD_NAVIGATION - case Qt::Key_Select: - if (!QApplication::keypadNavigationEnabled()) - break; -#endif - if (!d->completer->currentCompletion().isEmpty() && d->selend > d->selstart - && d->selend == d->text.length()) { - setText(d->completer->currentCompletion()); - inlineCompletionAccepted = true; - } - default: - break; // normal key processing - } - } - } -#endif // QT_NO_COMPLETER - -#ifdef QT_KEYPAD_NAVIGATION + #ifdef QT_KEYPAD_NAVIGATION bool select = false; switch (event->key()) { case Qt::Key_Select: if (QApplication::keypadNavigationEnabled()) { if (hasEditFocus()) { setEditFocus(false); - if (d->completer && d->completer->popup()->isVisible()) - d->completer->popup()->hide(); + if (d->control->completer() && d->control->completer()->popup()->isVisible()) + d->control->completer()->popup()->hide(); select = true; } } @@ -1916,274 +1561,7 @@ void QLineEdit::keyPressEvent(QKeyEvent *event) return; // Just start. No action. } #endif - - if (echoMode() == PasswordEchoOnEdit - && !d->passwordEchoEditing - && !isReadOnly() - && !event->text().isEmpty() -#ifdef QT_KEYPAD_NAVIGATION - && event->key() != Qt::Key_Select - && event->key() != Qt::Key_Up - && event->key() != Qt::Key_Down - && event->key() != Qt::Key_Back -#endif - && !(event->modifiers() & Qt::ControlModifier)) { - // Clear the edit and reset to normal echo mode while editing; the - // echo mode switches back when the edit loses focus. ### changes a - // public property, resets current content. dubious code; you can - // navigate with keys up, down, back, and select(?), but if you press - // "left" or "right" it clears? - d->updatePasswordEchoEditing(true); - clear(); - } - - d->setCursorVisible(true); - if (event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return) { - if (hasAcceptableInput() || d->fixup()) { - emit returnPressed(); - d->emitingEditingFinished = true; - emit editingFinished(); - d->emitingEditingFinished = false; - } - if (inlineCompletionAccepted) - event->accept(); - else - event->ignore(); - return; - } - bool unknown = false; - - if (false) { - } -#ifndef QT_NO_SHORTCUT - else if (event == QKeySequence::Undo) { - if (!d->readOnly) - undo(); - } - else if (event == QKeySequence::Redo) { - if (!d->readOnly) - redo(); - } - else if (event == QKeySequence::SelectAll) { - selectAll(); - } -#ifndef QT_NO_CLIPBOARD - else if (event == QKeySequence::Copy) { - copy(); - } - else if (event == QKeySequence::Paste) { - if (!d->readOnly) - paste(); - } - else if (event == QKeySequence::Cut) { - if (!d->readOnly) { - cut(); - } - } - else if (event == QKeySequence::DeleteEndOfLine) { - if (!d->readOnly) { - setSelection(d->cursor, d->text.size()); - copy(); - del(); - } - } -#endif //QT_NO_CLIPBOARD - else if (event == QKeySequence::MoveToStartOfLine) { - home(0); - } - else if (event == QKeySequence::MoveToEndOfLine) { - end(0); - } - else if (event == QKeySequence::SelectStartOfLine) { - home(1); - } - else if (event == QKeySequence::SelectEndOfLine) { - end(1); - } - else if (event == QKeySequence::MoveToNextChar) { -#if !defined(Q_WS_WIN) || defined(QT_NO_COMPLETER) - if (d->hasSelectedText()) { -#else - if (d->hasSelectedText() && d->completer - && d->completer->completionMode() == QCompleter::InlineCompletion) { -#endif - d->moveCursor(d->selend, false); - } else { - cursorForward(0, layoutDirection() == Qt::LeftToRight ? 1 : -1); - } - } - else if (event == QKeySequence::SelectNextChar) { - cursorForward(1, layoutDirection() == Qt::LeftToRight ? 1 : -1); - } - else if (event == QKeySequence::MoveToPreviousChar) { -#if !defined(Q_WS_WIN) || defined(QT_NO_COMPLETER) - if (d->hasSelectedText()) { -#else - if (d->hasSelectedText() && d->completer - && d->completer->completionMode() == QCompleter::InlineCompletion) { -#endif - d->moveCursor(d->selstart, false); - } else { - cursorBackward(0, layoutDirection() == Qt::LeftToRight ? 1 : -1); - } - } - else if (event == QKeySequence::SelectPreviousChar) { - cursorBackward(1, layoutDirection() == Qt::LeftToRight ? 1 : -1); - } - else if (event == QKeySequence::MoveToNextWord) { - if (echoMode() == Normal) - layoutDirection() == Qt::LeftToRight ? cursorWordForward(0) : cursorWordBackward(0); - else - layoutDirection() == Qt::LeftToRight ? end(0) : home(0); - } - else if (event == QKeySequence::MoveToPreviousWord) { - if (echoMode() == Normal) - layoutDirection() == Qt::LeftToRight ? cursorWordBackward(0) : cursorWordForward(0); - else if (!d->readOnly) { - layoutDirection() == Qt::LeftToRight ? home(0) : end(0); - } - } - else if (event == QKeySequence::SelectNextWord) { - if (echoMode() == Normal) - layoutDirection() == Qt::LeftToRight ? cursorWordForward(1) : cursorWordBackward(1); - else - layoutDirection() == Qt::LeftToRight ? end(1) : home(1); - } - else if (event == QKeySequence::SelectPreviousWord) { - if (echoMode() == Normal) - layoutDirection() == Qt::LeftToRight ? cursorWordBackward(1) : cursorWordForward(1); - else - layoutDirection() == Qt::LeftToRight ? home(1) : end(1); - } - else if (event == QKeySequence::Delete) { - if (!d->readOnly) - del(); - } - else if (event == QKeySequence::DeleteEndOfWord) { - if (!d->readOnly) { - cursorWordForward(true); - del(); - } - } - else if (event == QKeySequence::DeleteStartOfWord) { - if (!d->readOnly) { - cursorWordBackward(true); - del(); - } - } -#endif // QT_NO_SHORTCUT - else { -#ifdef Q_WS_MAC - if (event->key() == Qt::Key_Up || event->key() == Qt::Key_Down) { - Qt::KeyboardModifiers myModifiers = (event->modifiers() & ~Qt::KeypadModifier); - if (myModifiers & Qt::ShiftModifier) { - if (myModifiers == (Qt::ControlModifier|Qt::ShiftModifier) - || myModifiers == (Qt::AltModifier|Qt::ShiftModifier) - || myModifiers == Qt::ShiftModifier) { - - event->key() == Qt::Key_Up ? home(1) : end(1); - } - } else { - if ((myModifiers == Qt::ControlModifier - || myModifiers == Qt::AltModifier - || myModifiers == Qt::NoModifier)) { - event->key() == Qt::Key_Up ? home(0) : end(0); - } - } - } -#endif - if (event->modifiers() & Qt::ControlModifier) { - switch (event->key()) { - case Qt::Key_Backspace: - if (!d->readOnly) { - cursorWordBackward(true); - del(); - } - break; -#ifndef QT_NO_COMPLETER - case Qt::Key_Up: - case Qt::Key_Down: - d->complete(event->key()); - break; -#endif -#if defined(Q_WS_X11) - case Qt::Key_E: - end(0); - break; - - case Qt::Key_U: - if (!d->readOnly) { - setSelection(0, d->text.size()); -#ifndef QT_NO_CLIPBOARD - copy(); -#endif - del(); - } - break; -#endif - default: - unknown = true; - } - } else { // ### check for *no* modifier - switch (event->key()) { - case Qt::Key_Backspace: - if (!d->readOnly) { - backspace(); -#ifndef QT_NO_COMPLETER - d->complete(Qt::Key_Backspace); -#endif - } - break; -#ifdef QT_KEYPAD_NAVIGATION - case Qt::Key_Back: - if (QApplication::keypadNavigationEnabled() && !event->isAutoRepeat() - && !isReadOnly()) { - if (text().length() == 0) { - setText(d->origText); - - if (d->passwordEchoEditing) - d->updatePasswordEchoEditing(false); - - setEditFocus(false); - } else if (!d->deleteAllTimer.isActive()) { - d->deleteAllTimer.start(750, this); - } - } else { - unknown = true; - } - break; -#endif - - default: - unknown = true; - } - } - } - - if (event->key() == Qt::Key_Direction_L || event->key() == Qt::Key_Direction_R) { - setLayoutDirection((event->key() == Qt::Key_Direction_L) ? Qt::LeftToRight : Qt::RightToLeft); - d->updateTextLayout(); - update(); - unknown = false; - } - - if (unknown && !d->readOnly) { - QString t = event->text(); - if (!t.isEmpty() && t.at(0).isPrint() && - ((event->modifiers() & (Qt::ControlModifier | Qt::AltModifier | Qt::MetaModifier)) == Qt::NoModifier)) { - insert(t); -#ifndef QT_NO_COMPLETER - d->complete(event->key()); -#endif - event->accept(); - return; - } - } - - if (unknown) - event->ignore(); - else - event->accept(); + d->control->processKeyEvent(event); } /*! @@ -2197,50 +1575,17 @@ QRect QLineEdit::cursorRect() const return d->cursorRect(); } -/*! - This function is not intended as polymorphic usage. Just a shared code - fragment that calls QInputContext::mouseHandler for this - class. -*/ -bool QLineEditPrivate::sendMouseEventToInputContext( QMouseEvent *e ) -{ -#if !defined QT_NO_IM - Q_Q(QLineEdit); - if ( composeMode() ) { - int tmp_cursor = xToPos(e->pos().x()); - int mousePos = tmp_cursor - cursor; - if ( mousePos < 0 || mousePos > textLayout.preeditAreaText().length() ) { - mousePos = -1; - // don't send move events outside the preedit area - if ( e->type() == QEvent::MouseMove ) - return true; - } - - QInputContext *qic = q->inputContext(); - if ( qic ) - // may be causing reset() in some input methods - qic->mouseHandler(mousePos, e); - if (!textLayout.preeditAreaText().isEmpty()) - return true; - } -#else - Q_UNUSED(e); -#endif - - return false; -} - /*! \reimp */ void QLineEdit::inputMethodEvent(QInputMethodEvent *e) { Q_D(QLineEdit); - if (d->readOnly) { + if (d->control->isReadOnly()) { e->ignore(); return; } - if (echoMode() == PasswordEchoOnEdit && !d->passwordEchoEditing) { + if (echoMode() == PasswordEchoOnEdit && !d->control->passwordEchoEditing()) { // Clear the edit and reset to normal echo mode while entering input // method data; the echo mode switches back when the edit loses focus. // ### changes a public property, resets current content. @@ -2248,6 +1593,8 @@ void QLineEdit::inputMethodEvent(QInputMethodEvent *e) clear(); } + d->control->processInputMethodEvent(e); + #ifdef QT_KEYPAD_NAVIGATION // Focus in if currently in navigation focus on the widget // Only focus in on preedits, to allow input methods to @@ -2260,55 +1607,9 @@ void QLineEdit::inputMethodEvent(QInputMethodEvent *e) } #endif - int priorState = d->undoState; - d->removeSelectedText(); - - int c = d->cursor; // cursor position after insertion of commit string - if (e->replacementStart() <= 0) - c += e->commitString().length() + qMin(-e->replacementStart(), e->replacementLength()); - - d->cursor += e->replacementStart(); - - // insert commit string - if (e->replacementLength()) { - d->selstart = d->cursor; - d->selend = d->selstart + e->replacementLength(); - d->removeSelectedText(); - } - if (!e->commitString().isEmpty()) - d->insert(e->commitString()); - - d->cursor = qMin(c, d->text.length()); - - d->textLayout.setPreeditArea(d->cursor, e->preeditString()); - d->preeditCursor = e->preeditString().length(); - d->hideCursor = false; - QList formats; - for (int i = 0; i < e->attributes().size(); ++i) { - const QInputMethodEvent::Attribute &a = e->attributes().at(i); - if (a.type == QInputMethodEvent::Cursor) { - d->preeditCursor = a.start; - d->hideCursor = !a.length; - } else if (a.type == QInputMethodEvent::TextFormat) { - QTextCharFormat f = qvariant_cast(a.value).toCharFormat(); - if (f.isValid()) { - QTextLayout::FormatRange o; - o.start = a.start + d->cursor; - o.length = a.length; - o.format = f; - formats.append(o); - } - } - } - d->textLayout.setAdditionalFormats(formats); - d->updateTextLayout(); - update(); - if (!e->commitString().isEmpty()) - d->emitCursorPositionChanged(); - d->finishChange(priorState); #ifndef QT_NO_COMPLETER if (!e->commitString().isEmpty()) - d->complete(Qt::Key_unknown); + d->control->complete(Qt::Key_unknown); #endif } @@ -2323,9 +1624,9 @@ QVariant QLineEdit::inputMethodQuery(Qt::InputMethodQuery property) const case Qt::ImFont: return font(); case Qt::ImCursorPosition: - return QVariant((d->selend - d->selstart == 0) ? d->cursor : d->selend); + return QVariant(d->control->hasSelectedText() ? d->control->selectionEnd() : d->control->cursor()); case Qt::ImSurroundingText: - return QVariant(d->text); + return QVariant(text()); case Qt::ImCurrentSelection: return QVariant(selectedText()); default: @@ -2342,36 +1643,34 @@ void QLineEdit::focusInEvent(QFocusEvent *e) if (e->reason() == Qt::TabFocusReason || e->reason() == Qt::BacktabFocusReason || e->reason() == Qt::ShortcutFocusReason) { - if (d->maskData) - d->moveCursor(d->nextMaskBlank(0)); - else if (!d->hasSelectedText()) + if (!d->control->inputMask().isEmpty()) + d->control->moveCursor(d->control->nextMaskBlank(0)); + else if (!d->control->hasSelectedText()) selectAll(); } #ifdef QT_KEYPAD_NAVIGATION if (!QApplication::keypadNavigationEnabled() || (hasEditFocus() && e->reason() == Qt::PopupFocusReason)) #endif - if (!d->cursorTimer) { - int cft = QApplication::cursorFlashTime(); - d->cursorTimer = cft ? startTimer(cft/2) : -1; - } + int cft = QApplication::cursorFlashTime(); + d->control->setCursorBlinkPeriod(cft/2); QStyleOptionFrameV2 opt; initStyleOption(&opt); - if((!hasSelectedText() && d->textLayout.preeditAreaText().isEmpty()) + if((!hasSelectedText() && d->control->preeditAreaText().isEmpty()) || style()->styleHint(QStyle::SH_BlinkCursorWhenTextSelected, &opt, this)) d->setCursorVisible(true); #ifdef Q_WS_MAC - if (d->echoMode == Password || d->echoMode == NoEcho) + if (d->control->echoMode() == Password || d->control->echoMode() == NoEcho) qt_mac_secure_keyboard(true); #endif #ifdef QT_KEYPAD_NAVIGATION d->origText = d->text; #endif #ifndef QT_NO_COMPLETER - if (d->completer) { - d->completer->setWidget(this); - QObject::connect(d->completer, SIGNAL(activated(QString)), + if (d->control->completer()) { + d->control->completer()->setWidget(this); + QObject::connect(d->control->completer(), SIGNAL(activated(QString)), this, SLOT(setText(QString))); - QObject::connect(d->completer, SIGNAL(highlighted(QString)), + QObject::connect(d->control->completer(), SIGNAL(highlighted(QString)), this, SLOT(_q_completionHighlighted(QString))); } #endif @@ -2384,7 +1683,7 @@ void QLineEdit::focusInEvent(QFocusEvent *e) void QLineEdit::focusOutEvent(QFocusEvent *e) { Q_D(QLineEdit); - if (d->passwordEchoEditing) { + if (d->control->passwordEchoEditing()) { // Reset the echomode back to PasswordEchoOnEdit when the widget loses // focus. d->updatePasswordEchoEditing(false); @@ -2396,21 +1695,18 @@ void QLineEdit::focusOutEvent(QFocusEvent *e) deselect(); d->setCursorVisible(false); - if (d->cursorTimer > 0) - killTimer(d->cursorTimer); - d->cursorTimer = 0; - + d->control->setCursorBlinkPeriod(0); #ifdef QT_KEYPAD_NAVIGATION // editingFinished() is already emitted on LeaveEditFocus if (!QApplication::keypadNavigationEnabled()) #endif if (reason != Qt::PopupFocusReason || !(QApplication::activePopupWidget() && QApplication::activePopupWidget()->parentWidget() == this)) { - if (!d->emitingEditingFinished) { - if (hasAcceptableInput() || d->fixup()) { - d->emitingEditingFinished = true; + if (!d->control->emitingEditingFinished) { + if (hasAcceptableInput() || d->control->fixup()) { + d->control->emitingEditingFinished = true; emit editingFinished(); - d->emitingEditingFinished = false; + d->control->emitingEditingFinished = false; } } #ifdef QT3_SUPPORT @@ -2418,15 +1714,15 @@ void QLineEdit::focusOutEvent(QFocusEvent *e) #endif } #ifdef Q_WS_MAC - if (d->echoMode == Password || d->echoMode == NoEcho) + if (d->control->echoMode() == Password || d->control->echoMode() == NoEcho) qt_mac_secure_keyboard(false); #endif #ifdef QT_KEYPAD_NAVIGATION d->origText = QString(); #endif #ifndef QT_NO_COMPLETER - if (d->completer) { - QObject::disconnect(d->completer, 0, this, 0); + if (d->control->completer()) { + QObject::disconnect(d->control->completer(), 0, this, 0); } #endif update(); @@ -2456,24 +1752,19 @@ void QLineEdit::paintEvent(QPaintEvent *) Qt::Alignment va = QStyle::visualAlignment(layoutDirection(), QFlag(d->alignment)); switch (va & Qt::AlignVertical_Mask) { case Qt::AlignBottom: - d->vscroll = r.y() + r.height() - fm.height() - verticalMargin; + d->vscroll = r.y() + r.height() - fm.height() - d->verticalMargin; break; case Qt::AlignTop: - d->vscroll = r.y() + verticalMargin; + d->vscroll = r.y() + d->verticalMargin; break; default: //center d->vscroll = r.y() + (r.height() - fm.height() + 1) / 2; break; } - QRect lineRect(r.x() + horizontalMargin, d->vscroll, r.width() - 2*horizontalMargin, fm.height()); - QTextLine line = d->textLayout.lineAt(0); + QRect lineRect(r.x() + d->horizontalMargin, d->vscroll, r.width() - 2*d->horizontalMargin, fm.height()); - int cursor = d->cursor; - if (d->preeditCursor != -1) - cursor += d->preeditCursor; - // locate cursor position - int cix = qRound(line.cursorToX(cursor)); + int cix = qRound(d->control->cursorToX()); // horizontal scrolling. d->hscroll is the left indent from the beginning // of the text line to the left edge of lineRect. we update this value @@ -2483,7 +1774,7 @@ void QLineEdit::paintEvent(QPaintEvent *) // (cix). int minLB = qMax(0, -fm.minLeftBearing()); int minRB = qMax(0, -fm.minRightBearing()); - int widthUsed = qRound(line.naturalTextWidth()) + 1 + minRB; + int widthUsed = d->control->width() + minRB; if ((minLB + widthUsed) <= lineRect.width()) { // text fits in lineRect; use hscroll for alignment switch (va & ~(Qt::AlignAbsolute|Qt::AlignVertical_Mask)) { @@ -2511,7 +1802,7 @@ void QLineEdit::paintEvent(QPaintEvent *) d->hscroll = widthUsed - lineRect.width() + 1; } // the y offset is there to keep the baseline constant in case we have script changes in the text. - QPoint topLeft = lineRect.topLeft() - QPoint(d->hscroll, d->ascent - fm.ascent()); + QPoint topLeft = lineRect.topLeft() - QPoint(d->hscroll, d->control->ascent() - fm.ascent()); // draw text, selections and cursors #ifndef QT_NO_STYLE_STYLESHEET @@ -2521,33 +1812,23 @@ void QLineEdit::paintEvent(QPaintEvent *) #endif p.setPen(pal.text().color()); - QVector selections; + int flags = QLineControl::DrawText; + #ifdef QT_KEYPAD_NAVIGATION if (!QApplication::keypadNavigationEnabled() || hasEditFocus()) #endif - if (d->selstart < d->selend || (d->cursorVisible && d->maskData && !d->readOnly)) { - QTextLayout::FormatRange o; - if (d->selstart < d->selend) { - o.start = d->selstart; - o.length = d->selend - d->selstart; - o.format.setBackground(pal.brush(QPalette::Highlight)); - o.format.setForeground(pal.brush(QPalette::HighlightedText)); - } else { - // mask selection - o.start = d->cursor; - o.length = 1; - o.format.setBackground(pal.brush(QPalette::Text)); - o.format.setForeground(pal.brush(QPalette::Window)); - } - selections.append(o); - } + if (d->control->hasSelectedText() || (d->cursorVisible && !d->control->inputMask().isEmpty() && !d->control->isReadOnly())) + flags |= QLineControl::DrawSelections; // Asian users see an IM selection text as cursor on candidate // selection phase of input method, so the ordinary cursor should be // invisible if we have a preedit string. - d->textLayout.draw(&p, topLeft, selections, r); - if (d->cursorVisible && !d->readOnly && !d->hideCursor) - d->textLayout.drawCursor(&p, topLeft, cursor, style()->pixelMetric(QStyle::PM_TextCursorWidth)); + if (d->cursorVisible && !d->control->isReadOnly()) + flags |= QLineControl::DrawCursor; + + d->control->setCursorWidth(style()->pixelMetric(QStyle::PM_TextCursorWidth)); + d->control->draw(&p, topLeft, r, flags); + } @@ -2557,12 +1838,11 @@ void QLineEdit::paintEvent(QPaintEvent *) void QLineEdit::dragMoveEvent(QDragMoveEvent *e) { Q_D(QLineEdit); - if (!d->readOnly && e->mimeData()->hasFormat(QLatin1String("text/plain"))) { + if (!d->control->isReadOnly() && e->mimeData()->hasFormat(QLatin1String("text/plain"))) { e->acceptProposedAction(); - d->cursor = d->xToPos(e->pos().x()); + d->control->moveCursor(d->xToPos(e->pos().x()), false); d->cursorVisible = true; update(); - d->emitCursorPositionChanged(); } } @@ -2588,13 +1868,14 @@ void QLineEdit::dropEvent(QDropEvent* e) Q_D(QLineEdit); QString str = e->mimeData()->text(); - if (!str.isNull() && !d->readOnly) { + if (!str.isNull() && !d->control->isReadOnly()) { if (e->source() == this && e->dropAction() == Qt::CopyAction) deselect(); - d->cursor =d->xToPos(e->pos().x()); - int selStart = d->cursor; - int oldSelStart = d->selstart; - int oldSelEnd = d->selend; + int cursorPos = d->xToPos(e->pos().x()); + int selStart = cursorPos; + int oldSelStart = d->control->selectionStart(); + int oldSelEnd = d->control->selectionEnd(); + d->control->moveCursor(cursorPos, false); d->cursorVisible = false; e->acceptProposedAction(); insert(str); @@ -2616,22 +1897,6 @@ void QLineEdit::dropEvent(QDropEvent* e) } } -void QLineEditPrivate::drag() -{ - Q_Q(QLineEdit); - dndTimer.stop(); - QMimeData *data = new QMimeData; - data->setText(q->selectedText()); - QDrag *drag = new QDrag(q); - drag->setMimeData(data); - Qt::DropAction action = drag->start(); - if (action == Qt::MoveAction && !readOnly && drag->target() != q) { - int priorState = undoState; - removeSelectedText(); - finishChange(priorState); - } -} - #endif // QT_NO_DRAGANDDROP #ifndef QT_NO_CONTEXTMENU @@ -2676,37 +1941,37 @@ QMenu *QLineEdit::createStandardContextMenu() popup->setObjectName(QLatin1String("qt_edit_menu")); QAction *action = popup->addAction(QLineEdit::tr("&Undo") + ACCEL_KEY(QKeySequence::Undo)); - action->setEnabled(d->isUndoAvailable()); + action->setEnabled(d->control->isUndoAvailable()); connect(action, SIGNAL(triggered()), SLOT(undo())); action = popup->addAction(QLineEdit::tr("&Redo") + ACCEL_KEY(QKeySequence::Redo)); - action->setEnabled(d->isRedoAvailable()); + action->setEnabled(d->control->isRedoAvailable()); connect(action, SIGNAL(triggered()), SLOT(redo())); popup->addSeparator(); #ifndef QT_NO_CLIPBOARD action = popup->addAction(QLineEdit::tr("Cu&t") + ACCEL_KEY(QKeySequence::Cut)); - action->setEnabled(!d->readOnly && d->hasSelectedText() && d->echoMode == QLineEdit::Normal); + action->setEnabled(!d->control->isReadOnly() && d->control->hasSelectedText()); connect(action, SIGNAL(triggered()), SLOT(cut())); action = popup->addAction(QLineEdit::tr("&Copy") + ACCEL_KEY(QKeySequence::Copy)); - action->setEnabled(d->hasSelectedText() && d->echoMode == QLineEdit::Normal); + action->setEnabled(d->control->hasSelectedText()); connect(action, SIGNAL(triggered()), SLOT(copy())); action = popup->addAction(QLineEdit::tr("&Paste") + ACCEL_KEY(QKeySequence::Paste)); - action->setEnabled(!d->readOnly && !QApplication::clipboard()->text().isEmpty()); + action->setEnabled(!d->control->isReadOnly() && !QApplication::clipboard()->text().isEmpty()); connect(action, SIGNAL(triggered()), SLOT(paste())); #endif action = popup->addAction(QLineEdit::tr("Delete")); - action->setEnabled(!d->readOnly && !d->text.isEmpty() && d->hasSelectedText()); + action->setEnabled(!d->control->isReadOnly() && !d->control->text().isEmpty() && d->control->hasSelectedText()); connect(action, SIGNAL(triggered()), SLOT(_q_deleteSelected())); popup->addSeparator(); action = popup->addAction(QLineEdit::tr("Select All") + ACCEL_KEY(QKeySequence::SelectAll)); - action->setEnabled(!d->text.isEmpty() && !d->allSelected()); + action->setEnabled(!d->control->text().isEmpty() && !d->control->allSelected()); d->selectAllAction = action; connect(action, SIGNAL(triggered()), SLOT(selectAll())); @@ -2720,9 +1985,9 @@ QMenu *QLineEdit::createStandardContextMenu() #endif #if defined(Q_WS_WIN) - if (!d->readOnly && qt_use_rtl_extensions) { + if (!d->control->isReadOnly() && qt_use_rtl_extensions) { #else - if (!d->readOnly) { + if (!d->control->isReadOnly()) { #endif popup->addSeparator(); QUnicodeControlCharacterMenu *ctrlCharacterMenu = new QUnicodeControlCharacterMenu(this, popup); @@ -2736,806 +2001,26 @@ QMenu *QLineEdit::createStandardContextMenu() void QLineEdit::changeEvent(QEvent *ev) { Q_D(QLineEdit); - if(ev->type() == QEvent::ActivationChange) { + switch(ev->type()) + { + case QEvent::ActivationChange: if (!palette().isEqual(QPalette::Active, QPalette::Inactive)) update(); - } else if (ev->type() == QEvent::FontChange - || ev->type() == QEvent::StyleChange - || ev->type() == QEvent::LayoutDirectionChange) { - d->updateTextLayout(); - } - QWidget::changeEvent(ev); -} - -void QLineEditPrivate::_q_handleWindowActivate() -{ - Q_Q(QLineEdit); - if (!q->hasFocus() && q->hasSelectedText()) - q->deselect(); -} - -void QLineEditPrivate::_q_deleteSelected() -{ - Q_Q(QLineEdit); - if (!hasSelectedText()) - return; - - int priorState = undoState; - q->resetInputContext(); - removeSelectedText(); - separate(); - finishChange(priorState); -} - -void QLineEditPrivate::init(const QString& txt) -{ - Q_Q(QLineEdit); -#ifndef QT_NO_CURSOR - q->setCursor(Qt::IBeamCursor); -#endif - q->setFocusPolicy(Qt::StrongFocus); - q->setAttribute(Qt::WA_InputMethodEnabled); - // Specifies that this widget can use more, but is able to survive on - // less, horizontal space; and is fixed vertically. - q->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed, QSizePolicy::LineEdit)); - q->setBackgroundRole(QPalette::Base); - q->setAttribute(Qt::WA_KeyCompression); - q->setMouseTracking(true); - q->setAcceptDrops(true); - text = txt; - updateTextLayout(); - cursor = text.length(); - - q->setAttribute(Qt::WA_MacShowFocusRect); -} - -void QLineEditPrivate::updatePasswordEchoEditing(bool editing) -{ - Q_Q(QLineEdit); - passwordEchoEditing = editing; - q->setAttribute(Qt::WA_InputMethodEnabled, shouldEnableInputMethod(q)); - updateTextLayout(); - q->update(); -} - -void QLineEditPrivate::updateTextLayout() -{ - // replace certain non-printable characters with spaces (to avoid - // drawing boxes when using fonts that don't have glyphs for such - // characters) - Q_Q(QLineEdit); - QString str = q->displayText(); - QChar* uc = str.data(); - for (int i = 0; i < (int)str.length(); ++i) { - if ((uc[i] < 0x20 && uc[i] != 0x09) - || uc[i] == QChar::LineSeparator - || uc[i] == QChar::ParagraphSeparator - || uc[i] == QChar::ObjectReplacementCharacter) - uc[i] = QChar(0x0020); - } - textLayout.setFont(q->font()); - textLayout.setText(str); - QTextOption option; - option.setTextDirection(q->layoutDirection()); - option.setFlags(QTextOption::IncludeTrailingSpaces); - textLayout.setTextOption(option); - - textLayout.beginLayout(); - QTextLine l = textLayout.createLine(); - textLayout.endLayout(); - ascent = qRound(l.ascent()); -} - -int QLineEditPrivate::xToPos(int x, QTextLine::CursorPosition betweenOrOn) const -{ - QRect cr = adjustedContentsRect(); - x-= cr.x() - hscroll + horizontalMargin; - QTextLine l = textLayout.lineAt(0); - return l.xToCursor(x, betweenOrOn); -} - -QRect QLineEditPrivate::cursorRect() const -{ - Q_Q(const QLineEdit); - QRect cr = adjustedContentsRect(); - int cix = cr.x() - hscroll + horizontalMargin; - QTextLine l = textLayout.lineAt(0); - int c = cursor; - if (preeditCursor != -1) - c += preeditCursor; - cix += qRound(l.cursorToX(c)); - int ch = qMin(cr.height(), q->fontMetrics().height() + 1); - int w = q->style()->pixelMetric(QStyle::PM_TextCursorWidth); - return QRect(cix-5, vscroll, w + 9, ch); -} - -QRect QLineEditPrivate::adjustedContentsRect() const -{ - Q_Q(const QLineEdit); - QStyleOptionFrameV2 opt; - q->initStyleOption(&opt); - QRect r = q->style()->subElementRect(QStyle::SE_LineEditContents, &opt, q); - r.setX(r.x() + leftTextMargin); - r.setY(r.y() + topTextMargin); - r.setRight(r.right() - rightTextMargin); - r.setBottom(r.bottom() - bottomTextMargin); - return r; -} - -bool QLineEditPrivate::fixup() // this function assumes that validate currently returns != Acceptable -{ -#ifndef QT_NO_VALIDATOR - if (validator) { - QString textCopy = text; - int cursorCopy = cursor; - validator->fixup(textCopy); - if (validator->validate(textCopy, cursorCopy) == QValidator::Acceptable) { - if (textCopy != text || cursorCopy != cursor) - setText(textCopy, cursorCopy); - return true; - } - } -#endif - return false; -} - -void QLineEditPrivate::moveCursor(int pos, bool mark) -{ - Q_Q(QLineEdit); - if (pos != cursor) { - separate(); - if (maskData) - pos = pos > cursor ? nextMaskBlank(pos) : prevMaskBlank(pos); - } - bool fullUpdate = mark || hasSelectedText(); - if (mark) { - int anchor; - if (selend > selstart && cursor == selstart) - anchor = selend; - else if (selend > selstart && cursor == selend) - anchor = selstart; - else - anchor = cursor; - selstart = qMin(anchor, pos); - selend = qMax(anchor, pos); - updateTextLayout(); - } else { - deselect(); - } - if (fullUpdate) { - cursor = pos; - q->update(); - } else { - setCursorVisible(false); - cursor = pos; - setCursorVisible(true); - if (!adjustedContentsRect().contains(cursorRect())) - q->update(); - } - QStyleOptionFrameV2 opt; - q->initStyleOption(&opt); - if (mark && !q->style()->styleHint(QStyle::SH_BlinkCursorWhenTextSelected, &opt, q)) - setCursorVisible(false); - if (mark || selDirty) { - selDirty = false; - emit q->selectionChanged(); - } - emitCursorPositionChanged(); -} - -void QLineEditPrivate::finishChange(int validateFromState, bool update, bool edited) -{ - Q_Q(QLineEdit); - bool lineDirty = selDirty; - if (textDirty) { - // do validation - bool wasValidInput = validInput; - validInput = true; -#ifndef QT_NO_VALIDATOR - if (validator) { - validInput = false; - QString textCopy = text; - int cursorCopy = cursor; - validInput = (validator->validate(textCopy, cursorCopy) != QValidator::Invalid); - if (validInput) { - if (text != textCopy) { - setText(textCopy, cursorCopy); - return; - } - cursor = cursorCopy; - } - } -#endif - if (validateFromState >= 0 && wasValidInput && !validInput) { - undo(validateFromState); - history.resize(undoState); - if (modifiedState > undoState) - modifiedState = -1; - validInput = true; - textDirty = false; - } - updateTextLayout(); - lineDirty |= textDirty; - if (textDirty) { - textDirty = false; - QString actualText = maskData ? stripString(text) : text; - if (edited) - emit q->textEdited(actualText); - q->updateMicroFocus(); -#ifndef QT_NO_COMPLETER - if (edited && completer && completer->completionMode() != QCompleter::InlineCompletion) - complete(-1); // update the popup on cut/paste/del -#endif - emit q->textChanged(actualText); - } -#ifndef QT_NO_ACCESSIBILITY - QAccessible::updateAccessibility(q, 0, QAccessible::ValueChanged); -#endif - } - if (selDirty) { - selDirty = false; - emit q->selectionChanged(); - } - if (lineDirty || update) - q->update(); - emitCursorPositionChanged(); -} - -void QLineEditPrivate::emitCursorPositionChanged() -{ - Q_Q(QLineEdit); - if (cursor != lastCursorPos) { - const int oldLast = lastCursorPos; - lastCursorPos = cursor; - emit q->cursorPositionChanged(oldLast, cursor); - } -} - -void QLineEditPrivate::setText(const QString& txt, int pos, bool edited) -{ - Q_Q(QLineEdit); - q->resetInputContext(); - deselect(); - QString oldText = text; - if (maskData) { - text = maskString(0, txt, true); - text += clearString(text.length(), maxLength - text.length()); - } else { - text = txt.isEmpty() ? txt : txt.left(maxLength); - } - history.clear(); - modifiedState = undoState = 0; - cursor = (pos < 0 || pos > text.length()) ? text.length() : pos; - textDirty = (oldText != text); - finishChange(-1, true, edited); -} - - -void QLineEditPrivate::setCursorVisible(bool visible) -{ - Q_Q(QLineEdit); - if ((bool)cursorVisible == visible) - return; - if (cursorTimer) - cursorVisible = visible; - QRect r = cursorRect(); - if (maskData) - q->update(); - else - q->update(r); -} - -void QLineEditPrivate::addCommand(const Command& cmd) -{ - if (separator && undoState && history[undoState-1].type != Separator) { - history.resize(undoState + 2); - history[undoState++] = Command(Separator, cursor, 0, selstart, selend); - } else { - history.resize(undoState + 1); - } - separator = false; - history[undoState++] = cmd; -} - -void QLineEditPrivate::insert(const QString& s) -{ - if (hasSelectedText()) - addCommand(Command(SetSelection, cursor, 0, selstart, selend)); - if (maskData) { - QString ms = maskString(cursor, s); - for (int i = 0; i < (int) ms.length(); ++i) { - addCommand (Command(DeleteSelection, cursor+i, text.at(cursor+i), -1, -1)); - addCommand(Command(Insert, cursor+i, ms.at(i), -1, -1)); - } - text.replace(cursor, ms.length(), ms); - cursor += ms.length(); - cursor = nextMaskBlank(cursor); - textDirty = true; - } else { - int remaining = maxLength - text.length(); - if (remaining != 0) { - text.insert(cursor, s.left(remaining)); - for (int i = 0; i < (int) s.left(remaining).length(); ++i) - addCommand(Command(Insert, cursor++, s.at(i), -1, -1)); - textDirty = true; - } - } -} - -void QLineEditPrivate::del(bool wasBackspace) -{ - if (cursor < (int) text.length()) { - if (hasSelectedText()) - addCommand(Command(SetSelection, cursor, 0, selstart, selend)); - addCommand (Command((CommandType)((maskData?2:0)+(wasBackspace?Remove:Delete)), cursor, text.at(cursor), -1, -1)); - if (maskData) { - text.replace(cursor, 1, clearString(cursor, 1)); - addCommand(Command(Insert, cursor, text.at(cursor), -1, -1)); - } else { - text.remove(cursor, 1); - } - textDirty = true; - } -} - -void QLineEditPrivate::removeSelectedText() -{ - if (selstart < selend && selend <= (int) text.length()) { - separate(); - int i ; - addCommand(Command(SetSelection, cursor, 0, selstart, selend)); - if (selstart <= cursor && cursor < selend) { - // cursor is within the selection. Split up the commands - // to be able to restore the correct cursor position - for (i = cursor; i >= selstart; --i) - addCommand (Command(DeleteSelection, i, text.at(i), -1, 1)); - for (i = selend - 1; i > cursor; --i) - addCommand (Command(DeleteSelection, i - cursor + selstart - 1, text.at(i), -1, -1)); - } else { - for (i = selend-1; i >= selstart; --i) - addCommand (Command(RemoveSelection, i, text.at(i), -1, -1)); - } - if (maskData) { - text.replace(selstart, selend - selstart, clearString(selstart, selend - selstart)); - for (int i = 0; i < selend - selstart; ++i) - addCommand(Command(Insert, selstart + i, text.at(selstart + i), -1, -1)); - } else { - text.remove(selstart, selend - selstart); - } - if (cursor > selstart) - cursor -= qMin(cursor, selend) - selstart; - deselect(); - textDirty = true; - - // adjust hscroll to avoid gap - const int minRB = qMax(0, -q_func()->fontMetrics().minRightBearing()); - updateTextLayout(); - const QTextLine line = textLayout.lineAt(0); - const int widthUsed = qRound(line.naturalTextWidth()) + 1 + minRB; - hscroll = qMin(hscroll, widthUsed); - } -} - -void QLineEditPrivate::parseInputMask(const QString &maskFields) -{ - int delimiter = maskFields.indexOf(QLatin1Char(';')); - if (maskFields.isEmpty() || delimiter == 0) { - if (maskData) { - delete [] maskData; - maskData = 0; - maxLength = 32767; - setText(QString()); - } - return; - } - - if (delimiter == -1) { - blank = QLatin1Char(' '); - inputMask = maskFields; - } else { - inputMask = maskFields.left(delimiter); - blank = (delimiter + 1 < maskFields.length()) ? maskFields[delimiter + 1] : QLatin1Char(' '); - } - - // calculate maxLength / maskData length - maxLength = 0; - QChar c = 0; - for (int i=0; i 0 && inputMask.at(i-1) == QLatin1Char('\\')) { - maxLength++; - continue; - } - if (c != QLatin1Char('\\') && c != QLatin1Char('!') && - c != QLatin1Char('<') && c != QLatin1Char('>') && - c != QLatin1Char('{') && c != QLatin1Char('}') && - c != QLatin1Char('[') && c != QLatin1Char(']')) - maxLength++; - } - - delete [] maskData; - maskData = new MaskInputData[maxLength]; - - MaskInputData::Casemode m = MaskInputData::NoCaseMode; - c = 0; - bool s; - bool escape = false; - int index = 0; - for (int i = 0; i < inputMask.length(); i++) { - c = inputMask.at(i); - if (escape) { - s = true; - maskData[index].maskChar = c; - maskData[index].separator = s; - maskData[index].caseMode = m; - index++; - escape = false; - } else if (c == QLatin1Char('<')) { - m = MaskInputData::Lower; - } else if (c == QLatin1Char('>')) { - m = MaskInputData::Upper; - } else if (c == QLatin1Char('!')) { - m = MaskInputData::NoCaseMode; - } else if (c != QLatin1Char('{') && c != QLatin1Char('}') && c != QLatin1Char('[') && c != QLatin1Char(']')) { - switch (c.unicode()) { - case 'A': - case 'a': - case 'N': - case 'n': - case 'X': - case 'x': - case '9': - case '0': - case 'D': - case 'd': - case '#': - case 'H': - case 'h': - case 'B': - case 'b': - s = false; - break; - case '\\': - escape = true; - default: - s = true; - break; - } - - if (!escape) { - maskData[index].maskChar = c; - maskData[index].separator = s; - maskData[index].caseMode = m; - index++; - } - } - } - setText(text); -} - - -/* checks if the key is valid compared to the inputMask */ -bool QLineEditPrivate::isValidInput(QChar key, QChar mask) const -{ - switch (mask.unicode()) { - case 'A': - if (key.isLetter()) - return true; - break; - case 'a': - if (key.isLetter() || key == blank) - return true; - break; - case 'N': - if (key.isLetterOrNumber()) - return true; - break; - case 'n': - if (key.isLetterOrNumber() || key == blank) - return true; - break; - case 'X': - if (key.isPrint()) - return true; - break; - case 'x': - if (key.isPrint() || key == blank) - return true; - break; - case '9': - if (key.isNumber()) - return true; - break; - case '0': - if (key.isNumber() || key == blank) - return true; - break; - case 'D': - if (key.isNumber() && key.digitValue() > 0) - return true; - break; - case 'd': - if ((key.isNumber() && key.digitValue() > 0) || key == blank) - return true; - break; - case '#': - if (key.isNumber() || key == QLatin1Char('+') || key == QLatin1Char('-') || key == blank) - return true; break; - case 'B': - if (key == QLatin1Char('0') || key == QLatin1Char('1')) - return true; + case QEvent::FontChange: + d->control->setFont(font()); break; - case 'b': - if (key == QLatin1Char('0') || key == QLatin1Char('1') || key == blank) - return true; + case QEvent::StyleChange: + d->control->setPasswordCharacter(style()->styleHint(QStyle::SH_LineEdit_PasswordCharacter)); + update(); break; - case 'H': - if (key.isNumber() || (key >= QLatin1Char('a') && key <= QLatin1Char('f')) || (key >= QLatin1Char('A') && key <= QLatin1Char('F'))) - return true; - break; - case 'h': - if (key.isNumber() || (key >= QLatin1Char('a') && key <= QLatin1Char('f')) || (key >= QLatin1Char('A') && key <= QLatin1Char('F')) || key == blank) - return true; + case QEvent::LayoutDirectionChange: + d->control->setLayoutDirection(layoutDirection()); break; default: break; } - return false; -} - -bool QLineEditPrivate::hasAcceptableInput(const QString &str) const -{ -#ifndef QT_NO_VALIDATOR - QString textCopy = str; - int cursorCopy = cursor; - if (validator && validator->validate(textCopy, cursorCopy) - != QValidator::Acceptable) - return false; -#endif - - if (!maskData) - return true; - - if (str.length() != maxLength) - return false; - - for (int i=0; i < maxLength; ++i) { - if (maskData[i].separator) { - if (str.at(i) != maskData[i].maskChar) - return false; - } else { - if (!isValidInput(str.at(i), maskData[i].maskChar)) - return false; - } - } - return true; -} - -/* - Applies the inputMask on \a str starting from position \a pos in the mask. \a clear - specifies from where characters should be gotten when a separator is met in \a str - true means - that blanks will be used, false that previous input is used. - Calling this when no inputMask is set is undefined. -*/ -QString QLineEditPrivate::maskString(uint pos, const QString &str, bool clear) const -{ - if (pos >= (uint)maxLength) - return QString::fromLatin1(""); - - QString fill; - fill = clear ? clearString(0, maxLength) : text; - - int strIndex = 0; - QString s = QString::fromLatin1(""); - int i = pos; - while (i < maxLength) { - if (strIndex < str.length()) { - if (maskData[i].separator) { - s += maskData[i].maskChar; - if (str[(int)strIndex] == maskData[i].maskChar) - strIndex++; - ++i; - } else { - if (isValidInput(str[(int)strIndex], maskData[i].maskChar)) { - switch (maskData[i].caseMode) { - case MaskInputData::Upper: - s += str[(int)strIndex].toUpper(); - break; - case MaskInputData::Lower: - s += str[(int)strIndex].toLower(); - break; - default: - s += str[(int)strIndex]; - } - ++i; - } else { - // search for separator first - int n = findInMask(i, true, true, str[(int)strIndex]); - if (n != -1) { - if (str.length() != 1 || i == 0 || (i > 0 && (!maskData[i-1].separator || maskData[i-1].maskChar != str[(int)strIndex]))) { - s += fill.mid(i, n-i+1); - i = n + 1; // update i to find + 1 - } - } else { - // search for valid blank if not - n = findInMask(i, true, false, str[(int)strIndex]); - if (n != -1) { - s += fill.mid(i, n-i); - switch (maskData[n].caseMode) { - case MaskInputData::Upper: - s += str[(int)strIndex].toUpper(); - break; - case MaskInputData::Lower: - s += str[(int)strIndex].toLower(); - break; - default: - s += str[(int)strIndex]; - } - i = n + 1; // updates i to find + 1 - } - } - } - strIndex++; - } - } else - break; - } - - return s; -} - - - -/* - Returns a "cleared" string with only separators and blank chars. - Calling this when no inputMask is set is undefined. -*/ -QString QLineEditPrivate::clearString(uint pos, uint len) const -{ - if (pos >= (uint)maxLength) - return QString(); - - QString s; - int end = qMin((uint)maxLength, pos + len); - for (int i=pos; i= maxLength || pos < 0) - return -1; - - int end = forward ? maxLength : -1; - int step = forward ? 1 : -1; - int i = pos; - - while (i != end) { - if (findSeparator) { - if (maskData[i].separator && maskData[i].maskChar == searchChar) - return i; - } else { - if (!maskData[i].separator) { - if (searchChar.isNull()) - return i; - else if (isValidInput(searchChar, maskData[i].maskChar)) - return i; - } - } - i += step; - } - return -1; -} - -void QLineEditPrivate::undo(int until) -{ - if (!isUndoAvailable()) - return; - deselect(); - while (undoState && undoState > until) { - Command& cmd = history[--undoState]; - switch (cmd.type) { - case Insert: - text.remove(cmd.pos, 1); - cursor = cmd.pos; - break; - case SetSelection: - selstart = cmd.selStart; - selend = cmd.selEnd; - cursor = cmd.pos; - break; - case Remove: - case RemoveSelection: - text.insert(cmd.pos, cmd.uc); - cursor = cmd.pos + 1; - break; - case Delete: - case DeleteSelection: - text.insert(cmd.pos, cmd.uc); - cursor = cmd.pos; - break; - case Separator: - continue; - } - if (until < 0 && undoState) { - Command& next = history[undoState-1]; - if (next.type != cmd.type && next.type < RemoveSelection - && (cmd.type < RemoveSelection || next.type == Separator)) - break; - } - } - textDirty = true; - emitCursorPositionChanged(); -} - -void QLineEditPrivate::redo() { - if (!isRedoAvailable()) - return; - deselect(); - while (undoState < (int)history.size()) { - Command& cmd = history[undoState++]; - switch (cmd.type) { - case Insert: - text.insert(cmd.pos, cmd.uc); - cursor = cmd.pos + 1; - break; - case SetSelection: - selstart = cmd.selStart; - selend = cmd.selEnd; - cursor = cmd.pos; - break; - case Remove: - case Delete: - case RemoveSelection: - case DeleteSelection: - text.remove(cmd.pos, 1); - selstart = cmd.selStart; - selend = cmd.selEnd; - cursor = cmd.pos; - break; - case Separator: - selstart = cmd.selStart; - selend = cmd.selEnd; - cursor = cmd.pos; - break; - } - if (undoState < (int)history.size()) { - Command& next = history[undoState]; - if (next.type != cmd.type && cmd.type < RemoveSelection && next.type != Separator - && (next.type < RemoveSelection || cmd.type == Separator)) - break; - } - } - textDirty = true; - emitCursorPositionChanged(); + QWidget::changeEvent(ev); } /*! diff --git a/src/gui/widgets/qlineedit.h b/src/gui/widgets/qlineedit.h index a97dc9a..daac6a7 100644 --- a/src/gui/widgets/qlineedit.h +++ b/src/gui/widgets/qlineedit.h @@ -268,6 +268,8 @@ private: Q_DECLARE_PRIVATE(QLineEdit) Q_PRIVATE_SLOT(d_func(), void _q_handleWindowActivate()) Q_PRIVATE_SLOT(d_func(), void _q_deleteSelected()) + Q_PRIVATE_SLOT(d_func(), void _q_textEdited(const QString &)) + Q_PRIVATE_SLOT(d_func(), void _q_cursorPositionChanged(int, int)) #ifndef QT_NO_COMPLETER Q_PRIVATE_SLOT(d_func(), void _q_completionHighlighted(QString)) #endif diff --git a/src/gui/widgets/qlineedit_p.cpp b/src/gui/widgets/qlineedit_p.cpp new file mode 100644 index 0000000..0e39304 --- /dev/null +++ b/src/gui/widgets/qlineedit_p.cpp @@ -0,0 +1,253 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qlineedit.h" +#include "qlineedit_p.h" + +#ifndef QT_NO_LINEEDIT + +#include "qabstractitemview.h" +#include "qclipboard.h" +#ifndef QT_NO_ACCESSIBILITY +#include "qaccessible.h" +#endif +#ifndef QT_NO_IM +#include "qinputcontext.h" +#include "qlist.h" +#endif + +QT_BEGIN_NAMESPACE + +const int QLineEditPrivate::verticalMargin(1); +const int QLineEditPrivate::horizontalMargin(2); + +int QLineEditPrivate::xToPos(int x, QTextLine::CursorPosition betweenOrOn) const +{ + QRect cr = adjustedContentsRect(); + x-= cr.x() - hscroll + horizontalMargin; + return control->xToPos(x, betweenOrOn); +} + +QRect QLineEditPrivate::cursorRect() const +{ + QRect cr = adjustedContentsRect(); + int cix = cr.x() - hscroll + horizontalMargin; + QRect crect = control->cursorRect(); + crect.moveTo(crect.topLeft() + QPoint(cix, vscroll)); + return crect; +} + +#ifndef QT_NO_COMPLETER + +void QLineEditPrivate::_q_completionHighlighted(QString newText) +{ + Q_Q(QLineEdit); + if (control->completer()->completionMode() != QCompleter::InlineCompletion) { + q->setText(newText); + } else { + int c = control->cursor(); + QString text = control->text(); + q->setText(text.left(c) + newText.mid(c)); + control->moveCursor(control->end(), false); + control->moveCursor(c, true); + } +} + +#endif // QT_NO_COMPLETER + +void QLineEditPrivate::_q_clipboardChanged() +{ +} + +void QLineEditPrivate::_q_handleWindowActivate() +{ + Q_Q(QLineEdit); + if (!q->hasFocus() && control->hasSelectedText()) + control->deselect(); +} + +void QLineEditPrivate::_q_deleteSelected() +{ +} + +void QLineEditPrivate::_q_textEdited(const QString &text) +{ + Q_Q(QLineEdit); +#ifndef QT_NO_COMPLETER + if (control->completer() && + control->completer()->completionMode() != QCompleter::InlineCompletion) + control->complete(-1); // update the popup on cut/paste/del +#endif + emit q->textEdited(text); +} + +void QLineEditPrivate::_q_cursorPositionChanged(int from, int to) +{ + Q_Q(QLineEdit); + q->update(); + emit q->cursorPositionChanged(from, to); +} + +void QLineEditPrivate::init(const QString& txt) +{ + Q_Q(QLineEdit); + control = new QLineControl(txt); + QObject::connect(control, SIGNAL(textChanged(const QString &)), + q, SIGNAL(textChanged(const QString &))); + QObject::connect(control, SIGNAL(textEdited(const QString &)), + q, SLOT(_q_textEdited(const QString &))); + QObject::connect(control, SIGNAL(cursorPositionChanged(int, int)), + q, SLOT(_q_cursorPositionChanged(int, int))); + QObject::connect(control, SIGNAL(selectionChanged()), + q, SIGNAL(selectionChanged())); + QObject::connect(control, SIGNAL(accepted()), + q, SIGNAL(returnPressed())); + QObject::connect(control, SIGNAL(editingFinished()), + q, SIGNAL(editingFinished())); + + // for now, going completely overboard with updates. + QObject::connect(control, SIGNAL(selectionChanged()), + q, SLOT(update())); + + QObject::connect(control, SIGNAL(displayTextChanged(const QString &)), + q, SLOT(update())); + control->setPasswordCharacter(q->style()->styleHint(QStyle::SH_LineEdit_PasswordCharacter)); +#ifndef QT_NO_CURSOR + q->setCursor(Qt::IBeamCursor); +#endif + q->setFocusPolicy(Qt::StrongFocus); + q->setAttribute(Qt::WA_InputMethodEnabled); + // Specifies that this widget can use more, but is able to survive on + // less, horizontal space; and is fixed vertically. + q->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed, QSizePolicy::LineEdit)); + q->setBackgroundRole(QPalette::Base); + q->setAttribute(Qt::WA_KeyCompression); + q->setMouseTracking(true); + q->setAcceptDrops(true); + + q->setAttribute(Qt::WA_MacShowFocusRect); +} + +QRect QLineEditPrivate::adjustedContentsRect() const +{ + Q_Q(const QLineEdit); + QStyleOptionFrameV2 opt; + q->initStyleOption(&opt); + QRect r = q->style()->subElementRect(QStyle::SE_LineEditContents, &opt, q); + r.setX(r.x() + leftTextMargin); + r.setY(r.y() + topTextMargin); + r.setRight(r.right() - rightTextMargin); + r.setBottom(r.bottom() - bottomTextMargin); + return r; +} + +void QLineEditPrivate::setCursorVisible(bool visible) +{ + Q_Q(QLineEdit); + if ((bool)cursorVisible == visible) + return; + cursorVisible = visible; + QRect r = cursorRect(); + if (control->inputMask().isEmpty()) + q->update(r); + else + q->update(); +} + +void QLineEditPrivate::updatePasswordEchoEditing(bool editing) +{ + Q_Q(QLineEdit); + control->updatePasswordEchoEditing(editing); + q->setAttribute(Qt::WA_InputMethodEnabled, shouldEnableInputMethod()); +} + +/*! + This function is not intended as polymorphic usage. Just a shared code + fragment that calls QInputContext::mouseHandler for this + class. +*/ +bool QLineEditPrivate::sendMouseEventToInputContext( QMouseEvent *e ) +{ +#if !defined QT_NO_IM + Q_Q(QLineEdit); + if ( control->composeMode() ) { + int tmp_cursor = xToPos(e->pos().x()); + int mousePos = tmp_cursor - control->cursor(); + if ( mousePos < 0 || mousePos > control->preeditAreaText().length() ) { + mousePos = -1; + // don't send move events outside the preedit area + if ( e->type() == QEvent::MouseMove ) + return true; + } + + QInputContext *qic = q->inputContext(); + if ( qic ) + // may be causing reset() in some input methods + qic->mouseHandler(mousePos, e); + if (!control->preeditAreaText().isEmpty()) + return true; + } +#else + Q_UNUSED(e); +#endif + + return false; +} + +#ifndef QT_NO_DRAGANDDROP +void QLineEditPrivate::drag() +{ + Q_Q(QLineEdit); + dndTimer.stop(); + QMimeData *data = new QMimeData; + data->setText(control->selectedText()); + QDrag *drag = new QDrag(q); + drag->setMimeData(data); + Qt::DropAction action = drag->start(); + if (action == Qt::MoveAction && !control->isReadOnly() && drag->target() != q) + control->removeSelection(); +} + +#endif // QT_NO_DRAGANDDROP + +QT_END_NAMESPACE + +#endif diff --git a/src/gui/widgets/qlineedit_p.h b/src/gui/widgets/qlineedit_p.h index 7a4ff26..c6d7496 100644 --- a/src/gui/widgets/qlineedit_p.h +++ b/src/gui/widgets/qlineedit_p.h @@ -65,6 +65,8 @@ #include "QtCore/qpointer.h" #include "QtGui/qlineedit.h" +#include "private/qlinecontrol_p.h" + QT_BEGIN_NAMESPACE class QLineEditPrivate : public QWidgetPrivate @@ -73,168 +75,66 @@ class QLineEditPrivate : public QWidgetPrivate public: QLineEditPrivate() - : cursor(0), preeditCursor(0), cursorTimer(0), frame(1), - cursorVisible(0), hideCursor(false), separator(0), readOnly(0), - dragEnabled(0), contextMenuEnabled(1), echoMode(0), textDirty(0), - selDirty(0), validInput(1), alignment(Qt::AlignLeading | Qt::AlignVCenter), ascent(0), - maxLength(32767), hscroll(0), vscroll(0), lastCursorPos(-1), maskData(0), - modifiedState(0), undoState(0), selstart(0), selend(0), userInput(false), - emitingEditingFinished(false), passwordEchoEditing(false) -#ifndef QT_NO_COMPLETER - , completer(0) -#endif - , leftTextMargin(0), topTextMargin(0), rightTextMargin(0), bottomTextMargin(0) - { - } + : control(0), frame(1), contextMenuEnabled(1), cursorVisible(0), + dragEnabled(0), hscroll(0), vscroll(0), + alignment(Qt::AlignLeading | Qt::AlignVCenter), + leftTextMargin(0), topTextMargin(0), rightTextMargin(0), bottomTextMargin(0) + { + } ~QLineEditPrivate() { - delete [] maskData; } + + QLineControl *control; + +#ifndef QT_NO_CONTEXTMENU + QPointer selectAllAction; +#endif void init(const QString&); - QString text; - int cursor; - int preeditCursor; - int cursorTimer; // -1 for non blinking cursor. + int xToPos(int x, QTextLine::CursorPosition = QTextLine::CursorBetweenCharacters) const; + QRect cursorRect() const; + void setCursorVisible(bool visible); + + void updatePasswordEchoEditing(bool); + + inline bool shouldEnableInputMethod() const + { + return !control->isReadOnly() && (control->echoMode() == QLineEdit::Normal || control->echoMode() == QLineEdit::PasswordEchoOnEdit); + } + QPoint tripleClick; QBasicTimer tripleClickTimer; uint frame : 1; + uint contextMenuEnabled : 1; uint cursorVisible : 1; - uint hideCursor : 1; // used to hide the cursor inside preedit areas - uint separator : 1; - uint readOnly : 1; uint dragEnabled : 1; - uint contextMenuEnabled : 1; - uint echoMode : 2; - uint textDirty : 1; - uint selDirty : 1; - uint validInput : 1; - uint alignment; - int ascent; - int maxLength; int hscroll; int vscroll; - int lastCursorPos; - -#ifndef QT_NO_CONTEXTMENU - QPointer selectAllAction; -#endif + uint alignment; + static const int verticalMargin; + static const int horizontalMargin; - inline void emitCursorPositionChanged(); bool sendMouseEventToInputContext(QMouseEvent *e); - void finishChange(int validateFromState = -1, bool update = false, bool edited = true); - - QPointer validator; - struct MaskInputData { - enum Casemode { NoCaseMode, Upper, Lower }; - QChar maskChar; // either the separator char or the inputmask - bool separator; - Casemode caseMode; - }; - QString inputMask; - QChar blank; - MaskInputData *maskData; - inline int nextMaskBlank(int pos) { - int c = findInMask(pos, true, false); - separator |= (c != pos); - return (c != -1 ? c : maxLength); - } - inline int prevMaskBlank(int pos) { - int c = findInMask(pos, false, false); - separator |= (c != pos); - return (c != -1 ? c : 0); - } - - void setCursorVisible(bool visible); + QRect adjustedContentsRect() const; + void _q_clipboardChanged(); + void _q_handleWindowActivate(); + void _q_deleteSelected(); + void _q_textEdited(const QString &); + void _q_cursorPositionChanged(int, int); - // undo/redo handling - enum CommandType { Separator, Insert, Remove, Delete, RemoveSelection, DeleteSelection, SetSelection }; - struct Command { - inline Command() {} - inline Command(CommandType t, int p, QChar c, int ss, int se) : type(t),uc(c),pos(p),selStart(ss),selEnd(se) {} - uint type : 4; - QChar uc; - int pos, selStart, selEnd; - }; - int modifiedState; - int undoState; - QVector history; - void addCommand(const Command& cmd); - void insert(const QString& s); - void del(bool wasBackspace = false); - void remove(int pos); - - inline void separate() { separator = true; } - void undo(int until = -1); - void redo(); - inline bool isUndoAvailable() const { return !readOnly && undoState; } - inline bool isRedoAvailable() const { return !readOnly && undoState < (int)history.size(); } - - // selection - int selstart, selend; - inline bool allSelected() const { return !text.isEmpty() && selstart == 0 && selend == (int)text.length(); } - inline bool hasSelectedText() const { return !text.isEmpty() && selend > selstart; } - inline void deselect() { selDirty |= (selend > selstart); selstart = selend = 0; } - void removeSelectedText(); -#ifndef QT_NO_CLIPBOARD - void copy(bool clipboard = true) const; +#ifndef QT_NO_COMPLETER + void _q_completionHighlighted(QString); #endif - inline bool inSelection(int x) const - { if (selstart >= selend) return false; - int pos = xToPos(x, QTextLine::CursorOnCharacter); return pos >= selstart && pos < selend; } - - // masking - void parseInputMask(const QString &maskFields); - bool isValidInput(QChar key, QChar mask) const; - bool hasAcceptableInput(const QString &text) const; - QString maskString(uint pos, const QString &str, bool clear = false) const; - QString clearString(uint pos, uint len) const; - QString stripString(const QString &str) const; - int findInMask(int pos, bool forward, bool findSeparator, QChar searchChar = QChar()) const; - - // input methods - bool composeMode() const { return !textLayout.preeditAreaText().isEmpty(); } - - // complex text layout - QTextLayout textLayout; - void updateTextLayout(); - void moveCursor(int pos, bool mark = false); - void setText(const QString& txt, int pos = -1, bool edited = true); - int xToPos(int x, QTextLine::CursorPosition = QTextLine::CursorBetweenCharacters) const; - QRect cursorRect() const; - bool fixup(); - - QRect adjustedContentsRect() const; - #ifndef QT_NO_DRAGANDDROP - // drag and drop QPoint dndPos; QBasicTimer dndTimer; void drag(); #endif - void _q_handleWindowActivate(); - void _q_deleteSelected(); - bool userInput; - bool emitingEditingFinished; - -#ifdef QT_KEYPAD_NAVIGATION - QBasicTimer deleteAllTimer; // keypad navigation - QString origText; -#endif - - bool passwordEchoEditing; - void updatePasswordEchoEditing(bool editing); - -#ifndef QT_NO_COMPLETER - QPointer completer; - void complete(int key = -1); - void _q_completionHighlighted(QString); - bool advanceToEnabledItem(int n); -#endif int leftTextMargin; int topTextMargin; diff --git a/src/gui/widgets/qvalidator.h b/src/gui/widgets/qvalidator.h index ce78959..5ddc44e 100644 --- a/src/gui/widgets/qvalidator.h +++ b/src/gui/widgets/qvalidator.h @@ -61,7 +61,7 @@ class Q_GUI_EXPORT QValidator : public QObject { Q_OBJECT public: - explicit QValidator(QObject * parent); + explicit QValidator(QObject * parent=0); ~QValidator(); enum State { @@ -100,7 +100,7 @@ class Q_GUI_EXPORT QIntValidator : public QValidator Q_PROPERTY(int top READ top WRITE setTop) public: - explicit QIntValidator(QObject * parent); + explicit QIntValidator(QObject * parent=0); QIntValidator(int bottom, int top, QObject * parent); ~QIntValidator(); @@ -120,7 +120,7 @@ public: #endif private: - Q_DISABLE_COPY(QIntValidator) + /*Q_DISABLE_COPY(QIntValidator)*/ int b; int t; diff --git a/src/gui/widgets/widgets.pri b/src/gui/widgets/widgets.pri index 2d809a1..8f24fac 100644 --- a/src/gui/widgets/widgets.pri +++ b/src/gui/widgets/widgets.pri @@ -30,6 +30,7 @@ HEADERS += \ widgets/qlcdnumber.h \ widgets/qlineedit.h \ widgets/qlineedit_p.h \ + widgets/qlinecontrol_p.h \ widgets/qmainwindow.h \ widgets/qmainwindowlayout_p.h \ widgets/qmdiarea.h \ @@ -101,7 +102,9 @@ SOURCES += \ widgets/qgroupbox.cpp \ widgets/qlabel.cpp \ widgets/qlcdnumber.cpp \ + widgets/qlineedit_p.cpp \ widgets/qlineedit.cpp \ + widgets/qlinecontrol.cpp \ widgets/qmainwindow.cpp \ widgets/qmainwindowlayout.cpp \ widgets/qmdiarea.cpp \ -- cgit v0.12 From 043a9b2eb3dd346126cf13817b67ed0790a72f7a Mon Sep 17 00:00:00 2001 From: Alan Alpert Date: Tue, 7 Jul 2009 17:45:56 +1000 Subject: Manually integrate 099a32d121 to QLineControl This change to QLineEdit didn't merge, as it needs to be applied to QLineControl in this case. --- src/gui/widgets/qlinecontrol.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/gui/widgets/qlinecontrol.cpp b/src/gui/widgets/qlinecontrol.cpp index b762a00..08574b5 100644 --- a/src/gui/widgets/qlinecontrol.cpp +++ b/src/gui/widgets/qlinecontrol.cpp @@ -1685,7 +1685,8 @@ void QLineControl::processKeyEvent(QKeyEvent* event) if (unknown && !isReadOnly()) { QString t = event->text(); - if (!t.isEmpty() && t.at(0).isPrint()) { + if (!t.isEmpty() && t.at(0).isPrint() && + ((event->modifiers() & (Qt::ControlModifier | Qt::AltModifier | Qt::MetaModifier)) == Qt::NoModifier)) { insert(t); #ifndef QT_NO_COMPLETER complete(event->key()); -- cgit v0.12 From 96d3be9039baaebc64f5de5d6917dd56d7ed192b Mon Sep 17 00:00:00 2001 From: Alan Alpert Date: Tue, 7 Jul 2009 18:13:18 +1000 Subject: Finish remaining TODOs for QLineControl Didn't notice there were still some TODO markers left. They have now all been done. --- src/gui/widgets/qlinecontrol.cpp | 16 +++++++--------- src/gui/widgets/qlinecontrol_p.h | 14 ++++++++++++++ src/gui/widgets/qlineedit.cpp | 4 ++-- 3 files changed, 23 insertions(+), 11 deletions(-) diff --git a/src/gui/widgets/qlinecontrol.cpp b/src/gui/widgets/qlinecontrol.cpp index 08574b5..fc0a173 100644 --- a/src/gui/widgets/qlinecontrol.cpp +++ b/src/gui/widgets/qlinecontrol.cpp @@ -1232,7 +1232,6 @@ bool QLineControl::processEvent(QEvent* ev) return true; } } - //TODO: Needs a call to processKeyEvent? } else if (e->type() == QEvent::EnterEditFocus) { end(false); int cft = QApplication::cursorFlashTime(); @@ -1450,11 +1449,10 @@ void QLineControl::processKeyEvent(QKeyEvent* event) // ### resets current content. dubious code; you can // navigate with keys up, down, back, and select(?), but if you press // "left" or "right" it clears? - updatePasswordEchoEditing(true);//TODO: used to set a WA too + updatePasswordEchoEditing(true); clear(); } - //setCursorVisible(true);TODO: Who handles this? if (event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return) { if (hasAcceptableInput() || fixup()) { emit accepted(); @@ -1652,19 +1650,19 @@ void QLineControl::processKeyEvent(QKeyEvent* event) #endif } break; -#ifdef QT_KEYPAD_NAVIGATION//TODO: This section +#ifdef QT_KEYPAD_NAVIGATION case Qt::Key_Back: if (QApplication::keypadNavigationEnabled() && !event->isAutoRepeat() && !isReadOnly()) { if (text().length() == 0) { - setText(d->origText); + setText(m_cancelText); - if (d->passwordEchoEditing) - d->updatePasswordEchoEditing(false); + if (passwordEchoEditing) + updatePasswordEchoEditing(false); setEditFocus(false); - } else if (!d->deleteAllTimer.isActive()) { - d->deleteAllTimer.start(750, this); + } else if (!deleteAllTimer) { + deleteAllTimer = startTimer(750); } } else { unknown = true; diff --git a/src/gui/widgets/qlinecontrol_p.h b/src/gui/widgets/qlinecontrol_p.h index bb27778..600206d 100644 --- a/src/gui/widgets/qlinecontrol_p.h +++ b/src/gui/widgets/qlinecontrol_p.h @@ -217,6 +217,9 @@ public: int cursorBlinkPeriod() const; void setCursorBlinkPeriod(int msec); + QString cancelText() const; + void setCancelText(QString); + enum DrawFlags { DrawText = 0x01, DrawSelections = 0x02, @@ -265,6 +268,7 @@ private: QList transactions; QPoint m_tripleClick; int m_tripleClickTimer; + QString m_cancelText; void emitCursorPositionChanged(); @@ -706,6 +710,16 @@ inline int QLineControl::cursorBlinkPeriod() const return m_blinkPeriod; } +QString QLineControl::cancelText() const +{ + return m_cancelText; +} + +void QLineControl::setCancelText(QString s) +{ + m_cancelText = s; +} + QT_END_NAMESPACE QT_END_HEADER diff --git a/src/gui/widgets/qlineedit.cpp b/src/gui/widgets/qlineedit.cpp index baaad32..7fdda6c 100644 --- a/src/gui/widgets/qlineedit.cpp +++ b/src/gui/widgets/qlineedit.cpp @@ -1663,7 +1663,7 @@ void QLineEdit::focusInEvent(QFocusEvent *e) qt_mac_secure_keyboard(true); #endif #ifdef QT_KEYPAD_NAVIGATION - d->origText = d->text; + d->control->setCancelText(d->text); #endif #ifndef QT_NO_COMPLETER if (d->control->completer()) { @@ -1718,7 +1718,7 @@ void QLineEdit::focusOutEvent(QFocusEvent *e) qt_mac_secure_keyboard(false); #endif #ifdef QT_KEYPAD_NAVIGATION - d->origText = QString(); + d->control->setCancelText(QString()); #endif #ifndef QT_NO_COMPLETER if (d->control->completer()) { -- cgit v0.12 From fe6ca9332cf4516c84d9a1b8ca9ea2846458f98f Mon Sep 17 00:00:00 2001 From: Alan Alpert Date: Tue, 7 Jul 2009 18:28:54 +1000 Subject: Forgot to bring in the change to QAbstractSpinBox QAbstractSpinBox had some code using QLineEdit internals, this had to be move to use QLineControl as well. This commit also includes fixing some typos in my last commit. --- src/gui/widgets/qabstractspinbox.cpp | 2 +- src/gui/widgets/qlinecontrol_p.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/gui/widgets/qabstractspinbox.cpp b/src/gui/widgets/qabstractspinbox.cpp index 25acd6e..1d62ab4 100644 --- a/src/gui/widgets/qabstractspinbox.cpp +++ b/src/gui/widgets/qabstractspinbox.cpp @@ -970,7 +970,7 @@ void QAbstractSpinBox::keyPressEvent(QKeyEvent *event) #endif case Qt::Key_Enter: case Qt::Key_Return: - d->edit->d_func()->modifiedState = d->edit->d_func()->undoState = 0; + d->edit->d_func()->control->clearUndo(); d->interpret(d->keyboardTracking ? AlwaysEmit : EmitIfChanged); selectAll(); event->ignore(); diff --git a/src/gui/widgets/qlinecontrol_p.h b/src/gui/widgets/qlinecontrol_p.h index 600206d..4ecedcd 100644 --- a/src/gui/widgets/qlinecontrol_p.h +++ b/src/gui/widgets/qlinecontrol_p.h @@ -710,12 +710,12 @@ inline int QLineControl::cursorBlinkPeriod() const return m_blinkPeriod; } -QString QLineControl::cancelText() const +inline QString QLineControl::cancelText() const { return m_cancelText; } -void QLineControl::setCancelText(QString s) +inline void QLineControl::setCancelText(QString s) { m_cancelText = s; } -- cgit v0.12 From 3528101647e7320d07623e659138005d7d603980 Mon Sep 17 00:00:00 2001 From: Alan Alpert Date: Wed, 8 Jul 2009 15:54:33 +1000 Subject: Fixed one of the QT3_SUPPORT constructors. It was accidentally left commented out instead of working with QLineControl. --- src/gui/widgets/qlineedit.cpp | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/src/gui/widgets/qlineedit.cpp b/src/gui/widgets/qlineedit.cpp index 7fdda6c..8e7fdec 100644 --- a/src/gui/widgets/qlineedit.cpp +++ b/src/gui/widgets/qlineedit.cpp @@ -341,14 +341,9 @@ QLineEdit::QLineEdit(const QString& contents, const QString &inputMask, QWidget* { Q_D(QLineEdit); setObjectName(QString::fromAscii(name)); - //d->control->parseInputMask(inputMask); - //if (d->control->maskData) { - // QString ms = d->control->maskString(0, contents); - // d->init(ms + d->control->clearString(ms.length(), d->control->maxLength() - ms.length())); - // d->control->moveCursor(d->control->nextMaskBlank(ms.length())); - // } else { - d->init(contents); - // } + d->init(contents); + d->control->setInputMask(inputMask); + d->control->moveCursor(d->control->nextMaskBlank(contents.length())); } #endif -- cgit v0.12 From b9fc86cd9f51c80a1103e5e896940b49bf552b07 Mon Sep 17 00:00:00 2001 From: Alan Alpert Date: Thu, 9 Jul 2009 09:47:18 +1000 Subject: Accidental Behavioural changes have been identified and rectified. createStandardContextMenu should still only cut/copy in normal echo mode and the Qt3Support function validateAndSet will again only set if it is validated. --- src/gui/widgets/qlineedit.cpp | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/gui/widgets/qlineedit.cpp b/src/gui/widgets/qlineedit.cpp index 8e7fdec..2d6ef03 100644 --- a/src/gui/widgets/qlineedit.cpp +++ b/src/gui/widgets/qlineedit.cpp @@ -692,9 +692,14 @@ int QLineEdit::cursorPositionAt(const QPoint &pos) bool QLineEdit::validateAndSet(const QString &newText, int newPos, int newMarkAnchor, int newMarkDrag) { - // Note, this doesn't validate', but then neither - // does the suggested functions above in the docs. + // The suggested functions above in the docs don't seem to validate, + // below code tries to mimic previous behaviour. + QString oldText = text(); setText(newText); + if(!hasAcceptableInput()){ + setText(oldText); + return false; + } setCursorPosition(newPos); setSelection(qMin(newMarkAnchor, newMarkDrag), qAbs(newMarkAnchor - newMarkDrag)); return true; @@ -1947,11 +1952,13 @@ QMenu *QLineEdit::createStandardContextMenu() #ifndef QT_NO_CLIPBOARD action = popup->addAction(QLineEdit::tr("Cu&t") + ACCEL_KEY(QKeySequence::Cut)); - action->setEnabled(!d->control->isReadOnly() && d->control->hasSelectedText()); + action->setEnabled(!d->control->isReadOnly() && d->control->hasSelectedText() + && d->control->echoMode() == QLineEdit::Normal); connect(action, SIGNAL(triggered()), SLOT(cut())); action = popup->addAction(QLineEdit::tr("&Copy") + ACCEL_KEY(QKeySequence::Copy)); - action->setEnabled(d->control->hasSelectedText()); + action->setEnabled(d->control->hasSelectedText() + && d->control->echoMode() == QLineEdit::Normal); connect(action, SIGNAL(triggered()), SLOT(copy())); action = popup->addAction(QLineEdit::tr("&Paste") + ACCEL_KEY(QKeySequence::Paste)); -- cgit v0.12 From 61084f0e8dcbd9b7ecaa250c74cd53ba042210e1 Mon Sep 17 00:00:00 2001 From: Alan Alpert Date: Fri, 10 Jul 2009 10:33:20 +1000 Subject: Fix some minor mistakes --- src/gui/widgets/qlineedit.cpp | 6 +++--- src/gui/widgets/qvalidator.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/gui/widgets/qlineedit.cpp b/src/gui/widgets/qlineedit.cpp index 2d6ef03..977d00c 100644 --- a/src/gui/widgets/qlineedit.cpp +++ b/src/gui/widgets/qlineedit.cpp @@ -1409,7 +1409,7 @@ void QLineEdit::mousePressEvent(QMouseEvent* e) if (d->tripleClickTimer.isActive() && (e->pos() - d->tripleClick).manhattanLength() < QApplication::startDragDistance()) { selectAll(); - return; + return; } bool mark = e->modifiers() & Qt::ShiftModifier; int cursor = d->xToPos(e->pos().x()); @@ -1593,8 +1593,6 @@ void QLineEdit::inputMethodEvent(QInputMethodEvent *e) clear(); } - d->control->processInputMethodEvent(e); - #ifdef QT_KEYPAD_NAVIGATION // Focus in if currently in navigation focus on the widget // Only focus in on preedits, to allow input methods to @@ -1607,6 +1605,8 @@ void QLineEdit::inputMethodEvent(QInputMethodEvent *e) } #endif + d->control->processInputMethodEvent(e); + #ifndef QT_NO_COMPLETER if (!e->commitString().isEmpty()) d->control->complete(Qt::Key_unknown); diff --git a/src/gui/widgets/qvalidator.h b/src/gui/widgets/qvalidator.h index 5ddc44e..5c27d1d 100644 --- a/src/gui/widgets/qvalidator.h +++ b/src/gui/widgets/qvalidator.h @@ -120,7 +120,7 @@ public: #endif private: - /*Q_DISABLE_COPY(QIntValidator)*/ + Q_DISABLE_COPY(QIntValidator) int b; int t; -- cgit v0.12 From 2718577ecf7a4a5c9fc619a46ee79a468044b4d7 Mon Sep 17 00:00:00 2001 From: Alan Alpert Date: Tue, 14 Jul 2009 10:44:05 +1000 Subject: Move some keypad navigation code back out of QLineControl --- src/gui/widgets/qlinecontrol.cpp | 46 ----------------------------------- src/gui/widgets/qlineedit.cpp | 52 ++++++++++++++++++++++++++++++++++++---- 2 files changed, 48 insertions(+), 50 deletions(-) diff --git a/src/gui/widgets/qlinecontrol.cpp b/src/gui/widgets/qlinecontrol.cpp index fc0a173..dd3c057 100644 --- a/src/gui/widgets/qlinecontrol.cpp +++ b/src/gui/widgets/qlinecontrol.cpp @@ -1212,44 +1212,6 @@ void QLineControl::timerEvent ( QTimerEvent * event ) bool QLineControl::processEvent(QEvent* ev) { -#ifdef QT_KEYPAD_NAVIGATION - if (QApplication::keypadNavigationEnabled()) { - if ((ev->type() == QEvent::KeyPress) || (ev->type() == QEvent::KeyRelease)) { - QKeyEvent *ke = (QKeyEvent *)ev; - if (ke->key() == Qt::Key_Back) { - if (ke->isAutoRepeat()) { - // Swallow it. We don't want back keys running amok. - ke->accept(); - return true; - } - if ((ev->type() == QEvent::KeyRelease) - && !isReadOnly() - && deleteAllTimer) { - killTimer(m_deleteAllTimer); - m_deleteAllTimer = 0; - backspace(); - ke->accept(); - return true; - } - } - } else if (e->type() == QEvent::EnterEditFocus) { - end(false); - int cft = QApplication::cursorFlashTime(); - control->setCursorBlinkPeriod(cft/2); - } else if (e->type() == QEvent::LeaveEditFocus) { - d->setCursorVisible(false);//!!! - control->setCursorBlinkPeriod(0); - if (!m_emitingEditingFinished) { - if (hasAcceptableInput() || fixup()) { - m_emitingEditingFinished = true; - emit editingFinished(); - m_emitingEditingFinished = false; - } - } - } - return; - } -#endif switch(ev->type()){ #ifndef QT_NO_GRAPHICSVIEW case QEvent::GraphicsSceneMouseMove: @@ -1332,14 +1294,6 @@ void QLineControl::processMouseEvent(QMouseEvent* ev) } if (ev->button() == Qt::RightButton) return; -#ifdef QT_KEYPAD_NAVIGATION - if (QApplication::keypadNavigationEnabled() && !hasEditFocus()) { - setEditFocus(true); - // Get the completion list to pop up. - if (m_completer) - m_completer->complete(); - } -#endif bool mark = ev->modifiers() & Qt::ShiftModifier; int cursor = xToPos(ev->pos().x()); diff --git a/src/gui/widgets/qlineedit.cpp b/src/gui/widgets/qlineedit.cpp index 977d00c..b0c48b0 100644 --- a/src/gui/widgets/qlineedit.cpp +++ b/src/gui/widgets/qlineedit.cpp @@ -1361,7 +1361,45 @@ void QLineEdit::paste() bool QLineEdit::event(QEvent * e) { Q_D(QLineEdit); - if (e->type() == QEvent::Timer) { +#ifdef QT_KEYPAD_NAVIGATION + if (QApplication::keypadNavigationEnabled()) { + if ((ev->type() == QEvent::KeyPress) || (ev->type() == QEvent::KeyRelease)) { + QKeyEvent *ke = (QKeyEvent *)ev; + if (ke->key() == Qt::Key_Back) { + if (ke->isAutoRepeat()) { + // Swallow it. We don't want back keys running amok. + ke->accept(); + return true; + } + if ((ev->type() == QEvent::KeyRelease) + && !isReadOnly() + && deleteAllTimer) { + killTimer(m_deleteAllTimer); + m_deleteAllTimer = 0; + backspace(); + ke->accept(); + return true; + } + } + } else if (e->type() == QEvent::EnterEditFocus) { + end(false); + int cft = QApplication::cursorFlashTime(); + control->setCursorBlinkPeriod(cft/2); + } else if (e->type() == QEvent::LeaveEditFocus) { + d->setCursorVisible(false);//!!! + control->setCursorBlinkPeriod(0); + if (!m_emitingEditingFinished) { + if (hasAcceptableInput() || fixup()) { + m_emitingEditingFinished = true; + emit editingFinished(); + m_emitingEditingFinished = false; + } + } + } + return; + } +#endif + if (e->type() == QEvent::Timer) { // should be timerEvent, is here for binary compatibility int timerId = ((QTimerEvent*)e)->timerId(); if (false) { @@ -1442,9 +1480,7 @@ void QLineEdit::mouseMoveEvent(QMouseEvent * e) d->drag(); } else #endif - { d->control->moveCursor(d->xToPos(e->pos().x()), true); - } } } @@ -1463,10 +1499,18 @@ void QLineEdit::mouseReleaseEvent(QMouseEvent* e) d->drag(); } else #endif - { d->control->moveCursor(d->xToPos(e->pos().x()), true); + } +#ifndef QT_NO_CLIPBOARD + if (QApplication::clipboard()->supportsSelection()) { + if (e->button() == Qt::LeftButton) { + d->control->copy(QClipboard::Selection); + } else if (!d->control->isReadOnly() && e->button() == Qt::MidButton) { + deselect(); + insert(QApplication::clipboard()->text(QClipboard::Selection)); } } +#endif } /*! \reimp -- cgit v0.12 From 960332de7ae1206390169fb5ef03aa94dffb8f14 Mon Sep 17 00:00:00 2001 From: Alan Alpert Date: Tue, 14 Jul 2009 11:31:57 +1000 Subject: Actually, some of that can't be moved back into QLineEdit Also it should be executed a little later to avoid accidental behaviour changes. --- src/gui/widgets/qlinecontrol.cpp | 23 ++++++++++++++++ src/gui/widgets/qlineedit.cpp | 58 ++++++++++++++-------------------------- 2 files changed, 43 insertions(+), 38 deletions(-) diff --git a/src/gui/widgets/qlinecontrol.cpp b/src/gui/widgets/qlinecontrol.cpp index dd3c057..e6f397a 100644 --- a/src/gui/widgets/qlinecontrol.cpp +++ b/src/gui/widgets/qlinecontrol.cpp @@ -1212,6 +1212,29 @@ void QLineControl::timerEvent ( QTimerEvent * event ) bool QLineControl::processEvent(QEvent* ev) { +#ifdef QT_KEYPAD_NAVIGATION + if (QApplication::keypadNavigationEnabled()) { + if ((ev->type() == QEvent::KeyPress) || (ev->type() == QEvent::KeyRelease)) { + QKeyEvent *ke = (QKeyEvent *)ev; + if (ke->key() == Qt::Key_Back) { + if (ke->isAutoRepeat()) { + // Swallow it. We don't want back keys running amok. + ke->accept(); + return true; + } + if ((ev->type() == QEvent::KeyRelease) + && !isReadOnly() + && deleteAllTimer) { + killTimer(m_deleteAllTimer); + m_deleteAllTimer = 0; + backspace(); + ke->accept(); + return true; + } + } + } + } +#endif switch(ev->type()){ #ifndef QT_NO_GRAPHICSVIEW case QEvent::GraphicsSceneMouseMove: diff --git a/src/gui/widgets/qlineedit.cpp b/src/gui/widgets/qlineedit.cpp index b0c48b0..92dcfc4 100644 --- a/src/gui/widgets/qlineedit.cpp +++ b/src/gui/widgets/qlineedit.cpp @@ -1361,44 +1361,6 @@ void QLineEdit::paste() bool QLineEdit::event(QEvent * e) { Q_D(QLineEdit); -#ifdef QT_KEYPAD_NAVIGATION - if (QApplication::keypadNavigationEnabled()) { - if ((ev->type() == QEvent::KeyPress) || (ev->type() == QEvent::KeyRelease)) { - QKeyEvent *ke = (QKeyEvent *)ev; - if (ke->key() == Qt::Key_Back) { - if (ke->isAutoRepeat()) { - // Swallow it. We don't want back keys running amok. - ke->accept(); - return true; - } - if ((ev->type() == QEvent::KeyRelease) - && !isReadOnly() - && deleteAllTimer) { - killTimer(m_deleteAllTimer); - m_deleteAllTimer = 0; - backspace(); - ke->accept(); - return true; - } - } - } else if (e->type() == QEvent::EnterEditFocus) { - end(false); - int cft = QApplication::cursorFlashTime(); - control->setCursorBlinkPeriod(cft/2); - } else if (e->type() == QEvent::LeaveEditFocus) { - d->setCursorVisible(false);//!!! - control->setCursorBlinkPeriod(0); - if (!m_emitingEditingFinished) { - if (hasAcceptableInput() || fixup()) { - m_emitingEditingFinished = true; - emit editingFinished(); - m_emitingEditingFinished = false; - } - } - } - return; - } -#endif if (e->type() == QEvent::Timer) { // should be timerEvent, is here for binary compatibility int timerId = ((QTimerEvent*)e)->timerId(); @@ -1424,6 +1386,26 @@ bool QLineEdit::event(QEvent * e) d->control->setLayoutDirection((layoutDirection())); } +#ifdef QT_KEYPAD_NAVIGATION + if (QApplication::keypadNavigationEnabled()) { + if (e->type() == QEvent::EnterEditFocus) { + end(false); + int cft = QApplication::cursorFlashTime(); + d->control->setCursorBlinkPeriod(cft/2); + } else if (e->type() == QEvent::LeaveEditFocus) { + d->setCursorVisible(false); + d->control->setCursorBlinkPeriod(0); + if (!d->control->emitingEditingFinished) { + if (d->control->hasAcceptableInput() || d->control->fixup()) { + d->control->emitingEditingFinished = true; + emit editingFinished(); + d->control->emitingEditingFinished = false; + } + } + } + return; + } +#endif return QWidget::event(e); } -- cgit v0.12 From da3b21f6cf51ef10f230f2cf86e43fe0e6314193 Mon Sep 17 00:00:00 2001 From: Alan Alpert Date: Tue, 14 Jul 2009 13:34:40 +1000 Subject: Replace Q_ASSERT with qWarning This is probably more correct, but is also the way it used to behave. --- src/gui/widgets/qlinecontrol.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/gui/widgets/qlinecontrol.cpp b/src/gui/widgets/qlinecontrol.cpp index e6f397a..557892f 100644 --- a/src/gui/widgets/qlinecontrol.cpp +++ b/src/gui/widgets/qlinecontrol.cpp @@ -222,8 +222,10 @@ void QLineControl::clear() */ void QLineControl::setSelection(int start, int length) { - Q_ASSERT_X(start >= 0 && start <= (int)m_text.length(), - "QLineControl::setSelection", "Invalid start position"); + if(start < 0 || start > (int)m_text.length()){ + qWarning("QLineControl::setSelection: Invalid start position"); + return; + } if (length > 0) { selstart = start; -- cgit v0.12 From f6e0f0d549de292f0bbab98a67b035a8327175bf Mon Sep 17 00:00:00 2001 From: Alan Alpert Date: Tue, 14 Jul 2009 13:47:37 +1000 Subject: qlinecontrol_p_p.h isn't actually used at all, remove file. --- src/gui/widgets/qlinecontrol_p_p.h | 105 ------------------------------------- 1 file changed, 105 deletions(-) delete mode 100644 src/gui/widgets/qlinecontrol_p_p.h diff --git a/src/gui/widgets/qlinecontrol_p_p.h b/src/gui/widgets/qlinecontrol_p_p.h deleted file mode 100644 index e76794b..0000000 --- a/src/gui/widgets/qlinecontrol_p_p.h +++ /dev/null @@ -1,105 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). -** Contact: Qt Software Information (qt-info@nokia.com) -** -** This file is part of the QtGui module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the either Technology Preview License Agreement or the -** Beta Release License Agreement. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain -** additional rights. These rights are described in the Nokia Qt LGPL -** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this -** package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** If you are unsure which license is appropriate for your use, please -** contact the sales department at qt-sales@nokia.com. -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QLINECONTROL_P_P_H -#define QLINECONTROL_P_P_H - -// -// 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. -// - -#include "private/qobject_p.h" -#include "QtGui/qtextlayout.h" - -QT_BEGIN_NAMESPACE - -class QMimeData; -class QAbstractScrollArea; -class QInputContext; - -class QLineControlPrivate : public QObjectPrivate -{ - Q_DECLARE_PUBLIC(QLineControl) -public: - QLineControlPrivate() - : cursor(0), preeditCursor(0), cursorWidth(1), cursorTimer(0), - maxLength(32767), modifiedState(0), undoState(0), - selStart(0), selEnd(0), textInteractionFlags(0), - cursorVisible(0), hideCursor(0), echoMode(0) - {} - - QPalette palette; - QVector history; - QTextLayout textLayout; // display text - QString text; - - int cursor; - int preeditCursor; - int lastCursorPos; - int cursorWidth; - int cursorTimer; - - int maxLength; - - int modifiedState; - int undoState; - - int selStart, selEnd; - - Qt::TextInteractionFlags textInteractionFlags; - - // keep together and at end - uint cursorVisible : 1; - uint hideCursor : 1; // used to hide the cursor inside preedit areas - uint echoMode : 2; -}; - -QT_END_NAMESPACE - -#endif // QLINECONTROL_P_H - -- cgit v0.12 From 291703873d208fec1eba1a039a79a61543745b35 Mon Sep 17 00:00:00 2001 From: Alan Alpert Date: Tue, 14 Jul 2009 14:17:28 +1000 Subject: Cleanup some incorrect changes to QLineEdit --- src/gui/widgets/qlineedit.cpp | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/gui/widgets/qlineedit.cpp b/src/gui/widgets/qlineedit.cpp index 92dcfc4..9252888 100644 --- a/src/gui/widgets/qlineedit.cpp +++ b/src/gui/widgets/qlineedit.cpp @@ -1382,8 +1382,6 @@ bool QLineEdit::event(QEvent * e) QTimer::singleShot(0, this, SLOT(_q_handleWindowActivate())); }else if(e->type() == QEvent::ShortcutOverride){ d->control->processEvent(e); - }else if(e->type() == QEvent::LayoutDirectionChange){ - d->control->setLayoutDirection((layoutDirection())); } #ifdef QT_KEYPAD_NAVIGATION @@ -1462,7 +1460,9 @@ void QLineEdit::mouseMoveEvent(QMouseEvent * e) d->drag(); } else #endif + { d->control->moveCursor(d->xToPos(e->pos().x()), true); + } } } @@ -1473,16 +1473,15 @@ void QLineEdit::mouseReleaseEvent(QMouseEvent* e) Q_D(QLineEdit); if (d->sendMouseEventToInputContext(e)) return; - - if (e->buttons() & Qt::LeftButton) { #ifndef QT_NO_DRAGANDDROP + if (e->button() == Qt::LeftButton) { if (d->dndTimer.isActive()) { - if ((d->dndPos - e->pos()).manhattanLength() > QApplication::startDragDistance()) - d->drag(); - } else -#endif - d->control->moveCursor(d->xToPos(e->pos().x()), true); + d->dndTimer.stop(); + deselect(); + return; + } } +#endif #ifndef QT_NO_CLIPBOARD if (QApplication::clipboard()->supportsSelection()) { if (e->button() == Qt::LeftButton) { -- cgit v0.12 From 1bd89d1c8a9bc41f8ea76f55a2ebd17447fc2d70 Mon Sep 17 00:00:00 2001 From: Marius Bugge Monsen Date: Tue, 14 Jul 2009 15:05:42 +0200 Subject: Add '\internal' to the QLineControl documentation. --- src/gui/widgets/qlinecontrol.cpp | 142 ++++++++++++++++++++++++++++----------- 1 file changed, 102 insertions(+), 40 deletions(-) diff --git a/src/gui/widgets/qlinecontrol.cpp b/src/gui/widgets/qlinecontrol.cpp index 557892f..9b2a47a 100644 --- a/src/gui/widgets/qlinecontrol.cpp +++ b/src/gui/widgets/qlinecontrol.cpp @@ -59,7 +59,9 @@ QT_BEGIN_NAMESPACE -/* +/*! + \internal + Updates the display text based of the current edit text If the text has changed will emit displayTextChanged() */ @@ -105,7 +107,9 @@ void QLineControl::updateDisplayText() } #ifndef QT_NO_CLIPBOARD -/* +/*! + \internal + Copies the currently selected text into the clipboard using the given \a mode. @@ -124,7 +128,9 @@ void QLineControl::copy(QClipboard::Mode mode) const } } -/* +/*! + \internal + Inserts the text stored in the application clipboard into the line control. @@ -137,7 +143,9 @@ void QLineControl::paste() #endif // !QT_NO_CLIPBOARD -/* +/*! + \internal + Handles the behavior for the backspace key or function. Removes the current selection if there is a selection, otherwise removes the character prior to the cursor position. @@ -168,7 +176,9 @@ void QLineControl::backspace() finishChange(priorState); } -/* +/*! + \internal + Handles the behavior for the delete key or function. Removes the current selection if there is a selection, otherwise removes the character after the cursor position. @@ -188,7 +198,9 @@ void QLineControl::del() finishChange(priorState); } -/* +/*! + \internal + Inserts the given \a newText at the current cursor position. If there is any selected text it is removed prior to insertion of the new text. @@ -201,7 +213,9 @@ void QLineControl::insert(const QString &newText) finishChange(priorState); } -/* +/*! + \internal + Clears the line control text. */ void QLineControl::clear() @@ -214,7 +228,9 @@ void QLineControl::clear() finishChange(priorState, /*update*/false, /*edited*/false); } -/* +/*! + \internal + Sets \a length characters from the given \a start position as selected. The given \a start position must be within the current text for the line control. If \a length characters cannot be selected, then @@ -254,7 +270,9 @@ void QLineControl::_q_deleteSelected() finishChange(priorState); } -/* +/*! + \internal + Initializes the line control with a starting text value of \a txt. */ void QLineControl::init(const QString& txt) @@ -264,7 +282,9 @@ void QLineControl::init(const QString& txt) m_cursor = m_text.length(); } -/* +/*! + \internal + Sets the password echo editing to \a editing. If password echo editing is true, then the text of the password is displayed even if the echo mode is set to QLineEdit::PasswordEchoOnEdit. Password echoing editing @@ -276,7 +296,9 @@ void QLineControl::updatePasswordEchoEditing(bool editing) updateDisplayText(); } -/* +/*! + \internal + Returns the cursor position of the given \a x pixel value in relation to the displayed text. The given \a betweenOrOn specified what kind of cursor position is requested. @@ -286,7 +308,9 @@ int QLineControl::xToPos(int x, QTextLine::CursorPosition betweenOrOn) const return textLayout.lineAt(0).xToCursor(x, betweenOrOn); } -/* +/*! + \internal + Returns the bounds of the current cursor, as defined as a between characters cursor. */ @@ -303,7 +327,9 @@ QRect QLineControl::cursorRect() const return QRect(cix-5, 0, w+9, ch); } -/* +/*! + \internal + Fixes the current text so that it is valid given any set validators. Returns true if the text was changed. Otherwise returns false. @@ -325,7 +351,9 @@ bool QLineControl::fixup() // this function assumes that validate currently retu return false; } -/* +/*! + \internal + Moves the cursor to the given position \a pos. If \a mark is true will adjust the currently selected text. */ @@ -358,7 +386,9 @@ void QLineControl::moveCursor(int pos, bool mark) emitCursorPositionChanged(); } -/* +/*! + \internal + Applies the given input method event \a event to the text of the line control */ @@ -411,7 +441,9 @@ void QLineControl::processInputMethodEvent(QInputMethodEvent *event) finishChange(priorState); } -/* +/*! + \internal + Draws the display text for the line control using the given \a painter, \a clip, and \a offset. Which aspects of the display text are drawn is specified by the given \a flags. @@ -453,7 +485,9 @@ void QLineControl::draw(QPainter *painter, const QPoint &offset, const QRect &cl } } -/* +/*! + \internal + Sets the selection to cover the word at the given cursor position. The word boundries is defined by the behavior of QTextLayout::SkipWords cursor mode. @@ -469,7 +503,9 @@ void QLineControl::selectWordAtPos(int cursor) moveCursor(end, true); } -/* +/*! + \internal + Completes a change to the line control text. If the change is not valid will undo the line control state back to the given \a validateFromState. @@ -479,7 +515,6 @@ void QLineControl::selectWordAtPos(int cursor) The \a update value is currently unused. */ - bool QLineControl::finishChange(int validateFromState, bool update, bool edited) { Q_UNUSED(update) @@ -531,7 +566,9 @@ bool QLineControl::finishChange(int validateFromState, bool update, bool edited) return true; } -/* +/*! + \internal + An internal function for setting the text of the line control. */ void QLineControl::p_setText(const QString& txt, int pos, bool edited) @@ -553,7 +590,9 @@ void QLineControl::p_setText(const QString& txt, int pos, bool edited) } -/* +/*! + \internal + Adds the given \a command to the undo history of the line control. Does not apply the command. */ @@ -569,7 +608,9 @@ void QLineControl::addCommand(const Command& cmd) history[undoState++] = cmd; } -/* +/*! + \internal + Inserts the given string \a s into the line control. @@ -602,8 +643,9 @@ void QLineControl::p_insert(const QString& s) } } -/* +/*! \internal + deletes a single character from the current text. If \a wasBackspace, the character prior to the cursor is removed. Otherwise the character after the cursor is removed. @@ -628,8 +670,9 @@ void QLineControl::p_del(bool wasBackspace) } } -/* +/*! \internal + removes the currently selected text from the line control. Also adds the appropriate commands into the undo history. @@ -667,7 +710,9 @@ void QLineControl::removeSelectedText() } } -/* +/*! + \internal + Parses the input mask specified by \a maskFields to generate the mask data used to handle input masks. */ @@ -769,7 +814,11 @@ void QLineControl::parseInputMask(const QString &maskFields) } -/* checks if the key is valid compared to the inputMask */ +/*! + \internal + + checks if the key is valid compared to the inputMask +*/ bool QLineControl::isValidInput(QChar key, QChar mask) const { switch (mask.unicode()) { @@ -839,7 +888,9 @@ bool QLineControl::isValidInput(QChar key, QChar mask) const return false; } -/* +/*! + \internal + Returns true if the given text \a str is valid for any validator or input mask set for the line control. @@ -873,11 +924,13 @@ bool QLineControl::hasAcceptableInput(const QString &str) const return true; } -/* - Applies the inputMask on \a str starting from position \a pos in the mask. \a clear - specifies from where characters should be gotten when a separator is met in \a str - true means - that blanks will be used, false that previous input is used. - Calling this when no inputMask is set is undefined. +/*! + \internal + + Applies the inputMask on \a str starting from position \a pos in the mask. \a clear + specifies from where characters should be gotten when a separator is met in \a str - true means + that blanks will be used, false that previous input is used. + Calling this when no inputMask is set is undefined. */ QString QLineControl::maskString(uint pos, const QString &str, bool clear) const { @@ -948,9 +1001,11 @@ QString QLineControl::maskString(uint pos, const QString &str, bool clear) const -/* - Returns a "cleared" string with only separators and blank chars. - Calling this when no inputMask is set is undefined. +/*! + \internal + + Returns a "cleared" string with only separators and blank chars. + Calling this when no inputMask is set is undefined. */ QString QLineControl::clearString(uint pos, uint len) const { @@ -968,9 +1023,11 @@ QString QLineControl::clearString(uint pos, uint len) const return s; } -/* - Strips blank parts of the input in a QLineControl when an inputMask is set, - separators are still included. Typically "127.0__.0__.1__" becomes "127.0.0.1". +/*! + \internal + + Strips blank parts of the input in a QLineControl when an inputMask is set, + separators are still included. Typically "127.0__.0__.1__" becomes "127.0.0.1". */ QString QLineControl::stripString(const QString &str) const { @@ -989,7 +1046,10 @@ QString QLineControl::stripString(const QString &str) const return s; } -/* searches forward/backward in maskData for either a separator or a blank */ +/*! + \internal + searches forward/backward in maskData for either a separator or a blank +*/ int QLineControl::findInMask(int pos, bool forward, bool findSeparator, QChar searchChar) const { if (pos >= m_maxLength || pos < 0) @@ -1099,7 +1159,9 @@ void QLineControl::p_redo() { emitCursorPositionChanged(); } -/* +/*! + \internal + If the current cursor position differs from the last emited cursor position, emits cursorPositionChanged(). */ -- cgit v0.12 From 363221747e68b7a5930afdeef87a5454f40c5ffb Mon Sep 17 00:00:00 2001 From: Marius Bugge Monsen Date: Tue, 14 Jul 2009 15:19:35 +0200 Subject: Some minor style and whitespace fixes. --- src/gui/widgets/qlinecontrol.cpp | 59 ++++++++++++++++++++-------------------- src/gui/widgets/qlinecontrol_p.h | 23 ++++++++++------ 2 files changed, 44 insertions(+), 38 deletions(-) diff --git a/src/gui/widgets/qlinecontrol.cpp b/src/gui/widgets/qlinecontrol.cpp index 9b2a47a..6d8fe06 100644 --- a/src/gui/widgets/qlinecontrol.cpp +++ b/src/gui/widgets/qlinecontrol.cpp @@ -275,7 +275,7 @@ void QLineControl::_q_deleteSelected() Initializes the line control with a starting text value of \a txt. */ -void QLineControl::init(const QString& txt) +void QLineControl::init(const QString &txt) { m_text = txt; updateDisplayText(); @@ -571,7 +571,7 @@ bool QLineControl::finishChange(int validateFromState, bool update, bool edited) An internal function for setting the text of the line control. */ -void QLineControl::p_setText(const QString& txt, int pos, bool edited) +void QLineControl::p_setText(const QString &txt, int pos, bool edited) { p_deselect(); emit resetInputContext(); @@ -596,7 +596,7 @@ void QLineControl::p_setText(const QString& txt, int pos, bool edited) Adds the given \a command to the undo history of the line control. Does not apply the command. */ -void QLineControl::addCommand(const Command& cmd) +void QLineControl::addCommand(const Command &cmd) { if (separator && undoState && history[undoState-1].type != Separator) { history.resize(undoState + 2); @@ -618,15 +618,15 @@ void QLineControl::addCommand(const Command& cmd) This function does not call finishChange(), and may leave the text in an invalid state. */ -void QLineControl::p_insert(const QString& s) +void QLineControl::p_insert(const QString &s) { if (hasSelectedText()) addCommand(Command(SetSelection, m_cursor, 0, selstart, selend)); if (maskData) { QString ms = maskString(m_cursor, s); for (int i = 0; i < (int) ms.length(); ++i) { - addCommand (Command(DeleteSelection, m_cursor+i, m_text.at(m_cursor+i), -1, -1)); - addCommand(Command(Insert, m_cursor+i, ms.at(i), -1, -1)); + addCommand (Command(DeleteSelection, m_cursor + i, m_text.at(m_cursor + i), -1, -1)); + addCommand(Command(Insert, m_cursor + i, ms.at(i), -1, -1)); } m_text.replace(m_cursor, ms.length(), ms); m_cursor += ms.length(); @@ -659,7 +659,8 @@ void QLineControl::p_del(bool wasBackspace) if (m_cursor < (int) m_text.length()) { if (hasSelectedText()) addCommand(Command(SetSelection, m_cursor, 0, selstart, selend)); - addCommand (Command((CommandType)((maskData?2:0)+(wasBackspace?Remove:Delete)), m_cursor, m_text.at(m_cursor), -1, -1)); + addCommand(Command((CommandType)((maskData ? 2 : 0) + (wasBackspace ? Remove : Delete)), + m_cursor, m_text.at(m_cursor), -1, -1)); if (maskData) { m_text.replace(m_cursor, 1, clearString(m_cursor, 1)); addCommand(Command(Insert, m_cursor, m_text.at(m_cursor), -1, -1)); @@ -990,7 +991,7 @@ QString QLineControl::maskString(uint pos, const QString &str, bool clear) const } } } - strIndex++; + ++strIndex; } } else break; @@ -1014,7 +1015,7 @@ QString QLineControl::clearString(uint pos, uint len) const QString s; int end = qMin((uint)m_maxLength, pos + len); - for (int i=pos; itimerId() == m_blinkTimer) { + if (event->timerId() == m_blinkTimer) { m_blinkStatus = !m_blinkStatus; - emit updateNeeded(inputMask().isEmpty()?cursorRect():QRect()); - }else if(event->timerId() == m_deleteAllTimer){ + emit updateNeeded(inputMask().isEmpty() ? cursorRect() : QRect()); + } else if (event->timerId() == m_deleteAllTimer) { killTimer(m_deleteAllTimer); m_deleteAllTimer = 0; clear(); - }else if(event->timerId() == m_tripleClickTimer){ + } else if (event->timerId() == m_tripleClickTimer) { killTimer(m_tripleClickTimer); m_tripleClickTimer = 0; } @@ -1371,11 +1372,12 @@ bool QLineControl::processEvent(QEvent* ev) void QLineControl::processMouseEvent(QMouseEvent* ev) { - switch (ev->type()){ + switch (ev->type()) { case QEvent::GraphicsSceneMousePress: case QEvent::MouseButtonPress:{ - if (m_tripleClickTimer && (ev->pos() - m_tripleClick).manhattanLength() < - QApplication::startDragDistance()) { + if (m_tripleClickTimer + && (ev->pos() - m_tripleClick).manhattanLength() + < QApplication::startDragDistance()) { selectAll(); return; } @@ -1390,7 +1392,7 @@ void QLineControl::processMouseEvent(QMouseEvent* ev) case QEvent::MouseButtonDblClick: if (ev->button() == Qt::LeftButton) { selectWordAtPos(xToPos(ev->pos().x())); - if(m_tripleClickTimer) + if (m_tripleClickTimer) killTimer(m_tripleClickTimer); m_tripleClickTimer = startTimer(QApplication::doubleClickInterval()); m_tripleClick = ev->pos(); @@ -1412,7 +1414,7 @@ void QLineControl::processMouseEvent(QMouseEvent* ev) case QEvent::GraphicsSceneMouseMove: case QEvent::MouseMove: if (ev->buttons() & Qt::LeftButton) { - moveCursor(xToPos(ev->pos().x()), true); + moveCursor(xToPos(ev->pos().x()), true); } break; default: @@ -1422,7 +1424,6 @@ void QLineControl::processMouseEvent(QMouseEvent* ev) void QLineControl::processKeyEvent(QKeyEvent* event) { - bool inlineCompletionAccepted = false; #ifndef QT_NO_COMPLETER @@ -1472,8 +1473,6 @@ void QLineControl::processKeyEvent(QKeyEvent* event) } #endif // QT_NO_COMPLETER - - if (echoMode() == QLineEdit::PasswordEchoOnEdit && !passwordEchoEditing() && !isReadOnly() diff --git a/src/gui/widgets/qlinecontrol_p.h b/src/gui/widgets/qlinecontrol_p.h index 4ecedcd..2d93e90 100644 --- a/src/gui/widgets/qlinecontrol_p.h +++ b/src/gui/widgets/qlinecontrol_p.h @@ -462,8 +462,10 @@ inline void QLineControl::removeSelection() inline bool QLineControl::inSelection(int x) const { - if (selstart >= selend) return false; - int pos = xToPos(x, QTextLine::CursorOnCharacter); return pos >= selstart && pos < selend; + if (selstart >= selend) + return false; + int pos = xToPos(x, QTextLine::CursorOnCharacter); + return pos >= selstart && pos < selend; } inline int QLineControl::cursor() const @@ -557,22 +559,26 @@ inline QString QLineControl::displayText() const inline void QLineControl::deselect() { - p_deselect(); finishChange(); + p_deselect(); + finishChange(); } inline void QLineControl::selectAll() { - selstart = selend = m_cursor = 0; moveCursor(m_text.length(), true); + selstart = selend = m_cursor = 0; + moveCursor(m_text.length(), true); } inline void QLineControl::undo() { - p_undo(), finishChange(-1, true); + p_undo(); + finishChange(-1, true); } inline void QLineControl::redo() { - p_redo(), finishChange(); + p_redo(); + finishChange(); } inline uint QLineControl::echoMode() const @@ -625,7 +631,8 @@ inline void QLineControl::setCompleter(const QCompleter* c) inline void QLineControl::setCursorPosition(int pos) { - if (pos < 0) pos = 0; + if (pos < 0) + pos = 0; if (pos < m_text.length()) moveCursor(pos); } @@ -723,7 +730,7 @@ inline void QLineControl::setCancelText(QString s) QT_END_NAMESPACE QT_END_HEADER -#endif // QT_NO_LINEEDIT +#endif // QT_NO_LINEEDIT #endif // QLINECONTROL_P_H -- cgit v0.12 From aec21d2255e9927689e640b36150b7c9a4e9f522 Mon Sep 17 00:00:00 2001 From: Marius Bugge Monsen Date: Tue, 14 Jul 2009 16:16:47 +0200 Subject: Make the member variable names in QLineControl consistent. --- src/gui/widgets/qlinecontrol.cpp | 330 +++++++++++++++++++-------------------- src/gui/widgets/qlinecontrol_p.h | 161 ++++++++++--------- src/gui/widgets/qlineedit.cpp | 6 +- src/gui/widgets/qlineedit_p.h | 1 - 4 files changed, 253 insertions(+), 245 deletions(-) diff --git a/src/gui/widgets/qlinecontrol.cpp b/src/gui/widgets/qlinecontrol.cpp index 6d8fe06..50ce6e6 100644 --- a/src/gui/widgets/qlinecontrol.cpp +++ b/src/gui/widgets/qlinecontrol.cpp @@ -67,7 +67,7 @@ QT_BEGIN_NAMESPACE */ void QLineControl::updateDisplayText() { - QString orig = textLayout.text(); + QString orig = m_textLayout.text(); QString str; if (m_echoMode == QLineEdit::NoEcho) str = QString::fromLatin1(""); @@ -90,16 +90,16 @@ void QLineControl::updateDisplayText() uc[i] = QChar(0x0020); } - textLayout.setText(str); + m_textLayout.setText(str); QTextOption option; option.setTextDirection(m_layoutDirection); option.setFlags(QTextOption::IncludeTrailingSpaces); - textLayout.setTextOption(option); + m_textLayout.setTextOption(option); - textLayout.beginLayout(); - QTextLine l = textLayout.createLine(); - textLayout.endLayout(); + m_textLayout.beginLayout(); + QTextLine l = m_textLayout.createLine(); + m_textLayout.endLayout(); m_ascent = qRound(l.ascent()); if (str != orig) @@ -154,12 +154,12 @@ void QLineControl::paste() */ void QLineControl::backspace() { - int priorState = undoState; + int priorState = m_undoState; if (hasSelectedText()) { removeSelectedText(); } else if (m_cursor) { --m_cursor; - if (maskData) + if (m_maskData) m_cursor = prevMaskBlank(m_cursor); QChar uc = m_text.at(m_cursor); if (m_cursor > 0 && uc.unicode() >= 0xdc00 && uc.unicode() < 0xe000) { @@ -187,11 +187,11 @@ void QLineControl::backspace() */ void QLineControl::del() { - int priorState = undoState; + int priorState = m_undoState; if (hasSelectedText()) { removeSelectedText(); } else { - int n = textLayout.nextCursorPosition(m_cursor) - m_cursor; + int n = m_textLayout.nextCursorPosition(m_cursor) - m_cursor; while (n--) p_del(); } @@ -207,7 +207,7 @@ void QLineControl::del() */ void QLineControl::insert(const QString &newText) { - int priorState = undoState; + int priorState = m_undoState; removeSelectedText(); p_insert(newText); finishChange(priorState); @@ -220,9 +220,9 @@ void QLineControl::insert(const QString &newText) */ void QLineControl::clear() { - int priorState = undoState; - selstart = 0; - selend = m_text.length(); + int priorState = m_undoState; + m_selstart = 0; + m_selend = m_text.length(); removeSelectedText(); separate(); finishChange(priorState, /*update*/false, /*edited*/false); @@ -244,13 +244,13 @@ void QLineControl::setSelection(int start, int length) } if (length > 0) { - selstart = start; - selend = qMin(start + length, (int)m_text.length()); - m_cursor = selend; + m_selstart = start; + m_selend = qMin(start + length, (int)m_text.length()); + m_cursor = m_selend; } else { - selstart = qMax(start + length, 0); - selend = start; - m_cursor = selstart; + m_selstart = qMax(start + length, 0); + m_selend = start; + m_cursor = m_selstart; } } @@ -263,7 +263,7 @@ void QLineControl::_q_deleteSelected() if (!hasSelectedText()) return; - int priorState = undoState; + int priorState = m_undoState; emit resetInputContext(); removeSelectedText(); separate(); @@ -305,7 +305,7 @@ void QLineControl::updatePasswordEchoEditing(bool editing) */ int QLineControl::xToPos(int x, QTextLine::CursorPosition betweenOrOn) const { - return textLayout.lineAt(0).xToCursor(x, betweenOrOn); + return m_textLayout.lineAt(0).xToCursor(x, betweenOrOn); } /*! @@ -316,7 +316,7 @@ int QLineControl::xToPos(int x, QTextLine::CursorPosition betweenOrOn) const */ QRect QLineControl::cursorRect() const { - QTextLine l = textLayout.lineAt(0); + QTextLine l = m_textLayout.lineAt(0); int c = m_cursor; if (m_preeditCursor != -1) c += m_preeditCursor; @@ -361,26 +361,26 @@ void QLineControl::moveCursor(int pos, bool mark) { if (pos != m_cursor) { separate(); - if (maskData) + if (m_maskData) pos = pos > m_cursor ? nextMaskBlank(pos) : prevMaskBlank(pos); } if (mark) { int anchor; - if (selend > selstart && m_cursor == selstart) - anchor = selend; - else if (selend > selstart && m_cursor == selend) - anchor = selstart; + if (m_selend > m_selstart && m_cursor == m_selstart) + anchor = m_selend; + else if (m_selend > m_selstart && m_cursor == m_selend) + anchor = m_selstart; else anchor = m_cursor; - selstart = qMin(anchor, pos); - selend = qMax(anchor, pos); + m_selstart = qMin(anchor, pos); + m_selend = qMax(anchor, pos); updateDisplayText(); } else { p_deselect(); } m_cursor = pos; - if (mark || selDirty) { - selDirty = false; + if (mark || m_selDirty) { + m_selDirty = false; emit selectionChanged(); } emitCursorPositionChanged(); @@ -394,7 +394,7 @@ void QLineControl::moveCursor(int pos, bool mark) */ void QLineControl::processInputMethodEvent(QInputMethodEvent *event) { - int priorState = undoState; + int priorState = m_undoState; removeSelectedText(); int c = m_cursor; // cursor position after insertion of commit string @@ -405,8 +405,8 @@ void QLineControl::processInputMethodEvent(QInputMethodEvent *event) // insert commit string if (event->replacementLength()) { - selstart = m_cursor; - selend = selstart + event->replacementLength(); + m_selstart = m_cursor; + m_selend = m_selstart + event->replacementLength(); removeSelectedText(); } if (!event->commitString().isEmpty()) @@ -416,13 +416,13 @@ void QLineControl::processInputMethodEvent(QInputMethodEvent *event) setPreeditArea(m_cursor, event->preeditString()); m_preeditCursor = event->preeditString().length(); - hideCursor = false; + m_hideCursor = false; QList formats; for (int i = 0; i < event->attributes().size(); ++i) { const QInputMethodEvent::Attribute &a = event->attributes().at(i); if (a.type == QInputMethodEvent::Cursor) { m_preeditCursor = a.start; - hideCursor = !a.length; + m_hideCursor = !a.length; } else if (a.type == QInputMethodEvent::TextFormat) { QTextCharFormat f = qvariant_cast(a.value).toCharFormat(); if (f.isValid()) { @@ -434,7 +434,7 @@ void QLineControl::processInputMethodEvent(QInputMethodEvent *event) } } } - textLayout.setAdditionalFormats(formats); + m_textLayout.setAdditionalFormats(formats); updateDisplayText(); if (!event->commitString().isEmpty()) emitCursorPositionChanged(); @@ -461,9 +461,9 @@ void QLineControl::draw(QPainter *painter, const QPoint &offset, const QRect &cl QVector selections; if (flags & DrawSelections) { QTextLayout::FormatRange o; - if (selstart < selend) { - o.start = selstart; - o.length = selend - selstart; + if (m_selstart < m_selend) { + o.start = m_selstart; + o.length = m_selend - m_selstart; o.format.setBackground(m_palette.brush(QPalette::Highlight)); o.format.setForeground(m_palette.brush(QPalette::HighlightedText)); } else { @@ -477,11 +477,11 @@ void QLineControl::draw(QPainter *painter, const QPoint &offset, const QRect &cl } if (flags & DrawText) - textLayout.draw(painter, offset, selections, clip); + m_textLayout.draw(painter, offset, selections, clip); if (flags & DrawCursor){ if(!m_blinkPeriod || m_blinkStatus) - textLayout.drawCursor(painter, offset, m_cursor, m_cursorWidth); + m_textLayout.drawCursor(painter, offset, m_cursor, m_cursorWidth); } } @@ -494,10 +494,10 @@ void QLineControl::draw(QPainter *painter, const QPoint &offset, const QRect &cl */ void QLineControl::selectWordAtPos(int cursor) { - int c = textLayout.previousCursorPosition(cursor, QTextLayout::SkipWords); + int c = m_textLayout.previousCursorPosition(cursor, QTextLayout::SkipWords); moveCursor(c, false); // ## text layout should support end of words. - int end = textLayout.nextCursorPosition(cursor, QTextLayout::SkipWords); + int end = m_textLayout.nextCursorPosition(cursor, QTextLayout::SkipWords); while (end > cursor && m_text[end-1].isSpace()) --end; moveCursor(end, true); @@ -518,18 +518,18 @@ void QLineControl::selectWordAtPos(int cursor) bool QLineControl::finishChange(int validateFromState, bool update, bool edited) { Q_UNUSED(update) - bool lineDirty = selDirty; - if (textDirty) { + bool lineDirty = m_selDirty; + if (m_textDirty) { // do validation - bool wasValidInput = validInput; - validInput = true; + bool wasValidInput = m_validInput; + m_validInput = true; #ifndef QT_NO_VALIDATOR if (m_validator) { - validInput = false; + m_validInput = false; QString textCopy = m_text; int cursorCopy = m_cursor; - validInput = (m_validator->validate(textCopy, cursorCopy) != QValidator::Invalid); - if (validInput) { + m_validInput = (m_validator->validate(textCopy, cursorCopy) != QValidator::Invalid); + if (m_validInput) { if (m_text != textCopy) { p_setText(textCopy, cursorCopy); return true; @@ -538,28 +538,28 @@ bool QLineControl::finishChange(int validateFromState, bool update, bool edited) } } #endif - if (validateFromState >= 0 && wasValidInput && !validInput) { - if (transactions.count()) + if (validateFromState >= 0 && wasValidInput && !m_validInput) { + if (m_transactions.count()) return false; p_undo(validateFromState); - history.resize(undoState); - if (modifiedState > undoState) - modifiedState = -1; - validInput = true; - textDirty = false; + m_history.resize(m_undoState); + if (m_modifiedState > m_undoState) + m_modifiedState = -1; + m_validInput = true; + m_textDirty = false; } updateDisplayText(); - lineDirty |= textDirty; - if (textDirty) { - textDirty = false; + lineDirty |= m_textDirty; + if (m_textDirty) { + m_textDirty = false; QString actualText = text(); if (edited) emit textEdited(actualText); emit textChanged(actualText); } } - if (selDirty) { - selDirty = false; + if (m_selDirty) { + m_selDirty = false; emit selectionChanged(); } emitCursorPositionChanged(); @@ -576,16 +576,16 @@ void QLineControl::p_setText(const QString &txt, int pos, bool edited) p_deselect(); emit resetInputContext(); QString oldText = m_text; - if (maskData) { + if (m_maskData) { m_text = maskString(0, txt, true); m_text += clearString(m_text.length(), m_maxLength - m_text.length()); } else { m_text = txt.isEmpty() ? txt : txt.left(m_maxLength); } - history.clear(); - modifiedState = undoState = 0; + m_history.clear(); + m_modifiedState = m_undoState = 0; m_cursor = (pos < 0 || pos > m_text.length()) ? m_text.length() : pos; - textDirty = (oldText != m_text); + m_textDirty = (oldText != m_text); finishChange(-1, true, edited); } @@ -598,14 +598,14 @@ void QLineControl::p_setText(const QString &txt, int pos, bool edited) */ void QLineControl::addCommand(const Command &cmd) { - if (separator && undoState && history[undoState-1].type != Separator) { - history.resize(undoState + 2); - history[undoState++] = Command(Separator, m_cursor, 0, selstart, selend); + if (m_separator && m_undoState && m_history[m_undoState - 1].type != Separator) { + m_history.resize(m_undoState + 2); + m_history[m_undoState++] = Command(Separator, m_cursor, 0, m_selstart, m_selend); } else { - history.resize(undoState + 1); + m_history.resize(m_undoState + 1); } - separator = false; - history[undoState++] = cmd; + m_separator = false; + m_history[m_undoState++] = cmd; } /*! @@ -621,8 +621,8 @@ void QLineControl::addCommand(const Command &cmd) void QLineControl::p_insert(const QString &s) { if (hasSelectedText()) - addCommand(Command(SetSelection, m_cursor, 0, selstart, selend)); - if (maskData) { + addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend)); + if (m_maskData) { QString ms = maskString(m_cursor, s); for (int i = 0; i < (int) ms.length(); ++i) { addCommand (Command(DeleteSelection, m_cursor + i, m_text.at(m_cursor + i), -1, -1)); @@ -631,14 +631,14 @@ void QLineControl::p_insert(const QString &s) m_text.replace(m_cursor, ms.length(), ms); m_cursor += ms.length(); m_cursor = nextMaskBlank(m_cursor); - textDirty = true; + m_textDirty = true; } else { int remaining = m_maxLength - m_text.length(); if (remaining != 0) { m_text.insert(m_cursor, s.left(remaining)); for (int i = 0; i < (int) s.left(remaining).length(); ++i) addCommand(Command(Insert, m_cursor++, s.at(i), -1, -1)); - textDirty = true; + m_textDirty = true; } } } @@ -658,16 +658,16 @@ void QLineControl::p_del(bool wasBackspace) { if (m_cursor < (int) m_text.length()) { if (hasSelectedText()) - addCommand(Command(SetSelection, m_cursor, 0, selstart, selend)); - addCommand(Command((CommandType)((maskData ? 2 : 0) + (wasBackspace ? Remove : Delete)), + addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend)); + addCommand(Command((CommandType)((m_maskData ? 2 : 0) + (wasBackspace ? Remove : Delete)), m_cursor, m_text.at(m_cursor), -1, -1)); - if (maskData) { + if (m_maskData) { m_text.replace(m_cursor, 1, clearString(m_cursor, 1)); addCommand(Command(Insert, m_cursor, m_text.at(m_cursor), -1, -1)); } else { m_text.remove(m_cursor, 1); } - textDirty = true; + m_textDirty = true; } } @@ -682,32 +682,32 @@ void QLineControl::p_del(bool wasBackspace) */ void QLineControl::removeSelectedText() { - if (selstart < selend && selend <= (int) m_text.length()) { + if (m_selstart < m_selend && m_selend <= (int) m_text.length()) { separate(); int i ; - addCommand(Command(SetSelection, m_cursor, 0, selstart, selend)); - if (selstart <= m_cursor && m_cursor < selend) { + addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend)); + if (m_selstart <= m_cursor && m_cursor < m_selend) { // cursor is within the selection. Split up the commands // to be able to restore the correct cursor position - for (i = m_cursor; i >= selstart; --i) + for (i = m_cursor; i >= m_selstart; --i) addCommand (Command(DeleteSelection, i, m_text.at(i), -1, 1)); - for (i = selend - 1; i > m_cursor; --i) - addCommand (Command(DeleteSelection, i - m_cursor + selstart - 1, m_text.at(i), -1, -1)); + for (i = m_selend - 1; i > m_cursor; --i) + addCommand (Command(DeleteSelection, i - m_cursor + m_selstart - 1, m_text.at(i), -1, -1)); } else { - for (i = selend-1; i >= selstart; --i) + for (i = m_selend-1; i >= m_selstart; --i) addCommand (Command(RemoveSelection, i, m_text.at(i), -1, -1)); } - if (maskData) { - m_text.replace(selstart, selend - selstart, clearString(selstart, selend - selstart)); - for (int i = 0; i < selend - selstart; ++i) - addCommand(Command(Insert, selstart + i, m_text.at(selstart + i), -1, -1)); + if (m_maskData) { + m_text.replace(m_selstart, m_selend - m_selstart, clearString(m_selstart, m_selend - m_selstart)); + for (int i = 0; i < m_selend - m_selstart; ++i) + addCommand(Command(Insert, m_selstart + i, m_text.at(m_selstart + i), -1, -1)); } else { - m_text.remove(selstart, selend - selstart); + m_text.remove(m_selstart, m_selend - m_selstart); } - if (m_cursor > selstart) - m_cursor -= qMin(m_cursor, selend) - selstart; + if (m_cursor > m_selstart) + m_cursor -= qMin(m_cursor, m_selend) - m_selstart; p_deselect(); - textDirty = true; + m_textDirty = true; } } @@ -721,9 +721,9 @@ void QLineControl::parseInputMask(const QString &maskFields) { int delimiter = maskFields.indexOf(QLatin1Char(';')); if (maskFields.isEmpty() || delimiter == 0) { - if (maskData) { - delete [] maskData; - maskData = 0; + if (m_maskData) { + delete [] m_maskData; + m_maskData = 0; m_maxLength = 32767; p_setText(QString()); } @@ -731,14 +731,14 @@ void QLineControl::parseInputMask(const QString &maskFields) } if (delimiter == -1) { - blank = QLatin1Char(' '); + m_blank = QLatin1Char(' '); m_inputMask = maskFields; } else { m_inputMask = maskFields.left(delimiter); - blank = (delimiter + 1 < maskFields.length()) ? maskFields[delimiter + 1] : QLatin1Char(' '); + m_blank = (delimiter + 1 < maskFields.length()) ? maskFields[delimiter + 1] : QLatin1Char(' '); } - // calculate m_maxLength / maskData length + // calculate m_maxLength / m_maskData length m_maxLength = 0; QChar c = 0; for (int i=0; i 0) || key == blank) + if ((key.isNumber() && key.digitValue() > 0) || key == m_blank) return true; break; case '#': - if (key.isNumber() || key == QLatin1Char('+') || key == QLatin1Char('-') || key == blank) + if (key.isNumber() || key == QLatin1Char('+') || key == QLatin1Char('-') || key == m_blank) return true; break; case 'B': @@ -872,7 +872,7 @@ bool QLineControl::isValidInput(QChar key, QChar mask) const return true; break; case 'b': - if (key == QLatin1Char('0') || key == QLatin1Char('1') || key == blank) + if (key == QLatin1Char('0') || key == QLatin1Char('1') || key == m_blank) return true; break; case 'H': @@ -880,7 +880,7 @@ bool QLineControl::isValidInput(QChar key, QChar mask) const return true; break; case 'h': - if (key.isNumber() || (key >= QLatin1Char('a') && key <= QLatin1Char('f')) || (key >= QLatin1Char('A') && key <= QLatin1Char('F')) || key == blank) + if (key.isNumber() || (key >= QLatin1Char('a') && key <= QLatin1Char('f')) || (key >= QLatin1Char('A') && key <= QLatin1Char('F')) || key == m_blank) return true; break; default: @@ -907,18 +907,18 @@ bool QLineControl::hasAcceptableInput(const QString &str) const return false; #endif - if (!maskData) + if (!m_maskData) return true; if (str.length() != m_maxLength) return false; for (int i=0; i < m_maxLength; ++i) { - if (maskData[i].separator) { - if (str.at(i) != maskData[i].maskChar) + if (m_maskData[i].separator) { + if (str.at(i) != m_maskData[i].maskChar) return false; } else { - if (!isValidInput(str.at(i), maskData[i].maskChar)) + if (!isValidInput(str.at(i), m_maskData[i].maskChar)) return false; } } @@ -946,14 +946,14 @@ QString QLineControl::maskString(uint pos, const QString &str, bool clear) const int i = pos; while (i < m_maxLength) { if (strIndex < str.length()) { - if (maskData[i].separator) { - s += maskData[i].maskChar; - if (str[(int)strIndex] == maskData[i].maskChar) + if (m_maskData[i].separator) { + s += m_maskData[i].maskChar; + if (str[(int)strIndex] == m_maskData[i].maskChar) strIndex++; ++i; } else { - if (isValidInput(str[(int)strIndex], maskData[i].maskChar)) { - switch (maskData[i].caseMode) { + if (isValidInput(str[(int)strIndex], m_maskData[i].maskChar)) { + switch (m_maskData[i].caseMode) { case MaskInputData::Upper: s += str[(int)strIndex].toUpper(); break; @@ -968,16 +968,16 @@ QString QLineControl::maskString(uint pos, const QString &str, bool clear) const // search for separator first int n = findInMask(i, true, true, str[(int)strIndex]); if (n != -1) { - if (str.length() != 1 || i == 0 || (i > 0 && (!maskData[i-1].separator || maskData[i-1].maskChar != str[(int)strIndex]))) { + if (str.length() != 1 || i == 0 || (i > 0 && (!m_maskData[i-1].separator || m_maskData[i-1].maskChar != str[(int)strIndex]))) { s += fill.mid(i, n-i+1); i = n + 1; // update i to find + 1 } } else { - // search for valid blank if not + // search for valid m_blank if not n = findInMask(i, true, false, str[(int)strIndex]); if (n != -1) { s += fill.mid(i, n-i); - switch (maskData[n].caseMode) { + switch (m_maskData[n].caseMode) { case MaskInputData::Upper: s += str[(int)strIndex].toUpper(); break; @@ -1016,10 +1016,10 @@ QString QLineControl::clearString(uint pos, uint len) const QString s; int end = qMin((uint)m_maxLength, pos + len); for (int i = pos; i < end; ++i) - if (maskData[i].separator) - s += maskData[i].maskChar; + if (m_maskData[i].separator) + s += m_maskData[i].maskChar; else - s += blank; + s += m_blank; return s; } @@ -1032,16 +1032,16 @@ QString QLineControl::clearString(uint pos, uint len) const */ QString QLineControl::stripString(const QString &str) const { - if (!maskData) + if (!m_maskData) return str; QString s; int end = qMin(m_maxLength, (int)str.length()); for (int i = 0; i < end; ++i) - if (maskData[i].separator) - s += maskData[i].maskChar; + if (m_maskData[i].separator) + s += m_maskData[i].maskChar; else - if (str[i] != blank) + if (str[i] != m_blank) s += str[i]; return s; @@ -1049,7 +1049,7 @@ QString QLineControl::stripString(const QString &str) const /*! \internal - searches forward/backward in maskData for either a separator or a blank + searches forward/backward in m_maskData for either a separator or a m_blank */ int QLineControl::findInMask(int pos, bool forward, bool findSeparator, QChar searchChar) const { @@ -1062,13 +1062,13 @@ int QLineControl::findInMask(int pos, bool forward, bool findSeparator, QChar se while (i != end) { if (findSeparator) { - if (maskData[i].separator && maskData[i].maskChar == searchChar) + if (m_maskData[i].separator && m_maskData[i].maskChar == searchChar) return i; } else { - if (!maskData[i].separator) { + if (!m_maskData[i].separator) { if (searchChar.isNull()) return i; - else if (isValidInput(searchChar, maskData[i].maskChar)) + else if (isValidInput(searchChar, m_maskData[i].maskChar)) return i; } } @@ -1082,16 +1082,16 @@ void QLineControl::p_undo(int until) if (!isUndoAvailable()) return; p_deselect(); - while (undoState && undoState > until) { - Command& cmd = history[--undoState]; + while (m_undoState && m_undoState > until) { + Command& cmd = m_history[--m_undoState]; switch (cmd.type) { case Insert: m_text.remove(cmd.pos, 1); m_cursor = cmd.pos; break; case SetSelection: - selstart = cmd.selStart; - selend = cmd.selEnd; + m_selstart = cmd.selStart; + m_selend = cmd.selEnd; m_cursor = cmd.pos; break; case Remove: @@ -1107,14 +1107,14 @@ void QLineControl::p_undo(int until) case Separator: continue; } - if (until < 0 && undoState) { - Command& next = history[undoState-1]; + if (until < 0 && m_undoState) { + Command& next = m_history[m_undoState-1]; if (next.type != cmd.type && next.type < RemoveSelection && (cmd.type < RemoveSelection || next.type == Separator)) break; } } - textDirty = true; + m_textDirty = true; emitCursorPositionChanged(); } @@ -1122,16 +1122,16 @@ void QLineControl::p_redo() { if (!isRedoAvailable()) return; p_deselect(); - while (undoState < (int)history.size()) { - Command& cmd = history[undoState++]; + while (m_undoState < (int)m_history.size()) { + Command& cmd = m_history[m_undoState++]; switch (cmd.type) { case Insert: m_text.insert(cmd.pos, cmd.uc); m_cursor = cmd.pos + 1; break; case SetSelection: - selstart = cmd.selStart; - selend = cmd.selEnd; + m_selstart = cmd.selStart; + m_selend = cmd.selEnd; m_cursor = cmd.pos; break; case Remove: @@ -1139,24 +1139,24 @@ void QLineControl::p_redo() { case RemoveSelection: case DeleteSelection: m_text.remove(cmd.pos, 1); - selstart = cmd.selStart; - selend = cmd.selEnd; + m_selstart = cmd.selStart; + m_selend = cmd.selEnd; m_cursor = cmd.pos; break; case Separator: - selstart = cmd.selStart; - selend = cmd.selEnd; + m_selstart = cmd.selStart; + m_selend = cmd.selEnd; m_cursor = cmd.pos; break; } - if (undoState < (int)history.size()) { - Command& next = history[undoState]; + if (m_undoState < (int)m_history.size()) { + Command& next = m_history[m_undoState]; if (next.type != cmd.type && cmd.type < RemoveSelection && next.type != Separator && (next.type < RemoveSelection || cmd.type == Separator)) break; } } - textDirty = true; + m_textDirty = true; emitCursorPositionChanged(); } @@ -1168,9 +1168,9 @@ void QLineControl::p_redo() { */ void QLineControl::emitCursorPositionChanged() { - if (m_cursor != lastCursorPos) { - const int oldLast = lastCursorPos; - lastCursorPos = m_cursor; + if (m_cursor != m_lastCursorPos) { + const int oldLast = m_lastCursorPos; + m_lastCursorPos = m_cursor; cursorPositionChanged(oldLast, m_cursor); } } @@ -1496,9 +1496,9 @@ void QLineControl::processKeyEvent(QKeyEvent* event) if (event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return) { if (hasAcceptableInput() || fixup()) { emit accepted(); - emitingEditingFinished = true; + m_emitingEditingFinished = true; emit editingFinished(); - emitingEditingFinished = false; + m_emitingEditingFinished = false; } if (inlineCompletionAccepted) event->accept(); diff --git a/src/gui/widgets/qlinecontrol_p.h b/src/gui/widgets/qlinecontrol_p.h index 2d93e90..6029989 100644 --- a/src/gui/widgets/qlinecontrol_p.h +++ b/src/gui/widgets/qlinecontrol_p.h @@ -75,24 +75,24 @@ QT_MODULE(Gui) class Q_GUI_EXPORT QLineControl : public QObject { Q_OBJECT -public: +public: QLineControl(const QString &txt = QString()) - : emitingEditingFinished(0), + : m_emitingEditingFinished(0), m_cursor(0), m_preeditCursor(0), m_layoutDirection(Qt::LeftToRight), - hideCursor(false), separator(0), readOnly(0), - dragEnabled(0), m_echoMode(0), textDirty(0), selDirty(0), - validInput(1), m_blinkPeriod(0), m_blinkTimer(0), m_deleteAllTimer(0), - m_ascent(0), m_maxLength(32767), lastCursorPos(-1), - m_tripleClickTimer(0), maskData(0), modifiedState(0), undoState(0), - selstart(0), selend(0), m_passwordEchoEditing(false) + m_hideCursor(false), m_separator(0), m_readOnly(0), + m_dragEnabled(0), m_echoMode(0), m_textDirty(0), m_selDirty(0), + m_validInput(1), m_blinkPeriod(0), m_blinkTimer(0), m_deleteAllTimer(0), + m_ascent(0), m_maxLength(32767), m_lastCursorPos(-1), + m_tripleClickTimer(0), m_maskData(0), m_modifiedState(0), m_undoState(0), + m_selstart(0), m_selend(0), m_passwordEchoEditing(false) { init(txt); } ~QLineControl() { - delete [] maskData; + delete [] m_maskData; } int nextMaskBlank(int pos); @@ -154,7 +154,7 @@ public: void setReadOnly(bool enable); QString text() const; - void setText(const QString &); + void setText(const QString &txt); QString displayText() const; @@ -218,7 +218,7 @@ public: void setCursorBlinkPeriod(int msec); QString cancelText() const; - void setCancelText(QString); + void setCancelText(const QString &text); enum DrawFlags { DrawText = 0x01, @@ -228,19 +228,26 @@ public: }; void draw(QPainter *, const QPoint &, const QRect &, int flags = DrawAll); - bool processEvent(QEvent* ev); + bool processEvent(QEvent *ev); + + bool m_emitingEditingFinished; //Needed in QLineEdit FocusOut event - bool emitingEditingFinished;//Needed in QLineEdit FocusOut event private: - void init(const QString&); + void init(const QString &txt); void removeSelectedText(); - void p_setText(const QString& txt, int pos = -1, bool edited = true); + void p_setText(const QString &txt, int pos = -1, bool edited = true); void updateDisplayText(); - void p_insert(const QString& s); + void p_insert(const QString &s); void p_del(bool wasBackspace = false); void p_remove(int pos); - inline void p_deselect() { selDirty |= (selend > selstart); selstart = selend = 0; } + + inline void p_deselect() + { + m_selDirty |= (m_selend > m_selstart); + m_selstart = m_selend = 0; + } + void p_undo(int until = -1); void p_redo(); @@ -250,22 +257,22 @@ private: int m_preeditCursor; int m_cursorWidth; Qt::LayoutDirection m_layoutDirection; - uint hideCursor : 1; // used to hide the m_cursor inside preedit areas - uint separator : 1; - uint readOnly : 1; - uint dragEnabled : 1; + uint m_hideCursor : 1; // used to hide the m_cursor inside preedit areas + uint m_separator : 1; + uint m_readOnly : 1; + uint m_dragEnabled : 1; uint m_echoMode : 2; - uint textDirty : 1; - uint selDirty : 1; - uint validInput : 1; + uint m_textDirty : 1; + uint m_selDirty : 1; + uint m_validInput : 1; int m_blinkPeriod; // 0 for non-blinking cursor int m_blinkTimer; int m_deleteAllTimer; int m_blinkStatus; int m_ascent; int m_maxLength; - int lastCursorPos; - QList transactions; + int m_lastCursorPos; + QList m_transactions; QPoint m_tripleClick; int m_tripleClickTimer; QString m_cancelText; @@ -287,8 +294,8 @@ private: Casemode caseMode; }; QString m_inputMask; - QChar blank; - MaskInputData *maskData; + QChar m_blank; + MaskInputData *m_maskData; // undo/redo handling @@ -300,15 +307,16 @@ private: QChar uc; int pos, selStart, selEnd; }; - int modifiedState; - int undoState; - QVector history; + int m_modifiedState; + int m_undoState; + QVector m_history; void addCommand(const Command& cmd); - inline void separate() { separator = true; } + inline void separate() { m_separator = true; } // selection - int selstart, selend; + int m_selstart; + int m_selend; // masking void parseInputMask(const QString &maskFields); @@ -319,9 +327,8 @@ private: QString stripString(const QString &str) const; int findInMask(int pos, bool forward, bool findSeparator, QChar searchChar = QChar()) const; - // complex text layout - QTextLayout textLayout; + QTextLayout m_textLayout; bool m_passwordEchoEditing; QChar m_passwordCharacter; @@ -339,8 +346,10 @@ Q_SIGNALS: void accepted(); void editingFinished(); void updateNeeded(const QRect &); + protected: - virtual void timerEvent ( QTimerEvent * event ); + virtual void timerEvent(QTimerEvent *event); + private slots: void _q_clipboardChanged(); void _q_deleteSelected(); @@ -350,61 +359,61 @@ private slots: inline int QLineControl::nextMaskBlank(int pos) { int c = findInMask(pos, true, false); - separator |= (c != pos); + m_separator |= (c != pos); return (c != -1 ? c : m_maxLength); } inline int QLineControl::prevMaskBlank(int pos) { int c = findInMask(pos, false, false); - separator |= (c != pos); + m_separator |= (c != pos); return (c != -1 ? c : 0); } inline bool QLineControl::isUndoAvailable() const { - return !readOnly && undoState; + return !m_readOnly && m_undoState; } inline bool QLineControl::isRedoAvailable() const { - return !readOnly && undoState < (int)history.size(); + return !m_readOnly && m_undoState < (int)m_history.size(); } inline void QLineControl::clearUndo() { - history.clear(); - modifiedState = undoState = 0; + m_history.clear(); + m_modifiedState = m_undoState = 0; } inline bool QLineControl::isModified() const { - return modifiedState != undoState; + return m_modifiedState != m_undoState; } inline void QLineControl::setModified(bool modified) { - modifiedState = modified ? -1 : undoState; + m_modifiedState = modified ? -1 : m_undoState; } inline bool QLineControl::allSelected() const { - return !m_text.isEmpty() && selstart == 0 && selend == (int)m_text.length(); + return !m_text.isEmpty() && m_selstart == 0 && m_selend == (int)m_text.length(); } inline bool QLineControl::hasSelectedText() const { - return !m_text.isEmpty() && selend > selstart; + return !m_text.isEmpty() && m_selend > m_selstart; } inline int QLineControl::width() const { - return qRound(textLayout.lineAt(0).width()) + 1; + return qRound(m_textLayout.lineAt(0).width()) + 1; } inline int QLineControl::height() const { - return qRound(textLayout.lineAt(0).height()) + 1; + return qRound(m_textLayout.lineAt(0).height()) + 1; } inline int QLineControl::ascent() const @@ -415,32 +424,32 @@ inline int QLineControl::ascent() const inline QString QLineControl::selectedText() const { if (hasSelectedText()) - return m_text.mid(selstart, selend - selstart); + return m_text.mid(m_selstart, m_selend - m_selstart); return QString(); } inline QString QLineControl::textBeforeSelection() const { if (hasSelectedText()) - return m_text.left(selstart); + return m_text.left(m_selstart); return QString(); } inline QString QLineControl::textAfterSelection() const { if (hasSelectedText()) - return m_text.mid(selend); + return m_text.mid(m_selend); return QString(); } inline int QLineControl::selectionStart() const { - return hasSelectedText() ? selstart : -1; + return hasSelectedText() ? m_selstart : -1; } inline int QLineControl::selectionEnd() const { - return hasSelectedText() ? selend : -1; + return hasSelectedText() ? m_selend : -1; } inline int QLineControl::start() const @@ -455,17 +464,17 @@ inline int QLineControl::end() const inline void QLineControl::removeSelection() { - int priorState = undoState; + int priorState = m_undoState; removeSelectedText(); finishChange(priorState); } inline bool QLineControl::inSelection(int x) const { - if (selstart >= selend) + if (m_selstart >= m_selend) return false; int pos = xToPos(x, QTextLine::CursorOnCharacter); - return pos >= selstart && pos < selend; + return pos >= m_selstart && pos < m_selend; } inline int QLineControl::cursor() const @@ -492,18 +501,18 @@ inline void QLineControl::cursorForward(bool mark, int steps) { int c = m_cursor; if (steps > 0) { - while(steps--) - c = textLayout.nextCursorPosition(c); + while (steps--) + c = m_textLayout.nextCursorPosition(c); } else if (steps < 0) { while (steps++) - c = textLayout.previousCursorPosition(c); + c = m_textLayout.previousCursorPosition(c); } moveCursor(c, mark); } inline void QLineControl::cursorWordForward(bool mark) { - moveCursor(textLayout.nextCursorPosition(m_cursor, QTextLayout::SkipWords), mark); + moveCursor(m_textLayout.nextCursorPosition(m_cursor, QTextLayout::SkipWords), mark); } inline void QLineControl::home(bool mark) @@ -518,12 +527,12 @@ inline void QLineControl::end(bool mark) inline void QLineControl::cursorWordBackward(bool mark) { - moveCursor(textLayout.previousCursorPosition(m_cursor, QTextLayout::SkipWords), mark); + moveCursor(m_textLayout.previousCursorPosition(m_cursor, QTextLayout::SkipWords), mark); } inline qreal QLineControl::cursorToX(int cursor) const { - return textLayout.lineAt(0).cursorToX(cursor); + return m_textLayout.lineAt(0).cursorToX(cursor); } inline qreal QLineControl::cursorToX() const @@ -533,17 +542,17 @@ inline qreal QLineControl::cursorToX() const inline bool QLineControl::isReadOnly() const { - return readOnly; + return m_readOnly; } inline void QLineControl::setReadOnly(bool enable) { - readOnly = enable; + m_readOnly = enable; } inline QString QLineControl::text() const { - QString res = maskData ? stripString(m_text) : m_text; + QString res = m_maskData ? stripString(m_text) : m_text; return (res.isNull() ? QString::fromLatin1("") : res); } @@ -554,7 +563,7 @@ inline void QLineControl::setText(const QString &txt) inline QString QLineControl::displayText() const { - return textLayout.text(); + return m_textLayout.text(); } inline void QLineControl::deselect() @@ -565,7 +574,7 @@ inline void QLineControl::deselect() inline void QLineControl::selectAll() { - selstart = selend = m_cursor = 0; + m_selstart = m_selend = m_cursor = 0; moveCursor(m_text.length(), true); } @@ -595,7 +604,7 @@ inline void QLineControl::setEchoMode(uint mode) inline void QLineControl::setMaxLength(int maxLength) { - if (maskData) + if (m_maskData) return; m_maxLength = maxLength; setText(m_text); @@ -649,13 +658,13 @@ inline bool QLineControl::hasAcceptableInput() const inline QString QLineControl::inputMask() const { - return maskData ? m_inputMask + QLatin1Char(';') + blank : QString(); + return m_maskData ? m_inputMask + QLatin1Char(';') + m_blank : QString(); } inline void QLineControl::setInputMask(const QString &mask) { parseInputMask(mask); - if (maskData) + if (m_maskData) moveCursor(nextMaskBlank(0)); } @@ -663,18 +672,18 @@ inline void QLineControl::setInputMask(const QString &mask) #ifndef QT_NO_IM inline bool QLineControl::composeMode() const { - return !textLayout.preeditAreaText().isEmpty(); + return !m_textLayout.preeditAreaText().isEmpty(); } inline void QLineControl::setPreeditArea(int cursor, const QString &text) { - textLayout.setPreeditArea(cursor, text); + m_textLayout.setPreeditArea(cursor, text); } #endif inline QString QLineControl::preeditAreaText() const { - return textLayout.preeditAreaText(); + return m_textLayout.preeditAreaText(); } inline bool QLineControl::passwordEchoEditing() const @@ -708,7 +717,7 @@ inline void QLineControl::setLayoutDirection(Qt::LayoutDirection direction) inline void QLineControl::setFont(const QFont &font) { - textLayout.setFont(font); + m_textLayout.setFont(font); updateDisplayText(); } @@ -722,9 +731,9 @@ inline QString QLineControl::cancelText() const return m_cancelText; } -inline void QLineControl::setCancelText(QString s) +inline void QLineControl::setCancelText(const QString &text) { - m_cancelText = s; + m_cancelText = text; } QT_END_NAMESPACE diff --git a/src/gui/widgets/qlineedit.cpp b/src/gui/widgets/qlineedit.cpp index 9252888..6deb196 100644 --- a/src/gui/widgets/qlineedit.cpp +++ b/src/gui/widgets/qlineedit.cpp @@ -1727,11 +1727,11 @@ void QLineEdit::focusOutEvent(QFocusEvent *e) #endif if (reason != Qt::PopupFocusReason || !(QApplication::activePopupWidget() && QApplication::activePopupWidget()->parentWidget() == this)) { - if (!d->control->emitingEditingFinished) { + if (!d->control->m_emitingEditingFinished) { if (hasAcceptableInput() || d->control->fixup()) { - d->control->emitingEditingFinished = true; + d->control->m_emitingEditingFinished = true; emit editingFinished(); - d->control->emitingEditingFinished = false; + d->control->m_emitingEditingFinished = false; } } #ifdef QT3_SUPPORT diff --git a/src/gui/widgets/qlineedit_p.h b/src/gui/widgets/qlineedit_p.h index c6d7496..230023d 100644 --- a/src/gui/widgets/qlineedit_p.h +++ b/src/gui/widgets/qlineedit_p.h @@ -135,7 +135,6 @@ public: void drag(); #endif - int leftTextMargin; int topTextMargin; int rightTextMargin; -- cgit v0.12 From 4a2e73a06eb9cba373f9662700883bd3bd7f5047 Mon Sep 17 00:00:00 2001 From: Marius Bugge Monsen Date: Tue, 14 Jul 2009 16:34:13 +0200 Subject: Rename the p_foo() functions in QLineControl to internalFoo(). --- src/gui/widgets/qlinecontrol.cpp | 39 ++++++++++++++++++++------------------- src/gui/widgets/qlinecontrol_p.h | 23 +++++++++++------------ 2 files changed, 31 insertions(+), 31 deletions(-) diff --git a/src/gui/widgets/qlinecontrol.cpp b/src/gui/widgets/qlinecontrol.cpp index 50ce6e6..ba85182 100644 --- a/src/gui/widgets/qlinecontrol.cpp +++ b/src/gui/widgets/qlinecontrol.cpp @@ -167,11 +167,11 @@ void QLineControl::backspace() // if yes delete both at once uc = m_text.at(m_cursor - 1); if (uc.unicode() >= 0xd800 && uc.unicode() < 0xdc00) { - p_del(true); + internalDelete(true); --m_cursor; } } - p_del(true); + internalDelete(true); } finishChange(priorState); } @@ -193,7 +193,7 @@ void QLineControl::del() } else { int n = m_textLayout.nextCursorPosition(m_cursor) - m_cursor; while (n--) - p_del(); + internalDelete(); } finishChange(priorState); } @@ -209,7 +209,7 @@ void QLineControl::insert(const QString &newText) { int priorState = m_undoState; removeSelectedText(); - p_insert(newText); + internalInsert(newText); finishChange(priorState); } @@ -343,7 +343,7 @@ bool QLineControl::fixup() // this function assumes that validate currently retu m_validator->fixup(textCopy); if (m_validator->validate(textCopy, cursorCopy) == QValidator::Acceptable) { if (textCopy != m_text || cursorCopy != m_cursor) - p_setText(textCopy, cursorCopy); + internalSetText(textCopy, cursorCopy); return true; } } @@ -376,7 +376,7 @@ void QLineControl::moveCursor(int pos, bool mark) m_selend = qMax(anchor, pos); updateDisplayText(); } else { - p_deselect(); + internalDeselect(); } m_cursor = pos; if (mark || m_selDirty) { @@ -531,7 +531,7 @@ bool QLineControl::finishChange(int validateFromState, bool update, bool edited) m_validInput = (m_validator->validate(textCopy, cursorCopy) != QValidator::Invalid); if (m_validInput) { if (m_text != textCopy) { - p_setText(textCopy, cursorCopy); + internalSetText(textCopy, cursorCopy); return true; } m_cursor = cursorCopy; @@ -541,7 +541,7 @@ bool QLineControl::finishChange(int validateFromState, bool update, bool edited) if (validateFromState >= 0 && wasValidInput && !m_validInput) { if (m_transactions.count()) return false; - p_undo(validateFromState); + internalUndo(validateFromState); m_history.resize(m_undoState); if (m_modifiedState > m_undoState) m_modifiedState = -1; @@ -571,9 +571,9 @@ bool QLineControl::finishChange(int validateFromState, bool update, bool edited) An internal function for setting the text of the line control. */ -void QLineControl::p_setText(const QString &txt, int pos, bool edited) +void QLineControl::internalSetText(const QString &txt, int pos, bool edited) { - p_deselect(); + internalDeselect(); emit resetInputContext(); QString oldText = m_text; if (m_maskData) { @@ -618,7 +618,7 @@ void QLineControl::addCommand(const Command &cmd) This function does not call finishChange(), and may leave the text in an invalid state. */ -void QLineControl::p_insert(const QString &s) +void QLineControl::internalInsert(const QString &s) { if (hasSelectedText()) addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend)); @@ -654,7 +654,7 @@ void QLineControl::p_insert(const QString &s) This function does not call finishChange(), and may leave the text in an invalid state. */ -void QLineControl::p_del(bool wasBackspace) +void QLineControl::internalDelete(bool wasBackspace) { if (m_cursor < (int) m_text.length()) { if (hasSelectedText()) @@ -706,7 +706,7 @@ void QLineControl::removeSelectedText() } if (m_cursor > m_selstart) m_cursor -= qMin(m_cursor, m_selend) - m_selstart; - p_deselect(); + internalDeselect(); m_textDirty = true; } } @@ -725,7 +725,7 @@ void QLineControl::parseInputMask(const QString &maskFields) delete [] m_maskData; m_maskData = 0; m_maxLength = 32767; - p_setText(QString()); + internalSetText(QString()); } return; } @@ -811,7 +811,7 @@ void QLineControl::parseInputMask(const QString &maskFields) } } } - p_setText(m_text); + internalSetText(m_text); } @@ -1077,11 +1077,11 @@ int QLineControl::findInMask(int pos, bool forward, bool findSeparator, QChar se return -1; } -void QLineControl::p_undo(int until) +void QLineControl::internalUndo(int until) { if (!isUndoAvailable()) return; - p_deselect(); + internalDeselect(); while (m_undoState && m_undoState > until) { Command& cmd = m_history[--m_undoState]; switch (cmd.type) { @@ -1118,10 +1118,11 @@ void QLineControl::p_undo(int until) emitCursorPositionChanged(); } -void QLineControl::p_redo() { +void QLineControl::internalRedo() +{ if (!isRedoAvailable()) return; - p_deselect(); + internalDeselect(); while (m_undoState < (int)m_history.size()) { Command& cmd = m_history[m_undoState++]; switch (cmd.type) { diff --git a/src/gui/widgets/qlinecontrol_p.h b/src/gui/widgets/qlinecontrol_p.h index 6029989..68ff66b 100644 --- a/src/gui/widgets/qlinecontrol_p.h +++ b/src/gui/widgets/qlinecontrol_p.h @@ -235,21 +235,21 @@ public: private: void init(const QString &txt); void removeSelectedText(); - void p_setText(const QString &txt, int pos = -1, bool edited = true); + void internalSetText(const QString &txt, int pos = -1, bool edited = true); void updateDisplayText(); - void p_insert(const QString &s); - void p_del(bool wasBackspace = false); - void p_remove(int pos); + void internalInsert(const QString &s); + void internalDelete(bool wasBackspace = false); + void internalRemove(int pos); - inline void p_deselect() + inline void internalDeselect() { m_selDirty |= (m_selend > m_selstart); m_selstart = m_selend = 0; } - void p_undo(int until = -1); - void p_redo(); + void internalUndo(int until = -1); + void internalRedo(); QString m_text; QPalette m_palette; @@ -297,7 +297,6 @@ private: QChar m_blank; MaskInputData *m_maskData; - // undo/redo handling enum CommandType { Separator, Insert, Remove, Delete, RemoveSelection, DeleteSelection, SetSelection }; struct Command { @@ -558,7 +557,7 @@ inline QString QLineControl::text() const inline void QLineControl::setText(const QString &txt) { - p_setText(txt, -1, false); + internalSetText(txt, -1, false); } inline QString QLineControl::displayText() const @@ -568,7 +567,7 @@ inline QString QLineControl::displayText() const inline void QLineControl::deselect() { - p_deselect(); + internalDeselect(); finishChange(); } @@ -580,13 +579,13 @@ inline void QLineControl::selectAll() inline void QLineControl::undo() { - p_undo(); + internalUndo(); finishChange(-1, true); } inline void QLineControl::redo() { - p_redo(); + internalRedo(); finishChange(); } -- cgit v0.12 From 46fa45fd0f2a40580951903437a5fd1b6c5237ad Mon Sep 17 00:00:00 2001 From: Yann Bodson Date: Wed, 15 Jul 2009 15:43:35 +1000 Subject: Make QmlPalette properties notifiable. Handle palette changes in QmlPalette. --- src/declarative/util/qmlpalette.cpp | 25 +++++++++++++++++++++++++ src/declarative/util/qmlpalette.h | 31 +++++++++++++++++-------------- tools/qmlviewer/qmlviewer.cpp | 11 +---------- tools/qmlviewer/qmlviewer.h | 1 - 4 files changed, 43 insertions(+), 25 deletions(-) diff --git a/src/declarative/util/qmlpalette.cpp b/src/declarative/util/qmlpalette.cpp index 670966d..eda0ded 100644 --- a/src/declarative/util/qmlpalette.cpp +++ b/src/declarative/util/qmlpalette.cpp @@ -41,6 +41,7 @@ #include "private/qobject_p.h" #include "qmlpalette.h" +#include QT_BEGIN_NAMESPACE @@ -63,7 +64,9 @@ QmlPalette::QmlPalette(QObject *parent) : QObject(*(new QmlPalettePrivate), parent) { Q_D(QmlPalette); + d->palette = qApp->palette(); d->group = QPalette::Active; + qApp->installEventFilter(this); } QmlPalette::~QmlPalette() @@ -160,4 +163,26 @@ QPalette QmlPalette::palette() const return d->palette; } +bool QmlPalette::eventFilter(QObject *watched, QEvent *event) +{ + if (watched == qApp) { + if (event->type() == QEvent::ApplicationPaletteChange) { + QApplication::postEvent(this, new QEvent(QEvent::ApplicationPaletteChange)); + return false; + } + } + return QObject::eventFilter(watched, event); +} + +bool QmlPalette::event(QEvent *event) +{ + Q_D(QmlPalette); + if (event->type() == QEvent::ApplicationPaletteChange) { + d->palette = qApp->palette(); + emit paletteChanged(); + return true; + } + return QObject::event(event); +} + QT_END_NAMESPACE diff --git a/src/declarative/util/qmlpalette.h b/src/declarative/util/qmlpalette.h index f176764..1401ad1 100644 --- a/src/declarative/util/qmlpalette.h +++ b/src/declarative/util/qmlpalette.h @@ -62,19 +62,19 @@ public: QmlPalette(QObject *parent=0); ~QmlPalette(); - Q_PROPERTY(QColor window READ window CONSTANT) - Q_PROPERTY(QColor windowText READ windowText CONSTANT) - Q_PROPERTY(QColor base READ base CONSTANT) - Q_PROPERTY(QColor alternateBase READ alternateBase CONSTANT) - Q_PROPERTY(QColor button READ button CONSTANT) - Q_PROPERTY(QColor buttonText READ buttonText CONSTANT) - Q_PROPERTY(QColor light READ light CONSTANT) - Q_PROPERTY(QColor midlight READ midlight CONSTANT) - Q_PROPERTY(QColor dark READ dark CONSTANT) - Q_PROPERTY(QColor mid READ mid CONSTANT) - Q_PROPERTY(QColor shadow READ shadow CONSTANT) - Q_PROPERTY(QColor highlight READ highlight CONSTANT) - Q_PROPERTY(QColor highlightedText READ highlightedText CONSTANT) + Q_PROPERTY(QColor window READ window NOTIFY paletteChanged) + Q_PROPERTY(QColor windowText READ windowText NOTIFY paletteChanged) + Q_PROPERTY(QColor base READ base NOTIFY paletteChanged) + Q_PROPERTY(QColor alternateBase READ alternateBase NOTIFY paletteChanged) + Q_PROPERTY(QColor button READ button NOTIFY paletteChanged) + Q_PROPERTY(QColor buttonText READ buttonText NOTIFY paletteChanged) + Q_PROPERTY(QColor light READ light NOTIFY paletteChanged) + Q_PROPERTY(QColor midlight READ midlight NOTIFY paletteChanged) + Q_PROPERTY(QColor dark READ dark NOTIFY paletteChanged) + Q_PROPERTY(QColor mid READ mid NOTIFY paletteChanged) + Q_PROPERTY(QColor shadow READ shadow NOTIFY paletteChanged) + Q_PROPERTY(QColor highlight READ highlight NOTIFY paletteChanged) + Q_PROPERTY(QColor highlightedText READ highlightedText NOTIFY paletteChanged) QColor window() const; QColor windowText() const; @@ -98,8 +98,11 @@ public: void setColorGroup(QPalette::ColorGroup); + bool virtual eventFilter(QObject *watched, QEvent *event); + bool virtual event(QEvent *event); + Q_SIGNALS: - void updated(); + void paletteChanged(); }; QT_END_NAMESPACE diff --git a/tools/qmlviewer/qmlviewer.cpp b/tools/qmlviewer/qmlviewer.cpp index 6de1b97..677c08b 100644 --- a/tools/qmlviewer/qmlviewer.cpp +++ b/tools/qmlviewer/qmlviewer.cpp @@ -194,7 +194,7 @@ void QmlViewer::createMenu(QMenuBar *menu, QMenu *flatmenu) QAction *snapshotAction = new QAction(tr("&Take Snapsot\tF3"), parent); connect(snapshotAction, SIGNAL(triggered()), this, SLOT(takeSnapShot())); recordMenu->addAction(snapshotAction); - + recordAction = new QAction(tr("Start Recording &Video\tF2"), parent); connect(recordAction, SIGNAL(triggered()), this, SLOT(toggleRecordingWithSelection())); recordMenu->addAction(recordAction); @@ -502,15 +502,6 @@ void QmlViewer::setRecordFile(const QString& f) record_file = f; } -bool QmlViewer::event(QEvent *event) -{ - if (event->type() == QEvent::PaletteChange) { - setupPalettes(); - return true; - } - return QWidget::event(event); -} - void QmlViewer::setRecordPeriod(int ms) { record_period = ms; diff --git a/tools/qmlviewer/qmlviewer.h b/tools/qmlviewer/qmlviewer.h index 765d42f..11316c9 100644 --- a/tools/qmlviewer/qmlviewer.h +++ b/tools/qmlviewer/qmlviewer.h @@ -62,7 +62,6 @@ public slots: protected: virtual void keyPressEvent(QKeyEvent *); virtual void timerEvent(QTimerEvent *); - virtual bool event(QEvent *event); void createMenu(QMenuBar *menu, QMenu *flatmenu); -- cgit v0.12 From dc0a731659f2ed2f53ffe18bb98615d956c51ae4 Mon Sep 17 00:00:00 2001 From: Alan Alpert Date: Wed, 15 Jul 2009 15:58:48 +1000 Subject: Initial commit of the Same Game demo. Compare to KSame if on KDE. This demo primarily demonstrates use of JS and dynamic creation with QML, by creating a functional and animated game entirely with QML & JS --- demos/declarative/samegame/README | 10 ++ demos/declarative/samegame/SameGame.qml | 36 +++++ demos/declarative/samegame/TODO | 5 + demos/declarative/samegame/content/BoomBlock.qml | 48 ++++++ demos/declarative/samegame/content/FastBlock.qml | 41 ++++++ demos/declarative/samegame/content/MediaButton.qml | 39 +++++ demos/declarative/samegame/content/SameDialog.qml | 17 +++ .../samegame/content/pics/background.png | Bin 0 -> 153328 bytes .../samegame/content/pics/blueStone.png | Bin 0 -> 4823 bytes .../samegame/content/pics/button-pressed.png | Bin 0 -> 571 bytes demos/declarative/samegame/content/pics/button.png | Bin 0 -> 564 bytes .../samegame/content/pics/greenStone.png | Bin 0 -> 4724 bytes demos/declarative/samegame/content/pics/qtlogo.png | Bin 0 -> 2738 bytes .../declarative/samegame/content/pics/redStone.png | Bin 0 -> 4585 bytes demos/declarative/samegame/content/pics/star.png | Bin 0 -> 262 bytes .../samegame/content/pics/yellowStone.png | Bin 0 -> 4818 bytes demos/declarative/samegame/content/samegame.js | 163 +++++++++++++++++++++ 17 files changed, 359 insertions(+) create mode 100644 demos/declarative/samegame/README create mode 100644 demos/declarative/samegame/SameGame.qml create mode 100644 demos/declarative/samegame/TODO create mode 100644 demos/declarative/samegame/content/BoomBlock.qml create mode 100644 demos/declarative/samegame/content/FastBlock.qml create mode 100644 demos/declarative/samegame/content/MediaButton.qml create mode 100644 demos/declarative/samegame/content/SameDialog.qml create mode 100644 demos/declarative/samegame/content/pics/background.png create mode 100644 demos/declarative/samegame/content/pics/blueStone.png create mode 100644 demos/declarative/samegame/content/pics/button-pressed.png create mode 100644 demos/declarative/samegame/content/pics/button.png create mode 100644 demos/declarative/samegame/content/pics/greenStone.png create mode 100644 demos/declarative/samegame/content/pics/qtlogo.png create mode 100644 demos/declarative/samegame/content/pics/redStone.png create mode 100644 demos/declarative/samegame/content/pics/star.png create mode 100644 demos/declarative/samegame/content/pics/yellowStone.png create mode 100644 demos/declarative/samegame/content/samegame.js diff --git a/demos/declarative/samegame/README b/demos/declarative/samegame/README new file mode 100644 index 0000000..244b205 --- /dev/null +++ b/demos/declarative/samegame/README @@ -0,0 +1,10 @@ +This demo uses pictures from the KDE project (www.kde.org), +specifically the images from the KSame game. These images are + +background.png +blueStone.png +redStone.png +greenStone.png +yellowStone.png + +and are presumably under the same GPL2 license as the rest of kdegames diff --git a/demos/declarative/samegame/SameGame.qml b/demos/declarative/samegame/SameGame.qml new file mode 100644 index 0000000..0e5bb0f --- /dev/null +++ b/demos/declarative/samegame/SameGame.qml @@ -0,0 +1,36 @@ +import "content" + +Rect { + width: 400 + height: 700 + color: "white" + Script { source: "content/samegame.js" } + Rect{ + property int score: 0 + x:20; y:20; width:360; height:600; id: gameCanvas; + color: "white" + pen.width: 1 + Image { id:background; + source: "content/pics/qtlogo.png" + anchors.fill: parent + } + + MouseRegion { id: gameMR; anchors.fill: parent; + onClicked: handleClick(mouseX, mouseY); + } + } + HorizontalLayout { + anchors.top: gameCanvas.bottom + anchors.topMargin: 10 + anchors.horizontalCenter: parent.horizontalCenter + MediaButton { id: btnA; text: "New Game"; onClicked: {initBoard();} } + MediaButton { id: btnB; text: "Swap Theme"; onClicked: {swapTileSrc(); dialog.opacity = 1;} + } + Text{ text: "Score: " + gameCanvas.score; width:100 } + } + SameDialog { + id: dialog + anchors.centeredIn: parent + text: "Takes effect next game." + } +} diff --git a/demos/declarative/samegame/TODO b/demos/declarative/samegame/TODO new file mode 100644 index 0000000..b02ce54 --- /dev/null +++ b/demos/declarative/samegame/TODO @@ -0,0 +1,5 @@ +Still to do before initial release +-Garbage collect on click +-Particles with count 0->50 should work properly +-Particles are too slow to start +-Everything is too slow, we should have four times the number of tiles there diff --git a/demos/declarative/samegame/content/BoomBlock.qml b/demos/declarative/samegame/content/BoomBlock.qml new file mode 100644 index 0000000..5eaaade --- /dev/null +++ b/demos/declarative/samegame/content/BoomBlock.qml @@ -0,0 +1,48 @@ +Item { id:block + property bool dying: false + property bool spawning: false + property int type: 0 + property int targetX: 0 + property int targetY: 0 + + x: targetX + y: Follow { source: targetY; spring: 1.2; damping: 0.1 } + //y: Behavior { NumberAnimation { properties:"y"; duration: 200 } } + + Image { id: img + source: {if(type==0){"pics/redStone.png";}else if(type==1){"pics/blueStone.png";}else{"pics/greenStone.png";}} + opacity: 0 + opacity: Behavior { NumberAnimation { properties:"opacity"; duration: 200 } } + anchors.fill: parent + } + Particles { id: particles + width:1; height:1; anchors.centeredIn: parent; opacity: 0 + lifeSpan: 100000; source: "pics/star.png"; count:1; streamIn: false + angle: 0; angleDeviation: 360; velocity: 100; velocityDeviation:30 + } + states: [ + + State{ name: "SpawnState"; when: spawning == true && dying == false + SetProperties { target: img; opacity: 1 } + }, + State{ name: "DeathState"; when: dying == true + SetProperties { target: particles; count: 50 } + SetProperties { target: particles; opacity: 1 } + SetProperties { target: img; opacity: 0 } + } + ] +// transitions: [ +// Transition { +// fromState: "SpawnState" +// NumberAnimation { properties: "opacity"; duration: 200 } +// }, +// Transition { +// toState: "DeathState" +// SequentialAnimation { +// NumberAnimation { properties: "opacity"; duration: 200 } +// //TODO: Warning about following line, if it works +// //RunScriptAction { script: page.destroy() } +// } +// } +// ] +} diff --git a/demos/declarative/samegame/content/FastBlock.qml b/demos/declarative/samegame/content/FastBlock.qml new file mode 100644 index 0000000..3d14959 --- /dev/null +++ b/demos/declarative/samegame/content/FastBlock.qml @@ -0,0 +1,41 @@ +Rect { id:block + //Note: These properties are the interface used to control the blocks + property bool dying: false + property bool spawning: false + property int type: 0 + property int targetY: 0 + property int targetX: 0 + + color: {if(type==0){"red";}else if(type==1){"blue";}else{"green";}} + pen.width: 1 + pen.color: "black" + opacity: 0 + y: targetY + x: targetX + y: Behavior { NumberAnimation { properties:"y"; duration: 200 } } + opacity: Behavior { NumberAnimation { properties:"opacity"; duration: 200 } } + + states: [ + + State{ name: "SpawnState"; when: spawning == true && dying == false + SetProperties { target: block; opacity: 1 } + }, + State{ name: "DeathState"; when: dying == true + SetProperties { target: block; opacity: 0 } + } + ] +// transitions: [ +// Transition { +// fromState: "SpawnState" +// NumberAnimation { properties: "opacity"; duration: 200 } +// }, +// Transition { +// toState: "DeathState" +// SequentialAnimation { +// NumberAnimation { properties: "opacity"; duration: 200 } +// //TODO: Warning about following line, if it works +// //RunScriptAction { script: page.destroy() } +// } +// } +// ] +} diff --git a/demos/declarative/samegame/content/MediaButton.qml b/demos/declarative/samegame/content/MediaButton.qml new file mode 100644 index 0000000..49922f0 --- /dev/null +++ b/demos/declarative/samegame/content/MediaButton.qml @@ -0,0 +1,39 @@ +Item { + id: Container + + signal clicked + + property string text + + Image { + id: Image + source: "pics/button.png" + } + Image { + id: Pressed + source: "pics/button-pressed.png" + opacity: 0 + } + MouseRegion { + id: MouseRegion + anchors.fill: Image + onClicked: { Container.clicked(); } + } + Text { + font.bold: true + color: "white" + anchors.centeredIn: Image + text: Container.text + } + width: Image.width + states: [ + State { + name: "Pressed" + when: MouseRegion.pressed == true + SetProperties { + target: Pressed + opacity: 1 + } + } + ] +} diff --git a/demos/declarative/samegame/content/SameDialog.qml b/demos/declarative/samegame/content/SameDialog.qml new file mode 100644 index 0000000..eed52f0 --- /dev/null +++ b/demos/declarative/samegame/content/SameDialog.qml @@ -0,0 +1,17 @@ +Rect { + property string text: "Hello World!" + property int show: 0 + id: page + opacity: 0 + opacity: Behavior { + SequentialAnimation { + NumberAnimation {property: "opacity"; duration: 1000 } + NumberAnimation {property: "opacity"; to: 0; duration: 1000 } + } + } + color: "white" + pen.width: 1 + width: 200 + height: 60 + Text { anchors.centeredIn: parent; text: parent.text } +} diff --git a/demos/declarative/samegame/content/pics/background.png b/demos/declarative/samegame/content/pics/background.png new file mode 100644 index 0000000..25e885f Binary files /dev/null and b/demos/declarative/samegame/content/pics/background.png differ diff --git a/demos/declarative/samegame/content/pics/blueStone.png b/demos/declarative/samegame/content/pics/blueStone.png new file mode 100644 index 0000000..673f1ce Binary files /dev/null and b/demos/declarative/samegame/content/pics/blueStone.png differ diff --git a/demos/declarative/samegame/content/pics/button-pressed.png b/demos/declarative/samegame/content/pics/button-pressed.png new file mode 100644 index 0000000..e434d32 Binary files /dev/null and b/demos/declarative/samegame/content/pics/button-pressed.png differ diff --git a/demos/declarative/samegame/content/pics/button.png b/demos/declarative/samegame/content/pics/button.png new file mode 100644 index 0000000..56a63ce Binary files /dev/null and b/demos/declarative/samegame/content/pics/button.png differ diff --git a/demos/declarative/samegame/content/pics/greenStone.png b/demos/declarative/samegame/content/pics/greenStone.png new file mode 100644 index 0000000..0c087d0 Binary files /dev/null and b/demos/declarative/samegame/content/pics/greenStone.png differ diff --git a/demos/declarative/samegame/content/pics/qtlogo.png b/demos/declarative/samegame/content/pics/qtlogo.png new file mode 100644 index 0000000..399bd0b Binary files /dev/null and b/demos/declarative/samegame/content/pics/qtlogo.png differ diff --git a/demos/declarative/samegame/content/pics/redStone.png b/demos/declarative/samegame/content/pics/redStone.png new file mode 100644 index 0000000..80c2e2e Binary files /dev/null and b/demos/declarative/samegame/content/pics/redStone.png differ diff --git a/demos/declarative/samegame/content/pics/star.png b/demos/declarative/samegame/content/pics/star.png new file mode 100644 index 0000000..defbde5 Binary files /dev/null and b/demos/declarative/samegame/content/pics/star.png differ diff --git a/demos/declarative/samegame/content/pics/yellowStone.png b/demos/declarative/samegame/content/pics/yellowStone.png new file mode 100644 index 0000000..5349eff Binary files /dev/null and b/demos/declarative/samegame/content/pics/yellowStone.png differ diff --git a/demos/declarative/samegame/content/samegame.js b/demos/declarative/samegame/content/samegame.js new file mode 100644 index 0000000..f3bb5b6 --- /dev/null +++ b/demos/declarative/samegame/content/samegame.js @@ -0,0 +1,163 @@ +/* This script file handles the game logic */ + +var maxIdx = 18/2;//Nums are for tileSize 20 (desired tile size but too slow) +var maxY = 30/2; +var tileSize = 40; +var maxIndex = maxIdx*maxY; +var board = new Array(maxIndex); +var tileSrc = "content/FastBlock.qml"; +var backSrc = "content/pics/background.png"; +var swapped = false; + +var compSrc; +var component; + +function swapTileSrc(){ + if(swapped) + return; + if(tileSrc == "content/FastBlock.qml"){ + tileSrc = "content/BoomBlock.qml"; + backSrc = "content/pics/background.png"; + }else{ + backSrc = "content/pics/qtlogo.png"; + tileSrc = "content/FastBlock.qml"; + } + swapped = true; +} + +function index(xIdx,yIdx){ + return xIdx + (yIdx * maxIdx); +} + +function initBoard() +{ + background.source = backSrc; + swapped = false; + gameCanvas.score = 0; + for(xIdx=0; xIdx= maxIdx || xIdx < 0 || yIdx >= maxY || yIdx < 0) + return; + if(board[index(xIdx, yIdx)] == null) + return; + removed = 0; + floodKill(xIdx,yIdx, -1); + gameCanvas.score += removed * removed; + shuffleDown(); +} + +function floodKill(xIdx,yIdx,type) +{ + if(xIdx >= maxIdx || xIdx < 0 || yIdx >= maxY || yIdx < 0) + return; + if(board[index(xIdx, yIdx)] == null) + return; + if(type == -1){ + type = board[index(xIdx,yIdx)].type; + }else{ + if(type != board[index(xIdx,yIdx)].type) + return; + } + board[index(xIdx,yIdx)].dying = true; + board[index(xIdx,yIdx)] = null;//They'll have to destroy themselves(can we do that?) + removed += 1; + floodKill(xIdx+1,yIdx,type); + floodKill(xIdx-1,yIdx,type); + floodKill(xIdx,yIdx+1,type); + floodKill(xIdx,yIdx-1,type); +} + +function shuffleDown() +{ + for(xIdx=0; xIdx=0; yIdx--){ + if(board[index(xIdx,yIdx)] == null){ + fallDist += 1; + }else{ + if(fallDist > 0){ + obj = board[index(xIdx,yIdx)]; + obj.targetY += fallDist * tileSize; + board[index(xIdx,yIdx+fallDist)] = obj; + board[index(xIdx,yIdx)] = null; + } + } + } + } +} + +//Need a simpler method of doing this? +var waitStack = new Array(maxIndex); +var waitTop = -1; + +function finishCreatingBlock(xIdx,yIdx){ + //TODO: Doc that the 'xIdx', 'yIdx' here are hidden properties from the calling QFxItem + if(component.isReady()){ + if(xIdx == undefined){ + //Called without arguments, create a previously stored (xIdx,yIdx) + if(waitTop == -1) + return;//Don't have a previously stored (xIdx,yIdx) + xIdx = waitStack[waitTop] % maxIdx; + yIdx = Math.floor(waitStack[waitTop] / maxIdx); + waitTop -= 1; + } + dynamicObject = component.createObject(); + if(dynamicObject == null){ + print("error creating block"); + print(component.errorsString()); + return false; + } + dynamicObject.type = Math.floor(Math.random() * 3); + dynamicObject.parent = gameCanvas; + dynamicObject.targetX = xIdx*tileSize; + dynamicObject.targetY = yIdx*tileSize; + dynamicObject.width = tileSize; + dynamicObject.height = tileSize; + dynamicObject.spawning = true; + board[index(xIdx,yIdx)] = dynamicObject; + return true; + }else if(component.isError()){ + print("error creating block"); + print(component.errorsString()); + }else{ + //It isn't ready, but we'll be called again when it is. + //So store the requested (xIdx,yIdx) for later use + waitTop += 1; + waitStack[waitTop] = index(xIdx,yIdx); + } + return false; +} + +function startCreatingBlock(xIdx,yIdx){ + if(component!=null && compSrc == tileSrc){ + finishCreatingBlock(xIdx,yIdx); + return; + } + + if(component!=null){//Changed source + //delete component; //Does the engine handle this? + compSrc = tileSrc; + } + component = createComponent(tileSrc); + if(finishCreatingBlock(xIdx,yIdx)) + return; + component.statusChanged.connect(finishCreatingBlock()); + return; +} -- cgit v0.12 From 4f7e21dc04ce93531ef68f7694a5e8969448de8b Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Tue, 14 Jul 2009 13:54:55 +1000 Subject: Rework compiler to a two phase analyse/generate approach --- demos/declarative/flickr/content/Star.qml | 4 +- src/corelib/kernel/qmetaobjectbuilder.cpp | 81 +- src/corelib/kernel/qmetaobjectbuilder_p.h | 2 + src/declarative/qml/qml.pri | 1 + src/declarative/qml/qmlcompiledcomponent.cpp | 19 - src/declarative/qml/qmlcompiledcomponent_p.h | 6 +- src/declarative/qml/qmlcompiler.cpp | 1810 +++++++++++--------- src/declarative/qml/qmlcompiler_p.h | 117 +- src/declarative/qml/qmlcompositetypemanager.cpp | 2 - src/declarative/qml/qmlcontext.cpp | 9 +- src/declarative/qml/qmldom.cpp | 1 - src/declarative/qml/qmlinstruction.cpp | 29 +- src/declarative/qml/qmlinstruction_p.h | 20 - src/declarative/qml/qmlmetaproperty.cpp | 24 +- src/declarative/qml/qmlparser.cpp | 44 +- src/declarative/qml/qmlparser_p.h | 30 +- src/declarative/qml/qmlvme.cpp | 72 +- src/declarative/qml/qmlvmemetaobject.cpp | 11 +- src/declarative/qml/qmlvmemetaobject_p.h | 10 +- tests/auto/declarative/qmlbindengine/testtypes.h | 22 +- .../declarative/qmlparser/duplicateIDs.errors.txt | 2 +- .../qmlparser/failingComponent.errors.txt | 2 +- .../qmlparser/fakeDotProperty.errors.txt | 2 +- tests/auto/declarative/qmlparser/idProperty.txt | 2 +- .../declarative/qmlparser/invalidID.2.errors.txt | 2 +- .../declarative/qmlparser/invalidID.3.errors.txt | 2 +- .../declarative/qmlparser/invalidID.4.errors.txt | 2 +- .../declarative/qmlparser/invalidID.errors.txt | 2 +- .../declarative/qmlparser/missingSignal.errors.txt | 2 +- .../qmlparser/nonexistantProperty.1.errors.txt | 2 +- .../qmlparser/nonexistantProperty.2.errors.txt | 2 +- .../qmlparser/nonexistantProperty.3.errors.txt | 2 +- .../qmlparser/nonexistantProperty.4.errors.txt | 2 +- .../qmlparser/nonexistantProperty.6.errors.txt | 2 +- .../declarative/qmlparser/readOnly.1.errors.txt | 2 +- .../declarative/qmlparser/readOnly.2.errors.txt | 2 +- tests/auto/declarative/qmlparser/tst_qmlparser.cpp | 8 +- .../qmlparser/unsupportedProperty.errors.txt | 2 +- .../declarative/qmlparser/wrongType.1.errors.txt | 2 +- .../declarative/qmlparser/wrongType.10.errors.txt | 2 +- .../declarative/qmlparser/wrongType.11.errors.txt | 2 +- .../declarative/qmlparser/wrongType.12.errors.txt | 2 +- .../declarative/qmlparser/wrongType.13.errors.txt | 2 +- .../declarative/qmlparser/wrongType.14.errors.txt | 2 +- .../declarative/qmlparser/wrongType.2.errors.txt | 2 +- .../declarative/qmlparser/wrongType.3.errors.txt | 2 +- .../declarative/qmlparser/wrongType.4.errors.txt | 2 +- .../declarative/qmlparser/wrongType.5.errors.txt | 2 +- .../declarative/qmlparser/wrongType.6.errors.txt | 2 +- .../declarative/qmlparser/wrongType.7.errors.txt | 2 +- .../declarative/qmlparser/wrongType.8.errors.txt | 2 +- .../declarative/qmlparser/wrongType.9.errors.txt | 2 +- 52 files changed, 1293 insertions(+), 1091 deletions(-) diff --git a/demos/declarative/flickr/content/Star.qml b/demos/declarative/flickr/content/Star.qml index 2c2807a..0828bc0 100644 --- a/demos/declarative/flickr/content/Star.qml +++ b/demos/declarative/flickr/content/Star.qml @@ -3,8 +3,8 @@ Item { width: 24 height: 24 - property string rating - property string on + property int rating + property bool on signal clicked diff --git a/src/corelib/kernel/qmetaobjectbuilder.cpp b/src/corelib/kernel/qmetaobjectbuilder.cpp index 8775c5c..e6817fe 100644 --- a/src/corelib/kernel/qmetaobjectbuilder.cpp +++ b/src/corelib/kernel/qmetaobjectbuilder.cpp @@ -1167,8 +1167,10 @@ static QByteArray buildParameterNames // Build a QMetaObject in "buf" based on the information in "d". // If "buf" is null, then return the number of bytes needed to -// build the QMetaObject. -static int buildMetaObject(QMetaObjectBuilderPrivate *d, char *buf) +// build the QMetaObject. Returns -1 if the metaobject if +// relocatable is set, but the metaobject contains extradata. +static int buildMetaObject(QMetaObjectBuilderPrivate *d, char *buf, + bool relocatable) { int size = 0; int dataIndex; @@ -1176,18 +1178,23 @@ static int buildMetaObject(QMetaObjectBuilderPrivate *d, char *buf) int index; bool hasNotifySignals = false; + if (relocatable && + (d->relatedMetaObjects.size() > 0 || d->staticMetacallFunction)) + return -1; + // Create the main QMetaObject structure at the start of the buffer. QMetaObject *meta = reinterpret_cast(buf); size += sizeof(QMetaObject); ALIGN(size, int); if (buf) { - meta->d.superdata = d->superClass; + if (!relocatable) meta->d.superdata = d->superClass; meta->d.extradata = 0; } // Populate the QMetaObjectPrivate structure. QMetaObjectPrivate *pmeta = reinterpret_cast(buf + size); + int pmetaSize = size; dataIndex = 13; // Number of fields in the QMetaObjectPrivate. for (index = 0; index < d->properties.size(); ++index) { if (d->properties[index].notifySignal != -1) { @@ -1246,8 +1253,13 @@ static int buildMetaObject(QMetaObjectBuilderPrivate *d, char *buf) size += dataIndex * sizeof(int); char *str = reinterpret_cast(buf + size); if (buf) { - meta->d.stringdata = str; - meta->d.data = reinterpret_cast(data); + if (relocatable) { + meta->d.stringdata = reinterpret_cast((intptr_t)size); + meta->d.data = reinterpret_cast((intptr_t)pmetaSize); + } else { + meta->d.stringdata = str; + meta->d.data = reinterpret_cast(data); + } } // Reset the current data position to just past the QMetaObjectPrivate. @@ -1422,12 +1434,67 @@ static int buildMetaObject(QMetaObjectBuilderPrivate *d, char *buf) */ QMetaObject *QMetaObjectBuilder::toMetaObject() const { - int size = buildMetaObject(d, 0); + int size = buildMetaObject(d, 0, false); char *buf = reinterpret_cast(qMalloc(size)); - buildMetaObject(d, buf); + buildMetaObject(d, buf, false); return reinterpret_cast(buf); } +/* + \internal + + Converts this meta object builder into relocatable data. This data can + be stored, copied and later passed to fromRelocatableData() to create a + concrete QMetaObject. + + The data is specific to the architecture on which it was created, but is not + specific to the process that created it. Not all meta object builder's can + be converted to data in this way. If \a ok is provided, it will be set to + true if the conversion succeeds, and false otherwise. If a + staticMetacallFunction() or any relatedMetaObject()'s are specified the + conversion to relocatable data will fail. +*/ +QByteArray QMetaObjectBuilder::toRelocatableData(bool *ok) const +{ + int size = buildMetaObject(d, 0, true); + if (size == -1) { + if (ok) *ok = false; + return QByteArray(); + } + + QByteArray data; + data.resize(size); + char *buf = data.data(); + buildMetaObject(d, buf, true); + if (ok) *ok = true; + return data; +} + +/* + \internal + + Sets the \a data returned from toRelocatableData() onto a concrete + QMetaObject instance, \a output. As the meta object's super class is not + saved in the relocatable data, it must be passed as \a superClass. +*/ +void QMetaObjectBuilder::fromRelocatableData(QMetaObject *output, + const QMetaObject *superclass, + const QByteArray &data) +{ + if (!output) + return; + + const char *buf = data.constData(); + const QMetaObject *dataMo = reinterpret_cast(buf); + + intptr_t stringdataOffset = (intptr_t)dataMo->d.stringdata; + intptr_t dataOffset = (intptr_t)dataMo->d.data; + + output->d.superdata = superclass; + output->d.stringdata = buf + stringdataOffset; + output->d.data = reinterpret_cast(buf + dataOffset); +} + /*! \typedef QMetaObjectBuilder::StaticMetacallFunction diff --git a/src/corelib/kernel/qmetaobjectbuilder_p.h b/src/corelib/kernel/qmetaobjectbuilder_p.h index 952364a..d503163 100644 --- a/src/corelib/kernel/qmetaobjectbuilder_p.h +++ b/src/corelib/kernel/qmetaobjectbuilder_p.h @@ -169,6 +169,8 @@ public: void setStaticMetacallFunction(QMetaObjectBuilder::StaticMetacallFunction value); QMetaObject *toMetaObject() const; + QByteArray toRelocatableData(bool * = 0) const; + static void fromRelocatableData(QMetaObject *, const QMetaObject *, const QByteArray &); #ifndef QT_NO_DATASTREAM void serialize(QDataStream& stream) const; diff --git a/src/declarative/qml/qml.pri b/src/declarative/qml/qml.pri index f549a5e..d8f0f7f 100644 --- a/src/declarative/qml/qml.pri +++ b/src/declarative/qml/qml.pri @@ -12,6 +12,7 @@ SOURCES += qml/qmlparser.cpp \ qml/qmlproxymetaobject.cpp \ qml/qmlvme.cpp \ qml/qmlcompiler.cpp \ + qml/qmlcompileddata.cpp \ qml/qmlcompiledcomponent.cpp \ qml/qmlboundsignal.cpp \ qml/qmldom.cpp \ diff --git a/src/declarative/qml/qmlcompiledcomponent.cpp b/src/declarative/qml/qmlcompiledcomponent.cpp index bea736a..6ce89b7 100644 --- a/src/declarative/qml/qmlcompiledcomponent.cpp +++ b/src/declarative/qml/qmlcompiledcomponent.cpp @@ -50,7 +50,6 @@ QT_BEGIN_NAMESPACE DEFINE_BOOL_CONFIG_OPTION(compilerDump, QML_COMPILER_DUMP); QmlCompiledComponent::QmlCompiledComponent() -: dumpStatus(NoDump) { } @@ -60,7 +59,6 @@ QmlCompiledComponent::~QmlCompiledComponent() qFree(synthesizedMetaObjects.at(ii)); } - void QmlCompiledComponent::dumpInstructions() { if (!compilerDump()) @@ -76,21 +74,4 @@ void QmlCompiledComponent::dumpInstructions() qWarning() << "-------------------------------------------------------------------------------"; } -void QmlCompiledComponent::dumpPre() -{ - if (!(dumpStatus & DumpPre)) { - dumpInstructions(); - dumpStatus = (DumpStatus)(dumpStatus | DumpPre); - } -} - -void QmlCompiledComponent::dumpPost() -{ - if (!(dumpStatus & DumpPost)) { - dumpInstructions(); - dumpStatus = (DumpStatus)(dumpStatus | DumpPost); - } - -} - QT_END_NAMESPACE diff --git a/src/declarative/qml/qmlcompiledcomponent_p.h b/src/declarative/qml/qmlcompiledcomponent_p.h index 0945892..ddc1124 100644 --- a/src/declarative/qml/qmlcompiledcomponent_p.h +++ b/src/declarative/qml/qmlcompiledcomponent_p.h @@ -74,12 +74,8 @@ public: QmlCompiledComponent(); ~QmlCompiledComponent(); - void dumpPre(); - void dumpPost(); - -private: - enum DumpStatus { NoDump = 0x00, DumpPre = 0x01, DumpPost = 0x02 } dumpStatus; void dumpInstructions(); +private: void dump(QmlInstruction *, int idx = -1); friend class QmlCompiler; friend class QmlDomDocument; diff --git a/src/declarative/qml/qmlcompiler.cpp b/src/declarative/qml/qmlcompiler.cpp index b04c932..dafc581 100644 --- a/src/declarative/qml/qmlcompiler.cpp +++ b/src/declarative/qml/qmlcompiler.cpp @@ -71,90 +71,6 @@ QT_BEGIN_NAMESPACE using namespace QmlParser; -int QmlCompiledData::indexForString(const QString &data) -{ - int idx = primitives.indexOf(data); - if (idx == -1) { - idx = primitives.count(); - primitives << data; - } - return idx; -} - -int QmlCompiledData::indexForByteArray(const QByteArray &data) -{ - int idx = datas.indexOf(data); - if (idx == -1) { - idx = datas.count(); - datas << data; - } - return idx; -} - -int QmlCompiledData::indexForFloat(float *data, int count) -{ - Q_ASSERT(count > 0); - - for (int ii = 0; ii <= floatData.count() - count; ++ii) { - bool found = true; - for (int jj = 0; jj < count; ++jj) { - if (floatData.at(ii + jj) != data[jj]) { - found = false; - break; - } - } - - if (found) - return ii; - } - - int idx = floatData.count(); - for (int ii = 0; ii < count; ++ii) - floatData << data[ii]; - - return idx; -} - -int QmlCompiledData::indexForInt(int *data, int count) -{ - Q_ASSERT(count > 0); - - for (int ii = 0; ii <= intData.count() - count; ++ii) { - bool found = true; - for (int jj = 0; jj < count; ++jj) { - if (intData.at(ii + jj) != data[jj]) { - found = false; - break; - } - } - - if (found) - return ii; - } - - int idx = intData.count(); - for (int ii = 0; ii < count; ++ii) - intData << data[ii]; - - return idx; -} - -int QmlCompiledData::indexForLocation(const QmlParser::Location &l) -{ - // ### FIXME - int rv = locations.count(); - locations << l; - return rv; -} - -int QmlCompiledData::indexForLocation(const QmlParser::LocationSpan &l) -{ - // ### FIXME - int rv = locations.count(); - locations << l.start << l.end; - return rv; -} - QmlCompiler::QmlCompiler() : output(0) { @@ -241,14 +157,13 @@ bool QmlCompiler::isSignalPropertyName(const QByteArray &name) } // Compile a simple assignment of v to prop into instr -bool QmlCompiler::compileStoreInstruction(QmlInstruction &instr, - const QMetaProperty &prop, - QmlParser::Value *v) +bool QmlCompiler::testLiteralAssignment(const QMetaProperty &prop, + QmlParser::Value *v) { QString string = v->value.asScript(); if (!prop.isWritable()) - COMPILE_EXCEPTION2(v, "Cannot assign literal value to read-only property" << prop.name()); + COMPILE_EXCEPTION2(v, "Invalid property assignment: read-only property"); if (prop.isEnumType()) { int value; @@ -257,12 +172,136 @@ bool QmlCompiler::compileStoreInstruction(QmlInstruction &instr, } else value = prop.enumerator().keyToValue(string.toLatin1().constData()); if (value == -1) - COMPILE_EXCEPTION2(v, "Cannot assign unknown enumeration to property" << prop.name()); + COMPILE_EXCEPTION2(v, "Invalid property assignment: unknown enumeration"); + return true; + } + int type = prop.userType(); + switch(type) { + case -1: + break; + case QVariant::String: + if (!v->value.isString()) COMPILE_EXCEPTION2(v, "Invalid property assignment: string expected"); + break; + case QVariant::Url: + if (!v->value.isString()) COMPILE_EXCEPTION2(v, "Invalid property assignment: url expected"); + break; + case QVariant::UInt: + { + bool ok; + string.toUInt(&ok); + if (!v->value.isNumber() || !ok) COMPILE_EXCEPTION2(v, "Invalid property assignment: unsigned int expected"); + } + break; + case QVariant::Int: + { + bool ok; + string.toInt(&ok); + if (!v->value.isNumber() || !ok) COMPILE_EXCEPTION2(v, "Invalid property assignment: int expected"); + } + break; + case QMetaType::Float: + { + bool ok; + string.toFloat(&ok); + if (!v->value.isNumber() || !ok) COMPILE_EXCEPTION2(v, "Invalid property assignment: float expected"); + } + break; + case QVariant::Double: + { + bool ok; + string.toDouble(&ok); + if (!v->value.isNumber() || !ok) COMPILE_EXCEPTION2(v, "Invalid property assignment: double expected"); + } + break; + case QVariant::Color: + { + QColor c = QmlStringConverters::colorFromString(string); + if (!c.isValid()) COMPILE_EXCEPTION2(v, "Invalid property assignment: color expected"); + } + break; + case QVariant::Date: + { + QDate d = QDate::fromString(string, Qt::ISODate); + if (!d.isValid()) COMPILE_EXCEPTION2(v, "Invalid property assignment: date expected"); + } + break; + case QVariant::Time: + { + QTime time = QTime::fromString(string, Qt::ISODate); + if (!time.isValid()) COMPILE_EXCEPTION2(v, "Invalid property assignment: time expected"); + } + break; + case QVariant::DateTime: + { + QDateTime dateTime = QDateTime::fromString(string, Qt::ISODate); + if (!dateTime.isValid()) COMPILE_EXCEPTION2(v, "Invalid property assignment: datetime expected"); + } + break; + case QVariant::Point: + case QVariant::PointF: + { + bool ok; + QPointF point = QmlStringConverters::pointFFromString(string, &ok); + if (!ok) COMPILE_EXCEPTION2(v, "Invalid property assignment: point expected"); + } + break; + case QVariant::Size: + case QVariant::SizeF: + { + bool ok; + QSizeF size = QmlStringConverters::sizeFFromString(string, &ok); + if (!ok) COMPILE_EXCEPTION2(v, "Invalid property assignment: size expected"); + } + break; + case QVariant::Rect: + case QVariant::RectF: + { + bool ok; + QRectF rect = QmlStringConverters::rectFFromString(string, &ok); + if (!ok) COMPILE_EXCEPTION2(v, "Invalid property assignment: rect expected"); + } + break; + case QVariant::Bool: + { + if (!v->value.isBoolean()) COMPILE_EXCEPTION2(v, "Invalid property assignment: boolean expected"); + } + break; + default: + { + int t = prop.type(); + if (t == QVariant::UserType) + t = prop.userType(); + QmlMetaType::StringConverter converter = + QmlMetaType::customStringConverter(t); + if (!converter) + COMPILE_EXCEPTION2(v, "Invalid property assignment: unknown type" << prop.type()); + } + break; + } + return true; +} + +void QmlCompiler::genLiteralAssignment(const QMetaProperty &prop, + QmlParser::Value *v) +{ + QString string = v->value.asScript(); + + QmlInstruction instr; + instr.line = v->location.start.line; + if (prop.isEnumType()) { + int value; + if (prop.isFlagType()) { + value = prop.enumerator().keysToValue(string.toLatin1().constData()); + } else + value = prop.enumerator().keyToValue(string.toLatin1().constData()); + instr.type = QmlInstruction::StoreInteger; instr.storeInteger.propertyIndex = prop.propertyIndex(); instr.storeInteger.value = value; - return true; + output->bytecode << instr; + return; } + int type = prop.userType(); switch(type) { case -1: @@ -291,51 +330,33 @@ bool QmlCompiler::compileStoreInstruction(QmlInstruction &instr, { instr.type = QmlInstruction::StoreInteger; instr.storeInteger.propertyIndex = prop.propertyIndex(); - bool ok; - int value = string.toUInt(&ok); - if (!ok) - COMPILE_EXCEPTION2(v, "Cannot convert value" << string << "to unsigned integer"); - instr.storeInteger.value = value; + instr.storeInteger.value = string.toUInt(); } break; case QVariant::Int: { instr.type = QmlInstruction::StoreInteger; instr.storeInteger.propertyIndex = prop.propertyIndex(); - bool ok; - int value = string.toInt(&ok); - if (!ok) - COMPILE_EXCEPTION2(v, "Cannot convert value" << string << "to integer"); - instr.storeInteger.value = value; + instr.storeInteger.value = string.toInt(); } break; case QMetaType::Float: { instr.type = QmlInstruction::StoreFloat; instr.storeFloat.propertyIndex = prop.propertyIndex(); - bool ok; - float value = string.toFloat(&ok); - if (!ok) - COMPILE_EXCEPTION2(v, "Cannot convert value" << string << "to float number"); - instr.storeFloat.value = value; + instr.storeFloat.value = string.toFloat(); } break; case QVariant::Double: { instr.type = QmlInstruction::StoreDouble; instr.storeDouble.propertyIndex = prop.propertyIndex(); - bool ok; - double value = string.toDouble(&ok); - if (!ok) - COMPILE_EXCEPTION2(v, "Cannot convert value" << string << "to double number"); - instr.storeDouble.value = value; + instr.storeDouble.value = string.toDouble(); } break; case QVariant::Color: { QColor c = QmlStringConverters::colorFromString(string); - if (!c.isValid()) - COMPILE_EXCEPTION2(v, "Cannot convert value" << string << "to color"); instr.type = QmlInstruction::StoreColor; instr.storeColor.propertyIndex = prop.propertyIndex(); instr.storeColor.value = c.rgba(); @@ -344,8 +365,6 @@ bool QmlCompiler::compileStoreInstruction(QmlInstruction &instr, case QVariant::Date: { QDate d = QDate::fromString(string, Qt::ISODate); - if (!d.isValid()) - COMPILE_EXCEPTION2(v, "Cannot convert value" << string << "to date"); instr.type = QmlInstruction::StoreDate; instr.storeDate.propertyIndex = prop.propertyIndex(); instr.storeDate.value = d.toJulianDay(); @@ -354,9 +373,8 @@ bool QmlCompiler::compileStoreInstruction(QmlInstruction &instr, case QVariant::Time: { QTime time = QTime::fromString(string, Qt::ISODate); - if (!time.isValid()) - COMPILE_EXCEPTION2(v, "Cannot convert value" << string << "to time"); - int data[] = { time.hour(), time.minute(), time.second(), time.msec() }; + int data[] = { time.hour(), time.minute(), + time.second(), time.msec() }; int index = output->indexForInt(data, 4); instr.type = QmlInstruction::StoreTime; instr.storeTime.propertyIndex = prop.propertyIndex(); @@ -366,8 +384,6 @@ bool QmlCompiler::compileStoreInstruction(QmlInstruction &instr, case QVariant::DateTime: { QDateTime dateTime = QDateTime::fromString(string, Qt::ISODate); - if (!dateTime.isValid()) - COMPILE_EXCEPTION2(v, "Cannot convert value" << string << "to date and time"); int data[] = { dateTime.date().toJulianDay(), dateTime.time().hour(), dateTime.time().minute(), @@ -382,90 +398,76 @@ bool QmlCompiler::compileStoreInstruction(QmlInstruction &instr, case QVariant::Point: case QVariant::PointF: { - bool ok; - QPointF point = QmlStringConverters::pointFFromString(string, &ok); - if (!ok) - COMPILE_EXCEPTION2(v, "Cannot convert value" << string << "to point"); - float data[] = { point.x(), point.y() }; - int index = output->indexForFloat(data, 2); - if (type == QVariant::PointF) - instr.type = QmlInstruction::StorePointF; - else - instr.type = QmlInstruction::StorePoint; - instr.storeRealPair.propertyIndex = prop.propertyIndex(); - instr.storeRealPair.valueIndex = index; + bool ok; + QPointF point = + QmlStringConverters::pointFFromString(string, &ok); + float data[] = { point.x(), point.y() }; + int index = output->indexForFloat(data, 2); + if (type == QVariant::PointF) + instr.type = QmlInstruction::StorePointF; + else + instr.type = QmlInstruction::StorePoint; + instr.storeRealPair.propertyIndex = prop.propertyIndex(); + instr.storeRealPair.valueIndex = index; } break; case QVariant::Size: case QVariant::SizeF: { - bool ok; - QSizeF size = QmlStringConverters::sizeFFromString(string, &ok); - if (!ok) - COMPILE_EXCEPTION2(v, "Cannot convert value" << string << "to size"); - float data[] = { size.width(), size.height() }; - int index = output->indexForFloat(data, 2); - if (type == QVariant::SizeF) - instr.type = QmlInstruction::StoreSizeF; - else - instr.type = QmlInstruction::StoreSize; - instr.storeRealPair.propertyIndex = prop.propertyIndex(); - instr.storeRealPair.valueIndex = index; + bool ok; + QSizeF size = QmlStringConverters::sizeFFromString(string, &ok); + float data[] = { size.width(), size.height() }; + int index = output->indexForFloat(data, 2); + if (type == QVariant::SizeF) + instr.type = QmlInstruction::StoreSizeF; + else + instr.type = QmlInstruction::StoreSize; + instr.storeRealPair.propertyIndex = prop.propertyIndex(); + instr.storeRealPair.valueIndex = index; } break; case QVariant::Rect: case QVariant::RectF: { - bool ok; - QRectF rect = QmlStringConverters::rectFFromString(string, &ok); - if (!ok) - COMPILE_EXCEPTION2(v, "Cannot convert value" << string << "to rect"); - float data[] = { rect.x(), rect.y(), - rect.width(), rect.height() }; - int index = output->indexForFloat(data, 4); - if (type == QVariant::RectF) - instr.type = QmlInstruction::StoreRectF; - else - instr.type = QmlInstruction::StoreRect; - instr.storeRect.propertyIndex = prop.propertyIndex(); - instr.storeRect.valueIndex = index; + bool ok; + QRectF rect = QmlStringConverters::rectFFromString(string, &ok); + float data[] = { rect.x(), rect.y(), + rect.width(), rect.height() }; + int index = output->indexForFloat(data, 4); + if (type == QVariant::RectF) + instr.type = QmlInstruction::StoreRectF; + else + instr.type = QmlInstruction::StoreRect; + instr.storeRect.propertyIndex = prop.propertyIndex(); + instr.storeRect.valueIndex = index; } break; case QVariant::Bool: { - bool ok; - bool b = QmlStringConverters::boolFromString(string, &ok); - if (!ok) - COMPILE_EXCEPTION2(v, "Cannot convert value" << string << "to boolean"); - instr.type = QmlInstruction::StoreBool; - instr.storeBool.propertyIndex = prop.propertyIndex(); - instr.storeBool.value = b; + bool b = v->value.asBoolean(); + instr.type = QmlInstruction::StoreBool; + instr.storeBool.propertyIndex = prop.propertyIndex(); + instr.storeBool.value = b; } break; default: { - int t = prop.type(); - if (t == QVariant::UserType) - t = prop.userType(); - QmlMetaType::StringConverter converter = - QmlMetaType::customStringConverter(t); - if (converter) { - int index = output->customTypeData.count(); - instr.type = QmlInstruction::AssignCustomType; - instr.assignCustomType.propertyIndex = prop.propertyIndex(); - instr.assignCustomType.valueIndex = index; - - QmlCompiledData::CustomTypeData data; - data.index = output->indexForString(string); - data.type = t; - output->customTypeData << data; - break; - } + int t = prop.type(); + if (t == QVariant::UserType) + t = prop.userType(); + int index = output->customTypeData.count(); + instr.type = QmlInstruction::AssignCustomType; + instr.assignCustomType.propertyIndex = prop.propertyIndex(); + instr.assignCustomType.valueIndex = index; + + QmlCompiledData::CustomTypeData data; + data.index = output->indexForString(string); + data.type = t; + output->customTypeData << data; } - COMPILE_EXCEPTION2(v, "Cannot assign to property" << prop.name() << "of unknown type" << prop.type()); break; } - return true; + output->bytecode << instr; } void QmlCompiler::reset(QmlCompiledComponent *cc, bool deleteMemory) @@ -530,7 +532,7 @@ bool QmlCompiler::compile(QmlEngine *engine, compileTree(root); if (!isError()) { - out->dumpPre(); + out->dumpInstructions(); } else { reset(out, true); } @@ -544,24 +546,23 @@ void QmlCompiler::compileTree(Object *tree) { compileState.root = tree; + if (!buildObject(tree, BindingContext()) || !completeComponentBuild()) + return; + QmlInstruction init; init.type = QmlInstruction::Init; init.line = 0; - init.init.dataSize = 0; - init.init.bindingsSize = 0; - init.init.parserStatusSize = 0; + init.init.bindingsSize = compileState.bindings.count(); + init.init.parserStatusSize = compileState.parserStatusCount; output->bytecode << init; - if (!compileObject(tree, 0)) // Compile failed - return; + genObject(tree); QmlInstruction def; init.line = 0; def.type = QmlInstruction::SetDefault; output->bytecode << def; - finalizeComponent(0); - if (tree->metatype) static_cast(output->root) = *tree->metaObject(); else @@ -569,55 +570,35 @@ void QmlCompiler::compileTree(Object *tree) } -bool QmlCompiler::compileObject(Object *obj, const BindingContext &ctxt) +bool QmlCompiler::buildObject(Object *obj, const BindingContext &ctxt) { Q_ASSERT (obj->type != -1); - const QmlCompiledData::TypeReference &tr = output->types.at(obj->type); + const QmlCompiledData::TypeReference &tr = + output->types.at(obj->type); obj->metatype = tr.metaObject(); + if (tr.component) obj->url = tr.component->url(); - if (output->types.at(obj->type).className == "Component") { - COMPILE_CHECK(compileComponent(obj, ctxt)); + // This object is a "Component" element + if (obj->metatype == &QmlComponent::staticMetaObject) { + COMPILE_CHECK(buildComponent(obj, ctxt)); return true; } + // Object instantiations reset the binding context BindingContext objCtxt(obj); - int createInstrIdx = output->bytecode.count(); - // Create the object - QmlInstruction create; - create.type = QmlInstruction::CreateObject; - create.line = obj->location.start.line; - create.create.data = -1; - create.create.type = obj->type; - output->bytecode << create; - - // Create the synthesized meta object - COMPILE_CHECK(compileDynamicMeta(obj)); + // Create the synthesized meta object, ignoring aliases + COMPILE_CHECK(mergeDynamicMetaProperties(obj)); + COMPILE_CHECK(buildDynamicMeta(obj, IgnoreAliases)); // Find the native type and check for the QmlParserStatus interface - // ### Optimize - const QMetaObject *mo = obj->metatype; - QmlType *type = 0; - while (!type && mo) { - type = QmlMetaType::qmlType(mo); - mo = mo->superClass(); - } + QmlType *type = toQmlType(obj); Q_ASSERT(type); - int parserStatusCast = type->parserStatusCast(); - - // If the type support the QmlParserStatusInterface we need to invoke - // classBegin() - if (parserStatusCast != -1) { - QmlInstruction begin; - begin.type = QmlInstruction::BeginObject; - begin.begin.castValue = parserStatusCast; - begin.line = obj->location.start.line; - output->bytecode << begin; - + obj->parserStatusCast = type->parserStatusCast(); + if (obj->parserStatusCast != -1) compileState.parserStatusCount++; - } // Check if this is a custom parser type. Custom parser types allow // assignments to non-existant properties. These assignments are then @@ -626,57 +607,72 @@ bool QmlCompiler::compileObject(Object *obj, const BindingContext &ctxt) output->types.at(obj->type).type->customParser() != 0; QList customProps; - QStringList deferred = deferredProperties(obj); - QList deferredProps; + // Fetch the list of deferred properties + QStringList deferredList = deferredProperties(obj); + + // Must do id property first. This is to ensure that the id given to any + // id reference created matches the order in which the objects are + // instantiated + foreach(Property *prop, obj->properties) { + if (prop->name == "id") { + COMPILE_CHECK(buildProperty(prop, obj, objCtxt)); + break; + } + } - // Compile all explicit properties specified + // Build all explicit properties specified foreach(Property *prop, obj->properties) { + if (prop->name == "id") + continue; + + bool canDefer = false; if (isCustomParser) { - // Custom parser types don't support signal properties if (testProperty(prop, obj)) { - if (deferred.contains(QString::fromLatin1(prop->name.constData()))) - deferredProps << prop; - else - COMPILE_CHECK(compileProperty(prop, obj, objCtxt)); + int ids = compileState.ids.count(); + COMPILE_CHECK(buildProperty(prop, obj, objCtxt)); + canDefer = ids == compileState.ids.count(); } else { customProps << QmlCustomParserNodePrivate::fromProperty(prop); } } else { - if (isSignalPropertyName(prop->name)) { - COMPILE_CHECK(compileSignal(prop,obj)); + if (isSignalPropertyName(prop->name)) { + COMPILE_CHECK(buildSignal(prop,obj,objCtxt)); } else { - if (deferred.contains(QString::fromLatin1(prop->name.constData()))) - deferredProps << prop; - else - COMPILE_CHECK(compileProperty(prop, obj, objCtxt)); + int ids = compileState.ids.count(); + COMPILE_CHECK(buildProperty(prop, obj, objCtxt)); + canDefer = ids == compileState.ids.count(); } } + if (canDefer && !deferredList.isEmpty() && + deferredList.contains(prop->name)) + prop->isDeferred = true; + } - // Compile the default property + // Build the default property if (obj->defaultProperty) { Property *prop = obj->defaultProperty; + bool canDefer = false; if (isCustomParser) { if (testProperty(prop, obj)) { - QMetaProperty p = deferred.isEmpty()?QMetaProperty():QmlMetaType::defaultProperty(obj->metaObject()); - if (deferred.contains(QString::fromLatin1(p.name()))) - deferredProps << prop; - else - COMPILE_CHECK(compileProperty(prop, obj, objCtxt)); + int ids = compileState.ids.count(); + COMPILE_CHECK(buildProperty(prop, obj, objCtxt)); + canDefer = ids == compileState.ids.count(); } else { customProps << QmlCustomParserNodePrivate::fromProperty(prop); } } else { - QMetaProperty p = deferred.isEmpty()?QMetaProperty():QmlMetaType::defaultProperty(obj->metaObject()); - if (deferred.contains(QString::fromLatin1(p.name()))) - deferredProps << prop; - else - COMPILE_CHECK(compileProperty(prop, obj, objCtxt)); + int ids = compileState.ids.count(); + COMPILE_CHECK(buildProperty(prop, obj, objCtxt)); + canDefer = ids == compileState.ids.count(); } + if (canDefer && !deferredList.isEmpty() && + deferredList.contains(prop->name)) + prop->isDeferred = true; } // Compile custom parser parts @@ -684,16 +680,83 @@ bool QmlCompiler::compileObject(Object *obj, const BindingContext &ctxt) // ### Check for failure bool ok = false; QmlCustomParser *cp = output->types.at(obj->type).type->customParser(); - QByteArray customData = cp->compile(customProps, &ok); + obj->custom = cp->compile(customProps, &ok); if(!ok) COMPILE_EXCEPTION("Failure compiling custom type"); - if(!customData.isEmpty()) - output->bytecode[createInstrIdx].create.data = - output->indexForByteArray(customData); } - // Build the deferred block - if (!deferredProps.isEmpty()) { + return true; +} + +void QmlCompiler::genObject(QmlParser::Object *obj) +{ + if (obj->metatype == &QmlComponent::staticMetaObject) { + genComponent(obj); + return; + } + + // Create the object + QmlInstruction create; + create.type = QmlInstruction::CreateObject; + create.line = obj->location.start.line; + create.create.data = -1; + if (!obj->custom.isEmpty()) + create.create.data = output->indexForByteArray(obj->custom); + create.create.type = obj->type; + output->bytecode << create; + + // Setup the synthesized meta object if necessary + if (!obj->metadata.isEmpty()) { + QmlInstruction meta; + meta.type = QmlInstruction::StoreMetaObject; + meta.line = -1; + meta.storeMeta.data = output->indexForByteArray(obj->metadata); + meta.storeMeta.aliasData = output->indexForByteArray(obj->synthdata); + meta.storeMeta.slotData = -1; + output->bytecode << meta; + } + + // Set the object id + if (!obj->id.isEmpty()) { + QmlInstruction id; + id.type = QmlInstruction::SetId; + id.line = -1; + id.setId.value = output->indexForString(obj->id); + output->bytecode << id; + } + + // Begin the class + if (obj->parserStatusCast != -1) { + QmlInstruction begin; + begin.type = QmlInstruction::BeginObject; + begin.begin.castValue = obj->parserStatusCast; + begin.line = obj->location.start.line; + output->bytecode << begin; + } + + genObjectBody(obj); + + // Complete the the class + if (obj->parserStatusCast != -1) { + QmlInstruction complete; + complete.type = QmlInstruction::CompleteObject; + complete.complete.castValue = obj->parserStatusCast; + complete.line = obj->location.start.line; + output->bytecode << complete; + } +} + +void QmlCompiler::genObjectBody(QmlParser::Object *obj) +{ + bool seenDefer = false; + foreach(Property *prop, obj->valueProperties) { + if (prop->isDeferred) { + seenDefer = true; + continue; + } + genValueProperty(prop, obj); + } + if (seenDefer) { QmlInstruction defer; defer.type = QmlInstruction::Defer; defer.line = 0; @@ -701,44 +764,147 @@ bool QmlCompiler::compileObject(Object *obj, const BindingContext &ctxt) int deferIdx = output->bytecode.count(); output->bytecode << defer; - // ### This is lame, we should check if individual properties have - // ids defined within them - int idCount = compileState.ids.count(); - foreach (Property *prop, deferredProps) { - COMPILE_CHECK(compileProperty(prop, obj, objCtxt)); + foreach(Property *prop, obj->valueProperties) { + if (!prop->isDeferred) + continue; + genValueProperty(prop, obj); } - if (idCount == compileState.ids.count()) - output->bytecode[deferIdx].defer.deferCount = - output->bytecode.count() - deferIdx - 1; + + output->bytecode[deferIdx].defer.deferCount = + output->bytecode.count() - deferIdx - 1; } - // If the type support the QmlParserStatusInterface we need to invoke - // classComplete() - if (parserStatusCast != -1) { - QmlInstruction complete; - complete.type = QmlInstruction::CompleteObject; - complete.complete.castValue = parserStatusCast; - complete.line = obj->location.start.line; - output->bytecode << complete; - } + foreach(Property *prop, obj->signalProperties) { - return true; + QmlParser::Value *v = prop->values.at(0); + + if (v->type == Value::SignalObject) { + + genObject(v->object); + + QmlInstruction assign; + assign.type = QmlInstruction::AssignSignalObject; + assign.line = v->location.start.line; + assign.assignSignalObject.signal = + output->indexForByteArray(prop->name); + output->bytecode << assign; + + } else if (v->type == Value::SignalExpression) { + + QmlInstruction store; + store.type = QmlInstruction::StoreSignal; + store.line = v->location.start.line; + store.storeSignal.signalIndex = prop->index; + store.storeSignal.value = + output->indexForString(v->value.asScript().trimmed()); + output->bytecode << store; + + } + + } + + foreach(Property *prop, obj->attachedProperties) { + QmlInstruction fetch; + fetch.type = QmlInstruction::FetchAttached; + fetch.line = prop->location.start.line; + fetch.fetchAttached.id = prop->index; + output->bytecode << fetch; + + genObjectBody(prop->value); + + QmlInstruction pop; + pop.type = QmlInstruction::PopFetchedObject; + pop.line = prop->location.start.line; + output->bytecode << pop; + } + + foreach(Property *prop, obj->groupedProperties) { + QmlInstruction fetch; + fetch.type = QmlInstruction::FetchObject; + fetch.fetch.property = prop->index; + fetch.line = prop->location.start.line; + output->bytecode << fetch; + + genObjectBody(prop->value); + + QmlInstruction pop; + pop.type = QmlInstruction::PopFetchedObject; + pop.line = prop->location.start.line; + output->bytecode << pop; + } } -bool QmlCompiler::compileComponent(Object *obj, const BindingContext &ctxt) +void QmlCompiler::genComponent(QmlParser::Object *obj) { + QmlParser::Object *root = obj->defaultProperty->values.at(0)->object; + Q_ASSERT(root); + + QmlInstruction create; + create.type = QmlInstruction::CreateComponent; + create.line = root->location.start.line; + create.createComponent.endLine = root->location.end.line; + output->bytecode << create; + int count = output->bytecode.count(); + + ComponentCompileState oldCompileState = compileState; + compileState = componentState(root); + + QmlInstruction init; + init.type = QmlInstruction::Init; + init.init.bindingsSize = compileState.bindings.count(); + init.init.parserStatusSize = compileState.parserStatusCount; + init.line = obj->location.start.line; + output->bytecode << init; + + genObject(root); + + output->bytecode[count - 1].createComponent.count = + output->bytecode.count() - count; + + compileState = oldCompileState; + + if (!obj->id.isEmpty()) { + QmlInstruction id; + id.type = QmlInstruction::SetId; + id.line = -1; + id.setId.value = output->indexForString(obj->id);; + output->bytecode << id; + } +} + +bool QmlCompiler::buildComponent(QmlParser::Object *obj, + const BindingContext &ctxt) +{ + // The special "Component" element can only have the id property and a + // default property, that actually defines the component's tree + + // Find, check and set the "id" property (if any) Property *idProp = 0; if (obj->properties.count() > 1 || (obj->properties.count() == 1 && obj->properties.begin().key() != "id")) COMPILE_EXCEPTION("Invalid component specification"); + + if (obj->properties.count()) + idProp = *obj->properties.begin(); + if (idProp && (idProp->value || idProp->values.count() > 1 || !isValidId(idProp->values.first()->primitive()))) + COMPILE_EXCEPTION("Invalid component id specification"); + + if (idProp) { + QString idVal = idProp->values.first()->primitive().toUtf8(); + + if (compileState.ids.contains(idVal)) + COMPILE_EXCEPTION("id is not unique"); + + addId(idVal, obj); + + obj->id = idVal.toUtf8(); + } + + // Check the Component tree is well formed if (obj->defaultProperty && (obj->defaultProperty->value || obj->defaultProperty->values.count() > 1 || (obj->defaultProperty->values.count() == 1 && !obj->defaultProperty->values.first()->object))) COMPILE_EXCEPTION("Invalid component body specification"); - if (obj->properties.count()) - idProp = *obj->properties.begin(); - if (idProp && (idProp->value || idProp->values.count() > 1)) - COMPILE_EXCEPTION("Invalid component id specification"); Object *root = 0; if (obj->defaultProperty && obj->defaultProperty->values.count()) @@ -747,84 +913,68 @@ bool QmlCompiler::compileComponent(Object *obj, const BindingContext &ctxt) if (!root) COMPILE_EXCEPTION("Cannot create empty component specification"); - COMPILE_CHECK(compileComponentFromRoot(root, ctxt)); - - if (idProp && idProp->values.count()) { - QString val = idProp->values.at(0)->primitive(); - if (!isValidId(val)) - COMPILE_EXCEPTION("Invalid id property value"); - - if (compileState.ids.contains(val)) - COMPILE_EXCEPTION("id is not unique"); - - IdReference reference; - reference.id = val; - reference.object = obj; - reference.instructionIdx = output->bytecode.count(); - reference.idx = compileState.ids.count(); - compileState.ids.insert(val, reference); - - int pref = output->indexForString(val); - QmlInstruction id; - id.type = QmlInstruction::SetId; - id.line = idProp->location.start.line; - id.setId.value = pref; - id.setId.save = -1; - - output->bytecode << id; - } + // Build the component tree + COMPILE_CHECK(buildComponentFromRoot(root, ctxt)); return true; } -bool QmlCompiler::compileComponentFromRoot(Object *obj, const BindingContext &ctxt) +bool QmlCompiler::buildComponentFromRoot(QmlParser::Object *obj, + const BindingContext &ctxt) { - output->bytecode.push_back(QmlInstruction()); - QmlInstruction &create = output->bytecode.last(); - create.type = QmlInstruction::CreateComponent; - create.line = obj->location.start.line; - create.createComponent.endLine = obj->location.end.line; - int count = output->bytecode.count(); - - QmlInstruction init; - init.type = QmlInstruction::Init; - init.init.dataSize = 0; - init.init.bindingsSize = 0; - init.init.parserStatusSize = 0; - init.line = obj->location.start.line; - output->bytecode << init; - ComponentCompileState oldComponentCompileState = compileState; compileState = ComponentCompileState(); compileState.root = obj; + if (obj) - COMPILE_CHECK(compileObject(obj, ctxt)); + COMPILE_CHECK(buildObject(obj, ctxt)); + + COMPILE_CHECK(completeComponentBuild()); - COMPILE_CHECK(finalizeComponent(count)); - create.createComponent.count = output->bytecode.count() - count; compileState = oldComponentCompileState; + return true; } -bool QmlCompiler::compileFetchedObject(Object *obj, const BindingContext &ctxt) + +// Build a sub-object. A sub-object is one that was not created directly by +// QML - such as a grouped property object, or an attached object. Sub-object's +// can't have an id, involve a custom parser, have attached properties etc. +bool QmlCompiler::buildSubObject(Object *obj, const BindingContext &ctxt) { Q_ASSERT(obj->metatype); + Q_ASSERT(ctxt.isSubContext()); // sub-objects must always be in a binding + // sub-context if (obj->defaultProperty) - COMPILE_CHECK(compileProperty(obj->defaultProperty, obj, ctxt)); + COMPILE_CHECK(buildProperty(obj->defaultProperty, obj, ctxt)); foreach(Property *prop, obj->properties) { if (isSignalPropertyName(prop->name)) { - COMPILE_CHECK(compileSignal(prop, obj)); + COMPILE_CHECK(buildSignal(prop, obj, ctxt)); } else { - COMPILE_CHECK(compileProperty(prop, obj, ctxt)); + COMPILE_CHECK(buildProperty(prop, obj, ctxt)); } } return true; } -int QmlCompiler::signalByName(const QMetaObject *mo, const QByteArray &name) +int QmlCompiler::componentTypeRef() +{ + QmlType *t = QmlMetaType::qmlType("Component"); + for (int ii = output->types.count() - 1; ii >= 0; --ii) { + if (output->types.at(ii).type == t) + return ii; + } + QmlCompiledData::TypeReference ref; + ref.className = "Component"; + ref.type = t; + output->types << ref; + return output->types.count() - 1; +} + +int QmlCompiler::findSignalByName(const QMetaObject *mo, const QByteArray &name) { int methods = mo->methodCount(); for (int ii = methods - 1; ii >= 0; --ii) { @@ -839,15 +989,13 @@ int QmlCompiler::signalByName(const QMetaObject *mo, const QByteArray &name) return -1; } -bool QmlCompiler::compileSignal(Property *prop, Object *obj) +bool QmlCompiler::buildSignal(QmlParser::Property *prop, QmlParser::Object *obj, + const BindingContext &ctxt) { Q_ASSERT(obj->metaObject()); - if (prop->values.isEmpty() && !prop->value) - return true; - - if (prop->value || prop->values.count() > 1) - COMPILE_EXCEPTION("Incorrectly specified signal"); + if (prop->isEmpty()) + COMPILE_EXCEPTION2(prop, "Empty property assignment"); QByteArray name = prop->name; Q_ASSERT(name.startsWith("on")); @@ -855,47 +1003,26 @@ bool QmlCompiler::compileSignal(Property *prop, Object *obj) if(name[0] >= 'A' && name[0] <= 'Z') name[0] = name[0] - 'A' + 'a'; - int sigIdx = signalByName(obj->metaObject(), name); + int sigIdx = findSignalByName(obj->metaObject(), name); if (sigIdx == -1) { - COMPILE_CHECK(compileProperty(prop, obj, 0)); + // If the "on" name doesn't resolve into a signal, try it as a + // property. + COMPILE_CHECK(buildProperty(prop, obj, ctxt)); } else { - if (prop->values.at(0)->object) { - int pr = output->indexForByteArray(prop->name); - - bool rv = compileObject(prop->values.at(0)->object, 0); - - if (rv) { - QmlInstruction assign; - assign.type = QmlInstruction::AssignSignalObject; - assign.line = prop->values.at(0)->location.start.line; - assign.assignSignalObject.signal = pr; - - output->bytecode << assign; - - prop->values.at(0)->type = Value::SignalObject; - } + if (prop->value || prop->values.count() > 1) + COMPILE_EXCEPTION("Incorrectly specified signal"); - return rv; + prop->index = sigIdx; + obj->addSignalProperty(prop); + if (prop->values.at(0)->object) { + COMPILE_CHECK(buildObject(prop->values.at(0)->object, ctxt)); + prop->values.at(0)->type = Value::SignalObject; } else { - QString script = prop->values.at(0)->value.asScript().trimmed(); - if (script.isEmpty()) - return true; - - int idx = output->indexForString(script); - - QmlInstruction store; - store.line = prop->values.at(0)->location.start.line; - store.type = QmlInstruction::StoreSignal; - store.storeSignal.signalIndex = sigIdx; - store.storeSignal.value = idx; - - output->bytecode << store; - prop->values.at(0)->type = Value::SignalExpression; } } @@ -903,6 +1030,7 @@ bool QmlCompiler::compileSignal(Property *prop, Object *obj) return true; } + // Returns true if prop exists on obj, false otherwise bool QmlCompiler::testProperty(QmlParser::Property *prop, QmlParser::Object *obj) @@ -924,9 +1052,11 @@ bool QmlCompiler::testProperty(QmlParser::Property *prop, return false; } -bool QmlCompiler::compileProperty(Property *prop, Object *obj, const BindingContext &ctxt) +bool QmlCompiler::buildProperty(QmlParser::Property *prop, + QmlParser::Object *obj, + const BindingContext &ctxt) { - if (prop->values.isEmpty() && !prop->value) + if (prop->isEmpty()) COMPILE_EXCEPTION2(prop, "Empty property assignment"); const QMetaObject *metaObject = obj->metaObject(); @@ -934,167 +1064,309 @@ bool QmlCompiler::compileProperty(Property *prop, Object *obj, const BindingCont if (isAttachedPropertyName(prop->name)) { // Setup attached property data + + if (ctxt.isSubContext()) { + // Attached properties cannot be used on sub-objects. Sub-objects + // always exist in a binding sub-context, which is what we test + // for here. + COMPILE_EXCEPTION2(prop, "Attached properties cannot be used here"); + } + QmlType *type = QmlMetaType::qmlType(prop->name); - if (!type || !type->attachedPropertiesType()) - COMPILE_EXCEPTION2(prop, "Non-existant attached object"); + if (!type || !type->attachedPropertiesType()) + COMPILE_EXCEPTION2(prop, "Non-existant attached object"); + + if (!prop->value) + COMPILE_EXCEPTION2(prop, "Invalid attached object assignment"); + + prop->value->metatype = type->attachedPropertiesType(); + } else { + // Setup regular property data + QMetaProperty p; + + if (prop->isDefault) { + p = QmlMetaType::defaultProperty(metaObject); + + if (p.name()) { + prop->index = p.propertyIndex(); + prop->name = p.name(); + } + + } else { + prop->index = metaObject->indexOfProperty(prop->name.constData()); + + if (prop->index != -1) { + p = metaObject->property(prop->index); + Q_ASSERT(p.name()); + } + } + + // We can't error here as the "id" property does not require a + // successful index resolution + if (p.name()) { + int t = p.type(); + + if (t == QVariant::UserType) + t = p.userType(); + + prop->type = t; + } + } + + if (!prop->isDefault && prop->name == "id" && !ctxt.isSubContext()) { + + // The magic "id" behaviour doesn't apply when "id" is resolved as a + // default property or to sub-objects (which are always in binding + // sub-contexts) + COMPILE_CHECK(buildIdProperty(prop, obj)); + if (prop->type == QVariant::String && + prop->values.at(0)->value.isString()) + COMPILE_CHECK(buildPropertyAssignment(prop, obj, ctxt)); + + } else if (isAttachedPropertyName(prop->name)) { + + COMPILE_CHECK(buildAttachedProperty(prop, obj, ctxt)); + + } else if (prop->index == -1) { + + if (prop->isDefault) { + COMPILE_EXCEPTION2(prop->values.first(), "Cannot assign to non-existant default property"); + } else { + COMPILE_EXCEPTION2(prop, "Cannot assign to non-existant property" << prop->name); + } + + } else if (prop->value) { + + COMPILE_CHECK(buildGroupedProperty(prop, obj, ctxt)); + + } else if (QmlMetaType::isQmlList(prop->type) || + QmlMetaType::isList(prop->type)) { + + COMPILE_CHECK(buildListProperty(prop, obj, ctxt)); + + } else { + + COMPILE_CHECK(buildPropertyAssignment(prop, obj, ctxt)); + + } + + return true; +} + +void QmlCompiler::genValueProperty(QmlParser::Property *prop, + QmlParser::Object *obj) +{ + if (QmlMetaType::isQmlList(prop->type) || QmlMetaType::isList(prop->type)) { + genListProperty(prop, obj); + } else { + genPropertyAssignment(prop, obj); + } +} + +void QmlCompiler::genListProperty(QmlParser::Property *prop, + QmlParser::Object *obj) +{ + QmlInstruction::Type fetchType; + QmlInstruction::Type storeType; + int listType; + + if (QmlMetaType::isQmlList(prop->type)) { + fetchType = QmlInstruction::FetchQmlList; + storeType = QmlInstruction::StoreObjectQmlList; + listType = QmlMetaType::qmlListType(prop->type); + } else { + fetchType = QmlInstruction::FetchQList; + storeType = QmlInstruction::StoreObjectQList; + listType = QmlMetaType::listType(prop->type); + } + + QmlInstruction fetch; + fetch.type = fetchType; + fetch.line = prop->location.start.line; + fetch.fetchQmlList.property = prop->index; + bool listTypeIsInterface = QmlMetaType::isInterface(listType); + fetch.fetchQmlList.type = listType; + output->bytecode << fetch; + + for (int ii = 0; ii < prop->values.count(); ++ii) { + Value *v = prop->values.at(ii); + + if (v->type == Value::CreatedObject) { + + genObject(v->object); + if (listTypeIsInterface) { + QmlInstruction assign; + assign.type = QmlInstruction::AssignObjectList; + assign.line = prop->location.start.line; + output->bytecode << assign; + } else { + QmlInstruction store; + store.type = storeType; + store.line = prop->location.start.line; + output->bytecode << store; + } + + } else if (v->type == Value::PropertyBinding) { - if (!prop->value) - COMPILE_EXCEPTION2(prop, "Cannot assign directly to attached object"); + genBindingAssignment(v, prop, obj); - prop->value->metatype = type->attachedPropertiesType(); - } else { - // Setup regular property data - QMetaProperty p; + } - if (prop->isDefault) { - p = QmlMetaType::defaultProperty(metaObject); + } - if (p.name()) { - prop->index = p.propertyIndex(); - prop->name = p.name(); - } + QmlInstruction pop; + pop.type = QmlInstruction::PopQList; + pop.line = prop->location.start.line; + output->bytecode << pop; +} - } else { - prop->index = metaObject->indexOfProperty(prop->name.constData()); +void QmlCompiler::genPropertyAssignment(QmlParser::Property *prop, + QmlParser::Object *obj) +{ + for (int ii = 0; ii < prop->values.count(); ++ii) { + QmlParser::Value *v = prop->values.at(ii); - if (prop->index != -1) { - p = metaObject->property(prop->index); - Q_ASSERT(p.name()); - } - } + if (v->type == Value::CreatedObject) { - // We can't error here as the "id" property does not require a - // successful index resolution - if (p.name()) { - int t = p.type(); + genObject(v->object); - if (t == QVariant::UserType) - t = p.userType(); + if (QmlMetaType::isInterface(prop->type)) { - prop->type = t; - } - } + QmlInstruction store; + store.type = QmlInstruction::StoreInterface; + store.line = v->object->location.start.line; + store.storeObject.propertyIndex = prop->index; + output->bytecode << store; - if (!prop->isDefault && prop->name == "id") { + } else if (prop->type == -1) { - COMPILE_CHECK(compileIdProperty(prop, obj)); + QmlInstruction store; + store.type = QmlInstruction::StoreVariantObject; + store.line = v->object->location.start.line; + store.storeObject.propertyIndex = prop->index; + output->bytecode << store; - } else if (isAttachedPropertyName(prop->name)) { + } else { - COMPILE_CHECK(compileAttachedProperty(prop, ctxt)); + QmlInstruction store; + store.type = QmlInstruction::StoreObject; + store.line = v->object->location.start.line; + store.storeObject.propertyIndex = prop->index; + output->bytecode << store; - } else if (prop->index == -1) { + } + } else if (v->type == Value::ValueSource) { - if (prop->isDefault) { - COMPILE_EXCEPTION2(prop, "Cannot assign to non-existant default property"); - } else { - COMPILE_EXCEPTION2(prop, "Cannot assign to non-existant property" << prop->name); - } + genObject(v->object); - } else if (prop->value) { + QmlInstruction store; + store.type = QmlInstruction::StoreValueSource; + store.line = v->object->location.start.line; + store.assignValueSource.property = prop->index; + output->bytecode << store; - COMPILE_CHECK(compileNestedProperty(prop, ctxt)); + } else if (v->type == Value::PropertyBinding) { - } else if (QmlMetaType::isQmlList(prop->type) || - QmlMetaType::isList(prop->type)) { + genBindingAssignment(v, prop, obj); - COMPILE_CHECK(compileListProperty(prop, obj, ctxt)); + } else if (v->type == Value::Literal) { - } else { + QMetaProperty mp = obj->metaObject()->property(prop->index); + genLiteralAssignment(mp, v); - COMPILE_CHECK(compilePropertyAssignment(prop, obj, ctxt)); + } } - - return true; } -bool QmlCompiler::compileIdProperty(QmlParser::Property *prop, - QmlParser::Object *obj) +bool QmlCompiler::buildIdProperty(QmlParser::Property *prop, + QmlParser::Object *obj) { - if (prop->value) - COMPILE_EXCEPTION2(prop,"The id property cannot be fetched"); - if (prop->values.count() > 1) - COMPILE_EXCEPTION2(prop, "The object id may only be set once"); + if (prop->value || + prop->values.count() > 1 || + prop->values.at(0)->object) + COMPILE_EXCEPTION2(prop, "Invalid use of id property"); - if (prop->values.at(0)->object) - COMPILE_EXCEPTION("Cannot assign an object as an id"); QString val = prop->values.at(0)->primitive(); + if (!isValidId(val)) - COMPILE_EXCEPTION(val << "is not a valid id"); + COMPILE_EXCEPTION2(prop, val << "is not a valid object id"); + if (compileState.ids.contains(val)) - COMPILE_EXCEPTION("id is not unique"); + COMPILE_EXCEPTION2(prop, "id is not unique"); - int pref = output->indexForString(val); + obj->id = val.toUtf8(); - if (prop->type == QVariant::String) { - QmlInstruction assign; - assign.type = QmlInstruction::StoreString; - assign.storeString.propertyIndex = prop->index; - assign.storeString.value = pref; - assign.line = prop->values.at(0)->location.start.line; - output->bytecode << assign; + prop->values.at(0)->type = Value::Id; - prop->values.at(0)->type = Value::Id; - } else { - prop->values.at(0)->type = Value::Literal; - } + addId(val, obj); + + return true; +} +void QmlCompiler::addId(const QString &id, QmlParser::Object *obj) +{ IdReference reference; - reference.id = val; + reference.id = id; reference.object = obj; - reference.instructionIdx = output->bytecode.count(); reference.idx = compileState.ids.count(); - compileState.ids.insert(val, reference); + compileState.ids.insert(id, reference); +} + +void QmlCompiler::addBindingReference(const BindingReference &ref) +{ + int id = compileState.bindings.count(); + compileState.bindings << ref; + compileState.bindingMap.insert(ref.value, id); +} - QmlInstruction id; - id.type = QmlInstruction::SetId; - id.line = prop->values.at(0)->location.start.line; - id.setId.value = pref; - id.setId.save = -1; - output->bytecode << id; +void QmlCompiler::saveComponentState() +{ + Q_ASSERT(compileState.root); + Q_ASSERT(!savedCompileStates.contains(compileState.root)); - obj->id = val.toLatin1(); + savedCompileStates.insert(compileState.root, compileState); +} - return true; +QmlCompiler::ComponentCompileState +QmlCompiler::componentState(QmlParser::Object *obj) +{ + Q_ASSERT(savedCompileStates.contains(obj)); + return savedCompileStates.value(obj); } -// Compile attached property object. In this example, +// Build attached property object. In this example, // Text { // GridView.row: 10 // } // GridView is an attached property object. -bool QmlCompiler::compileAttachedProperty(QmlParser::Property *prop, - const BindingContext &ctxt) +bool QmlCompiler::buildAttachedProperty(QmlParser::Property *prop, + QmlParser::Object *obj, + const BindingContext &ctxt) { Q_ASSERT(prop->value); int id = QmlMetaType::attachedPropertiesFuncId(prop->name); Q_ASSERT(id != -1); // This is checked in compileProperty() - QmlInstruction fetch; - fetch.type = QmlInstruction::FetchAttached; - fetch.line = prop->location.start.line; - fetch.fetchAttached.id = id; - output->bytecode << fetch; - - COMPILE_CHECK(compileFetchedObject(prop->value, ctxt.incr())); + prop->index = id; + obj->addAttachedProperty(prop); - QmlInstruction pop; - pop.type = QmlInstruction::PopFetchedObject; - pop.line = prop->location.start.line; - output->bytecode << pop; + COMPILE_CHECK(buildSubObject(prop->value, ctxt.incr())); return true; } -// Compile "nested" properties. In this example: + +// Build "grouped" properties. In this example: // Text { // font.size: 12 +// font.family: "Helvetica" // } -// font is a nested property. size is not. -bool QmlCompiler::compileNestedProperty(QmlParser::Property *prop, - const BindingContext &ctxt) +// font is a nested property. size and family are not. +bool QmlCompiler::buildGroupedProperty(QmlParser::Property *prop, + QmlParser::Object *obj, + const BindingContext &ctxt) { Q_ASSERT(prop->type != 0); Q_ASSERT(prop->index != -1); @@ -1104,132 +1376,90 @@ bool QmlCompiler::compileNestedProperty(QmlParser::Property *prop, if (!prop->value->metatype) COMPILE_EXCEPTION2(prop, "Cannot nest non-QObject property" << prop->name); - QmlInstruction fetch; - fetch.type = QmlInstruction::FetchObject; - fetch.fetch.property = prop->index; - fetch.fetch.isObject = true; - fetch.line = prop->location.start.line; - output->bytecode << fetch; - - COMPILE_CHECK(compileFetchedObject(prop->value, ctxt.incr())); + obj->addGroupedProperty(prop); - QmlInstruction pop; - pop.type = QmlInstruction::PopFetchedObject; - pop.line = prop->location.start.line; - output->bytecode << pop; + COMPILE_CHECK(buildSubObject(prop->value, ctxt.incr())); return true; } -// Compile assignments to QML lists. QML lists are properties of type + +// Build assignments to QML lists. QML lists are properties of type // QList * and QmlList *. // // QList * types can accept a list of objects, or a single binding // QmlList * types can accept a list of objects -bool QmlCompiler::compileListProperty(QmlParser::Property *prop, - QmlParser::Object *obj, - const BindingContext &ctxt) +bool QmlCompiler::buildListProperty(QmlParser::Property *prop, + QmlParser::Object *obj, + const BindingContext &ctxt) { Q_ASSERT(QmlMetaType::isList(prop->type) || QmlMetaType::isQmlList(prop->type)); int t = prop->type; + obj->addValueProperty(prop); + if (QmlMetaType::isQmlList(t)) { - QmlInstruction fetch; - fetch.line = prop->location.start.line; - fetch.type = QmlInstruction::FetchQmlList; - fetch.fetchQmlList.property = prop->index; int listType = QmlMetaType::qmlListType(t); bool listTypeIsInterface = QmlMetaType::isInterface(listType); - fetch.fetchQmlList.type = listType; - output->bytecode << fetch; for (int ii = 0; ii < prop->values.count(); ++ii) { Value *v = prop->values.at(ii); if (v->object) { v->type = Value::CreatedObject; - COMPILE_CHECK(compileObject(v->object, ctxt)); + COMPILE_CHECK(buildObject(v->object, ctxt)); + // We check object coercian here. We check interface assignment + // at runtime. if (!listTypeIsInterface) { - if (canConvert(listType, v->object)) { - QmlInstruction store; - store.type = QmlInstruction::StoreObjectQmlList; - store.line = prop->location.start.line; - output->bytecode << store; - } else { + if (!canCoerce(listType, v->object)) { COMPILE_EXCEPTION("Cannot assign object to list"); } - - } else { - QmlInstruction assign; - assign.type = QmlInstruction::AssignObjectList; - assign.line = prop->location.start.line; - output->bytecode << assign; } + } else { COMPILE_EXCEPTION("Cannot assign primitives to lists"); } } - QmlInstruction pop; - pop.type = QmlInstruction::PopQList; - pop.line = prop->location.start.line; - output->bytecode << pop; } else { - QmlInstruction fetch; - fetch.type = QmlInstruction::FetchQList; - fetch.line = prop->location.start.line; - fetch.fetchQmlList.property = prop->index; int listType = QmlMetaType::listType(t); bool listTypeIsInterface = QmlMetaType::isInterface(listType); - fetch.fetchQmlList.type = listType; - output->bytecode << fetch; bool assignedBinding = false; for (int ii = 0; ii < prop->values.count(); ++ii) { Value *v = prop->values.at(ii); if (v->object) { v->type = Value::CreatedObject; - COMPILE_CHECK(compileObject(v->object, ctxt)); + COMPILE_CHECK(buildObject(v->object, ctxt)); + // We check object coercian here. We check interface assignment + // at runtime. if (!listTypeIsInterface) { - if (canConvert(listType, v->object)) { - QmlInstruction store; - store.type = QmlInstruction::StoreObjectQList; - store.line = prop->location.start.line; - output->bytecode << store; - } else { + if (!canCoerce(listType, v->object)) { COMPILE_EXCEPTION("Cannot assign object to list"); } - } else { - QmlInstruction assign; - assign.type = QmlInstruction::AssignObjectList; - assign.line = v->location.start.line; - output->bytecode << assign; - } + } + } else if (v->value.isScript()) { if (assignedBinding) COMPILE_EXCEPTION("Can only assign one binding to lists"); assignedBinding = true; - COMPILE_CHECK(compileBinding(v, prop, ctxt)); + COMPILE_CHECK(buildBinding(v, prop, ctxt)); v->type = Value::PropertyBinding; } else { COMPILE_EXCEPTION("Cannot assign primitives to lists"); } } - QmlInstruction pop; - pop.line = prop->location.start.line; - pop.type = QmlInstruction::PopQList; - output->bytecode << pop; } return true; } -// Compile regular property assignments of the form property: +// Compile regular property assignments of the form "property: " // // ### The following problems exist // @@ -1244,19 +1474,21 @@ bool QmlCompiler::compileListProperty(QmlParser::Property *prop, // } // // We allow assignming multiple values to single value properties -bool QmlCompiler::compilePropertyAssignment(QmlParser::Property *prop, - QmlParser::Object *obj, - const BindingContext &ctxt) +bool QmlCompiler::buildPropertyAssignment(QmlParser::Property *prop, + QmlParser::Object *obj, + const BindingContext &ctxt) { + obj->addValueProperty(prop); + for (int ii = 0; ii < prop->values.count(); ++ii) { Value *v = prop->values.at(ii); if (v->object) { - COMPILE_CHECK(compilePropertyObjectAssignment(prop, v, ctxt)); + COMPILE_CHECK(buildPropertyObjectAssignment(prop, obj, v, ctxt)); } else { - COMPILE_CHECK(compilePropertyLiteralAssignment(prop, obj, v, ctxt)); + COMPILE_CHECK(buildPropertyLiteralAssignment(prop, obj, v, ctxt)); } } @@ -1265,9 +1497,10 @@ bool QmlCompiler::compilePropertyAssignment(QmlParser::Property *prop, } // Compile assigning a single object instance to a regular property -bool QmlCompiler::compilePropertyObjectAssignment(QmlParser::Property *prop, - QmlParser::Value *v, - const BindingContext &ctxt) +bool QmlCompiler::buildPropertyObjectAssignment(QmlParser::Property *prop, + QmlParser::Object *obj, + QmlParser::Value *v, + const BindingContext &ctxt) { Q_ASSERT(prop->index != -1); Q_ASSERT(v->object->type != -1); @@ -1275,30 +1508,18 @@ bool QmlCompiler::compilePropertyObjectAssignment(QmlParser::Property *prop, if (QmlMetaType::isInterface(prop->type)) { // Assigning an object to an interface ptr property - COMPILE_CHECK(compileObject(v->object, ctxt)); - - QmlInstruction assign; - assign.type = QmlInstruction::StoreInterface; - assign.line = v->object->location.start.line; - assign.storeObject.propertyIndex = prop->index; - output->bytecode << assign; + COMPILE_CHECK(buildObject(v->object, ctxt)); v->type = Value::CreatedObject; } else if (prop->type == -1) { // Assigning an object to a QVariant - COMPILE_CHECK(compileObject(v->object, ctxt)); - - QmlInstruction assign; - assign.type = QmlInstruction::StoreVariantObject; - assign.line = v->object->location.start.line; - assign.storeObject.propertyIndex = prop->index; - output->bytecode << assign; + COMPILE_CHECK(buildObject(v->object, ctxt)); v->type = Value::CreatedObject; } else { - // Normally compileObject() will set this up, but we need the static + // Normally buildObject() will set this up, but we need the static // meta object earlier to test for assignability. It doesn't matter // that there may still be outstanding synthesized meta object changes // on this type, as they are not relevant for assignability testing @@ -1333,39 +1554,29 @@ bool QmlCompiler::compilePropertyObjectAssignment(QmlParser::Property *prop, if (isAssignable) { // Simple assignment - COMPILE_CHECK(compileObject(v->object, ctxt)); - - QmlInstruction assign; - assign.type = QmlInstruction::StoreObject; - assign.line = v->object->location.start.line; - assign.storeObject.propertyIndex = prop->index; - output->bytecode << assign; + COMPILE_CHECK(buildObject(v->object, ctxt)); v->type = Value::CreatedObject; } else if (propertyMetaObject == &QmlComponent::staticMetaObject) { // Automatic "Component" insertion - COMPILE_CHECK(compileComponentFromRoot(v->object, ctxt)); - - QmlInstruction assign; - assign.type = QmlInstruction::StoreObject; - assign.line = v->object->location.start.line; - assign.storeObject.propertyIndex = prop->index; - output->bytecode << assign; - - v->type = Value::Component; + QmlParser::Object *root = v->object; + QmlParser::Object *component = new QmlParser::Object; + component->type = componentTypeRef(); + component->typeName = "Component"; + component->metatype = &QmlComponent::staticMetaObject; + component->location = root->location; + QmlParser::Value *componentValue = new QmlParser::Value; + componentValue->object = root; + component->getDefaultProperty()->addValue(componentValue); + v->object = component; + COMPILE_CHECK(buildPropertyObjectAssignment(prop, obj, v, ctxt)); } else if (isPropertyValue) { // Assign as a property value source - COMPILE_CHECK(compileObject(v->object, ctxt)); - - QmlInstruction assign; - assign.type = QmlInstruction::StoreValueSource; - assign.line = v->object->location.start.line; - assign.assignValueSource.property = prop->index; - output->bytecode << assign; + COMPILE_CHECK(buildObject(v->object, ctxt)); v->type = Value::ValueSource; } else { - COMPILE_EXCEPTION2(v->object, "Unassignable object"); + COMPILE_EXCEPTION2(v->object, "Cannot assign object to property"); } } @@ -1373,25 +1584,22 @@ bool QmlCompiler::compilePropertyObjectAssignment(QmlParser::Property *prop, } // Compile assigning a literal or binding to a regular property -bool QmlCompiler::compilePropertyLiteralAssignment(QmlParser::Property *prop, - QmlParser::Object *obj, - QmlParser::Value *v, - const BindingContext &ctxt) +bool QmlCompiler::buildPropertyLiteralAssignment(QmlParser::Property *prop, + QmlParser::Object *obj, + QmlParser::Value *v, + const BindingContext &ctxt) { Q_ASSERT(prop->index != -1); if (v->value.isScript()) { - COMPILE_CHECK(compileBinding(v, prop, ctxt)); + COMPILE_CHECK(buildBinding(v, prop, ctxt)); v->type = Value::PropertyBinding; } else { - QmlInstruction assign; - assign.line = v->location.start.line; - COMPILE_CHECK(compileStoreInstruction(assign, obj->metaObject()->property(prop->index), v)); - output->bytecode << assign; + COMPILE_CHECK(testLiteralAssignment(obj->metaObject()->property(prop->index), v)); v->type = Value::Literal; } @@ -1399,31 +1607,99 @@ bool QmlCompiler::compilePropertyLiteralAssignment(QmlParser::Property *prop, return true; } -bool QmlCompiler::compileDynamicMeta(QmlParser::Object *obj, int preAlias) +// Ensures that the dynamic meta specification on obj is valid +bool QmlCompiler::checkDynamicMeta(QmlParser::Object *obj) +{ + QSet propNames; + QSet methodNames; + bool seenDefaultProperty = false; + + // Check properties + for (int ii = 0; ii < obj->dynamicProperties.count(); ++ii) { + const QmlParser::Object::DynamicProperty &prop = + obj->dynamicProperties.at(ii); + + if (prop.isDefaultProperty) { + if (seenDefaultProperty) + COMPILE_EXCEPTION("Duplicate default property"); + seenDefaultProperty = true; + } + + if (propNames.contains(prop.name)) + COMPILE_EXCEPTION("Duplicate property name"); + + propNames.insert(prop.name); + } + + for (int ii = 0; ii < obj->dynamicSignals.count(); ++ii) { + QByteArray name = obj->dynamicSignals.at(ii).name; + if (methodNames.contains(name)) + COMPILE_EXCEPTION("Duplicate signal name"); + methodNames.insert(name); + } + for (int ii = 0; ii < obj->dynamicSlots.count(); ++ii) { + QByteArray name = obj->dynamicSlots.at(ii).name; + if (methodNames.contains(name)) + COMPILE_EXCEPTION("Duplicate method name"); + methodNames.insert(name); + } + + return true; +} + +bool QmlCompiler::mergeDynamicMetaProperties(QmlParser::Object *obj) +{ + for (int ii = 0; ii < obj->dynamicProperties.count(); ++ii) { + const Object::DynamicProperty &p = obj->dynamicProperties.at(ii); + + if (!p.defaultValue || p.type == Object::DynamicProperty::Alias) + continue; + + Property *property = 0; + if (p.isDefaultProperty) + property = obj->getDefaultProperty(); + else + property = obj->getProperty(p.name); + + if (property->value) + COMPILE_EXCEPTION2(property, "Invalid property nesting"); + + for (int ii = 0; ii < p.defaultValue->values.count(); ++ii) { + Value *v = p.defaultValue->values.at(ii); + v->addref(); + property->values.append(v); + } + } + return true; +} + +bool QmlCompiler::buildDynamicMeta(QmlParser::Object *obj, DynamicMetaMode mode) { - // ### FIXME - Check that there is only one default property etc. if (obj->dynamicProperties.isEmpty() && obj->dynamicSignals.isEmpty() && obj->dynamicSlots.isEmpty()) return true; + COMPILE_CHECK(checkDynamicMeta(obj)); + QByteArray dynamicData(sizeof(QmlVMEMetaData), (char)0); QMetaObjectBuilder builder; if (obj->metatype) - builder.setClassName(QByteArray(obj->metatype->className()) + "QML"); - + builder.setClassName(QByteArray(obj->metatype->className()) + "_QML"); builder.setFlags(QMetaObjectBuilder::DynamicMetaObject); + bool hasAlias = false; for (int ii = 0; ii < obj->dynamicProperties.count(); ++ii) { const Object::DynamicProperty &p = obj->dynamicProperties.at(ii); if (p.isDefaultProperty && - (p.type != Object::DynamicProperty::Alias || preAlias != -1)) + (p.type != Object::DynamicProperty::Alias || + mode == ResolveAliases)) builder.addClassInfo("DefaultProperty", p.name); QByteArray type; - int propertyType; + int propertyType = 0; switch(p.type) { case Object::DynamicProperty::Alias: hasAlias = true; @@ -1471,7 +1747,7 @@ bool QmlCompiler::compileDynamicMeta(QmlParser::Object *obj, int preAlias) builder.addProperty(p.name, type, ii); } - if (preAlias != -1) { + if (mode == ResolveAliases) { for (int ii = 0; ii < obj->dynamicProperties.count(); ++ii) { const Object::DynamicProperty &p = obj->dynamicProperties.at(ii); @@ -1495,8 +1771,6 @@ bool QmlCompiler::compileDynamicMeta(QmlParser::Object *obj, int preAlias) ((QmlVMEMetaData *)dynamicData.data())->signalCount++; } - int slotStart = obj->dynamicSlots.isEmpty()?-1:output->primitives.count(); - for (int ii = 0; ii < obj->dynamicSlots.count(); ++ii) { const Object::DynamicSlot &s = obj->dynamicSlots.at(ii); QByteArray sig(s.name + "("); @@ -1509,57 +1783,37 @@ bool QmlCompiler::compileDynamicMeta(QmlParser::Object *obj, int preAlias) b.setParameterNames(s.parameterNames); ((QmlVMEMetaData *)dynamicData.data())->methodCount++; - QmlVMEMetaData::MethodData methodData = { s.parameterNames.count() }; - dynamicData.append((char *)&methodData, sizeof(methodData)); + QmlVMEMetaData::MethodData methodData = + { s.parameterNames.count(), 0, s.body.length(), 0 }; - if (preAlias == -1) - output->primitives << s.body; + dynamicData.append((char *)&methodData, sizeof(methodData)); } - if (obj->metatype) - builder.setSuperClass(obj->metatype); - - obj->extObjectData = builder.toMetaObject(); - static_cast(obj->extObject) = *obj->extObjectData; - - if (preAlias != -1) { - QmlInstruction &store = output->bytecode[preAlias]; - - store.storeMeta.aliasData = output->indexForByteArray(dynamicData); - qFree(output->synthesizedMetaObjects.at(store.storeMeta.data)); - output->synthesizedMetaObjects[store.storeMeta.data] = obj->extObjectData; - - } else { - output->synthesizedMetaObjects << obj->extObjectData; - QmlInstruction store; - store.type = QmlInstruction::StoreMetaObject; - store.storeMeta.data = output->synthesizedMetaObjects.count() - 1; - store.storeMeta.slotData = slotStart; - store.storeMeta.aliasData = output->indexForByteArray(dynamicData); - store.line = obj->location.start.line; - output->bytecode << store; - - if (hasAlias) { - AliasReference alias; - alias.object = obj; - alias.instructionIdx = output->bytecode.count() - 1; - compileState.aliases << alias; - } + for (int ii = 0; ii < obj->dynamicSlots.count(); ++ii) { + const Object::DynamicSlot &s = obj->dynamicSlots.at(ii); + QmlVMEMetaData::MethodData *data = + ((QmlVMEMetaData *)dynamicData.data())->methodData() + ii; + + data->bodyOffset = dynamicData.size(); + + dynamicData.append((const char *)s.body.constData(), + (s.body.length() * sizeof(QChar))); } - for (int ii = 0; ii < obj->dynamicProperties.count(); ++ii) { - const Object::DynamicProperty &p = obj->dynamicProperties.at(ii); + obj->metadata = builder.toRelocatableData(); + builder.fromRelocatableData(&obj->extObject, obj->metatype, obj->metadata); - if (p.type == Object::DynamicProperty::Alias) - continue; + // ### Remove me + obj->extObjectData = &obj->extObject; - if (p.defaultValue) { - p.defaultValue->name = p.name; - p.defaultValue->isDefault = false; - COMPILE_CHECK(compileProperty(p.defaultValue, obj, 0)); - } + if (mode == IgnoreAliases && hasAlias) { + AliasReference alias; + alias.object = obj; + compileState.aliases << alias; } + obj->synthdata = dynamicData; + return true; } @@ -1623,9 +1877,9 @@ bool QmlCompiler::compileAlias(QMetaObjectBuilder &builder, return true; } -bool QmlCompiler::compileBinding(QmlParser::Value *value, - QmlParser::Property *prop, - const BindingContext &ctxt) +bool QmlCompiler::buildBinding(QmlParser::Value *value, + QmlParser::Property *prop, + const BindingContext &ctxt) { Q_ASSERT(prop->index); Q_ASSERT(prop->parent); @@ -1633,7 +1887,7 @@ bool QmlCompiler::compileBinding(QmlParser::Value *value, QMetaProperty mp = prop->parent->metaObject()->property(prop->index); if (!mp.isWritable() && !QmlMetaType::isList(prop->type)) - COMPILE_EXCEPTION2(prop, "Cannot assign binding to read-only property"); + COMPILE_EXCEPTION2(prop, "Invalid property assignment: read-only property"); BindingReference reference; reference.expression = value->value; @@ -1641,185 +1895,104 @@ bool QmlCompiler::compileBinding(QmlParser::Value *value, reference.value = value; reference.instructionIdx = output->bytecode.count(); reference.bindingContext = ctxt; - compileState.bindings << reference; - - output->bytecode << QmlInstruction();; + addBindingReference(reference); return true; } -#if 0 - -#include -#ifdef Q_CC_GNU -#include -#endif - -//////////////////////////////////////////////////////////////////////////////// -// AST Dump -//////////////////////////////////////////////////////////////////////////////// -class Dump: protected QmlJS::AST::Visitor -{ - std::ostream &out; - int depth; - -public: - Dump(std::ostream &out) - : out(out), depth(-1) - { } - - void operator()(QmlJS::AST::Node *node) - { QmlJS::AST::Node::acceptChild(node, this); } - -protected: - virtual bool preVisit(QmlJS::AST::Node *node) - { - const char *name = typeid(*node).name(); -#ifdef Q_CC_GNU - name = abi::__cxa_demangle(name, 0, 0, 0) + 17; -#endif - std::cout << std::string(++depth, ' ') << name << std::endl; - return true; - } - - virtual void postVisit(QmlJS::AST::Node *) - { - --depth; - } -}; -#endif - -// Update the init instruction with final data, and optimize some simple -// bindings -bool QmlCompiler::finalizeComponent(int patch) +void QmlCompiler::genBindingAssignment(QmlParser::Value *binding, + QmlParser::Property *prop, + QmlParser::Object *obj) { - for (int ii = 0; ii < compileState.bindings.count(); ++ii) { - const BindingReference &binding = compileState.bindings.at(ii); - finalizeBinding(binding); - } + Q_ASSERT(compileState.bindingMap.contains(binding)); - for (int ii = 0; ii < compileState.aliases.count(); ++ii) { - const AliasReference &alias = compileState.aliases.at(ii); - COMPILE_CHECK(finalizeAlias(alias)); + const BindingReference &ref = + compileState.bindings.at(compileState.bindingMap.value(binding)); + + QMetaProperty mp = obj->metaObject()->property(prop->index); + + QmlInstruction store; + int dataRef; + if (ref.compiledData.isEmpty()) { + dataRef = output->indexForString(ref.expression.asScript()); + store.type = QmlInstruction::StoreBinding; + } else { + dataRef = output->indexForByteArray(ref.compiledData); + store.type = QmlInstruction::StoreCompiledBinding; } - output->bytecode[patch].init.dataSize = compileState.savedObjects;; - output->bytecode[patch].init.bindingsSize = compileState.bindings.count(); - output->bytecode[patch].init.parserStatusSize = - compileState.parserStatusCount; + store.assignBinding.property = prop->index; + store.assignBinding.value = dataRef; + store.assignBinding.category = QmlMetaProperty::propertyCategory(mp); + store.assignBinding.context = ref.bindingContext.stack; - return true; + output->bytecode << store; } -bool QmlCompiler::finalizeAlias(const AliasReference &alias) +bool QmlCompiler::completeComponentBuild() { - COMPILE_CHECK(compileDynamicMeta(alias.object, alias.instructionIdx)); -} + saveComponentState(); + + for (int ii = 0; ii < compileState.aliases.count(); ++ii) { + const AliasReference &alias = compileState.aliases.at(ii); + COMPILE_CHECK(buildDynamicMeta(alias.object, ResolveAliases)); + } + -void QmlCompiler::finalizeBinding(const BindingReference &binding) -{ - QmlBasicScript bs; QmlBasicScript::Expression expr; expr.component = compileState.root; - expr.context = binding.bindingContext.object; - expr.property = binding.property; - expr.expression = binding.expression; - foreach (const IdReference &id, compileState.ids) + foreach (const IdReference &id, compileState.ids) { expr.ids.insert(id.id, qMakePair(id.object, id.idx)); + } - bs.compile(expr); - - QmlInstruction &instr = output->bytecode[binding.instructionIdx]; - instr.line = binding.value->location.start.line; - - // Single load optimization - if (bs.isValid() && bs.isSingleLoad()) { - - QString singleLoadTarget = QLatin1String(bs.singleLoadTarget()); - - if (singleLoadTarget.at(0).isUpper() && - compileState.ids.contains(singleLoadTarget) && - QmlMetaType::isObject(binding.property->type)) { - - IdReference reference = compileState.ids[singleLoadTarget]; - - const QMetaObject *idMo = reference.object->metaObject(); - const QMetaObject *storeMo = - QmlMetaType::rawMetaObjectForType(binding.property->type); - - Q_ASSERT(idMo); - Q_ASSERT(storeMo); - - bool canAssign = false; - while (!canAssign && idMo) { - if (idMo == storeMo) - canAssign = true; - else - idMo = idMo->superClass(); - } - - if (canAssign) { - int instructionIdx = reference.instructionIdx; - if (output->bytecode.at(instructionIdx).setId.save == -1) { - output->bytecode[instructionIdx].setId.save = - compileState.savedObjects++; - } - int saveId = output->bytecode.at(instructionIdx).setId.save; + for (int ii = 0; ii < compileState.bindings.count(); ++ii) { + BindingReference &binding = compileState.bindings[ii]; - instr.type = QmlInstruction::PushProperty; - instr.pushProperty.property = binding.property->index; - QmlInstruction store; - store.type = QmlInstruction::StoreStackObject; - store.line = 0; - store.assignStackObject.property = - compileState.pushedProperties++; - store.assignStackObject.object = saveId; - output->bytecode << store; - return; - } - } - } + QmlBasicScript bs; + expr.context = binding.bindingContext.object; + expr.property = binding.property; + expr.expression = binding.expression; - // General binding fallback - int bref; - if (bs.isValid()) { - bref = output->indexForByteArray(QByteArray(bs.compileData(), bs.compileDataSize())); - } else { - bref = output->indexForString(binding.expression.asScript()); + bs.compile(expr); + if (bs.isValid()) + binding.compiledData = + QByteArray(bs.compileData(), bs.compileDataSize()); } - instr.assignBinding.context = binding.bindingContext.stack; - - if (bs.isValid()) - instr.type = QmlInstruction::StoreCompiledBinding; - else - instr.type = QmlInstruction::StoreBinding; - - instr.assignBinding.property = binding.property->index; - instr.assignBinding.value = bref; - QMetaProperty mp = binding.property->parent->metaObject()->property(binding.property->index); - instr.assignBinding.category = QmlMetaProperty::propertyCategory(mp); + return true; } /*! - Returns true if object can be assigned to a (QObject) property of type - convertType. + Returns true if from can be assigned to a (QObject) property of type + to. */ -bool QmlCompiler::canConvert(int convertType, QmlParser::Object *object) +bool QmlCompiler::canCoerce(int to, QmlParser::Object *from) { - const QMetaObject *convertTypeMo = - QmlMetaType::rawMetaObjectForType(convertType); - const QMetaObject *objectMo = object->metaObject(); + const QMetaObject *toMo = + QmlMetaType::rawMetaObjectForType(to); + const QMetaObject *fromMo = from->metaObject(); - while (objectMo) { - if (objectMo == convertTypeMo) + while (fromMo) { + if (fromMo == toMo) return true; - objectMo = objectMo->superClass(); + fromMo = fromMo->superClass(); } return false; } +QmlType *QmlCompiler::toQmlType(QmlParser::Object *from) +{ + // ### Optimize + const QMetaObject *mo = from->metatype; + QmlType *type = 0; + while (!type && mo) { + type = QmlMetaType::qmlType(mo); + mo = mo->superClass(); + } + return type; +} + QStringList QmlCompiler::deferredProperties(QmlParser::Object *obj) { const QMetaObject *mo = obj->metatype; @@ -1833,63 +2006,4 @@ QStringList QmlCompiler::deferredProperties(QmlParser::Object *obj) return rv; } -QmlCompiledData::QmlCompiledData() -{ -} - -QmlCompiledData::QmlCompiledData(const QmlCompiledData &other) -{ - *this = other; -} - -QmlCompiledData::~QmlCompiledData() -{ - for (int ii = 0; ii < types.count(); ++ii) { - if (types.at(ii).ref) - types.at(ii).ref->release(); - } -} - -QmlCompiledData &QmlCompiledData::operator=(const QmlCompiledData &other) -{ - types = other.types; - root = other.root; - primitives = other.primitives; - floatData = other.floatData; - intData = other.intData; - customTypeData = other.customTypeData; - datas = other.datas; - synthesizedMetaObjects = other.synthesizedMetaObjects; - bytecode = other.bytecode; - return *this; -} - -QObject *QmlCompiledData::TypeReference::createInstance(QmlContext *ctxt) const -{ - if (type) { - QObject *rv = type->create(); - if (rv) - QmlEngine::setContextForObject(rv, ctxt); - return rv; - } else { - Q_ASSERT(component); - QObject *rv = component->create(ctxt); - QmlContext *ctxt = qmlContext(rv); - if(ctxt) { - static_cast(QObjectPrivate::get(ctxt))->typeName = className; - } - return rv; - } -} - -const QMetaObject *QmlCompiledData::TypeReference::metaObject() const -{ - if (type) { - return type->metaObject(); - } else { - Q_ASSERT(component); - return &static_cast(QObjectPrivate::get(component))->cc->root; - } -} - QT_END_NAMESPACE diff --git a/src/declarative/qml/qmlcompiler_p.h b/src/declarative/qml/qmlcompiler_p.h index 1c45f57..b97de19 100644 --- a/src/declarative/qml/qmlcompiler_p.h +++ b/src/declarative/qml/qmlcompiler_p.h @@ -109,7 +109,10 @@ public: QList bytecode; private: + QByteArray packData; friend class QmlCompiler; + int pack(const char *, size_t); + int indexForString(const QString &); int indexForByteArray(const QByteArray &); int indexForFloat(float *, int); @@ -146,57 +149,79 @@ private: rv.stack = stack + 1; return rv; } + bool isSubContext() const { return stack != 0; } int stack; QmlParser::Object *object; }; void compileTree(QmlParser::Object *tree); - bool compileObject(QmlParser::Object *obj, const BindingContext &); - bool compileComponent(QmlParser::Object *obj, const BindingContext &); - bool compileComponentFromRoot(QmlParser::Object *obj, const BindingContext &); - bool compileFetchedObject(QmlParser::Object *obj, const BindingContext &); - bool compileSignal(QmlParser::Property *prop, QmlParser::Object *obj); - bool testProperty(QmlParser::Property *prop, QmlParser::Object *obj); - int signalByName(const QMetaObject *, const QByteArray &name); - bool compileProperty(QmlParser::Property *prop, QmlParser::Object *obj, const BindingContext &); - bool compileIdProperty(QmlParser::Property *prop, - QmlParser::Object *obj); - bool compileAttachedProperty(QmlParser::Property *prop, - const BindingContext &ctxt); - bool compileNestedProperty(QmlParser::Property *prop, + + + bool buildObject(QmlParser::Object *obj, const BindingContext &); + bool buildComponent(QmlParser::Object *obj, const BindingContext &); + bool buildSubObject(QmlParser::Object *obj, const BindingContext &); + bool buildSignal(QmlParser::Property *prop, QmlParser::Object *obj, + const BindingContext &); + bool buildProperty(QmlParser::Property *prop, QmlParser::Object *obj, + const BindingContext &); + bool buildIdProperty(QmlParser::Property *prop, QmlParser::Object *obj); + bool buildAttachedProperty(QmlParser::Property *prop, + QmlParser::Object *obj, const BindingContext &ctxt); - bool compileListProperty(QmlParser::Property *prop, - QmlParser::Object *obj, - const BindingContext &ctxt); - bool compilePropertyAssignment(QmlParser::Property *prop, - QmlParser::Object *obj, - const BindingContext &ctxt); - bool compilePropertyObjectAssignment(QmlParser::Property *prop, - QmlParser::Value *value, - const BindingContext &ctxt); - bool compilePropertyLiteralAssignment(QmlParser::Property *prop, - QmlParser::Object *obj, - QmlParser::Value *value, - const BindingContext &ctxt); - bool compileStoreInstruction(QmlInstruction &instr, - const QMetaProperty &prop, - QmlParser::Value *value); - - bool compileDynamicMeta(QmlParser::Object *obj, int preAlias = -1); + bool buildGroupedProperty(QmlParser::Property *prop, + QmlParser::Object *obj, + const BindingContext &ctxt); + bool buildListProperty(QmlParser::Property *prop, + QmlParser::Object *obj, + const BindingContext &ctxt); + bool buildPropertyAssignment(QmlParser::Property *prop, + QmlParser::Object *obj, + const BindingContext &ctxt); + bool buildPropertyObjectAssignment(QmlParser::Property *prop, + QmlParser::Object *obj, + QmlParser::Value *value, + const BindingContext &ctxt); + bool buildPropertyLiteralAssignment(QmlParser::Property *prop, + QmlParser::Object *obj, + QmlParser::Value *value, + const BindingContext &ctxt); + bool testProperty(QmlParser::Property *prop, QmlParser::Object *obj); + bool testLiteralAssignment(const QMetaProperty &prop, + QmlParser::Value *value); + enum DynamicMetaMode { IgnoreAliases, ResolveAliases }; + bool mergeDynamicMetaProperties(QmlParser::Object *obj); + bool buildDynamicMeta(QmlParser::Object *obj, DynamicMetaMode mode); + bool checkDynamicMeta(QmlParser::Object *obj); + bool buildBinding(QmlParser::Value *, QmlParser::Property *prop, + const BindingContext &ctxt); + bool buildComponentFromRoot(QmlParser::Object *obj, const BindingContext &); bool compileAlias(QMetaObjectBuilder &, QByteArray &data, QmlParser::Object *obj, const QmlParser::Object::DynamicProperty &); - bool compileBinding(QmlParser::Value *, QmlParser::Property *prop, - const BindingContext &ctxt); + bool completeComponentBuild(); - bool finalizeComponent(int patch); - struct BindingReference; - void finalizeBinding(const BindingReference &); - struct AliasReference; - bool finalizeAlias(const AliasReference &); - bool canConvert(int, QmlParser::Object *); + void genObject(QmlParser::Object *obj); + void genObjectBody(QmlParser::Object *obj); + void genComponent(QmlParser::Object *obj); + void genValueProperty(QmlParser::Property *prop, QmlParser::Object *obj); + void genListProperty(QmlParser::Property *prop, QmlParser::Object *obj); + void genPropertyAssignment(QmlParser::Property *prop, + QmlParser::Object *obj); + void genLiteralAssignment(const QMetaProperty &prop, + QmlParser::Value *value); + void genBindingAssignment(QmlParser::Value *binding, + QmlParser::Property *prop, + QmlParser::Object *obj); + + + int componentTypeRef(); + + static int findSignalByName(const QMetaObject *, const QByteArray &name); + static bool canCoerce(int to, QmlParser::Object *from); + static QmlType *toQmlType(QmlParser::Object *from); + QStringList deferredProperties(QmlParser::Object *); struct IdReference { @@ -205,6 +230,7 @@ private: int instructionIdx; int idx; }; + void addId(const QString &, QmlParser::Object *); struct AliasReference { QmlParser::Object *object; @@ -215,28 +241,35 @@ private: QmlParser::Variant expression; QmlParser::Property *property; QmlParser::Value *value; + QByteArray compiledData; int instructionIdx; BindingContext bindingContext; }; + void addBindingReference(const BindingReference &); struct ComponentCompileState { - ComponentCompileState() : parserStatusCount(0), savedObjects(0), pushedProperties(0), root(0) {} + ComponentCompileState() + : parserStatusCount(0), savedObjects(0), + pushedProperties(0), root(0) {} QHash ids; int parserStatusCount; int savedObjects; int pushedProperties; QList bindings; + QHash bindingMap; QList aliases; QmlParser::Object *root; }; ComponentCompileState compileState; + void saveComponentState(); + ComponentCompileState componentState(QmlParser::Object *); + QHash savedCompileStates; + QList exceptions; QmlCompiledData *output; - }; - QT_END_NAMESPACE #endif // QMLCOMPILER_P_H diff --git a/src/declarative/qml/qmlcompositetypemanager.cpp b/src/declarative/qml/qmlcompositetypemanager.cpp index ef77803..c7ef765 100644 --- a/src/declarative/qml/qmlcompositetypemanager.cpp +++ b/src/declarative/qml/qmlcompositetypemanager.cpp @@ -110,8 +110,6 @@ QmlCompositeTypeData::toCompiledComponent(QmlEngine *engine) if (!compiler.compile(engine, this, compiledComponent)) { status = Error; errors = compiler.errors(); - for(int ii = 0; ii < errors.count(); ++ii) - errors[ii].setUrl(compiledComponent->url); compiledComponent->release(); compiledComponent = 0; } diff --git a/src/declarative/qml/qmlcontext.cpp b/src/declarative/qml/qmlcontext.cpp index 0b2742d..c3cee4c 100644 --- a/src/declarative/qml/qmlcontext.cpp +++ b/src/declarative/qml/qmlcontext.cpp @@ -73,6 +73,8 @@ void QmlContextPrivate::dump(int depth) void QmlContextPrivate::destroyed(QObject *obj) { + Q_Q(QmlContext); + defaultObjects.removeAll(obj); QVariant variantObject = QVariant::fromValue(obj); @@ -84,10 +86,9 @@ void QmlContextPrivate::destroyed(QObject *obj) } } - // ### Work around bug in shutdown - // for (int ii = 0; ii < notifies.count(); ++ii) { - // QMetaObject::activate(q, notifies[ii] + notifyIndex, 0); - // } + for (int ii = 0; ii < notifies.count(); ++ii) { + QMetaObject::activate(q, notifies[ii] + notifyIndex, 0); + } } void QmlContextPrivate::init() diff --git a/src/declarative/qml/qmldom.cpp b/src/declarative/qml/qmldom.cpp index 648eb36..b5d3c80 100644 --- a/src/declarative/qml/qmldom.cpp +++ b/src/declarative/qml/qmldom.cpp @@ -1379,7 +1379,6 @@ QmlDomValue::Type QmlDomValue::type() const return PropertyBinding; case QmlParser::Value::ValueSource: return ValueSource; - case QmlParser::Value::Component: case QmlParser::Value::CreatedObject: return Object; case QmlParser::Value::SignalObject: diff --git a/src/declarative/qml/qmlinstruction.cpp b/src/declarative/qml/qmlinstruction.cpp index 1647a12..863ff9a 100644 --- a/src/declarative/qml/qmlinstruction.cpp +++ b/src/declarative/qml/qmlinstruction.cpp @@ -54,13 +54,13 @@ void QmlCompiledComponent::dump(QmlInstruction *instr, int idx) switch(instr->type) { case QmlInstruction::Init: - qWarning() << idx << "\t" << line << "\t" << "INIT\t\t\t" << instr->init.dataSize; + qWarning() << idx << "\t" << line << "\t" << "INIT"; break; case QmlInstruction::CreateObject: qWarning() << idx << "\t" << line << "\t" << "CREATE\t\t\t" << instr->create.type << "\t\t\t" << types.at(instr->create.type).className; break; case QmlInstruction::SetId: - qWarning() << idx << "\t" << line << "\t" << "SETID\t\t\t" << instr->setId.value << "\t" << instr->setId.save << "\t\t" << primitives.at(instr->setId.value); + qWarning() << idx << "\t" << line << "\t" << "SETID\t\t\t" << instr->setId.value << "\t\t\t\t" << primitives.at(instr->setId.value); break; case QmlInstruction::SetDefault: qWarning() << idx << "\t" << line << "\t" << "SET_DEFAULT"; @@ -125,8 +125,11 @@ void QmlCompiledComponent::dump(QmlInstruction *instr, int idx) case QmlInstruction::StoreObject: qWarning() << idx << "\t" << line << "\t" << "STORE_OBJECT\t\t" << instr->storeObject.propertyIndex; break; - case QmlInstruction::AssignCustomType: - qWarning() << idx << "\t" << line << "\t" << "ASSIGN_CUSTOMTYPE\t\t" << instr->assignCustomType.propertyIndex << "\t" << instr->assignCustomType.valueIndex; + case QmlInstruction::StoreVariantObject: + qWarning() << idx << "\t" << line << "\t" << "STORE_VARIANT_OBJECT\t" << instr->storeObject.propertyIndex; + break; + case QmlInstruction::StoreInterface: + qWarning() << idx << "\t" << line << "\t" << "STORE_INTERFACE\t\t" << instr->storeObject.propertyIndex; break; case QmlInstruction::StoreSignal: qWarning() << idx << "\t" << line << "\t" << "STORE_SIGNAL\t\t" << instr->storeSignal.signalIndex << "\t" << instr->storeSignal.value << "\t\t" << primitives.at(instr->storeSignal.value); @@ -134,6 +137,9 @@ void QmlCompiledComponent::dump(QmlInstruction *instr, int idx) case QmlInstruction::AssignSignalObject: qWarning() << idx << "\t" << line << "\t" << "ASSIGN_SIGNAL_OBJECT\t" << instr->assignSignalObject.signal << "\t\t\t" << datas.at(instr->assignSignalObject.signal); break; + case QmlInstruction::AssignCustomType: + qWarning() << idx << "\t" << line << "\t" << "ASSIGN_CUSTOMTYPE\t\t" << instr->assignCustomType.propertyIndex << "\t" << instr->assignCustomType.valueIndex; + break; case QmlInstruction::StoreBinding: qWarning() << idx << "\t" << line << "\t" << "STORE_BINDING\t\t" << instr->assignBinding.property << "\t" << instr->assignBinding.value << "\t\t" << instr->assignBinding.context << primitives.at(instr->assignBinding.value); break; @@ -149,6 +155,12 @@ void QmlCompiledComponent::dump(QmlInstruction *instr, int idx) case QmlInstruction::CompleteObject: qWarning() << idx << "\t" << line << "\t" << "COMPLETE\t\t" << instr->complete.castValue; break; + case QmlInstruction::StoreObjectQmlList: + qWarning() << idx << "\t" << line << "\t" << "STORE_OBJECT_QMLLIST"; + break; + case QmlInstruction::StoreObjectQList: + qWarning() << idx << "\t" << line << "\t" << "STORE_OBJECT_QLIST"; + break; case QmlInstruction::AssignObjectList: qWarning() << idx << "\t" << line << "\t" << "ASSIGN_OBJECT_LIST\t"; break; @@ -170,14 +182,11 @@ void QmlCompiledComponent::dump(QmlInstruction *instr, int idx) case QmlInstruction::PopQList: qWarning() << idx << "\t" << line << "\t" << "POP_QLIST"; break; - case QmlInstruction::PushProperty: - qWarning() << idx << "\t" << line << "\t" << "PUSH_PROPERTY" << "\t\t" << instr->pushProperty.property; - break; - case QmlInstruction::StoreStackObject: - qWarning() << idx << "\t" << line << "\t" << "STORE_STACK_OBJ" << "\t" << instr->assignStackObject.property << "\t" << instr->assignStackObject.object; + case QmlInstruction::Defer: + qWarning() << idx << "\t" << line << "\t" << "DEFER" << "\t\t" << instr->defer.deferCount; break; default: - qWarning() << idx << "\t" << line << "\t" << "XXX UNKOWN INSTRUCTION"; + qWarning() << idx << "\t" << line << "\t" << "XXX UNKOWN INSTRUCTION" << "\t" << instr->type; break; } } diff --git a/src/declarative/qml/qmlinstruction_p.h b/src/declarative/qml/qmlinstruction_p.h index 40f9a32..39196a1 100644 --- a/src/declarative/qml/qmlinstruction_p.h +++ b/src/declarative/qml/qmlinstruction_p.h @@ -118,8 +118,6 @@ public: StoreSignal, /* storeSignal */ - // XXX need to handle storing objects in variants - // // Unresolved single assignment // @@ -154,14 +152,6 @@ public: // Deferred creation // Defer, /* defer */ - - // - // Expression optimizations - // - // PushProperty - Save the property for later use - // StoreStackObject - Assign the stack object (no checks) - PushProperty, /* pushProperty */ - StoreStackObject /* assignStackObject */ }; QmlInstruction() : line(0) {} @@ -170,7 +160,6 @@ public: unsigned short line; union { struct { - int dataSize; int bindingsSize; int parserStatusSize; } init; @@ -185,7 +174,6 @@ public: } storeMeta; struct { int value; - int save; } setId; struct { int property; @@ -198,7 +186,6 @@ public: } assignBinding; struct { int property; - bool isObject; } fetch; struct { int property; @@ -281,13 +268,6 @@ public: int id; } fetchAttached; struct { - int property; - } pushProperty; - struct { - int property; - int object; - } assignStackObject; - struct { int deferCount; } defer; }; diff --git a/src/declarative/qml/qmlmetaproperty.cpp b/src/declarative/qml/qmlmetaproperty.cpp index e158adf..6602021 100644 --- a/src/declarative/qml/qmlmetaproperty.cpp +++ b/src/declarative/qml/qmlmetaproperty.cpp @@ -663,9 +663,6 @@ void QmlMetaPropertyPrivate::writeValueProperty(const QVariant &value) return; } - if (!value.isValid()) - return; - int t = propertyType(); int vt = value.userType(); int category = propertyCategory(); @@ -684,19 +681,22 @@ void QmlMetaPropertyPrivate::writeValueProperty(const QVariant &value) QObject *o = QmlMetaType::toQObject(value); - if (!o) - return; + const QMetaObject *valMo = 0; - const QMetaObject *valMo = o->metaObject(); - const QMetaObject *propMo = QmlMetaType::rawMetaObjectForType(t); + if (o) { + + valMo = o->metaObject(); + const QMetaObject *propMo = QmlMetaType::rawMetaObjectForType(t); + + while (valMo) { + if (valMo == propMo) + break; + valMo = valMo->superClass(); + } - while (valMo) { - if (valMo == propMo) - break; - valMo = valMo->superClass(); } - if (valMo) { + if (valMo || !o) { void *args[] = { &o, 0 }; QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, diff --git a/src/declarative/qml/qmlparser.cpp b/src/declarative/qml/qmlparser.cpp index 8daab6a..02f229e 100644 --- a/src/declarative/qml/qmlparser.cpp +++ b/src/declarative/qml/qmlparser.cpp @@ -62,7 +62,8 @@ QT_BEGIN_NAMESPACE using namespace QmlParser; QmlParser::Object::Object() -: type(-1), metatype(0), extObjectData(0), defaultProperty(0) +: type(-1), metatype(0), extObjectData(0), defaultProperty(0), + parserStatusCast(-1) { } @@ -71,6 +72,10 @@ QmlParser::Object::~Object() if (defaultProperty) defaultProperty->release(); foreach(Property *prop, properties) prop->release(); + foreach(Property *prop, valueProperties) + prop->release(); + foreach(Property *prop, signalProperties) + prop->release(); } const QMetaObject *Object::metaObject() const @@ -90,6 +95,30 @@ QmlParser::Property *Object::getDefaultProperty() return defaultProperty; } +void QmlParser::Object::addValueProperty(Property *p) +{ + p->addref(); + valueProperties << p; +} + +void QmlParser::Object::addSignalProperty(Property *p) +{ + p->addref(); + signalProperties << p; +} + +void QmlParser::Object::addAttachedProperty(Property *p) +{ + p->addref(); + attachedProperties << p; +} + +void QmlParser::Object::addGroupedProperty(Property *p) +{ + p->addref(); + groupedProperties << p; +} + Property *QmlParser::Object::getProperty(const QByteArray &name, bool create) { if (!properties.contains(name)) { @@ -160,12 +189,13 @@ void QmlParser::Object::dump(int indent) const } QmlParser::Property::Property() -: parent(0), type(0), index(-1), value(0), isDefault(true) +: parent(0), type(0), index(-1), value(0), isDefault(true), isDeferred(false) { } QmlParser::Property::Property(const QByteArray &n) -: parent(0), type(0), index(-1), value(0), name(n), isDefault(false) +: parent(0), type(0), index(-1), value(0), name(n), isDefault(false), + isDeferred(false) { } @@ -187,6 +217,11 @@ void QmlParser::Property::addValue(Value *v) values << v; } +bool QmlParser::Property::isEmpty() const +{ + return !value && values.isEmpty(); +} + void QmlParser::Property::dump(int indent) const { QByteArray ba(indent * 4, ' '); @@ -232,9 +267,6 @@ void QmlParser::Value::dump(int indent) const case Value::SignalExpression: type = "SignalExpression"; break; - case Value::Component: - type = "Component"; - break; case Value::Id: type = "Id"; break; diff --git a/src/declarative/qml/qmlparser_p.h b/src/declarative/qml/qmlparser_p.h index 7550870..d96a43e 100644 --- a/src/declarative/qml/qmlparser_p.h +++ b/src/declarative/qml/qmlparser_p.h @@ -110,8 +110,8 @@ namespace QmlParser virtual ~Object(); // Type of the object. The integer is an index into the - // QmlCompiledData::types array, or -1 if the object is a fetched - // object. + // QmlCompiledData::types array, or -1 if the object is a property + // group. int type; // The url of this object if it is an external type. Used by the DOM QUrl url; @@ -131,6 +131,8 @@ namespace QmlParser // this type. Otherwise null QMetaObject *extObjectData; QAbstractDynamicMetaObject extObject; + QByteArray metadata; // Generated by compiler + QByteArray synthdata; // Generated by compiler Property *getDefaultProperty(); Property *getProperty(const QByteArray &name, bool create=true); @@ -138,6 +140,22 @@ namespace QmlParser Property *defaultProperty; QHash properties; + // Output of the compilation phase (these properties continue to exist + // in either the defaultProperty or properties members too) + void addValueProperty(Property *); + void addSignalProperty(Property *); + void addAttachedProperty(Property *); + void addGroupedProperty(Property *); + QList valueProperties; + QList signalProperties; + QList attachedProperties; + QList groupedProperties; + + // The bytes to cast instances by to get to the QmlParserStatus + // interface. -1 indicates the type doesn't support this interface. + // Set by the QmlCompiler. + int parserStatusCast; + LocationSpan location; struct DynamicProperty { @@ -242,8 +260,6 @@ namespace QmlParser SignalObject, // This is used as a signal expression assignment SignalExpression, - // This is used as an implicit component creation - Component, // This is used as an id assignment only Id }; @@ -281,6 +297,9 @@ namespace QmlParser // The metaobject index of this property, or -1 if unknown. int index; + // Returns true if this is an empty property - both value and values + // are unset. + bool isEmpty() const; // The list of values assigned to this property. Content in values // and value are mutually exclusive QList values; @@ -291,6 +310,9 @@ namespace QmlParser QByteArray name; // True if this property was accessed as the default property. bool isDefault; + // True if the setting of this property will be deferred. Set by the + // QmlCompiler + bool isDeferred; LocationSpan location; LocationRange listValueRange; diff --git a/src/declarative/qml/qmlvme.cpp b/src/declarative/qml/qmlvme.cpp index 2acf1e2..dfb066b 100644 --- a/src/declarative/qml/qmlvme.cpp +++ b/src/declarative/qml/qmlvme.cpp @@ -152,7 +152,6 @@ QObject *QmlVME::run(QStack &stack, QmlContext *ctxt, QmlCompiledComp QStack qliststack; QStack pushedProperties; - QObject **savedObjects = 0; vmeErrors.clear(); @@ -162,12 +161,6 @@ QObject *QmlVME::run(QStack &stack, QmlContext *ctxt, QmlCompiledComp switch(instr.type) { case QmlInstruction::Init: { - if (instr.init.dataSize) { - savedObjects = new QObject*[instr.init.dataSize]; - ::memset(savedObjects, 0, - sizeof(QObject *)*instr.init.dataSize); - } - if (instr.init.bindingsSize) bindValues = QmlEnginePrivate::SimpleList(instr.init.bindingsSize); if (instr.init.parserStatusSize) @@ -214,9 +207,6 @@ QObject *QmlVME::run(QStack &stack, QmlContext *ctxt, QmlCompiledComp QmlContext *ctxt = QmlContext::activeContext(); ctxt->setContextProperty(primitives.at(instr.setId.value), target); - - if (instr.setId.save != -1) - savedObjects[instr.setId.save] = target; } break; @@ -239,7 +229,16 @@ QObject *QmlVME::run(QStack &stack, QmlContext *ctxt, QmlCompiledComp case QmlInstruction::StoreMetaObject: { QObject *target = stack.top(); - new QmlVMEMetaObject(target, synthesizedMetaObjects.at(instr.storeMeta.data), &comp->primitives, instr.storeMeta.slotData, (const QmlVMEMetaData *)datas.at(instr.storeMeta.aliasData).constData(), comp); + + QMetaObject mo; + const QByteArray &metadata = datas.at(instr.storeMeta.data); + QMetaObjectBuilder::fromRelocatableData(&mo, 0, metadata); + + const QmlVMEMetaData *data = (const QmlVMEMetaData *)datas.at(instr.storeMeta.aliasData).constData(); + + (void)new QmlVMEMetaObject(target, &mo, data, comp); + + // new QmlVMEMetaObject(target, synthesizedMetaObjects.at(instr.storeMeta.data), &comp->primitives, instr.storeMeta.slotData, (const QmlVMEMetaData *)datas.at(instr.storeMeta.aliasData).constData(), comp); } break; @@ -545,15 +544,6 @@ QObject *QmlVME::run(QStack &stack, QmlContext *ctxt, QmlCompiledComp } break; - case QmlInstruction::PushProperty: - { - QObject *target = stack.top(); - QmlMetaProperty mp(target, instr.pushProperty.property, - QmlMetaProperty::Object); - pushedProperties.push(mp); - } - break; - case QmlInstruction::StoreCompiledBinding: { QObject *target = stack.top(); @@ -745,22 +735,12 @@ QObject *QmlVME::run(QStack &stack, QmlContext *ctxt, QmlCompiledComp QObject *target = stack.top(); QObject *obj = 0; - if (instr.fetch.isObject) { - // NOTE: This assumes a cast to QObject does not alter the - // object pointer - void *a[1]; - a[0] = &obj; - QMetaObject::metacall(target, QMetaObject::ReadProperty, - instr.fetch.property, a); - } else { - void *a[1]; - QVariant var; - a[0] = &var; - QMetaObject::metacall(target, QMetaObject::ReadProperty, - instr.fetch.property, a); - obj = QmlMetaType::toQObject(var); - - } + // NOTE: This assumes a cast to QObject does not alter the + // object pointer + void *a[1]; + a[0] = &obj; + QMetaObject::metacall(target, QMetaObject::ReadProperty, + instr.fetch.property, a); if (!obj) VME_EXCEPTION("Cannot set properties on" << target->metaObject()->property(instr.fetch.property).name() << "as it is null"); @@ -795,21 +775,6 @@ QObject *QmlVME::run(QStack &stack, QmlContext *ctxt, QmlCompiledComp } break; - case QmlInstruction::StoreStackObject: - { - const QmlMetaProperty &prop = - pushedProperties.at(instr.assignStackObject.property); - QObject *obj = savedObjects[instr.assignStackObject.object]; - - // NOTE: This assumes a cast to QObject does not alter the - // object pointer - void *a[1]; - a[0] = (void *)&obj; - QMetaObject::metacall(prop.object(), QMetaObject::WriteProperty, - prop.coreIndex(), a); - } - break; - default: qFatal("QmlCompiledComponent: Internal error - unknown instruction %d", instr.type); break; @@ -832,11 +797,6 @@ QObject *QmlVME::run(QStack &stack, QmlContext *ctxt, QmlCompiledComp if (parserStatus.count) ep->parserStatus << parserStatus; - comp->dumpPost(); - - if (savedObjects) - delete [] savedObjects; - if (stack.isEmpty()) return 0; else diff --git a/src/declarative/qml/qmlvmemetaobject.cpp b/src/declarative/qml/qmlvmemetaobject.cpp index 6d14689..33a31a4 100644 --- a/src/declarative/qml/qmlvmemetaobject.cpp +++ b/src/declarative/qml/qmlvmemetaobject.cpp @@ -53,12 +53,9 @@ QT_BEGIN_NAMESPACE QmlVMEMetaObject::QmlVMEMetaObject(QObject *obj, const QMetaObject *other, - QList *strData, - int slotData, const QmlVMEMetaData *meta, QmlRefCount *rc) -: object(obj), ref(rc), metaData(meta), slotData(strData), - slotDataIdx(slotData), parent(0) +: object(obj), ref(rc), metaData(meta), parent(0) { if (ref) ref->addref(); @@ -208,7 +205,11 @@ int QmlVMEMetaObject::metaCall(QMetaObject::Call c, int _id, void **a) id -= plainSignals; if (id < metaData->methodCount) { - QString code = slotData->at(id + slotDataIdx); + QmlVMEMetaData::MethodData *data = metaData->methodData() + id; + const QChar *body = + (const QChar *)(((const char*)metaData) + data->bodyOffset); + + QString code = QString::fromRawData(body, data->bodyLength); QmlContext *ctxt = qmlContext(object); if (0 == (metaData->methodData() + id)->parameterCount) { diff --git a/src/declarative/qml/qmlvmemetaobject_p.h b/src/declarative/qml/qmlvmemetaobject_p.h index 6421c3f..931d22c 100644 --- a/src/declarative/qml/qmlvmemetaobject_p.h +++ b/src/declarative/qml/qmlvmemetaobject_p.h @@ -78,6 +78,9 @@ struct QmlVMEMetaData struct MethodData { int parameterCount; + int bodyOffset; + int bodyLength; + int _dummy; }; PropertyData *propertyData() const { @@ -89,7 +92,7 @@ struct QmlVMEMetaData } MethodData *methodData() const { - return (MethodData *)(aliasData() + propertyCount); + return (MethodData *)(aliasData() + aliasCount); } }; @@ -97,7 +100,8 @@ class QmlRefCount; class QmlVMEMetaObject : public QAbstractDynamicMetaObject { public: - QmlVMEMetaObject(QObject *, const QMetaObject *, QList *, int slotData, const QmlVMEMetaData *data, QmlRefCount * = 0); + QmlVMEMetaObject(QObject *, const QMetaObject *, const QmlVMEMetaData *data, + QmlRefCount * = 0); ~QmlVMEMetaObject(); protected: @@ -114,8 +118,10 @@ private: QVariant *data; QBitArray aConnected; +#if 0 QList *slotData; int slotDataIdx; +#endif QAbstractDynamicMetaObject *parent; diff --git a/tests/auto/declarative/qmlbindengine/testtypes.h b/tests/auto/declarative/qmlbindengine/testtypes.h index df31f7a..f5b309e 100644 --- a/tests/auto/declarative/qmlbindengine/testtypes.h +++ b/tests/auto/declarative/qmlbindengine/testtypes.h @@ -8,8 +8,8 @@ class MyQmlObject : public QObject { Q_OBJECT - Q_PROPERTY(bool trueProperty READ trueProperty) - Q_PROPERTY(bool falseProperty READ falseProperty) + Q_PROPERTY(bool trueProperty READ trueProperty CONSTANT) + Q_PROPERTY(bool falseProperty READ falseProperty CONSTANT) Q_PROPERTY(QString stringProperty READ stringProperty WRITE setStringProperty NOTIFY stringChanged) Q_PROPERTY(QObject *objectProperty READ objectProperty WRITE setObjectProperty NOTIFY objectChanged); public: @@ -64,14 +64,14 @@ QML_DECLARE_TYPE(MyQmlObject); class MyQmlContainer : public QObject { Q_OBJECT - Q_PROPERTY(QList* children READ children) + Q_PROPERTY(QList* children READ children) public: MyQmlContainer() {} - QList *children() { return &m_children; } + QList *children() { return &m_children; } private: - QList m_children; + QList m_children; }; QML_DECLARE_TYPE(MyQmlContainer); @@ -94,8 +94,8 @@ public: class MyDefaultObject1 : public QObject { Q_OBJECT - Q_PROPERTY(int horseLegs READ horseLegs); - Q_PROPERTY(int antLegs READ antLegs); + Q_PROPERTY(int horseLegs READ horseLegs CONSTANT); + Q_PROPERTY(int antLegs READ antLegs CONSTANT); public: int horseLegs() const { return 4; } int antLegs() const { return 6; } @@ -104,8 +104,8 @@ public: class MyDefaultObject2 : public QObject { Q_OBJECT - Q_PROPERTY(int antLegs READ antLegs); - Q_PROPERTY(int emuLegs READ emuLegs); + Q_PROPERTY(int antLegs READ antLegs CONSTANT); + Q_PROPERTY(int emuLegs READ emuLegs CONSTANT); public: int antLegs() const { return 5; } // Had an accident int emuLegs() const { return 2; } @@ -114,8 +114,8 @@ public: class MyDefaultObject3 : public QObject { Q_OBJECT - Q_PROPERTY(int antLegs READ antLegs); - Q_PROPERTY(int humanLegs READ humanLegs); + Q_PROPERTY(int antLegs READ antLegs CONSTANT); + Q_PROPERTY(int humanLegs READ humanLegs CONSTANT); public: int antLegs() const { return 7; } // Mutant int humanLegs() const { return 2; } diff --git a/tests/auto/declarative/qmlparser/duplicateIDs.errors.txt b/tests/auto/declarative/qmlparser/duplicateIDs.errors.txt index b03f735..99f4c7c 100644 --- a/tests/auto/declarative/qmlparser/duplicateIDs.errors.txt +++ b/tests/auto/declarative/qmlparser/duplicateIDs.errors.txt @@ -1 +1 @@ -3:5:id is not unique +3:19:id is not unique diff --git a/tests/auto/declarative/qmlparser/failingComponent.errors.txt b/tests/auto/declarative/qmlparser/failingComponent.errors.txt index 12fb4e7..a18f2e7 100644 --- a/tests/auto/declarative/qmlparser/failingComponent.errors.txt +++ b/tests/auto/declarative/qmlparser/failingComponent.errors.txt @@ -1,2 +1,2 @@ -1:-1:Unable to create type FailingComponent -2:5:Cannot assign value to non-existant property "a" +2:5:Cannot assign to non-existant property "a" diff --git a/tests/auto/declarative/qmlparser/fakeDotProperty.errors.txt b/tests/auto/declarative/qmlparser/fakeDotProperty.errors.txt index a94b38e..25f22ce 100644 --- a/tests/auto/declarative/qmlparser/fakeDotProperty.errors.txt +++ b/tests/auto/declarative/qmlparser/fakeDotProperty.errors.txt @@ -1 +1 @@ -2:11:Cannot assign value to non-existant property "something" +2:5:Cannot nest non-QObject property "value" diff --git a/tests/auto/declarative/qmlparser/idProperty.txt b/tests/auto/declarative/qmlparser/idProperty.txt index 9c7d6fb..c3c2e50 100644 --- a/tests/auto/declarative/qmlparser/idProperty.txt +++ b/tests/auto/declarative/qmlparser/idProperty.txt @@ -2,6 +2,6 @@ MyContainer { property var object : MyObjectId MyTypeObject { - id: MyObjectId + id: "MyObjectId" } } diff --git a/tests/auto/declarative/qmlparser/invalidID.2.errors.txt b/tests/auto/declarative/qmlparser/invalidID.2.errors.txt index 6380750..9c54aab 100644 --- a/tests/auto/declarative/qmlparser/invalidID.2.errors.txt +++ b/tests/auto/declarative/qmlparser/invalidID.2.errors.txt @@ -1,2 +1,2 @@ -1:1:"" is not a valid id +2:5:"" is not a valid object id diff --git a/tests/auto/declarative/qmlparser/invalidID.3.errors.txt b/tests/auto/declarative/qmlparser/invalidID.3.errors.txt index 05937f0..36cd489 100644 --- a/tests/auto/declarative/qmlparser/invalidID.3.errors.txt +++ b/tests/auto/declarative/qmlparser/invalidID.3.errors.txt @@ -1 +1 @@ -2:5:The id property cannot be fetched +2:5:Invalid use of id property diff --git a/tests/auto/declarative/qmlparser/invalidID.4.errors.txt b/tests/auto/declarative/qmlparser/invalidID.4.errors.txt index 50c8960..bb811cf 100644 --- a/tests/auto/declarative/qmlparser/invalidID.4.errors.txt +++ b/tests/auto/declarative/qmlparser/invalidID.4.errors.txt @@ -1 +1 @@ -3:5:The object id may only be set once +3:5:Invalid use of id property diff --git a/tests/auto/declarative/qmlparser/invalidID.errors.txt b/tests/auto/declarative/qmlparser/invalidID.errors.txt index eed1869..7cefb7e 100644 --- a/tests/auto/declarative/qmlparser/invalidID.errors.txt +++ b/tests/auto/declarative/qmlparser/invalidID.errors.txt @@ -1 +1 @@ -1:1:"1" is not a valid id +2:5:"1" is not a valid object id diff --git a/tests/auto/declarative/qmlparser/missingSignal.errors.txt b/tests/auto/declarative/qmlparser/missingSignal.errors.txt index 5c612cc..bcee331 100644 --- a/tests/auto/declarative/qmlparser/missingSignal.errors.txt +++ b/tests/auto/declarative/qmlparser/missingSignal.errors.txt @@ -1 +1 @@ -2:5:Cannot assign binding to non-existant property "onClicked" +2:5:Cannot assign to non-existant property "onClicked" diff --git a/tests/auto/declarative/qmlparser/nonexistantProperty.1.errors.txt b/tests/auto/declarative/qmlparser/nonexistantProperty.1.errors.txt index e8f1a91..6f85946 100644 --- a/tests/auto/declarative/qmlparser/nonexistantProperty.1.errors.txt +++ b/tests/auto/declarative/qmlparser/nonexistantProperty.1.errors.txt @@ -1 +1 @@ -1:15:Cannot assign value to non-existant property "something" +1:15:Cannot assign to non-existant property "something" diff --git a/tests/auto/declarative/qmlparser/nonexistantProperty.2.errors.txt b/tests/auto/declarative/qmlparser/nonexistantProperty.2.errors.txt index c154f91..8d6dfb4 100644 --- a/tests/auto/declarative/qmlparser/nonexistantProperty.2.errors.txt +++ b/tests/auto/declarative/qmlparser/nonexistantProperty.2.errors.txt @@ -1 +1 @@ -2:5:Cannot assign value to non-existant property "something" +2:5:Cannot assign to non-existant property "something" diff --git a/tests/auto/declarative/qmlparser/nonexistantProperty.3.errors.txt b/tests/auto/declarative/qmlparser/nonexistantProperty.3.errors.txt index a254d7d..8d6dfb4 100644 --- a/tests/auto/declarative/qmlparser/nonexistantProperty.3.errors.txt +++ b/tests/auto/declarative/qmlparser/nonexistantProperty.3.errors.txt @@ -1 +1 @@ -2:5:Cannot assign binding to non-existant property "something" +2:5:Cannot assign to non-existant property "something" diff --git a/tests/auto/declarative/qmlparser/nonexistantProperty.4.errors.txt b/tests/auto/declarative/qmlparser/nonexistantProperty.4.errors.txt index a254d7d..8d6dfb4 100644 --- a/tests/auto/declarative/qmlparser/nonexistantProperty.4.errors.txt +++ b/tests/auto/declarative/qmlparser/nonexistantProperty.4.errors.txt @@ -1 +1 @@ -2:5:Cannot assign binding to non-existant property "something" +2:5:Cannot assign to non-existant property "something" diff --git a/tests/auto/declarative/qmlparser/nonexistantProperty.6.errors.txt b/tests/auto/declarative/qmlparser/nonexistantProperty.6.errors.txt index 3183b6d..fac833e 100644 --- a/tests/auto/declarative/qmlparser/nonexistantProperty.6.errors.txt +++ b/tests/auto/declarative/qmlparser/nonexistantProperty.6.errors.txt @@ -1 +1 @@ -2:-1:Cannot assign to default property +2:5:Cannot assign to non-existant default property diff --git a/tests/auto/declarative/qmlparser/readOnly.1.errors.txt b/tests/auto/declarative/qmlparser/readOnly.1.errors.txt index 89009ce..8608370 100644 --- a/tests/auto/declarative/qmlparser/readOnly.1.errors.txt +++ b/tests/auto/declarative/qmlparser/readOnly.1.errors.txt @@ -1 +1 @@ -2:21:Cannot assign value "Hello World" to the read-only property readOnlyString +2:21:Invalid property assignment: read-only property diff --git a/tests/auto/declarative/qmlparser/readOnly.2.errors.txt b/tests/auto/declarative/qmlparser/readOnly.2.errors.txt index ab27946..633d56f 100644 --- a/tests/auto/declarative/qmlparser/readOnly.2.errors.txt +++ b/tests/auto/declarative/qmlparser/readOnly.2.errors.txt @@ -1 +1 @@ -2:-1:Cannot assign a binding to read-only property "readOnlyString" +2:5:Invalid property assignment: read-only property diff --git a/tests/auto/declarative/qmlparser/tst_qmlparser.cpp b/tests/auto/declarative/qmlparser/tst_qmlparser.cpp index cdc2a72..7023263 100644 --- a/tests/auto/declarative/qmlparser/tst_qmlparser.cpp +++ b/tests/auto/declarative/qmlparser/tst_qmlparser.cpp @@ -98,7 +98,7 @@ void tst_qmlparser::errors_data() QTest::newRow("nonExistantProperty.3") << "nonexistantProperty.3.txt" << "nonexistantProperty.3.errors.txt" << false; QTest::newRow("nonExistantProperty.4") << "nonexistantProperty.4.txt" << "nonexistantProperty.4.errors.txt" << false; QTest::newRow("nonExistantProperty.5") << "nonexistantProperty.5.txt" << "nonexistantProperty.5.errors.txt" << false; - QTest::newRow("nonExistantProperty.6") << "nonexistantProperty.6.txt" << "nonexistantProperty.6.errors.txt" << true; + QTest::newRow("nonExistantProperty.6") << "nonexistantProperty.6.txt" << "nonexistantProperty.6.errors.txt" << false; QTest::newRow("wrongType (string for int)") << "wrongType.1.txt" << "wrongType.1.errors.txt" << false; QTest::newRow("wrongType (int for bool)") << "wrongType.2.txt" << "wrongType.2.errors.txt" << false; @@ -117,7 +117,7 @@ void tst_qmlparser::errors_data() QTest::newRow("wrongType (int for string)") << "wrongType.14.txt" << "wrongType.14.errors.txt" << false; QTest::newRow("readOnly.1") << "readOnly.1.txt" << "readOnly.1.errors.txt" << false; - QTest::newRow("readOnly.2") << "readOnly.2.txt" << "readOnly.2.errors.txt" << true; + QTest::newRow("readOnly.2") << "readOnly.2.txt" << "readOnly.2.errors.txt" << false; QTest::newRow("listAssignment.1") << "listAssignment.1.txt" << "listAssignment.1.errors.txt" << false; QTest::newRow("listAssignment.2") << "listAssignment.2.txt" << "listAssignment.2.errors.txt" << false; @@ -344,8 +344,8 @@ void tst_qmlparser::dynamicProperties() QVERIFY(object != 0); QCOMPARE(object->property("intProperty"), QVariant(10)); QCOMPARE(object->property("boolProperty"), QVariant(false)); - QCOMPARE(object->property("doubleProperty"), QVariant((float)-10.1)); - QCOMPARE(object->property("realProperty"), QVariant((float)-19.9)); + QCOMPARE(object->property("doubleProperty"), QVariant(-10.1)); + QCOMPARE(object->property("realProperty"), QVariant((qreal)-19.9)); QCOMPARE(object->property("stringProperty"), QVariant("Hello World!")); QCOMPARE(object->property("colorProperty"), QVariant(QColor("red"))); QCOMPARE(object->property("dateProperty"), QVariant(QDate(1945, 9, 2))); diff --git a/tests/auto/declarative/qmlparser/unsupportedProperty.errors.txt b/tests/auto/declarative/qmlparser/unsupportedProperty.errors.txt index a067ecb..7ccfc75 100644 --- a/tests/auto/declarative/qmlparser/unsupportedProperty.errors.txt +++ b/tests/auto/declarative/qmlparser/unsupportedProperty.errors.txt @@ -1 +1 @@ -2:5:Cannot assign value to property matrix of unknown type +2:13:Invalid property assignment: unknown type QVariant::QMatrix diff --git a/tests/auto/declarative/qmlparser/wrongType.1.errors.txt b/tests/auto/declarative/qmlparser/wrongType.1.errors.txt index 8976ee1..194da94 100644 --- a/tests/auto/declarative/qmlparser/wrongType.1.errors.txt +++ b/tests/auto/declarative/qmlparser/wrongType.1.errors.txt @@ -1 +1 @@ -2:12:Cannot assign value "hello" to property value +2:12:Invalid property assignment: int expected diff --git a/tests/auto/declarative/qmlparser/wrongType.10.errors.txt b/tests/auto/declarative/qmlparser/wrongType.10.errors.txt index 562cd6c..f391e2a 100644 --- a/tests/auto/declarative/qmlparser/wrongType.10.errors.txt +++ b/tests/auto/declarative/qmlparser/wrongType.10.errors.txt @@ -1 +1 @@ -2:23:Cannot assign value "12" to property dateTimeProperty +2:23:Invalid property assignment: datetime expected diff --git a/tests/auto/declarative/qmlparser/wrongType.11.errors.txt b/tests/auto/declarative/qmlparser/wrongType.11.errors.txt index 24d27d5..9f5ebc9 100644 --- a/tests/auto/declarative/qmlparser/wrongType.11.errors.txt +++ b/tests/auto/declarative/qmlparser/wrongType.11.errors.txt @@ -1 +1 @@ -2:20:Cannot assign value "apples" to property pointProperty +2:20:Invalid property assignment: point expected diff --git a/tests/auto/declarative/qmlparser/wrongType.12.errors.txt b/tests/auto/declarative/qmlparser/wrongType.12.errors.txt index b57e70e..4bbb2bf 100644 --- a/tests/auto/declarative/qmlparser/wrongType.12.errors.txt +++ b/tests/auto/declarative/qmlparser/wrongType.12.errors.txt @@ -1 +1 @@ -2:19:Cannot assign value "red" to property sizeProperty +2:19:Invalid property assignment: size expected diff --git a/tests/auto/declarative/qmlparser/wrongType.13.errors.txt b/tests/auto/declarative/qmlparser/wrongType.13.errors.txt index 7ff4bf3..194da94 100644 --- a/tests/auto/declarative/qmlparser/wrongType.13.errors.txt +++ b/tests/auto/declarative/qmlparser/wrongType.13.errors.txt @@ -1 +1 @@ -2:12:Cannot assign value "12" to property value +2:12:Invalid property assignment: int expected diff --git a/tests/auto/declarative/qmlparser/wrongType.14.errors.txt b/tests/auto/declarative/qmlparser/wrongType.14.errors.txt index ec41e01..f90b8c6 100644 --- a/tests/auto/declarative/qmlparser/wrongType.14.errors.txt +++ b/tests/auto/declarative/qmlparser/wrongType.14.errors.txt @@ -1 +1 @@ -2:23:Cannot assign value 10 to property stringProperty +2:21:Invalid property assignment: string expected diff --git a/tests/auto/declarative/qmlparser/wrongType.2.errors.txt b/tests/auto/declarative/qmlparser/wrongType.2.errors.txt index 301d258..4353165 100644 --- a/tests/auto/declarative/qmlparser/wrongType.2.errors.txt +++ b/tests/auto/declarative/qmlparser/wrongType.2.errors.txt @@ -1 +1 @@ -2:14:Cannot assign value "5" to property enabled +2:14:Invalid property assignment: boolean expected diff --git a/tests/auto/declarative/qmlparser/wrongType.3.errors.txt b/tests/auto/declarative/qmlparser/wrongType.3.errors.txt index 3afcc2b..87b4eed 100644 --- a/tests/auto/declarative/qmlparser/wrongType.3.errors.txt +++ b/tests/auto/declarative/qmlparser/wrongType.3.errors.txt @@ -1 +1 @@ -2:11:Cannot assign value "5,5x10" to property rect +2:11:Invalid property assignment: rect expected diff --git a/tests/auto/declarative/qmlparser/wrongType.4.errors.txt b/tests/auto/declarative/qmlparser/wrongType.4.errors.txt index 6bf88be..57a0744 100644 --- a/tests/auto/declarative/qmlparser/wrongType.4.errors.txt +++ b/tests/auto/declarative/qmlparser/wrongType.4.errors.txt @@ -1 +1 @@ -2:19:Cannot assign value "InvalidEnumName" to property enumProperty +2:19:Invalid property assignment: unknown enumeration diff --git a/tests/auto/declarative/qmlparser/wrongType.5.errors.txt b/tests/auto/declarative/qmlparser/wrongType.5.errors.txt index 0e40d84..0023d1d 100644 --- a/tests/auto/declarative/qmlparser/wrongType.5.errors.txt +++ b/tests/auto/declarative/qmlparser/wrongType.5.errors.txt @@ -1 +1 @@ -2:19:Cannot assign value "-13" to property uintProperty +2:19:Invalid property assignment: unsigned int expected diff --git a/tests/auto/declarative/qmlparser/wrongType.6.errors.txt b/tests/auto/declarative/qmlparser/wrongType.6.errors.txt index 9692997..06349e7 100644 --- a/tests/auto/declarative/qmlparser/wrongType.6.errors.txt +++ b/tests/auto/declarative/qmlparser/wrongType.6.errors.txt @@ -1 +1 @@ -2:19:Cannot assign value "Hello" to property realProperty +2:19:Invalid property assignment: double expected diff --git a/tests/auto/declarative/qmlparser/wrongType.7.errors.txt b/tests/auto/declarative/qmlparser/wrongType.7.errors.txt index f44073a..e053f3b 100644 --- a/tests/auto/declarative/qmlparser/wrongType.7.errors.txt +++ b/tests/auto/declarative/qmlparser/wrongType.7.errors.txt @@ -1 +1 @@ -2:20:Cannot assign value "12" to property colorProperty +2:20:Invalid property assignment: color expected diff --git a/tests/auto/declarative/qmlparser/wrongType.8.errors.txt b/tests/auto/declarative/qmlparser/wrongType.8.errors.txt index 8a45ffb..b11f92b 100644 --- a/tests/auto/declarative/qmlparser/wrongType.8.errors.txt +++ b/tests/auto/declarative/qmlparser/wrongType.8.errors.txt @@ -1 +1 @@ -2:19:Cannot assign value "12" to property dateProperty +2:19:Invalid property assignment: date expected diff --git a/tests/auto/declarative/qmlparser/wrongType.9.errors.txt b/tests/auto/declarative/qmlparser/wrongType.9.errors.txt index cba3339..419a5ce 100644 --- a/tests/auto/declarative/qmlparser/wrongType.9.errors.txt +++ b/tests/auto/declarative/qmlparser/wrongType.9.errors.txt @@ -1 +1 @@ -2:19:Cannot assign value "12" to property timeProperty +2:19:Invalid property assignment: time expected -- cgit v0.12 From 958dc50e2b0fe2e875a704554438be75907ed3c5 Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Wed, 15 Jul 2009 17:53:25 +1000 Subject: Use a function object when evaluating bindings --- src/declarative/qml/qmlexpression.cpp | 18 +++++++++++++----- src/declarative/qml/qmlexpression_p.h | 4 ++++ 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/src/declarative/qml/qmlexpression.cpp b/src/declarative/qml/qmlexpression.cpp index 84352b8..3d8ee37 100644 --- a/src/declarative/qml/qmlexpression.cpp +++ b/src/declarative/qml/qmlexpression.cpp @@ -52,17 +52,17 @@ QT_BEGIN_NAMESPACE DEFINE_BOOL_CONFIG_OPTION(qmlDebugger, QML_DEBUGGER) QmlExpressionPrivate::QmlExpressionPrivate(QmlExpression *b) -: q(b), ctxt(0), sseData(0), proxy(0), me(0), trackChange(false), line(-1), id(0), log(0) +: q(b), ctxt(0), expressionFunctionValid(false), sseData(0), proxy(0), me(0), trackChange(false), line(-1), id(0), log(0) { } QmlExpressionPrivate::QmlExpressionPrivate(QmlExpression *b, void *expr, QmlRefCount *rc) -: q(b), ctxt(0), sse((const char *)expr, rc), sseData(0), proxy(0), me(0), trackChange(true), line(-1), id(0), log(0) +: q(b), ctxt(0), expressionFunctionValid(false), sse((const char *)expr, rc), sseData(0), proxy(0), me(0), trackChange(true), line(-1), id(0), log(0) { } QmlExpressionPrivate::QmlExpressionPrivate(QmlExpression *b, const QString &expr) -: q(b), ctxt(0), expression(expr), sseData(0), proxy(0), me(0), trackChange(true), line(-1), id(0), log(0) +: q(b), ctxt(0), expression(expr), expressionFunctionValid(false), sseData(0), proxy(0), me(0), trackChange(true), line(-1), id(0), log(0) { } @@ -177,6 +177,8 @@ void QmlExpression::setExpression(const QString &expression) delete d->proxy; d->proxy = 0; d->expression = expression; + d->expressionFunctionValid = false; + d->expressionFunction = QScriptValue(); d->sse.clear(); } @@ -234,8 +236,14 @@ QVariant QmlExpressionPrivate::evalQtScript() for (int i = ctxtPriv->scopeChain.size() - 1; i > -1; --i) scriptEngine->currentContext()->pushScope(ctxtPriv->scopeChain.at(i)); - QScriptValue svalue = - scriptEngine->evaluate(expression, fileName.toString(), line); + if (!expressionFunctionValid) { + expressionFunction = + scriptEngine->evaluate("function() {" +expression+"}", + fileName.toString(), line); + expressionFunctionValid = true; + } + + QScriptValue svalue = expressionFunction.call(); if (scriptEngine->hasUncaughtException()) { if (scriptEngine->uncaughtException().isError()){ diff --git a/src/declarative/qml/qmlexpression_p.h b/src/declarative/qml/qmlexpression_p.h index 5883125..09745a3 100644 --- a/src/declarative/qml/qmlexpression_p.h +++ b/src/declarative/qml/qmlexpression_p.h @@ -55,6 +55,7 @@ #include "qmlbasicscript_p.h" #include "qmlexpression.h" +#include QT_BEGIN_NAMESPACE @@ -73,6 +74,9 @@ public: QmlExpression *q; QmlContext *ctxt; QString expression; + bool expressionFunctionValid; + QScriptValue expressionFunction; + QmlBasicScript sse; void *sseData; QmlExpressionBindProxy *proxy; -- cgit v0.12 From c1f79fb0b4b778a2f41204aa62711060a3b021fc Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Wed, 15 Jul 2009 17:57:50 +1000 Subject: Fix memory leak --- src/declarative/qml/qmlparser.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/declarative/qml/qmlparser.cpp b/src/declarative/qml/qmlparser.cpp index 02f229e..8ee3b4e 100644 --- a/src/declarative/qml/qmlparser.cpp +++ b/src/declarative/qml/qmlparser.cpp @@ -76,6 +76,10 @@ QmlParser::Object::~Object() prop->release(); foreach(Property *prop, signalProperties) prop->release(); + foreach(Property *prop, attachedProperties) + prop->release(); + foreach(Property *prop, groupedProperties) + prop->release(); } const QMetaObject *Object::metaObject() const -- cgit v0.12 From 9b427652044114a1a77f7c1a32526d570f2bb3e8 Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Wed, 15 Jul 2009 18:21:56 +1000 Subject: Revert "Use a function object when evaluating bindings" Turns out this simple approach doesn't work. Fortunately we have a volunteer to do it properly. This reverts commit 958dc50e2b0fe2e875a704554438be75907ed3c5. --- src/declarative/qml/qmlexpression.cpp | 18 +++++------------- src/declarative/qml/qmlexpression_p.h | 4 ---- 2 files changed, 5 insertions(+), 17 deletions(-) diff --git a/src/declarative/qml/qmlexpression.cpp b/src/declarative/qml/qmlexpression.cpp index 3d8ee37..84352b8 100644 --- a/src/declarative/qml/qmlexpression.cpp +++ b/src/declarative/qml/qmlexpression.cpp @@ -52,17 +52,17 @@ QT_BEGIN_NAMESPACE DEFINE_BOOL_CONFIG_OPTION(qmlDebugger, QML_DEBUGGER) QmlExpressionPrivate::QmlExpressionPrivate(QmlExpression *b) -: q(b), ctxt(0), expressionFunctionValid(false), sseData(0), proxy(0), me(0), trackChange(false), line(-1), id(0), log(0) +: q(b), ctxt(0), sseData(0), proxy(0), me(0), trackChange(false), line(-1), id(0), log(0) { } QmlExpressionPrivate::QmlExpressionPrivate(QmlExpression *b, void *expr, QmlRefCount *rc) -: q(b), ctxt(0), expressionFunctionValid(false), sse((const char *)expr, rc), sseData(0), proxy(0), me(0), trackChange(true), line(-1), id(0), log(0) +: q(b), ctxt(0), sse((const char *)expr, rc), sseData(0), proxy(0), me(0), trackChange(true), line(-1), id(0), log(0) { } QmlExpressionPrivate::QmlExpressionPrivate(QmlExpression *b, const QString &expr) -: q(b), ctxt(0), expression(expr), expressionFunctionValid(false), sseData(0), proxy(0), me(0), trackChange(true), line(-1), id(0), log(0) +: q(b), ctxt(0), expression(expr), sseData(0), proxy(0), me(0), trackChange(true), line(-1), id(0), log(0) { } @@ -177,8 +177,6 @@ void QmlExpression::setExpression(const QString &expression) delete d->proxy; d->proxy = 0; d->expression = expression; - d->expressionFunctionValid = false; - d->expressionFunction = QScriptValue(); d->sse.clear(); } @@ -236,14 +234,8 @@ QVariant QmlExpressionPrivate::evalQtScript() for (int i = ctxtPriv->scopeChain.size() - 1; i > -1; --i) scriptEngine->currentContext()->pushScope(ctxtPriv->scopeChain.at(i)); - if (!expressionFunctionValid) { - expressionFunction = - scriptEngine->evaluate("function() {" +expression+"}", - fileName.toString(), line); - expressionFunctionValid = true; - } - - QScriptValue svalue = expressionFunction.call(); + QScriptValue svalue = + scriptEngine->evaluate(expression, fileName.toString(), line); if (scriptEngine->hasUncaughtException()) { if (scriptEngine->uncaughtException().isError()){ diff --git a/src/declarative/qml/qmlexpression_p.h b/src/declarative/qml/qmlexpression_p.h index 09745a3..5883125 100644 --- a/src/declarative/qml/qmlexpression_p.h +++ b/src/declarative/qml/qmlexpression_p.h @@ -55,7 +55,6 @@ #include "qmlbasicscript_p.h" #include "qmlexpression.h" -#include QT_BEGIN_NAMESPACE @@ -74,9 +73,6 @@ public: QmlExpression *q; QmlContext *ctxt; QString expression; - bool expressionFunctionValid; - QScriptValue expressionFunction; - QmlBasicScript sse; void *sseData; QmlExpressionBindProxy *proxy; -- cgit v0.12 From fa04625271c725deb669500a8196a07f0c1683b5 Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Wed, 15 Jul 2009 18:34:13 +1000 Subject: Missing file --- src/declarative/qml/qmlcompileddata.cpp | 211 ++++++++++++++++++++++++++++++++ 1 file changed, 211 insertions(+) create mode 100644 src/declarative/qml/qmlcompileddata.cpp diff --git a/src/declarative/qml/qmlcompileddata.cpp b/src/declarative/qml/qmlcompileddata.cpp new file mode 100644 index 0000000..5c47d62 --- /dev/null +++ b/src/declarative/qml/qmlcompileddata.cpp @@ -0,0 +1,211 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmlcompiler_p.h" +#include "qmlengine.h" +#include "qmlcomponent.h" +#include "qmlcomponent_p.h" +#include "qmlcompiledcomponent_p.h" +#include "qmlcontext.h" +#include "qmlcontext_p.h" +#include + +QT_BEGIN_NAMESPACE + +int QmlCompiledData::pack(const char *data, size_t size) +{ + const char *p = packData.constData(); + unsigned int ps = packData.size(); + + for (unsigned int ii = 0; (ii + size) <= ps; ii += sizeof(int)) { + if (0 == ::memcmp(p + ii, data, size)) + return ii; + } + + int rv = packData.size(); + packData.append(data, size); + return rv; +} + +int QmlCompiledData::indexForString(const QString &data) +{ + int idx = primitives.indexOf(data); + if (idx == -1) { + idx = primitives.count(); + primitives << data; + } + return idx; +} + +int QmlCompiledData::indexForByteArray(const QByteArray &data) +{ + int idx = datas.indexOf(data); + if (idx == -1) { + idx = datas.count(); + datas << data; + } + return idx; +} + +int QmlCompiledData::indexForFloat(float *data, int count) +{ + Q_ASSERT(count > 0); + + for (int ii = 0; ii <= floatData.count() - count; ++ii) { + bool found = true; + for (int jj = 0; jj < count; ++jj) { + if (floatData.at(ii + jj) != data[jj]) { + found = false; + break; + } + } + + if (found) + return ii; + } + + int idx = floatData.count(); + for (int ii = 0; ii < count; ++ii) + floatData << data[ii]; + + return idx; +} + +int QmlCompiledData::indexForInt(int *data, int count) +{ + Q_ASSERT(count > 0); + + for (int ii = 0; ii <= intData.count() - count; ++ii) { + bool found = true; + for (int jj = 0; jj < count; ++jj) { + if (intData.at(ii + jj) != data[jj]) { + found = false; + break; + } + } + + if (found) + return ii; + } + + int idx = intData.count(); + for (int ii = 0; ii < count; ++ii) + intData << data[ii]; + + return idx; +} + +int QmlCompiledData::indexForLocation(const QmlParser::Location &l) +{ + // ### FIXME + int rv = locations.count(); + locations << l; + return rv; +} + +int QmlCompiledData::indexForLocation(const QmlParser::LocationSpan &l) +{ + // ### FIXME + int rv = locations.count(); + locations << l.start << l.end; + return rv; +} + +QmlCompiledData::QmlCompiledData() +{ +} + +QmlCompiledData::QmlCompiledData(const QmlCompiledData &other) +{ + *this = other; +} + +QmlCompiledData::~QmlCompiledData() +{ + for (int ii = 0; ii < types.count(); ++ii) { + if (types.at(ii).ref) + types.at(ii).ref->release(); + } +} + +QmlCompiledData &QmlCompiledData::operator=(const QmlCompiledData &other) +{ + types = other.types; + root = other.root; + primitives = other.primitives; + floatData = other.floatData; + intData = other.intData; + customTypeData = other.customTypeData; + datas = other.datas; + bytecode = other.bytecode; + return *this; +} + +QObject *QmlCompiledData::TypeReference::createInstance(QmlContext *ctxt) const +{ + if (type) { + QObject *rv = type->create(); + if (rv) + QmlEngine::setContextForObject(rv, ctxt); + return rv; + } else { + Q_ASSERT(component); + QObject *rv = component->create(ctxt); + QmlContext *ctxt = qmlContext(rv); + if(ctxt) { + static_cast(QObjectPrivate::get(ctxt))->typeName = className; + } + return rv; + } +} + +const QMetaObject *QmlCompiledData::TypeReference::metaObject() const +{ + if (type) { + return type->metaObject(); + } else { + Q_ASSERT(component); + return &static_cast(QObjectPrivate::get(component))->cc->root; + } +} + + +QT_END_NAMESPACE -- cgit v0.12 From 09e9472d5548b21d31c6b246babb3e8840cf45c5 Mon Sep 17 00:00:00 2001 From: Alan Alpert Date: Wed, 15 Jul 2009 18:57:18 +1000 Subject: Restyle SameGame demo based on feedback -Uses a more familar rule set -Default theme swapped -Sizing altered. Now the tiles are 40x40 so as to be able to be pretty and have shiny animations, board size is set by what can fit in the game canvas. --- demos/declarative/samegame/SameGame.qml | 11 ++- demos/declarative/samegame/content/BoomBlock.qml | 17 +---- demos/declarative/samegame/content/FastBlock.qml | 14 ---- demos/declarative/samegame/content/samegame.js | 91 ++++++++++++++++++------ 4 files changed, 80 insertions(+), 53 deletions(-) diff --git a/demos/declarative/samegame/SameGame.qml b/demos/declarative/samegame/SameGame.qml index 0e5bb0f..c929c91 100644 --- a/demos/declarative/samegame/SameGame.qml +++ b/demos/declarative/samegame/SameGame.qml @@ -1,17 +1,22 @@ import "content" Rect { - width: 400 + width: 460 height: 700 color: "white" Script { source: "content/samegame.js" } Rect{ property int score: 0 - x:20; y:20; width:360; height:600; id: gameCanvas; + y:20; width:400; height:600; id: gameCanvas; + //For Fixed Size + anchors.horizontalCenter: parent.horizontalCenter + //For flexible width + //anchors.left: parent.left; anchors.leftMargin: 30 + //anchors.right: parent.right; anchors.rightMargin: 30 color: "white" pen.width: 1 Image { id:background; - source: "content/pics/qtlogo.png" + source: "content/pics/background.png" anchors.fill: parent } diff --git a/demos/declarative/samegame/content/BoomBlock.qml b/demos/declarative/samegame/content/BoomBlock.qml index 5eaaade..68e0e1a 100644 --- a/demos/declarative/samegame/content/BoomBlock.qml +++ b/demos/declarative/samegame/content/BoomBlock.qml @@ -5,9 +5,8 @@ Item { id:block property int targetX: 0 property int targetY: 0 - x: targetX + x: Follow { source: targetX; spring: 1.2; damping: 0.1 } y: Follow { source: targetY; spring: 1.2; damping: 0.1 } - //y: Behavior { NumberAnimation { properties:"y"; duration: 200 } } Image { id: img source: {if(type==0){"pics/redStone.png";}else if(type==1){"pics/blueStone.png";}else{"pics/greenStone.png";}} @@ -31,18 +30,4 @@ Item { id:block SetProperties { target: img; opacity: 0 } } ] -// transitions: [ -// Transition { -// fromState: "SpawnState" -// NumberAnimation { properties: "opacity"; duration: 200 } -// }, -// Transition { -// toState: "DeathState" -// SequentialAnimation { -// NumberAnimation { properties: "opacity"; duration: 200 } -// //TODO: Warning about following line, if it works -// //RunScriptAction { script: page.destroy() } -// } -// } -// ] } diff --git a/demos/declarative/samegame/content/FastBlock.qml b/demos/declarative/samegame/content/FastBlock.qml index 3d14959..04eb59b 100644 --- a/demos/declarative/samegame/content/FastBlock.qml +++ b/demos/declarative/samegame/content/FastBlock.qml @@ -24,18 +24,4 @@ Rect { id:block SetProperties { target: block; opacity: 0 } } ] -// transitions: [ -// Transition { -// fromState: "SpawnState" -// NumberAnimation { properties: "opacity"; duration: 200 } -// }, -// Transition { -// toState: "DeathState" -// SequentialAnimation { -// NumberAnimation { properties: "opacity"; duration: 200 } -// //TODO: Warning about following line, if it works -// //RunScriptAction { script: page.destroy() } -// } -// } -// ] } diff --git a/demos/declarative/samegame/content/samegame.js b/demos/declarative/samegame/content/samegame.js index f3bb5b6..fe5ac87 100644 --- a/demos/declarative/samegame/content/samegame.js +++ b/demos/declarative/samegame/content/samegame.js @@ -1,11 +1,11 @@ /* This script file handles the game logic */ -var maxIdx = 18/2;//Nums are for tileSize 20 (desired tile size but too slow) -var maxY = 30/2; +var maxX = 10;//Nums are for tileSize 40 +var maxY = 15; var tileSize = 40; -var maxIndex = maxIdx*maxY; +var maxIndex = maxX*maxY; var board = new Array(maxIndex); -var tileSrc = "content/FastBlock.qml"; +var tileSrc = "content/BoomBlock.qml"; var backSrc = "content/pics/background.png"; var swapped = false; @@ -26,20 +26,27 @@ function swapTileSrc(){ } function index(xIdx,yIdx){ - return xIdx + (yIdx * maxIdx); + return xIdx + (yIdx * maxX); } function initBoard() { + for(i = 0; i= maxIdx || xIdx < 0 || yIdx >= maxY || yIdx < 0) + if(xIdx >= maxX || xIdx < 0 || yIdx >= maxY || yIdx < 0) return; if(board[index(xIdx, yIdx)] == null) return; removed = 0; + floodBoard = new Array(maxIndex); floodKill(xIdx,yIdx, -1); - gameCanvas.score += removed * removed; + if(removed <= 0) + return; + gameCanvas.score += (removed - 1) * (removed - 1); shuffleDown(); + victoryCheck(); } function floodKill(xIdx,yIdx,type) { - if(xIdx >= maxIdx || xIdx < 0 || yIdx >= maxY || yIdx < 0) + if(xIdx >= maxX || xIdx < 0 || yIdx >= maxY || yIdx < 0) + return; + if(floodBoard[index(xIdx, yIdx)] == 1) return; if(board[index(xIdx, yIdx)] == null) return; + var first = false; if(type == -1){ type = board[index(xIdx,yIdx)].type; + first = true; }else{ if(type != board[index(xIdx,yIdx)].type) return; } - board[index(xIdx,yIdx)].dying = true; - board[index(xIdx,yIdx)] = null;//They'll have to destroy themselves(can we do that?) - removed += 1; + floodBoard[index(xIdx, yIdx)] = 1; floodKill(xIdx+1,yIdx,type); floodKill(xIdx-1,yIdx,type); floodKill(xIdx,yIdx+1,type); floodKill(xIdx,yIdx-1,type); + if(first==true && removed == 0){ + //TODO: Provide a way to inform the delegate + return;//Can't remove single tiles + } + board[index(xIdx,yIdx)].dying = true; + board[index(xIdx,yIdx)] = null;//They'll have to destroy themselves(can we do that?) + removed += 1; } function shuffleDown() { - for(xIdx=0; xIdx=0; yIdx--){ if(board[index(xIdx,yIdx)] == null){ @@ -101,6 +123,35 @@ function shuffleDown() } } } + //Fall to the left + fallDist = 0; + for(xIdx=0; xIdx 0){ + for(yIdx=0; yIdx=0; xIdx--) + if(board[index(xIdx, maxY - 1)] != null) + deservesBonus = false; + if(deservesBonus) + gameCanvas.score += 250; } //Need a simpler method of doing this? @@ -108,14 +159,14 @@ var waitStack = new Array(maxIndex); var waitTop = -1; function finishCreatingBlock(xIdx,yIdx){ - //TODO: Doc that the 'xIdx', 'yIdx' here are hidden properties from the calling QFxItem + //TODO: Doc that the 'x', 'y' that were here are hidden properties from the calling QFxItem if(component.isReady()){ if(xIdx == undefined){ //Called without arguments, create a previously stored (xIdx,yIdx) if(waitTop == -1) return;//Don't have a previously stored (xIdx,yIdx) - xIdx = waitStack[waitTop] % maxIdx; - yIdx = Math.floor(waitStack[waitTop] / maxIdx); + xIdx = waitStack[waitTop] % maxX; + yIdx = Math.floor(waitStack[waitTop] / maxX); waitTop -= 1; } dynamicObject = component.createObject(); -- cgit v0.12 From f828db056642ac2373c8592c11039e1c7f1b1046 Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Wed, 15 Jul 2009 19:22:42 +1000 Subject: Remove pointless QmlCompiledComponent class --- src/declarative/qml/qml.pri | 2 - src/declarative/qml/qmlcompiledcomponent.cpp | 77 ---------------------- src/declarative/qml/qmlcompiledcomponent_p.h | 88 ------------------------- src/declarative/qml/qmlcompileddata.cpp | 37 +++++------ src/declarative/qml/qmlcompiler.cpp | 18 ++--- src/declarative/qml/qmlcompiler_p.h | 14 ++-- src/declarative/qml/qmlcomponent.cpp | 6 +- src/declarative/qml/qmlcomponent.h | 4 +- src/declarative/qml/qmlcomponent_p.h | 4 +- src/declarative/qml/qmlcompositetypemanager.cpp | 8 +-- src/declarative/qml/qmlcompositetypemanager_p.h | 8 +-- src/declarative/qml/qmlcontext_p.h | 1 - src/declarative/qml/qmldeclarativedata_p.h | 4 +- src/declarative/qml/qmldom.cpp | 3 +- src/declarative/qml/qmlengine.cpp | 2 +- src/declarative/qml/qmlinstruction.cpp | 8 +-- src/declarative/qml/qmlinstruction_p.h | 4 +- src/declarative/qml/qmlvme.cpp | 17 ++--- src/declarative/qml/qmlvme_p.h | 6 +- 19 files changed, 66 insertions(+), 245 deletions(-) delete mode 100644 src/declarative/qml/qmlcompiledcomponent.cpp delete mode 100644 src/declarative/qml/qmlcompiledcomponent_p.h diff --git a/src/declarative/qml/qml.pri b/src/declarative/qml/qml.pri index d8f0f7f..7f1c3f7 100644 --- a/src/declarative/qml/qml.pri +++ b/src/declarative/qml/qml.pri @@ -13,7 +13,6 @@ SOURCES += qml/qmlparser.cpp \ qml/qmlvme.cpp \ qml/qmlcompiler.cpp \ qml/qmlcompileddata.cpp \ - qml/qmlcompiledcomponent.cpp \ qml/qmlboundsignal.cpp \ qml/qmldom.cpp \ qml/qmlrefcount.cpp \ @@ -44,7 +43,6 @@ HEADERS += qml/qmlparser_p.h \ qml/qmlboundsignal_p.h \ qml/qmlparserstatus.h \ qml/qmlproxymetaobject_p.h \ - qml/qmlcompiledcomponent_p.h \ qml/qmlvme_p.h \ qml/qmlcompiler_p.h \ qml/qmlengine_p.h \ diff --git a/src/declarative/qml/qmlcompiledcomponent.cpp b/src/declarative/qml/qmlcompiledcomponent.cpp deleted file mode 100644 index 6ce89b7..0000000 --- a/src/declarative/qml/qmlcompiledcomponent.cpp +++ /dev/null @@ -1,77 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). -** Contact: Qt Software Information (qt-info@nokia.com) -** -** This file is part of the QtDeclarative module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the either Technology Preview License Agreement or the -** Beta Release License Agreement. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain -** additional rights. These rights are described in the Nokia Qt LGPL -** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this -** package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** If you are unsure which license is appropriate for your use, please -** contact the sales department at qt-sales@nokia.com. -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qmlcompiledcomponent_p.h" -#include "qmlparser_p.h" -#include -#include -using namespace QmlParser; - -QT_BEGIN_NAMESPACE - -DEFINE_BOOL_CONFIG_OPTION(compilerDump, QML_COMPILER_DUMP); - -QmlCompiledComponent::QmlCompiledComponent() -{ -} - -QmlCompiledComponent::~QmlCompiledComponent() -{ - for (int ii = 0; ii < synthesizedMetaObjects.count(); ++ii) - qFree(synthesizedMetaObjects.at(ii)); -} - -void QmlCompiledComponent::dumpInstructions() -{ - if (!compilerDump()) - return; - - if (!name.isEmpty()) - qWarning() << name; - qWarning() << "Index\tLine\tOperation\t\tData1\tData2\t\tComments"; - qWarning() << "-------------------------------------------------------------------------------"; - for (int ii = 0; ii < bytecode.count(); ++ii) { - dump(&bytecode[ii], ii); - } - qWarning() << "-------------------------------------------------------------------------------"; -} - -QT_END_NAMESPACE diff --git a/src/declarative/qml/qmlcompiledcomponent_p.h b/src/declarative/qml/qmlcompiledcomponent_p.h deleted file mode 100644 index ddc1124..0000000 --- a/src/declarative/qml/qmlcompiledcomponent_p.h +++ /dev/null @@ -1,88 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). -** Contact: Qt Software Information (qt-info@nokia.com) -** -** This file is part of the QtDeclarative module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the either Technology Preview License Agreement or the -** Beta Release License Agreement. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain -** additional rights. These rights are described in the Nokia Qt LGPL -** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this -** package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** If you are unsure which license is appropriate for your use, please -** contact the sales department at qt-sales@nokia.com. -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QMLCOMPILEDCOMPONENT_P_H -#define QMLCOMPILEDCOMPONENT_P_H - -// -// 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. -// - -#include -#include -#include -#include - -QT_BEGIN_HEADER - -QT_BEGIN_NAMESPACE - -namespace QmlParser { - class Property; - class Object; - class Value; -}; - -class QmlCompiledComponent : public QmlRefCount, public QmlCompiledData -{ -public: - QmlCompiledComponent(); - ~QmlCompiledComponent(); - - void dumpInstructions(); -private: - void dump(QmlInstruction *, int idx = -1); - friend class QmlCompiler; - friend class QmlDomDocument; -}; - -QT_END_NAMESPACE - -QT_END_HEADER - -#endif // QMLCOMPILEDCOMPONENT_P_H diff --git a/src/declarative/qml/qmlcompileddata.cpp b/src/declarative/qml/qmlcompileddata.cpp index 5c47d62..0834794 100644 --- a/src/declarative/qml/qmlcompileddata.cpp +++ b/src/declarative/qml/qmlcompileddata.cpp @@ -43,13 +43,15 @@ #include "qmlengine.h" #include "qmlcomponent.h" #include "qmlcomponent_p.h" -#include "qmlcompiledcomponent_p.h" #include "qmlcontext.h" #include "qmlcontext_p.h" #include +#include QT_BEGIN_NAMESPACE +DEFINE_BOOL_CONFIG_OPTION(compilerDump, QML_COMPILER_DUMP); + int QmlCompiledData::pack(const char *data, size_t size) { const char *p = packData.constData(); @@ -153,11 +155,6 @@ QmlCompiledData::QmlCompiledData() { } -QmlCompiledData::QmlCompiledData(const QmlCompiledData &other) -{ - *this = other; -} - QmlCompiledData::~QmlCompiledData() { for (int ii = 0; ii < types.count(); ++ii) { @@ -166,19 +163,6 @@ QmlCompiledData::~QmlCompiledData() } } -QmlCompiledData &QmlCompiledData::operator=(const QmlCompiledData &other) -{ - types = other.types; - root = other.root; - primitives = other.primitives; - floatData = other.floatData; - intData = other.intData; - customTypeData = other.customTypeData; - datas = other.datas; - bytecode = other.bytecode; - return *this; -} - QObject *QmlCompiledData::TypeReference::createInstance(QmlContext *ctxt) const { if (type) { @@ -207,5 +191,20 @@ const QMetaObject *QmlCompiledData::TypeReference::metaObject() const } } +void QmlCompiledData::dumpInstructions() +{ + if (!compilerDump()) + return; + + if (!name.isEmpty()) + qWarning() << name; + qWarning() << "Index\tLine\tOperation\t\tData1\tData2\t\tComments"; + qWarning() << "-------------------------------------------------------------------------------"; + for (int ii = 0; ii < bytecode.count(); ++ii) { + dump(&bytecode[ii], ii); + } + qWarning() << "-------------------------------------------------------------------------------"; +} + QT_END_NAMESPACE diff --git a/src/declarative/qml/qmlcompiler.cpp b/src/declarative/qml/qmlcompiler.cpp index dafc581..ed9df03 100644 --- a/src/declarative/qml/qmlcompiler.cpp +++ b/src/declarative/qml/qmlcompiler.cpp @@ -52,7 +52,6 @@ #include #include #include -#include #include #include #include @@ -470,7 +469,7 @@ void QmlCompiler::genLiteralAssignment(const QMetaProperty &prop, output->bytecode << instr; } -void QmlCompiler::reset(QmlCompiledComponent *cc, bool deleteMemory) +void QmlCompiler::reset(QmlCompiledData *cc) { cc->types.clear(); cc->primitives.clear(); @@ -478,17 +477,12 @@ void QmlCompiler::reset(QmlCompiledComponent *cc, bool deleteMemory) cc->intData.clear(); cc->customTypeData.clear(); cc->datas.clear(); - if (deleteMemory) { - for (int ii = 0; ii < cc->synthesizedMetaObjects.count(); ++ii) - qFree(cc->synthesizedMetaObjects.at(ii)); - } - cc->synthesizedMetaObjects.clear(); cc->bytecode.clear(); } bool QmlCompiler::compile(QmlEngine *engine, QmlCompositeTypeData *unit, - QmlCompiledComponent *out) + QmlCompiledData *out) { #ifdef Q_ENABLE_PERFORMANCE_LOG QFxPerfTimer pc; @@ -496,14 +490,14 @@ bool QmlCompiler::compile(QmlEngine *engine, exceptions.clear(); Q_ASSERT(out); - reset(out, true); + reset(out); output = out; // Compile types for (int ii = 0; ii < unit->types.count(); ++ii) { QmlCompositeTypeData::TypeReference &tref = unit->types[ii]; - QmlCompiledComponent::TypeReference ref; + QmlCompiledData::TypeReference ref; if (tref.type) ref.type = tref.type; else if (tref.unit) { @@ -516,7 +510,7 @@ bool QmlCompiler::compile(QmlEngine *engine, unit->data.types().at(ii)); exceptions << error; exceptions << ref.component->errors(); - reset(out, true); + reset(out); return false; } ref.ref = tref.unit; @@ -534,7 +528,7 @@ bool QmlCompiler::compile(QmlEngine *engine, if (!isError()) { out->dumpInstructions(); } else { - reset(out, true); + reset(out); } output = 0; diff --git a/src/declarative/qml/qmlcompiler_p.h b/src/declarative/qml/qmlcompiler_p.h index b97de19..e09665f 100644 --- a/src/declarative/qml/qmlcompiler_p.h +++ b/src/declarative/qml/qmlcompiler_p.h @@ -65,15 +65,12 @@ QT_BEGIN_NAMESPACE class QmlEngine; class QmlComponent; -class QmlCompiledComponent; class QmlContext; -class QmlCompiledData +class QmlCompiledData : public QmlRefCount { public: QmlCompiledData(); - QmlCompiledData(const QmlCompiledData &other); - QmlCompiledData &operator=(const QmlCompiledData &other); virtual ~QmlCompiledData(); QByteArray name; @@ -104,11 +101,14 @@ public: QList intData; QList customTypeData; QList datas; - QList synthesizedMetaObjects; QList locations; QList bytecode; + void dumpInstructions(); private: + void dump(QmlInstruction *, int idx = -1); + QmlCompiledData(const QmlCompiledData &other); + QmlCompiledData &operator=(const QmlCompiledData &other); QByteArray packData; friend class QmlCompiler; int pack(const char *, size_t); @@ -127,7 +127,7 @@ class Q_DECLARATIVE_EXPORT QmlCompiler public: QmlCompiler(); - bool compile(QmlEngine *, QmlCompositeTypeData *, QmlCompiledComponent *); + bool compile(QmlEngine *, QmlCompositeTypeData *, QmlCompiledData *); bool isError() const; QList errors() const; @@ -137,7 +137,7 @@ public: static bool isSignalPropertyName(const QByteArray &); private: - void reset(QmlCompiledComponent *, bool); + void reset(QmlCompiledData *); struct BindingContext { BindingContext() diff --git a/src/declarative/qml/qmlcomponent.cpp b/src/declarative/qml/qmlcomponent.cpp index 52315f9..0e68f8a 100644 --- a/src/declarative/qml/qmlcomponent.cpp +++ b/src/declarative/qml/qmlcomponent.cpp @@ -41,6 +41,7 @@ #include "qmlcomponent.h" #include "qmlcomponent_p.h" +#include "qmlcompiler_p.h" #include "private/qmlcontext_p.h" #include "private/qmlengine_p.h" #include "qmlvme_p.h" @@ -51,7 +52,6 @@ #include #include #include -#include "qmlcompiledcomponent_p.h" #include #include @@ -123,7 +123,7 @@ void QmlComponentPrivate::typeDataReady() void QmlComponentPrivate::fromTypeData(QmlCompositeTypeData *data) { url = data->imports.baseUrl(); - QmlCompiledComponent *c = data->toCompiledComponent(engine); + QmlCompiledData *c = data->toCompiledComponent(engine); if (!c) { Q_ASSERT(data->status == QmlCompositeTypeData::Error); @@ -303,7 +303,7 @@ QmlComponent::QmlComponent(QmlEngine *engine, const QByteArray &data, const QUrl /*! \internal */ -QmlComponent::QmlComponent(QmlEngine *engine, QmlCompiledComponent *cc, int start, int count, QObject *parent) +QmlComponent::QmlComponent(QmlEngine *engine, QmlCompiledData *cc, int start, int count, QObject *parent) : QObject(*(new QmlComponentPrivate), parent) { Q_D(QmlComponent); diff --git a/src/declarative/qml/qmlcomponent.h b/src/declarative/qml/qmlcomponent.h index 5e6dce9..9c712df 100644 --- a/src/declarative/qml/qmlcomponent.h +++ b/src/declarative/qml/qmlcomponent.h @@ -55,7 +55,7 @@ QT_BEGIN_NAMESPACE QT_MODULE(Declarative) -class QmlCompiledComponent; +class QmlCompiledData; class QByteArray; class QmlComponentPrivate; class QmlEngine; @@ -102,7 +102,7 @@ protected: QmlComponent(QmlComponentPrivate &dd, QObject* parent); private: - QmlComponent(QmlEngine *, QmlCompiledComponent *, int, int, QObject *parent); + QmlComponent(QmlEngine *, QmlCompiledData *, int, int, QObject *parent); friend class QmlVME; friend struct QmlCompositeTypeData; diff --git a/src/declarative/qml/qmlcomponent_p.h b/src/declarative/qml/qmlcomponent_p.h index 0be3dc6..25af342 100644 --- a/src/declarative/qml/qmlcomponent_p.h +++ b/src/declarative/qml/qmlcomponent_p.h @@ -67,7 +67,7 @@ QT_BEGIN_NAMESPACE class QmlComponent; class QmlEngine; -class QmlCompiledComponent; +class QmlCompiledData; class QmlComponentPrivate : public QObjectPrivate { @@ -86,7 +86,7 @@ public: int start; int count; - QmlCompiledComponent *cc; + QmlCompiledData *cc; QList > bindValues; QList > parserStatus; diff --git a/src/declarative/qml/qmlcompositetypemanager.cpp b/src/declarative/qml/qmlcompositetypemanager.cpp index c7f86ba..9af5c3c 100644 --- a/src/declarative/qml/qmlcompositetypemanager.cpp +++ b/src/declarative/qml/qmlcompositetypemanager.cpp @@ -41,7 +41,6 @@ #include #include -#include #include #include #include @@ -49,6 +48,7 @@ #include #include #include +#include QT_BEGIN_NAMESPACE @@ -83,7 +83,7 @@ QmlComponent *QmlCompositeTypeData::toComponent(QmlEngine *engine) { if (!component) { - QmlCompiledComponent *cc = toCompiledComponent(engine); + QmlCompiledData *cc = toCompiledComponent(engine); if (cc) { component = new QmlComponent(engine, cc, -1, -1, 0); } else { @@ -97,12 +97,12 @@ QmlComponent *QmlCompositeTypeData::toComponent(QmlEngine *engine) return component; } -QmlCompiledComponent * +QmlCompiledData * QmlCompositeTypeData::toCompiledComponent(QmlEngine *engine) { if (status == Complete && !compiledComponent) { - compiledComponent = new QmlCompiledComponent; + compiledComponent = new QmlCompiledData; compiledComponent->url = imports.baseUrl(); compiledComponent->name = compiledComponent->url.toString().toLatin1(); // ### diff --git a/src/declarative/qml/qmlcompositetypemanager_p.h b/src/declarative/qml/qmlcompositetypemanager_p.h index a393da4..0685b03 100644 --- a/src/declarative/qml/qmlcompositetypemanager_p.h +++ b/src/declarative/qml/qmlcompositetypemanager_p.h @@ -61,7 +61,7 @@ QT_BEGIN_NAMESPACE -class QmlCompiledComponent; +class QmlCompiledData; class QmlComponentPrivate; class QmlComponent; class QmlDomDocument; @@ -94,9 +94,9 @@ struct QmlCompositeTypeData : public QmlRefCount // state. The QmlComponent is owned by the QmlCompositeTypeData, so a // reference should be kept to keep the QmlComponent alive. QmlComponent *toComponent(QmlEngine *); - // Return a QmlCompiledComponent if possible, or 0 if an error + // Return a QmlCompiledData if possible, or 0 if an error // occurs - QmlCompiledComponent *toCompiledComponent(QmlEngine *); + QmlCompiledData *toCompiledComponent(QmlEngine *); struct TypeReference { @@ -123,7 +123,7 @@ private: QmlScriptParser data; QList waiters; QmlComponent *component; - QmlCompiledComponent *compiledComponent; + QmlCompiledData *compiledComponent; }; class QmlCompositeTypeManager : public QObject diff --git a/src/declarative/qml/qmlcontext_p.h b/src/declarative/qml/qmlcontext_p.h index f896873..fc615b6 100644 --- a/src/declarative/qml/qmlcontext_p.h +++ b/src/declarative/qml/qmlcontext_p.h @@ -66,7 +66,6 @@ class QmlContext; class QmlExpression; class QmlEngine; class QmlExpression; -class QmlCompiledComponent; class QmlContextPrivate : public QObjectPrivate { diff --git a/src/declarative/qml/qmldeclarativedata_p.h b/src/declarative/qml/qmldeclarativedata_p.h index 559f0ee..b473e77 100644 --- a/src/declarative/qml/qmldeclarativedata_p.h +++ b/src/declarative/qml/qmldeclarativedata_p.h @@ -71,7 +71,7 @@ public: bool create = false); }; -class QmlCompiledComponent; +class QmlCompiledData; class QmlInstanceDeclarativeData : public QmlSimpleDeclarativeData { public: @@ -79,7 +79,7 @@ public: virtual void destroyed(QObject *); - QmlCompiledComponent *deferredComponent; + QmlCompiledData *deferredComponent; unsigned int deferredIdx; static inline QmlInstanceDeclarativeData *get(QObject *object, diff --git a/src/declarative/qml/qmldom.cpp b/src/declarative/qml/qmldom.cpp index 467d2e9..e3cb563 100644 --- a/src/declarative/qml/qmldom.cpp +++ b/src/declarative/qml/qmldom.cpp @@ -43,7 +43,6 @@ #include "qmldom_p.h" #include "private/qmlcompiler_p.h" #include "private/qmlengine_p.h" -#include "qmlcompiledcomponent_p.h" #include #include #include @@ -165,7 +164,7 @@ bool QmlDomDocument::load(QmlEngine *engine, const QByteArray &data, const QUrl d->errors.clear(); d->imports.clear(); - QmlCompiledComponent component; + QmlCompiledData component; QmlCompiler compiler; QmlCompositeTypeData *td = ((QmlEnginePrivate *)QmlEnginePrivate::get(engine))->typeManager.getImmediate(data, url); diff --git a/src/declarative/qml/qmlengine.cpp b/src/declarative/qml/qmlengine.cpp index 46c8b30..acbeb26 100644 --- a/src/declarative/qml/qmlengine.cpp +++ b/src/declarative/qml/qmlengine.cpp @@ -43,6 +43,7 @@ #include #include #include +#include #ifdef QT_SCRIPTTOOLS_LIB #include @@ -60,7 +61,6 @@ #include #include #include "private/qmlbasicscript_p.h" -#include "private/qmlcompiledcomponent_p.h" #include "qmlengine.h" #include "qmlcontext.h" #include "qmlexpression.h" diff --git a/src/declarative/qml/qmlinstruction.cpp b/src/declarative/qml/qmlinstruction.cpp index 863ff9a..83fb18b 100644 --- a/src/declarative/qml/qmlinstruction.cpp +++ b/src/declarative/qml/qmlinstruction.cpp @@ -39,13 +39,13 @@ ** ****************************************************************************/ -#include "private/qmlinstruction_p.h" -#include "private/qmlcompiledcomponent_p.h" -#include +#include "qmlinstruction_p.h" +#include "qmlcompiler_p.h" +#include QT_BEGIN_NAMESPACE -void QmlCompiledComponent::dump(QmlInstruction *instr, int idx) +void QmlCompiledData::dump(QmlInstruction *instr, int idx) { QByteArray lineNumber = QByteArray::number(instr->line); if (instr->line == (unsigned short)-1) diff --git a/src/declarative/qml/qmlinstruction_p.h b/src/declarative/qml/qmlinstruction_p.h index 39196a1..a7221c0 100644 --- a/src/declarative/qml/qmlinstruction_p.h +++ b/src/declarative/qml/qmlinstruction_p.h @@ -57,7 +57,7 @@ QT_BEGIN_NAMESPACE -class QmlCompiledComponent; +class QmlCompiledData; class Q_DECLARATIVE_EXPORT QmlInstruction { public: @@ -272,7 +272,7 @@ public: } defer; }; - void dump(QmlCompiledComponent *); + void dump(QmlCompiledData *); }; QT_END_NAMESPACE diff --git a/src/declarative/qml/qmlvme.cpp b/src/declarative/qml/qmlvme.cpp index dfb066b..3b33686 100644 --- a/src/declarative/qml/qmlvme.cpp +++ b/src/declarative/qml/qmlvme.cpp @@ -40,6 +40,7 @@ ****************************************************************************/ #include "qmlvme_p.h" +#include "qmlcompiler_p.h" #include #include #include @@ -49,7 +50,6 @@ #include #include #include -#include #include #include #include @@ -98,7 +98,7 @@ struct ListInstance QmlPrivate::ListInterface *qmlListInterface; }; -QObject *QmlVME::run(QmlContext *ctxt, QmlCompiledComponent *comp, int start, int count) +QObject *QmlVME::run(QmlContext *ctxt, QmlCompiledData *comp, int start, int count) { QStack stack; @@ -117,7 +117,7 @@ void QmlVME::runDeferred(QObject *object) QmlContext *ctxt = data->context; ctxt->activate(); - QmlCompiledComponent *comp = data->deferredComponent; + QmlCompiledData *comp = data->deferredComponent; int start = data->deferredIdx + 1; int count = data->deferredComponent->bytecode.at(data->deferredIdx).defer.deferCount; QStack stack; @@ -127,7 +127,7 @@ void QmlVME::runDeferred(QObject *object) ctxt->deactivate(); } -QObject *QmlVME::run(QStack &stack, QmlContext *ctxt, QmlCompiledComponent *comp, int start, int count) +QObject *QmlVME::run(QStack &stack, QmlContext *ctxt, QmlCompiledData *comp, int start, int count) { // XXX - All instances of QmlContext::activeContext() here should be // replaced with the use of ctxt. However, this cannot be done until @@ -137,10 +137,9 @@ QObject *QmlVME::run(QStack &stack, QmlContext *ctxt, QmlCompiledComp // sub-instances on that type. Q_ASSERT(comp); Q_ASSERT(ctxt); - const QList &types = comp->types; + const QList &types = comp->types; const QList &primitives = comp->primitives; const QList &datas = comp->datas; - const QList &synthesizedMetaObjects = comp->synthesizedMetaObjects;; const QList &customTypeData = comp->customTypeData; const QList &intData = comp->intData; const QList &floatData = comp->floatData; @@ -237,8 +236,6 @@ QObject *QmlVME::run(QStack &stack, QmlContext *ctxt, QmlCompiledComp const QmlVMEMetaData *data = (const QmlVMEMetaData *)datas.at(instr.storeMeta.aliasData).constData(); (void)new QmlVMEMetaObject(target, &mo, data, comp); - - // new QmlVMEMetaObject(target, synthesizedMetaObjects.at(instr.storeMeta.data), &comp->primitives, instr.storeMeta.slotData, (const QmlVMEMetaData *)datas.at(instr.storeMeta.aliasData).constData(), comp); } break; @@ -464,7 +461,7 @@ QObject *QmlVME::run(QStack &stack, QmlContext *ctxt, QmlCompiledComp { QObject *target = stack.top(); void *a[1]; - QmlCompiledComponent::CustomTypeData data = customTypeData.at(instr.assignCustomType.valueIndex); + QmlCompiledData::CustomTypeData data = customTypeData.at(instr.assignCustomType.valueIndex); const QString &primitive = primitives.at(data.index); QmlMetaType::StringConverter converter = QmlMetaType::customStringConverter(data.type); @@ -776,7 +773,7 @@ QObject *QmlVME::run(QStack &stack, QmlContext *ctxt, QmlCompiledComp break; default: - qFatal("QmlCompiledComponent: Internal error - unknown instruction %d", instr.type); + qFatal("QmlCompiledData: Internal error - unknown instruction %d", instr.type); break; } } diff --git a/src/declarative/qml/qmlvme_p.h b/src/declarative/qml/qmlvme_p.h index 2da7bb4..30a6e4f 100644 --- a/src/declarative/qml/qmlvme_p.h +++ b/src/declarative/qml/qmlvme_p.h @@ -61,7 +61,7 @@ QT_BEGIN_NAMESPACE class QObject; class QmlInstruction; -class QmlCompiledComponent; +class QmlCompiledData; class QmlCompiledData; class QmlContext; @@ -70,14 +70,14 @@ class QmlVME public: QmlVME(); - QObject *run(QmlContext *, QmlCompiledComponent *, int start = -1, int count = -1); + QObject *run(QmlContext *, QmlCompiledData *, int start = -1, int count = -1); void runDeferred(QObject *); bool isError() const; QList errors() const; private: - QObject *run(QStack &, QmlContext *, QmlCompiledComponent *, int start, int count); + QObject *run(QStack &, QmlContext *, QmlCompiledData *, int start, int count); QList vmeErrors; }; -- cgit v0.12 From e09973fb8244c47a39a42c780bb6a2be2fa5cc63 Mon Sep 17 00:00:00 2001 From: Roberto Raggi Date: Wed, 15 Jul 2009 13:37:57 +0200 Subject: Added support for parsing toplevel expressions and statements. --- src/declarative/qml/parser/qmljs.g | 72 +- src/declarative/qml/parser/qmljsgrammar.cpp | 1856 +++++++++++---------------- src/declarative/qml/parser/qmljsgrammar_p.h | 29 +- src/declarative/qml/parser/qmljsparser.cpp | 1003 ++++----------- src/declarative/qml/parser/qmljsparser_p.h | 41 +- 5 files changed, 1098 insertions(+), 1903 deletions(-) diff --git a/src/declarative/qml/parser/qmljs.g b/src/declarative/qml/parser/qmljs.g index 8297c08..43cce40 100644 --- a/src/declarative/qml/parser/qmljs.g +++ b/src/declarative/qml/parser/qmljs.g @@ -86,11 +86,16 @@ %token T_IMPORT "import" %token T_AS "as" +--- feed tokens +%token T_FEED_UI_PROGRAM +%token T_FEED_JS_STATEMENT +%token T_FEED_JS_EXPRESSION + %nonassoc SHIFT_THERE %nonassoc T_IDENTIFIER T_COLON T_SIGNAL T_PROPERTY %nonassoc REDUCE_HERE -%start UiProgram +%start TopLevel /. /**************************************************************************** @@ -272,10 +277,29 @@ public: Parser(Engine *engine); ~Parser(); - bool parse(); + // parse a UI program + bool parse() { return parse(T_FEED_UI_PROGRAM); } + bool parseStatement() { return parse(T_FEED_JS_STATEMENT); } + bool parseExpression() { return parse(T_FEED_JS_EXPRESSION); } + + AST::UiProgram *ast() const + { return AST::cast(program); } + + AST::Statement *statement() const + { + if (! program) + return 0; - AST::UiProgram *ast() - { return program; } + return program->statementCast(); + } + + AST::ExpressionNode *expression() const + { + if (! program) + return 0; + + return program->expressionCast(); + } QList diagnosticMessages() const { return diagnostic_messages; } @@ -300,6 +324,8 @@ public: { return diagnosticMessage().loc.startColumn; } protected: + bool parse(int startToken); + void reallocateStack(); inline Value &sym(int index) @@ -318,7 +344,7 @@ protected: int *state_stack; AST::SourceLocation *location_stack; - AST::UiProgram *program; + AST::Node *program; // error recovery enum { TOKEN_BUFFER_SIZE = 3 }; @@ -439,14 +465,16 @@ AST::UiQualifiedId *Parser::reparseAsQualifiedId(AST::ExpressionNode *expr) return 0; } -bool Parser::parse() +bool Parser::parse(int startToken) { Lexer *lexer = driver->lexer(); bool hadErrors = false; int yytoken = -1; int action = 0; - first_token = last_token = 0; + token_buffer[0].token = startToken; + first_token = &token_buffer[0]; + last_token = &token_buffer[1]; tos = -1; program = 0; @@ -494,12 +522,35 @@ bool Parser::parse() -- Declarative UI -------------------------------------------------------------------------------------------------------- +TopLevel: T_FEED_UI_PROGRAM UiProgram ; +/. +case $rule_number: { + sym(1).Node = sym(2).Node; + program = sym(1).Node; +} break; +./ + +TopLevel: T_FEED_JS_STATEMENT Statement ; +/. +case $rule_number: { + sym(1).Node = sym(2).Node; + program = sym(1).Node; +} break; +./ + +TopLevel: T_FEED_JS_EXPRESSION Expression ; +/. +case $rule_number: { + sym(1).Node = sym(2).Node; + program = sym(1).Node; +} break; +./ + UiProgram: UiImportListOpt UiRootMember ; /. case $rule_number: { - program = makeAstNode (driver->nodePool(), sym(1).UiImportList, + sym(1).UiProgram = makeAstNode (driver->nodePool(), sym(1).UiImportList, sym(2).UiObjectMemberList->finish()); - sym(1).UiProgram = program; } break; ./ @@ -2962,7 +3013,8 @@ PropertyNameAndValueListOpt: PropertyNameAndValueList ; } for (int tk = 1; tk < TERMINAL_COUNT; ++tk) { - if (tk == T_AUTOMATIC_SEMICOLON) + if (tk == T_AUTOMATIC_SEMICOLON || tk == T_FEED_UI_PROGRAM || + tk == T_FEED_JS_STATEMENT || tk == T_FEED_JS_EXPRESSION) continue; int a = t_action(errorState, tk); diff --git a/src/declarative/qml/parser/qmljsgrammar.cpp b/src/declarative/qml/parser/qmljsgrammar.cpp index ff25d65..4fba480 100644 --- a/src/declarative/qml/parser/qmljsgrammar.cpp +++ b/src/declarative/qml/parser/qmljsgrammar.cpp @@ -52,930 +52,556 @@ const char *const QmlJSGrammar::spell [] = { ")", ";", 0, "*", "*=", "string literal", "property", "signal", "switch", "this", "throw", "~", "try", "typeof", "var", "void", "while", "with", "^", "^=", "null", "true", "false", "const", "debugger", "reserved word", "multiline string literal", "public", "import", "as", - 0, 0, -#ifndef QLALR_NO_QMLJSGRAMMAR_DEBUG_INFO -"UiProgram", "UiImportListOpt", "UiRootMember", "Empty", "UiImportList", "UiImport", "JsIdentifier", "UiQualifiedId", - "UiObjectDefinition", "UiObjectMemberList", "UiObjectMember", "UiArrayMemberList", "UiObjectInitializer", "UiMultilineStringLiteral", "UiMultilineStringStatement", "Expression", "Block", "EmptyStatement", - "ExpressionStatement", "DebuggerStatement", "IfStatement", "UiPropertyType", "UiParameterListOpt", "UiParameterList", "FunctionDeclaration", "VariableStatement", "PrimaryExpression", "Elision", - "ElementList", "PropertyNameAndValueListOpt", "PropertyNameAndValueList", "AssignmentExpression", "PropertyName", "ReservedIdentifier", "PropertyIdentifier", "MemberExpression", "FunctionExpression", "ArgumentListOpt", - "NewExpression", "CallExpression", "ArgumentList", "LeftHandSideExpression", "PostfixExpression", "UnaryExpression", "MultiplicativeExpression", "AdditiveExpression", "ShiftExpression", "RelationalExpression", - "RelationalExpressionNotIn", "EqualityExpression", "EqualityExpressionNotIn", "BitwiseANDExpression", "BitwiseANDExpressionNotIn", "BitwiseXORExpression", "BitwiseXORExpressionNotIn", "BitwiseORExpression", "BitwiseORExpressionNotIn", "LogicalANDExpression", - "LogicalANDExpressionNotIn", "LogicalORExpression", "LogicalORExpressionNotIn", "ConditionalExpression", "ConditionalExpressionNotIn", "AssignmentExpressionNotIn", "AssignmentOperator", "ExpressionOpt", "ExpressionNotIn", "ExpressionNotInOpt", - "Statement", "IterationStatement", "ContinueStatement", "BreakStatement", "ReturnStatement", "WithStatement", "LabelledStatement", "SwitchStatement", "ThrowStatement", "TryStatement", - "StatementListOpt", "StatementList", "VariableDeclarationKind", "VariableDeclarationList", "VariableDeclaration", "VariableDeclarationListNotIn", "VariableDeclarationNotIn", "InitialiserOpt", "InitialiserNotInOpt", "Initialiser", - "InitialiserNotIn", "CaseBlock", "CaseClausesOpt", "DefaultClause", "CaseClauses", "CaseClause", "Catch", "Finally", "FormalParameterListOpt", "FunctionBodyOpt", - "IdentifierOpt", "FormalParameterList", "FunctionBody", "SourceElements", "SourceElement", "$accept" -#endif // QLALR_NO_QMLJSGRAMMAR_DEBUG_INFO -}; + 0, 0, 0, 0, 0}; const int QmlJSGrammar::lhs [] = { - 92, 93, 93, 96, 96, 97, 97, 97, 97, 97, - 97, 97, 97, 97, 97, 97, 97, 95, 94, 101, - 101, 103, 103, 104, 104, 100, 102, 102, 105, 106, - 106, 102, 102, 102, 102, 102, 102, 102, 113, 113, - 113, 114, 114, 115, 115, 102, 102, 102, 102, 102, - 102, 102, 102, 102, 102, 102, 102, 99, 99, 98, - 98, 98, 118, 118, 118, 118, 118, 118, 118, 118, - 118, 118, 118, 118, 118, 118, 118, 118, 118, 99, - 99, 120, 120, 120, 120, 119, 119, 122, 122, 124, - 124, 124, 124, 124, 124, 125, 125, 125, 125, 125, - 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, - 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, - 125, 125, 125, 125, 125, 125, 126, 126, 127, 127, - 127, 127, 127, 130, 130, 131, 131, 131, 131, 129, - 129, 132, 132, 133, 133, 134, 134, 134, 135, 135, - 135, 135, 135, 135, 135, 135, 135, 135, 136, 136, - 136, 136, 137, 137, 137, 138, 138, 138, 138, 139, - 139, 139, 139, 139, 139, 139, 140, 140, 140, 140, - 140, 140, 141, 141, 141, 141, 141, 142, 142, 142, - 142, 142, 143, 143, 144, 144, 145, 145, 146, 146, - 147, 147, 148, 148, 149, 149, 150, 150, 151, 151, - 152, 152, 153, 153, 154, 154, 123, 123, 155, 155, - 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, - 156, 156, 107, 107, 157, 157, 158, 158, 159, 159, - 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, - 160, 160, 160, 160, 160, 108, 171, 171, 170, 170, - 117, 117, 172, 172, 173, 173, 175, 175, 174, 176, - 179, 177, 177, 180, 178, 178, 109, 110, 110, 112, - 112, 161, 161, 161, 161, 161, 161, 161, 162, 162, - 162, 162, 163, 163, 163, 163, 164, 164, 165, 167, - 181, 181, 184, 184, 182, 182, 185, 183, 166, 166, - 166, 168, 168, 169, 169, 169, 186, 187, 111, 111, - 116, 128, 191, 191, 188, 188, 189, 189, 192, 193, - 193, 194, 194, 190, 190, 121, 121, 195}; + 95, 95, 95, 96, 99, 99, 102, 102, 103, 103, + 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, + 101, 100, 107, 107, 109, 109, 110, 110, 106, 108, + 108, 111, 112, 112, 108, 108, 108, 108, 108, 108, + 108, 118, 118, 118, 119, 119, 120, 120, 108, 108, + 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, + 105, 105, 104, 104, 104, 123, 123, 123, 123, 123, + 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, + 123, 123, 105, 105, 125, 125, 125, 125, 124, 124, + 127, 127, 129, 129, 129, 129, 129, 129, 130, 130, + 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, + 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, + 130, 130, 130, 130, 130, 130, 130, 130, 130, 131, + 131, 132, 132, 132, 132, 132, 135, 135, 136, 136, + 136, 136, 134, 134, 137, 137, 138, 138, 139, 139, + 139, 140, 140, 140, 140, 140, 140, 140, 140, 140, + 140, 141, 141, 141, 141, 142, 142, 142, 143, 143, + 143, 143, 144, 144, 144, 144, 144, 144, 144, 145, + 145, 145, 145, 145, 145, 146, 146, 146, 146, 146, + 147, 147, 147, 147, 147, 148, 148, 149, 149, 150, + 150, 151, 151, 152, 152, 153, 153, 154, 154, 155, + 155, 156, 156, 157, 157, 158, 158, 159, 159, 128, + 128, 160, 160, 161, 161, 161, 161, 161, 161, 161, + 161, 161, 161, 161, 161, 98, 98, 162, 162, 163, + 163, 164, 164, 97, 97, 97, 97, 97, 97, 97, + 97, 97, 97, 97, 97, 97, 97, 97, 113, 175, + 175, 174, 174, 122, 122, 176, 176, 177, 177, 179, + 179, 178, 180, 183, 181, 181, 184, 182, 182, 114, + 115, 115, 117, 117, 165, 165, 165, 165, 165, 165, + 165, 166, 166, 166, 166, 167, 167, 167, 167, 168, + 168, 169, 171, 185, 185, 188, 188, 186, 186, 189, + 187, 170, 170, 170, 172, 172, 173, 173, 173, 190, + 191, 116, 116, 121, 133, 195, 195, 192, 192, 193, + 193, 196, 197, 197, 198, 198, 194, 194, 126, 126, + 199}; const int QmlJSGrammar:: rhs[] = { - 2, 1, 1, 1, 2, 3, 3, 5, 5, 3, - 3, 4, 4, 6, 6, 5, 5, 0, 1, 1, - 2, 1, 3, 2, 3, 2, 1, 5, 1, 2, - 2, 4, 3, 3, 3, 3, 3, 3, 1, 1, - 1, 0, 1, 2, 4, 5, 2, 4, 4, 5, - 5, 6, 6, 7, 7, 1, 1, 1, 1, 1, + 2, 2, 2, 2, 1, 1, 1, 2, 3, 3, + 5, 5, 3, 3, 4, 4, 6, 6, 5, 5, + 0, 1, 1, 2, 1, 3, 2, 3, 2, 1, + 5, 1, 2, 2, 4, 3, 3, 3, 3, 3, + 3, 1, 1, 1, 0, 1, 2, 4, 5, 2, + 4, 4, 5, 5, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 2, 3, 3, 4, 5, 3, 4, 3, 1, - 3, 1, 2, 3, 4, 1, 2, 3, 5, 1, + 1, 1, 1, 1, 2, 3, 3, 4, 5, 3, + 4, 3, 1, 3, 1, 2, 3, 4, 1, 2, + 3, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 4, 3, 5, 1, 2, 4, 4, 4, 3, 0, - 1, 1, 3, 1, 1, 1, 2, 2, 1, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 1, 3, - 3, 3, 1, 3, 3, 1, 3, 3, 3, 1, - 3, 3, 3, 3, 3, 3, 1, 3, 3, 3, - 3, 3, 1, 3, 3, 3, 3, 1, 3, 3, - 3, 3, 1, 3, 1, 3, 1, 3, 1, 3, - 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, - 1, 3, 1, 5, 1, 5, 1, 3, 1, 3, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 3, 0, 1, 1, 3, 0, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 3, 1, 2, 0, 1, - 3, 3, 1, 1, 1, 3, 1, 3, 2, 2, - 2, 0, 1, 2, 0, 1, 1, 2, 2, 7, - 5, 7, 7, 5, 9, 10, 7, 8, 2, 2, - 3, 3, 2, 2, 3, 3, 3, 3, 5, 5, - 3, 5, 1, 2, 0, 1, 4, 3, 3, 3, - 3, 3, 3, 3, 3, 4, 5, 2, 2, 2, - 8, 8, 1, 3, 0, 1, 0, 1, 1, 1, - 2, 1, 1, 0, 1, 0, 1, 2}; - - -#ifndef QLALR_NO_QMLJSGRAMMAR_DEBUG_INFO -const int QmlJSGrammar::rule_info [] = { - 92, 93, 94 - , 93, 95 - , 93, 96 - , 96, 97 - , 96, 96, 97 - , 97, 88, 65, 62 - , 97, 88, 65, 61 - , 97, 88, 65, 89, 98, 62 - , 97, 88, 65, 89, 98, 61 - , 97, 88, 99, 62 - , 97, 88, 99, 61 - , 97, 88, 99, 47, 62 - , 97, 88, 99, 47, 61 - , 97, 88, 99, 47, 89, 98, 62 - , 97, 88, 99, 47, 89, 98, 61 - , 97, 88, 99, 89, 98, 62 - , 97, 88, 99, 89, 98, 61 - , 95 - , 94, 100 - , 101, 102 - , 101, 101, 102 - , 103, 100 - , 103, 103, 8, 100 - , 104, 33, 55 - , 104, 33, 101, 55 - , 100, 99, 104 - , 102, 100 - , 102, 99, 7, 34, 103, 56 - , 105, 86 - , 106, 105, 62 - , 106, 105, 61 - , 102, 99, 7, 107, 104 - , 102, 99, 7, 108 - , 102, 99, 7, 109 - , 102, 99, 7, 110 - , 102, 99, 7, 111 - , 102, 99, 7, 106 - , 102, 99, 7, 112 - , 113, 74 - , 113, 85 - , 113, 29 - , 114 - , 114, 115 - , 115, 113, 98 - , 115, 115, 8, 113, 98 - , 102, 67, 29, 36, 114, 60 - , 102, 67, 29 - , 102, 66, 113, 29, 62 - , 102, 66, 113, 29, 61 - , 102, 10, 66, 113, 29, 62 - , 102, 10, 66, 113, 29, 61 - , 102, 66, 113, 29, 7, 107, 62 - , 102, 66, 113, 29, 7, 107, 61 - , 102, 10, 66, 113, 29, 7, 107, 62 - , 102, 10, 66, 113, 29, 7, 107, 61 - , 102, 116 - , 102, 117 - , 99, 85 - , 99, 59 - , 98, 29 - , 98, 66 - , 98, 67 - , 118, 69 - , 118, 98 - , 118, 80 - , 118, 81 - , 118, 82 - , 118, 47 - , 118, 65 - , 118, 12 - , 118, 13 - , 118, 34, 56 - , 118, 34, 119, 56 - , 118, 34, 120, 56 - , 118, 34, 120, 8, 56 - , 118, 34, 120, 8, 119, 56 - , 118, 33, 121, 55 - , 118, 33, 122, 8, 55 - , 118, 36, 107, 60 - , 99, 98 - , 99, 99, 15, 98 - , 120, 123 - , 120, 119, 123 - , 120, 120, 8, 123 - , 120, 120, 8, 119, 123 - , 119, 8 - , 119, 119, 8 - , 122, 124, 7, 123 - , 122, 122, 8, 124, 7, 123 - , 124, 29 - , 124, 67 - , 124, 66 - , 124, 65 - , 124, 47 - , 124, 125 - , 125, 4 - , 125, 5 - , 125, 6 - , 125, 9 - , 125, 10 - , 125, 11 - , 125, 14 - , 125, 16 - , 125, 82 - , 125, 20 - , 125, 21 - , 125, 22 - , 125, 30 - , 125, 31 - , 125, 32 - , 125, 43 - , 125, 80 - , 125, 59 - , 125, 68 - , 125, 69 - , 125, 70 - , 125, 81 - , 125, 72 - , 125, 73 - , 125, 74 - , 125, 75 - , 125, 76 - , 125, 83 - , 125, 84 - , 125, 85 - , 125, 77 - , 126, 98 - , 126, 125 - , 127, 118 - , 127, 128 - , 127, 127, 34, 107, 56 - , 127, 127, 15, 126 - , 127, 43, 127, 36, 129, 60 - , 130, 127 - , 130, 43, 130 - , 131, 127, 36, 129, 60 - , 131, 131, 36, 129, 60 - , 131, 131, 34, 107, 56 - , 131, 131, 15, 126 - , 129 - , 129, 132 - , 132, 123 - , 132, 132, 8, 123 - , 133, 130 - , 133, 131 - , 134, 133 - , 134, 133, 53 - , 134, 133, 42 - , 135, 134 - , 135, 11, 135 - , 135, 75, 135 - , 135, 73, 135 - , 135, 53, 135 - , 135, 42, 135 - , 135, 51, 135 - , 135, 40, 135 - , 135, 71, 135 - , 135, 44, 135 - , 136, 135 - , 136, 136, 63, 135 - , 136, 136, 12, 135 - , 136, 136, 57, 135 - , 137, 136 - , 137, 137, 51, 136 - , 137, 137, 40, 136 - , 138, 137 - , 138, 138, 38, 137 - , 138, 138, 25, 137 - , 138, 138, 27, 137 - , 139, 138 - , 139, 139, 37, 138 - , 139, 139, 24, 138 - , 139, 139, 35, 138 - , 139, 139, 23, 138 - , 139, 139, 32, 138 - , 139, 139, 31, 138 - , 140, 138 - , 140, 140, 37, 138 - , 140, 140, 24, 138 - , 140, 140, 35, 138 - , 140, 140, 23, 138 - , 140, 140, 32, 138 - , 141, 139 - , 141, 141, 18, 139 - , 141, 141, 45, 139 - , 141, 141, 19, 139 - , 141, 141, 46, 139 - , 142, 140 - , 142, 142, 18, 140 - , 142, 142, 45, 140 - , 142, 142, 19, 140 - , 142, 142, 46, 140 - , 143, 141 - , 143, 143, 1, 141 - , 144, 142 - , 144, 144, 1, 142 - , 145, 143 - , 145, 145, 78, 143 - , 146, 144 - , 146, 146, 78, 144 - , 147, 145 - , 147, 147, 48, 145 - , 148, 146 - , 148, 148, 48, 146 - , 149, 147 - , 149, 149, 2, 147 - , 150, 148 - , 150, 150, 2, 148 - , 151, 149 - , 151, 151, 50, 149 - , 152, 150 - , 152, 152, 50, 150 - , 153, 151 - , 153, 151, 54, 123, 7, 123 - , 154, 152 - , 154, 152, 54, 155, 7, 155 - , 123, 153 - , 123, 133, 156, 123 - , 155, 154 - , 155, 133, 156, 155 - , 156, 17 - , 156, 64 - , 156, 13 - , 156, 58 - , 156, 52 - , 156, 41 - , 156, 39 - , 156, 26 - , 156, 28 - , 156, 3 - , 156, 79 - , 156, 49 - , 107, 123 - , 107, 107, 8, 123 - , 157 - , 157, 107 - , 158, 155 - , 158, 158, 8, 155 - , 159 - , 159, 158 - , 160, 108 - , 160, 117 - , 160, 109 - , 160, 110 - , 160, 112 - , 160, 161 - , 160, 162 - , 160, 163 - , 160, 164 - , 160, 165 - , 160, 166 - , 160, 167 - , 160, 168 - , 160, 169 - , 160, 111 - , 108, 33, 170, 55 - , 171, 160 - , 171, 171, 160 - , 170 - , 170, 171 - , 117, 172, 173, 62 - , 117, 172, 173, 61 - , 172, 83 - , 172, 74 - , 173, 174 - , 173, 173, 8, 174 - , 175, 176 - , 175, 175, 8, 176 - , 174, 98, 177 - , 176, 98, 178 - , 179, 17, 123 - , 177 - , 177, 179 - , 180, 17, 155 - , 178 - , 178, 180 - , 109, 61 - , 110, 107, 62 - , 110, 107, 61 - , 112, 30, 36, 107, 60, 160, 16, 160 - , 112, 30, 36, 107, 60, 160 - , 161, 14, 160, 76, 36, 107, 60, 62 - , 161, 14, 160, 76, 36, 107, 60, 61 - , 161, 76, 36, 107, 60, 160 - , 161, 21, 36, 159, 61, 157, 61, 157, 60, 160 - , 161, 21, 36, 74, 175, 61, 157, 61, 157, 60, 160 - , 161, 21, 36, 133, 31, 107, 60, 160 - , 161, 21, 36, 74, 176, 31, 107, 60, 160 - , 162, 9, 62 - , 162, 9, 61 - , 162, 9, 98, 62 - , 162, 9, 98, 61 - , 163, 4, 62 - , 163, 4, 61 - , 163, 4, 98, 62 - , 163, 4, 98, 61 - , 164, 59, 157, 62 - , 164, 59, 157, 61 - , 165, 77, 36, 107, 60, 160 - , 167, 68, 36, 107, 60, 181 - , 181, 33, 182, 55 - , 181, 33, 182, 183, 182, 55 - , 184, 185 - , 184, 184, 185 - , 182 - , 182, 184 - , 185, 5, 107, 7, 170 - , 183, 10, 7, 170 - , 166, 67, 7, 160 - , 166, 66, 7, 160 - , 166, 29, 7, 160 - , 168, 70, 107, 62 - , 168, 70, 107, 61 - , 169, 72, 108, 186 - , 169, 72, 108, 187 - , 169, 72, 108, 186, 187 - , 186, 6, 36, 98, 60, 108 - , 187, 20, 108 - , 111, 84, 62 - , 111, 84, 61 - , 116, 22, 98, 36, 188, 60, 33, 189, 55 - , 128, 22, 190, 36, 188, 60, 33, 189, 55 - , 191, 98 - , 191, 191, 8, 98 - , 188 - , 188, 191 - , 189 - , 189, 192 - , 192, 193 - , 193, 194 - , 193, 193, 194 - , 194, 160 - , 194, 116 - , 190 - , 190, 98 - , 121 - , 121, 122 - , 195, 92, 0}; - -const int QmlJSGrammar::rule_index [] = { - 0, 3, 5, 7, 9, 12, 16, 20, 26, 32, - 36, 40, 45, 50, 57, 64, 70, 76, 77, 79, - 81, 84, 86, 90, 93, 97, 100, 102, 108, 110, - 113, 116, 121, 125, 129, 133, 137, 141, 145, 147, - 149, 151, 152, 154, 157, 162, 168, 171, 176, 181, - 187, 193, 200, 207, 215, 223, 225, 227, 229, 231, - 233, 235, 237, 239, 241, 243, 245, 247, 249, 251, - 253, 255, 258, 262, 266, 271, 277, 281, 286, 290, - 292, 296, 298, 301, 305, 310, 312, 315, 319, 325, - 327, 329, 331, 333, 335, 337, 339, 341, 343, 345, - 347, 349, 351, 353, 355, 357, 359, 361, 363, 365, - 367, 369, 371, 373, 375, 377, 379, 381, 383, 385, - 387, 389, 391, 393, 395, 397, 399, 401, 403, 405, - 407, 412, 416, 422, 424, 427, 432, 437, 442, 446, - 447, 449, 451, 455, 457, 459, 461, 464, 467, 469, - 472, 475, 478, 481, 484, 487, 490, 493, 496, 498, - 502, 506, 510, 512, 516, 520, 522, 526, 530, 534, - 536, 540, 544, 548, 552, 556, 560, 562, 566, 570, - 574, 578, 582, 584, 588, 592, 596, 600, 602, 606, - 610, 614, 618, 620, 624, 626, 630, 632, 636, 638, - 642, 644, 648, 650, 654, 656, 660, 662, 666, 668, - 672, 674, 678, 680, 686, 688, 694, 696, 700, 702, - 706, 708, 710, 712, 714, 716, 718, 720, 722, 724, - 726, 728, 730, 732, 736, 737, 739, 741, 745, 746, - 748, 750, 752, 754, 756, 758, 760, 762, 764, 766, - 768, 770, 772, 774, 776, 778, 782, 784, 787, 788, - 790, 794, 798, 800, 802, 804, 808, 810, 814, 817, - 820, 823, 824, 826, 829, 830, 832, 834, 837, 840, - 848, 854, 862, 870, 876, 886, 897, 905, 914, 917, - 920, 924, 928, 931, 934, 938, 942, 946, 950, 956, - 962, 966, 972, 974, 977, 978, 980, 985, 989, 993, - 997, 1001, 1005, 1009, 1013, 1017, 1022, 1028, 1031, 1034, - 1037, 1046, 1055, 1057, 1061, 1062, 1064, 1065, 1067, 1069, - 1071, 1074, 1076, 1078, 1079, 1081, 1082, 1084}; -#endif // QLALR_NO_QMLJSGRAMMAR_DEBUG_INFO + 1, 1, 1, 4, 3, 5, 1, 2, 4, 4, + 4, 3, 0, 1, 1, 3, 1, 1, 1, 2, + 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 1, 3, 3, 3, 1, 3, 3, 1, 3, + 3, 3, 1, 3, 3, 3, 3, 3, 3, 1, + 3, 3, 3, 3, 3, 1, 3, 3, 3, 3, + 1, 3, 3, 3, 3, 1, 3, 1, 3, 1, + 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, + 3, 1, 3, 1, 3, 1, 5, 1, 5, 1, + 3, 1, 3, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 3, 0, 1, 1, + 3, 0, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, + 2, 0, 1, 3, 3, 1, 1, 1, 3, 1, + 3, 2, 2, 2, 0, 1, 2, 0, 1, 1, + 2, 2, 7, 5, 7, 7, 5, 9, 10, 7, + 8, 2, 2, 3, 3, 2, 2, 3, 3, 3, + 3, 5, 5, 3, 5, 1, 2, 0, 1, 4, + 3, 3, 3, 3, 3, 3, 3, 3, 4, 5, + 2, 2, 2, 8, 8, 1, 3, 0, 1, 0, + 1, 1, 1, 2, 1, 1, 0, 1, 0, 1, + 2}; const int QmlJSGrammar::action_default [] = { - 18, 2, 0, 4, 3, 0, 0, 80, 60, 61, - 58, 59, 62, 0, 0, 0, 6, 7, 0, 8, - 9, 0, 10, 0, 0, 11, 0, 16, 17, 81, - 0, 12, 13, 0, 14, 15, 5, 19, 0, 1, - 0, 26, 56, 263, 0, 0, 61, 24, 62, 264, - 27, 20, 0, 0, 0, 57, 0, 41, 40, 39, - 0, 0, 50, 0, 51, 166, 233, 197, 205, 201, - 145, 217, 193, 0, 130, 64, 146, 209, 213, 134, - 163, 144, 149, 129, 183, 170, 0, 70, 71, 67, - 334, 336, 0, 0, 0, 0, 0, 0, 65, 68, - 0, 0, 69, 63, 0, 66, 0, 0, 159, 0, - 0, 146, 165, 148, 147, 0, 0, 0, 161, 162, - 160, 164, 0, 194, 0, 0, 0, 0, 184, 0, - 0, 0, 0, 0, 0, 174, 0, 0, 0, 168, - 169, 167, 172, 176, 175, 173, 171, 186, 185, 187, - 0, 202, 0, 198, 0, 0, 140, 127, 139, 128, - 96, 97, 98, 123, 99, 124, 100, 101, 102, 103, - 104, 105, 106, 107, 108, 109, 110, 111, 112, 125, - 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, - 126, 0, 0, 138, 234, 141, 0, 142, 0, 143, - 137, 54, 55, 0, 230, 223, 221, 228, 229, 227, - 226, 232, 225, 224, 222, 231, 218, 0, 206, 0, - 0, 210, 0, 0, 214, 0, 0, 140, 132, 0, - 131, 0, 136, 150, 0, 335, 325, 326, 0, 323, - 0, 324, 0, 327, 241, 248, 247, 255, 243, 0, - 244, 328, 0, 333, 245, 246, 251, 249, 330, 329, - 332, 252, 0, 0, 0, 0, 0, 334, 60, 0, - 336, 61, 235, 277, 62, 0, 0, 0, 0, 0, - 253, 254, 242, 250, 278, 279, 322, 331, 0, 293, - 294, 295, 296, 0, 289, 290, 291, 292, 319, 320, - 0, 0, 0, 0, 0, 282, 283, 239, 237, 199, - 207, 203, 219, 195, 240, 0, 146, 211, 215, 188, - 177, 0, 0, 196, 0, 0, 0, 0, 189, 0, - 0, 0, 0, 0, 181, 179, 182, 180, 178, 191, - 190, 192, 0, 204, 0, 200, 0, 238, 146, 0, - 220, 235, 236, 0, 235, 0, 0, 285, 0, 0, - 0, 287, 0, 208, 0, 0, 212, 0, 0, 216, - 275, 0, 267, 276, 270, 0, 274, 0, 235, 268, - 0, 235, 0, 0, 286, 0, 0, 0, 288, 335, - 325, 0, 0, 327, 0, 321, 0, 311, 0, 0, - 0, 281, 0, 280, 0, 337, 0, 95, 257, 260, - 0, 96, 263, 99, 124, 101, 102, 67, 106, 107, - 60, 108, 111, 65, 68, 61, 235, 62, 69, 114, - 63, 116, 66, 118, 119, 264, 121, 122, 126, 0, - 88, 0, 0, 90, 94, 92, 78, 91, 93, 0, - 89, 77, 258, 256, 134, 135, 140, 0, 133, 0, - 310, 0, 297, 298, 0, 309, 0, 0, 0, 300, - 305, 303, 306, 0, 0, 304, 305, 0, 301, 0, - 302, 259, 308, 0, 259, 307, 0, 312, 313, 0, - 259, 314, 315, 0, 0, 316, 0, 0, 0, 317, - 318, 152, 151, 0, 0, 0, 284, 0, 0, 0, - 299, 82, 0, 0, 86, 72, 0, 74, 84, 0, - 75, 85, 87, 76, 83, 73, 0, 79, 156, 154, - 158, 155, 153, 157, 0, 0, 0, 48, 0, 49, - 0, 52, 53, 47, 42, 43, 0, 0, 0, 0, - 45, 46, 44, 25, 21, 0, 33, 36, 34, 0, - 35, 38, 259, 0, 29, 0, 37, 32, 96, 263, - 99, 124, 101, 102, 67, 106, 107, 60, 108, 111, - 65, 68, 61, 235, 62, 69, 114, 63, 116, 66, - 118, 119, 264, 121, 122, 126, 64, 0, 22, 0, - 28, 23, 30, 31, 272, 265, 0, 273, 269, 0, - 271, 261, 0, 262, 266, 338}; + 0, 0, 0, 21, 0, 169, 236, 200, 208, 204, + 148, 220, 196, 3, 133, 67, 149, 212, 216, 137, + 166, 147, 152, 132, 186, 173, 0, 73, 74, 70, + 337, 63, 339, 0, 0, 0, 0, 0, 0, 68, + 71, 0, 0, 64, 65, 72, 66, 0, 69, 0, + 0, 162, 0, 0, 149, 168, 151, 150, 0, 0, + 0, 164, 165, 163, 167, 0, 197, 0, 0, 0, + 0, 187, 0, 0, 0, 0, 0, 0, 177, 0, + 0, 0, 171, 172, 170, 175, 179, 178, 176, 174, + 189, 188, 190, 0, 205, 0, 201, 0, 0, 143, + 130, 142, 131, 99, 100, 101, 126, 102, 127, 103, + 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, + 114, 115, 128, 116, 117, 118, 119, 120, 121, 122, + 123, 124, 125, 129, 0, 0, 141, 237, 144, 0, + 145, 0, 146, 140, 0, 233, 226, 224, 231, 232, + 230, 229, 235, 228, 227, 225, 234, 221, 0, 209, + 0, 0, 213, 0, 0, 217, 0, 0, 143, 135, + 0, 134, 0, 139, 153, 0, 338, 328, 329, 0, + 326, 0, 327, 0, 330, 244, 251, 250, 258, 246, + 0, 247, 331, 0, 336, 248, 249, 254, 252, 333, + 332, 335, 255, 0, 266, 0, 0, 0, 0, 337, + 63, 0, 339, 64, 238, 280, 65, 0, 0, 0, + 267, 0, 0, 256, 257, 0, 245, 253, 281, 282, + 325, 334, 0, 296, 297, 298, 299, 0, 292, 293, + 294, 295, 322, 323, 0, 0, 0, 0, 0, 285, + 286, 242, 240, 202, 210, 206, 222, 198, 243, 0, + 149, 214, 218, 191, 180, 0, 0, 199, 0, 0, + 0, 0, 192, 0, 0, 0, 0, 0, 184, 182, + 185, 183, 181, 194, 193, 195, 0, 207, 0, 203, + 0, 241, 149, 0, 223, 238, 239, 0, 238, 0, + 0, 288, 0, 0, 0, 290, 0, 211, 0, 0, + 215, 0, 0, 219, 278, 0, 270, 279, 273, 0, + 277, 0, 238, 271, 0, 238, 0, 0, 289, 0, + 0, 0, 291, 338, 328, 0, 0, 330, 0, 324, + 0, 314, 0, 0, 0, 284, 0, 283, 0, 340, + 0, 98, 260, 263, 0, 99, 266, 102, 127, 104, + 105, 70, 109, 110, 63, 111, 114, 68, 71, 64, + 238, 65, 72, 117, 66, 119, 69, 121, 122, 267, + 124, 125, 129, 0, 91, 0, 0, 93, 97, 95, + 81, 94, 96, 0, 92, 80, 261, 259, 137, 138, + 143, 0, 136, 0, 313, 0, 300, 301, 0, 312, + 0, 0, 0, 303, 308, 306, 309, 0, 0, 307, + 308, 0, 304, 0, 305, 262, 311, 0, 262, 310, + 0, 315, 316, 0, 262, 317, 318, 0, 0, 319, + 0, 0, 0, 320, 321, 155, 154, 0, 0, 0, + 287, 0, 0, 0, 302, 275, 268, 0, 276, 272, + 0, 274, 264, 0, 265, 269, 85, 0, 0, 89, + 75, 0, 77, 87, 0, 78, 88, 90, 79, 86, + 76, 0, 82, 159, 157, 161, 158, 156, 160, 2, + 5, 0, 7, 6, 0, 1, 83, 61, 62, 0, + 0, 0, 9, 10, 0, 11, 12, 0, 13, 0, + 0, 14, 0, 19, 20, 84, 0, 15, 16, 0, + 17, 18, 8, 22, 0, 4, 0, 29, 59, 0, + 0, 64, 27, 65, 30, 23, 0, 0, 60, 0, + 44, 43, 42, 0, 0, 53, 0, 54, 0, 57, + 58, 0, 0, 0, 51, 0, 52, 0, 55, 56, + 50, 45, 46, 0, 0, 0, 0, 48, 49, 47, + 28, 24, 0, 36, 39, 37, 0, 38, 41, 262, + 0, 32, 0, 40, 35, 99, 266, 102, 127, 104, + 105, 70, 109, 110, 63, 111, 114, 68, 71, 64, + 238, 65, 72, 117, 66, 119, 69, 121, 122, 267, + 124, 125, 129, 67, 0, 25, 0, 31, 26, 33, + 34, 341}; const int QmlJSGrammar::goto_default [] = { - 6, 5, 39, 1, 4, 3, 75, 38, 50, 52, - 51, 597, 41, 565, 566, 249, 244, 248, 250, 247, - 254, 535, 546, 545, 253, 282, 83, 513, 512, 406, - 405, 66, 404, 407, 158, 79, 74, 196, 81, 70, - 195, 76, 82, 108, 80, 65, 85, 84, 319, 72, - 313, 67, 309, 69, 311, 68, 310, 77, 317, 78, - 318, 71, 312, 308, 349, 461, 314, 315, 408, 255, - 246, 245, 257, 283, 256, 261, 280, 281, 410, 409, - 54, 606, 605, 371, 372, 608, 374, 607, 373, 469, - 473, 476, 472, 471, 491, 492, 238, 252, 234, 237, - 251, 259, 258, 0}; + 4, 495, 352, 190, 494, 525, 490, 493, 492, 15, + 524, 534, 536, 535, 614, 527, 582, 583, 185, 189, + 191, 188, 195, 552, 563, 562, 194, 226, 23, 468, + 467, 350, 349, 6, 348, 351, 101, 19, 14, 139, + 21, 10, 138, 16, 22, 51, 20, 5, 25, 24, + 263, 12, 257, 7, 253, 9, 255, 8, 254, 17, + 261, 18, 262, 11, 256, 252, 293, 405, 258, 259, + 196, 187, 186, 198, 227, 197, 202, 223, 224, 354, + 353, 225, 457, 456, 315, 316, 459, 318, 458, 317, + 413, 417, 420, 416, 415, 435, 436, 179, 193, 175, + 178, 192, 200, 199, 0}; const int QmlJSGrammar::action_index [] = { - 7, -92, 389, -92, -10, 343, 168, -92, -92, -92, - -92, -92, -92, 233, 308, 178, -92, -92, 86, -92, - -92, 173, -92, 151, 137, -92, 108, -92, -92, -92, - 184, -92, -92, 105, -92, -92, -92, -92, 82, -92, - 456, -92, -92, -92, 44, 190, 195, -92, -27, -92, - -92, -92, 431, 208, 187, -92, 214, -92, -92, -92, - -15, 224, -92, 764, -92, 109, -92, 8, -47, -78, - 194, -92, 376, 143, -92, -92, 603, 6, 85, 186, - 213, -92, -92, -92, 514, 302, 764, -92, -92, -92, - 237, 1607, 1014, 764, 764, 764, 683, 764, -92, -92, - 764, 764, -92, -92, 764, -92, 764, 764, -92, 764, - 764, 133, 220, -92, -92, 764, 764, 764, -92, -92, - -92, 149, 764, 376, 764, 764, 764, 764, 412, 764, - 764, 764, 764, 764, 764, 302, 764, 764, 764, 131, - 152, 145, 302, 235, 235, 302, 235, 514, 427, 392, - 764, -73, 764, 11, 1519, 764, 764, -92, -92, -92, - -92, -92, -92, -92, -92, -92, -92, -92, -92, -92, - -92, -92, -92, -92, -92, -92, -92, -92, -92, -92, - -92, -92, -92, -92, -92, -92, -92, -92, -92, -92, - -92, 94, 764, -92, -92, 91, 78, -92, 764, -92, - -92, -92, -92, 764, -92, -92, -92, -92, -92, -92, - -92, -92, -92, -92, -92, -92, -92, 764, -41, 764, - 764, 45, 37, 764, -92, 1519, 764, 764, -92, 120, - -92, 41, -92, -92, 73, -92, 171, 54, 26, -92, - 258, -92, 52, 1871, -92, -92, -92, -92, -92, 253, - -92, -92, 2, -92, -92, -92, -92, -92, -92, 1871, - -92, -92, 346, 364, 126, 1783, 30, 250, 56, 25, - 2047, 58, 764, -92, 61, 40, 764, 39, 35, 34, - -92, -92, -92, -92, -92, -92, -92, -92, 122, -92, - -92, -92, -92, 128, -92, -92, -92, -92, -92, -92, - 27, 70, 764, 118, 132, -92, -92, 930, -92, 89, - 65, 67, -92, 320, 83, -2, 516, 92, 141, 445, - 235, 192, 764, 312, 764, 764, 764, 764, 445, 764, - 764, 764, 764, 764, 235, 235, 235, 235, 235, 336, - 445, 445, 764, -67, 764, 76, 764, -92, 603, 764, - -92, 764, -4, -37, 764, -12, 1783, -92, 764, 119, - 1783, -92, 764, 3, 764, 764, 50, 46, 764, -92, - 33, 136, 9, -92, -92, 764, -92, 245, 764, -92, - -30, 764, -22, 1783, -92, 764, 117, 1783, -92, -3, - 234, 69, 12, 1871, -23, -92, 1783, -92, 764, 97, - 1783, 20, 1783, -92, 28, 29, -13, -92, -92, 1783, - -21, 280, 18, 372, 81, 764, 1783, 19, -9, 284, - 23, -8, 683, 22, 36, -92, 849, -92, 42, 24, - 49, 764, 48, 21, 764, 32, 764, 5, 10, 764, - -92, 1695, 16, -92, -92, -92, -92, -92, -92, 764, - -92, -92, -92, -92, 193, -92, 764, -57, -92, 1783, - -92, 111, -92, -92, 1783, -92, 764, 114, -16, -92, - 13, -92, 17, 110, 764, -92, 15, 14, -92, -45, - -92, 1783, -92, 116, 1783, -92, 206, -92, -92, 112, - 1783, -7, -92, -20, -14, -92, 205, -54, -18, -92, - -92, -92, -92, 764, 99, 1783, -92, 764, 103, 1783, - -92, -92, 106, 1266, -92, -92, 1098, -92, -92, 1182, - -92, -92, -92, -92, -92, -92, 104, -92, -92, -92, - -92, -92, -92, -92, 60, 64, 174, -92, 764, -92, - 203, -92, -92, 72, 217, 90, 71, 226, 204, 181, - -92, -92, -92, -92, -92, 1431, -92, -92, -92, 274, - -92, -92, 1959, 1350, -92, 79, -92, -92, 323, 80, - 325, 93, 764, 1783, 62, 38, 297, 51, 31, 683, - 57, 66, -92, 849, -92, 68, 43, 74, 764, 75, - 59, 764, 77, 764, 53, 47, 55, 96, -92, 315, - -92, -92, -92, -92, 63, -92, 244, -92, -92, 764, - -92, -92, 252, -92, -92, -92, + 236, 824, 1879, -3, 176, 80, -95, 102, 36, -14, + 266, -95, 337, 90, -95, -95, 528, 100, 78, 344, + 220, -95, -95, -95, 565, 177, 824, -95, -95, -95, + 209, -95, 1697, 1083, 824, 824, 824, 740, 824, -95, + -95, 824, 824, -95, -95, -95, -95, 824, -95, 824, + 824, -95, 824, 824, 136, 183, -95, -95, 824, 824, + 824, -95, -95, -95, 146, 824, 342, 824, 824, 690, + 824, 565, 824, 824, 824, 824, 824, 824, 156, 824, + 824, 824, 134, 124, 84, 232, 255, 261, 260, 218, + 487, 472, 565, 824, 49, 824, 73, 1606, 824, 824, + -95, -95, -95, -95, -95, -95, -95, -95, -95, -95, + -95, -95, -95, -95, -95, -95, -95, -95, -95, -95, + -95, -95, -95, -95, -95, -95, -95, -95, -95, -95, + -95, -95, -95, -95, 137, 824, -95, -95, 63, 35, + -95, 824, -95, -95, 824, -95, -95, -95, -95, -95, + -95, -95, -95, -95, -95, -95, -95, -95, 824, 38, + 824, 824, 70, 62, 824, -95, 1606, 824, 824, -95, + 104, -95, 37, -95, -95, 40, -95, 198, 67, 46, + -95, 168, -95, 45, 1970, -95, -95, -95, -95, -95, + 205, -95, -95, 44, -95, -95, -95, -95, -95, -95, + 1970, -95, -95, 375, -95, 427, 82, 1879, 32, 243, + 59, 53, 2152, 74, 824, -95, 76, 58, 824, 57, + -95, 65, 64, -95, -95, 300, -95, -95, -95, -95, + -95, -95, 79, -95, -95, -95, -95, 77, -95, -95, + -95, -95, -95, -95, 50, 68, 824, 110, 72, -95, + -95, 996, -95, 60, 34, -8, -95, 421, 71, 19, + 582, 61, 92, 420, 287, 249, 824, 304, 824, 824, + 824, 824, 394, 824, 824, 824, 824, 824, 308, 279, + 286, 293, 294, 379, 373, 493, 824, -5, 824, 66, + 824, -95, 657, 824, -95, 824, 54, 30, 824, 33, + 1879, -95, 824, 117, 1879, -95, 824, 69, 824, 824, + 94, 52, 824, -95, 75, 111, 56, -95, -95, 824, + -95, 278, 824, -95, 55, 824, -15, 1879, -95, 824, + 122, 1879, -95, -22, 305, -42, -27, 1970, -51, -95, + 1879, -95, 824, 113, 1879, -1, 1879, -95, 6, 3, + -45, -95, -95, 1879, -32, 409, 14, 424, 107, 824, + 1879, 2, -34, 318, 81, -35, 740, -4, -7, -95, + 912, -95, 0, -12, 21, 824, 41, 20, 824, 43, + 824, 16, 15, 824, -95, 1788, 31, -95, -95, -95, + -95, -95, -95, 824, -95, -95, -95, -95, 269, -95, + 824, 17, -95, 1879, -95, 86, -95, -95, 1879, -95, + 824, 103, 23, -95, 42, -95, 26, 112, 824, -95, + 28, 25, -95, -25, -95, 1879, -95, 101, 1879, -95, + 281, -95, -95, 109, 1879, 9, -95, -10, 11, -95, + 272, -17, 8, -95, -95, -95, -95, 824, 99, 1879, + -95, 824, 106, 1879, -95, 22, -95, 190, -95, -95, + 824, -95, -95, 229, -95, -95, -95, 105, 1257, -95, + -95, 1344, -95, -95, 1170, -95, -95, -95, -95, -95, + -95, 97, -95, -95, -95, -95, -95, -95, -95, -95, + -95, 468, -95, -39, 334, -95, -95, -95, -95, 201, + 359, 194, -95, -95, 88, -95, -95, 202, -95, 207, + 164, -95, 129, -95, -95, -95, 181, -95, -95, 91, + -95, -95, -95, -95, 121, -95, 491, -95, -95, -9, + 225, 170, -95, 7, -95, -95, 477, 264, -95, 126, + -95, -95, -95, 5, 144, -95, 824, -95, 188, -95, + -95, 4, 13, 158, -95, 824, -95, 180, -95, -95, + 1, 133, 27, -33, 155, 127, 163, -95, -95, -95, + -95, -95, 1428, -95, -95, -95, 329, -95, -95, 2061, + 1515, -95, 125, -95, -95, 398, 51, 384, 118, 824, + 1879, 18, 24, 328, 81, 29, 740, 48, 47, -95, + 912, -95, 39, -28, -2, 824, 12, -11, 824, 10, + 824, -20, -24, -13, 115, -95, 395, -95, -95, -95, + -95, -95, - -104, -104, 82, -104, 6, 78, -104, -104, -104, -104, - -104, -104, -104, -104, -104, 28, -104, -104, -104, -104, - -104, 15, -104, 11, -104, -104, -104, -104, -104, -104, - 19, -104, -104, -104, -104, -104, -104, -104, -104, -104, - 343, -104, -104, -104, -104, 27, -104, -104, -104, -104, - -104, -104, 260, -104, 26, -104, -6, -104, -104, -104, - -104, -104, -104, -11, -104, -104, -104, -104, -104, -104, - -104, -104, -104, -104, -104, -104, -56, -104, -104, -104, - -104, -104, -104, -104, -104, -104, 137, -104, -104, -104, - 60, -104, 50, 64, 141, 144, 90, 147, -104, -104, - 126, 106, -104, -104, 109, -104, 105, 110, -104, 182, - 121, -104, -104, -104, -104, 113, 101, 171, -104, -104, - -104, -104, 164, -104, 170, 152, 150, 151, -104, 154, - 99, 155, 161, 81, 55, -104, 57, 66, 63, -104, - -104, -104, -104, -104, -104, -104, -104, -104, -104, -104, - 80, -104, 69, -104, 93, 36, 38, -104, -104, -104, - -104, -104, -104, -104, -104, -104, -104, -104, -104, -104, - -104, -104, -104, -104, -104, -104, -104, -104, -104, -104, - -104, -104, -104, -104, -104, -104, -104, -104, -104, -104, - -104, -104, 41, -104, -104, -104, -104, -104, -12, -104, - -104, -104, -104, -17, -104, -104, -104, -104, -104, -104, - -104, -104, -104, -104, -104, -104, -104, 118, -104, 165, - -2, -104, -104, 25, -104, 209, 16, 172, -104, -104, - -104, -104, -104, -104, -104, -104, 17, -104, -104, -104, - 18, -104, -104, -46, -104, -104, -104, -104, -104, -104, - -104, -104, -104, -104, -104, -104, -104, -104, -104, 56, - -104, -104, 0, 30, -104, -65, -104, 12, -104, -104, - -104, -104, 119, -104, -104, -104, 13, 14, -104, -104, - -104, -104, -104, -104, -104, -104, -104, -104, -104, -104, - -104, -104, -104, -104, -104, -104, -104, -104, -104, -104, - -104, -104, 23, -104, -104, -104, -104, 148, -104, -104, - -104, -104, -104, -104, -104, -104, -104, -104, -104, -104, - -104, 7, 178, -104, 179, 188, 245, 191, -104, 133, - 131, 129, 140, 130, -104, -104, -104, -104, -104, -104, - -104, -104, 207, -104, 205, -104, 217, -104, -104, 199, - -104, 70, -104, -104, 65, -104, -10, -104, 45, -104, - -16, -104, 203, -104, 223, 219, -104, -104, 192, -104, - -104, -104, -104, -104, -104, 189, -104, 77, 76, -104, - -104, 72, -104, 2, -104, 47, -104, 49, -104, -104, - 87, -104, -104, 71, -104, -104, 10, -104, 34, -104, - -1, -104, -20, -104, -104, -104, -104, -104, -104, -5, - -104, 48, -104, 53, -104, 73, 3, -104, -104, 39, - -104, -104, 68, -104, -104, -104, 119, -104, -104, -104, - -104, 58, -104, 59, 54, -104, 114, -104, -104, 46, - -104, 44, -104, -104, -104, -104, -104, -104, -104, 43, - -104, -104, -104, -104, -104, -104, 173, -104, -104, -4, - -104, -104, -104, -104, -7, -104, 42, -104, -104, -104, - -104, -104, -49, -104, 40, -104, -40, -104, -104, -104, - -104, -31, -104, -104, 4, -104, -104, -104, -104, -104, - -104, -30, -104, -104, 52, -104, 37, -104, -15, -104, - -104, -104, -104, -13, -104, -68, -104, -3, -104, -63, - -104, -104, -104, -24, -104, -104, 92, -104, -104, -22, - -104, -104, -104, -104, -104, -104, -104, -104, -104, -104, - -104, -104, -104, -104, -104, -104, -104, -104, 22, -104, - -104, -104, -104, -104, 21, -104, -104, 35, 32, 33, - -104, -104, -104, -104, -104, 256, -104, -104, -104, 8, - -104, -104, -104, 210, -104, -104, -104, -104, 20, -104, - 30, -104, 51, -41, -104, -104, 29, -104, -104, 74, - -104, -104, -104, 1, -104, -104, -104, -104, 31, -104, - 24, 88, -104, 95, -104, -104, -104, -104, -104, 107, - -104, -104, -104, -104, -104, -104, -104, -104, -104, -21, - -104, -104, 84, -104, -104, -104}; + -105, 21, 23, -105, -105, -105, -105, -105, -105, -105, + -105, -105, -105, -105, -105, -105, -45, -105, -105, -105, + -105, -105, -105, -105, -105, -105, 82, -105, -105, -105, + 35, -105, -105, 31, 33, 179, 161, 176, 165, -105, + -105, 183, 182, -105, -105, -105, -105, 140, -105, 143, + 139, -105, 159, 135, -105, -105, -105, -105, 156, 155, + 152, -105, -105, -105, -105, 90, -105, 126, 128, 130, + 160, -105, 169, 115, 87, 89, 124, 97, -105, 73, + 76, 39, -105, -105, -105, -105, -105, -105, -105, -105, + -105, -105, -105, 168, -105, 108, -105, 80, 74, 70, + -105, -105, -105, -105, -105, -105, -105, -105, -105, -105, + -105, -105, -105, -105, -105, -105, -105, -105, -105, -105, + -105, -105, -105, -105, -105, -105, -105, -105, -105, -105, + -105, -105, -105, -105, -105, 62, -105, -105, -105, -105, + -105, 55, -105, -105, 66, -105, -105, -105, -105, -105, + -105, -105, -105, -105, -105, -105, -105, -105, 100, -105, + 148, -31, -105, -105, -33, -105, 206, 37, 103, -105, + -105, -105, -105, -105, -105, -105, -105, 22, -105, -105, + -105, 19, -105, -105, 28, -105, -105, -105, -105, -105, + -105, -105, -105, -105, -105, -105, -105, -105, -105, -105, + 91, -105, -105, 64, -105, 50, -105, 41, -105, 43, + -105, -105, -105, -105, 54, -105, -105, -105, 42, 67, + -105, -105, -105, -105, -105, 4, -105, -105, -105, -105, + -105, -105, -105, -105, -105, -105, -105, -105, -105, -105, + -105, -105, -105, -105, -105, -105, 34, -105, -105, -105, + -105, 107, -105, -105, -105, -105, -105, -105, -105, -105, + -105, -105, -105, -105, -105, 17, 197, -105, 230, 234, + 242, 211, -105, 122, 116, 105, 96, 78, -105, -105, + -105, -105, -105, -105, -105, -105, 188, -105, 215, -105, + 214, -105, -105, 203, -105, 153, -105, -105, 273, -105, + 5, -105, 3, -105, 12, -105, 217, -105, 223, 190, + -105, -105, 187, -105, -105, -105, -105, -105, -105, 238, + -105, 129, 186, -105, -105, 189, -105, 52, -105, 53, + -105, 56, -105, -105, 137, -105, -105, 98, -105, -105, + 40, -105, 45, -105, 44, -105, 59, -105, -105, -105, + -105, -105, -105, 61, -105, 57, -105, 60, -105, 109, + 68, -105, -105, 46, -105, -105, 150, -105, -105, -105, + 29, -105, -105, -105, -105, 0, -105, 32, 86, -105, + 123, -105, -105, -6, -105, -26, -105, -105, -105, -105, + -105, -105, -105, -24, -105, -105, -105, -105, -105, -105, + 95, -105, -105, 16, -105, -105, -105, -105, 2, -105, + 8, -105, -105, -105, -105, -105, -19, -105, 75, -105, + -38, -105, -105, -105, -105, -17, -105, -105, -30, -105, + -105, -105, -105, -105, -105, -58, -105, -105, 58, -105, + 51, -105, 49, -105, -105, -105, -105, 171, -105, 72, + -105, 65, -105, 63, -105, -105, -105, -105, -105, -105, + 38, -105, -105, 184, -105, -105, -105, -105, 47, -105, + -105, 147, -105, -105, 48, -105, -105, -105, -105, -105, + -105, -105, -105, -105, -105, -105, -105, -105, -105, -105, + -105, 88, -105, 71, 85, -105, -105, -105, -105, -105, + -105, 1, -105, -105, -105, -105, -105, -4, -105, 6, + -105, -105, -105, -105, -105, -105, 7, -105, -105, -105, + -105, -105, -105, -105, -105, -105, 369, -105, -105, -105, + 10, -105, -105, -105, -105, -105, 278, -105, -105, -22, + -105, -105, -105, -105, -105, -105, 69, -105, -105, -105, + -105, -105, -105, -105, -105, 9, -105, -105, -105, -105, + -105, 24, -105, -105, 11, 18, 25, -105, -105, -105, + -105, -105, 290, -105, -105, -105, 36, -105, -105, -105, + 210, -105, -105, -105, -105, 30, -105, 26, -105, 79, + 27, -105, -105, 13, -105, -105, 77, -105, -105, -105, + 20, -105, -105, -105, -105, 14, -105, 15, 117, -105, + 104, -105, -105, -105, -105, -105, 81, -105, -105, -105, + -105, -105}; const int QmlJSGrammar::action_info [] = { - 152, 150, 543, 458, 192, 152, 498, 150, 217, 122, - 480, 344, 122, 494, 61, 490, 496, 470, 474, 490, - 474, 481, 474, 449, 354, -123, -104, 307, 398, -112, - -90, 381, 395, 390, 453, 439, 402, 441, 383, -120, - 385, 503, 451, -94, 223, 393, 507, 217, 356, -93, - 375, 342, 362, 368, 490, -117, -115, 286, -90, 351, - 466, 398, 240, 396, -112, 459, 307, 398, 464, -104, - 507, 503, 490, -94, 307, -93, 466, 322, 2, 466, - 609, -115, -117, 507, -120, 243, 242, -123, -80, 503, - 322, 346, 490, 536, 362, 2, 390, 23, 548, 198, - 0, 232, 192, 301, 599, 192, 302, 192, 544, 236, - 56, 192, 192, 342, 516, 40, 0, 0, 493, 0, - 477, 0, 192, 484, 192, 192, 192, 192, 192, 392, - 0, 551, 494, 0, 0, 219, 0, 0, 200, 220, - 603, 602, 299, 298, 377, 344, 0, 20, 19, 109, - 193, 192, 600, 0, 299, 298, 0, 400, 0, 505, - 110, 115, 517, 509, 527, 478, 35, 34, 615, 28, - 27, 109, 463, 462, 468, 113, 230, 387, 304, 360, - 8, 538, 110, 292, 291, 109, 114, 299, 298, 297, - 296, 364, 109, 306, 305, 365, 110, 378, 32, 31, - 8, 225, 8, 110, 202, 201, 116, 8, 225, 154, - 8, 192, 117, 8, 192, 555, 8, 9, 12, 8, - 226, 8, 227, 23, 57, 115, 30, 226, 155, 456, - 156, 63, 115, 57, 8, 539, 537, 9, 12, 9, - 12, 40, 0, 57, 9, 12, 57, 9, 12, 0, - 9, 12, 612, 9, 12, 8, 9, 12, 9, 12, - 136, 192, 137, 8, 542, 541, 8, 488, 487, 59, - 116, 9, 12, 138, 8, 0, 117, 116, 59, 8, - 58, 8, 192, 117, 0, 64, 62, 8, 59, 58, - 0, 59, 9, 12, 17, 16, 0, 0, 0, 58, - 9, 12, 58, 9, 12, 613, 611, 40, 0, 8, - 0, 9, 12, 8, 285, 284, 9, 12, 9, 12, - -334, 0, 15, 23, 9, 12, 8, 136, 0, 137, - 324, 325, 0, -334, 0, 285, 284, 0, 324, 325, - 138, 290, 289, 0, 8, 0, 9, 12, 0, 0, - 9, 12, 8, 0, 8, 24, 0, 326, 327, 329, - 330, 0, 0, 9, 12, 326, 327, 0, 331, 25, - 22, 332, 8, 333, 11, 8, 0, 0, 0, 0, - 0, 9, 12, 0, 290, 289, 295, 294, 0, 9, - 12, 9, 12, 8, 124, 125, 0, 21, 0, 0, - 10, 8, 11, 0, 0, 0, 0, 290, 289, 9, - 12, 0, 9, 12, 0, 129, 130, 0, 8, 0, - 0, 126, 127, 131, 132, 295, 294, 133, 10, 134, - 9, 12, 0, 295, 294, 129, 130, 0, 9, 12, - 0, 44, 0, 131, 132, 0, 0, 133, 11, 134, - 129, 130, 0, 45, 13, 9, 12, 0, 131, 132, - 8, 0, 133, 0, 134, 0, 44, 0, 329, 330, - 0, 0, 0, 0, 10, 0, 0, 331, 45, 0, - 332, 0, 333, 0, 0, 8, 553, 0, 0, 0, - 11, 0, 0, 0, 0, 0, 0, 46, 48, 0, - 0, 0, 0, 0, 0, 49, 0, 0, 0, 0, - 0, 47, 0, 0, 43, 11, 10, 0, 0, 204, - 0, 0, 46, 48, 0, 0, 0, 0, 0, 205, - 49, 0, 0, 206, 0, 0, 0, 129, 130, 43, - 0, 10, 207, 0, 208, 131, 132, 358, 0, 133, - 0, 134, 0, 0, 0, 209, 0, 210, 113, 0, - 0, 0, 0, 0, 0, 211, 0, 0, 212, 114, - 0, 0, 0, 0, 213, 0, 0, 0, 0, 0, - 214, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 215, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 204, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 205, 0, 0, 0, - 206, 0, 0, 0, 0, 0, 0, 0, 0, 207, - 0, 208, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 209, 0, 210, 113, 0, 0, 0, 0, - 0, 0, 211, 0, 0, 212, 114, 0, 0, 0, - 0, 213, 0, 0, 0, 0, 0, 214, 0, 0, + -97, 342, 251, -115, 339, -118, 337, -96, 410, -107, + 395, 385, 451, 383, 334, 346, 447, -123, 336, -120, + -83, -126, 434, 397, 410, -107, 440, 568, -118, 438, + 424, 418, 425, 418, 544, 565, 560, 561, 393, 460, + 334, 434, 553, 442, 434, 327, -96, 418, -120, 491, + -123, 451, 447, 434, -97, -115, 414, 539, -126, 312, + 251, 266, 135, 306, 95, 342, 340, 266, 251, 164, + 288, 141, 158, 288, 65, 181, 177, 402, 184, 290, + 295, 403, 286, 408, 93, 491, 93, 329, -93, 342, + 434, 298, 319, 300, 410, 143, 306, 173, 135, 230, + 451, 447, 158, 65, 246, 135, 183, 135, 428, 135, + 0, 135, 135, 471, 135, 437, 325, 286, 135, 321, + 52, 135, 421, 616, 52, 135, 245, 95, 160, 438, + 135, 53, 161, 250, 249, 53, 509, 0, 241, 240, + 236, 235, 308, 243, 242, 135, 309, 407, 406, 506, + 505, 546, 521, 520, 526, 540, 540, 482, 58, 449, + 171, 472, 540, 412, 52, 555, 453, 422, 243, 242, + 248, 617, 322, 344, 52, 53, 621, 304, 56, 243, + 242, 79, 331, 80, 31, 53, 620, 619, 135, 57, + 514, 513, 31, 136, 81, 58, 135, 31, 463, 540, + 542, 542, 79, 59, 80, 547, 545, 542, 0, 60, + 31, 541, 541, 135, 0, 81, 0, 0, 541, 556, + 554, 43, 44, 31, 0, 518, 517, 31, 0, 43, + 44, 31, 58, 0, 43, 44, 31, 0, 31, 0, + 59, 559, 558, 79, 542, 80, 60, 43, 44, 550, + 549, 464, 462, 516, 31, 541, 81, 79, 31, 80, + 43, 44, 503, 502, 43, 44, 229, 228, 43, 44, + 81, 572, 31, 43, 44, 43, 44, 59, 31, 509, + 79, 97, 80, 60, 166, 79, 79, 80, 80, 135, + 501, 43, 44, 81, 0, 43, 44, 526, 81, 81, + 98, 31, 99, 167, 79, 400, 80, 31, 0, 43, + 44, 79, 79, 80, 80, 43, 44, 81, 79, 79, + 80, 80, 268, 269, 81, 81, 3, 2, 1, 31, + 0, 81, 81, 79, 31, 80, 0, 135, 43, 44, + 0, 0, 432, 431, 43, 44, 81, 31, 0, 270, + 271, 0, 0, 0, -337, 67, 68, 31, 0, 166, + 67, 68, 526, 31, -337, 0, 43, 44, 0, 0, + 0, 43, 44, 0, 509, 0, 0, 0, 167, 0, + 168, 0, 69, 70, 43, 44, 0, 69, 70, 0, + 229, 228, 0, 498, 43, 44, 273, 274, 0, 0, + 43, 44, 273, 274, 31, 275, 510, 0, 276, 0, + 277, 275, 0, 31, 276, 0, 277, 273, 274, 497, + 511, 508, 0, 0, 31, 0, 275, 31, 0, 276, + 0, 277, 0, 0, 0, 0, 234, 233, 31, 268, + 269, 43, 44, 273, 274, 239, 238, 0, 507, 0, + 43, 44, 275, 31, 498, 276, 31, 277, 0, 234, + 233, 43, 44, 0, 43, 44, 270, 271, 0, 0, + 234, 233, 0, 0, 0, 43, 44, 0, 0, 0, + 497, 0, 0, 0, 0, 239, 238, 529, 239, 238, + 43, 44, 0, 43, 44, 72, 73, 31, 0, 530, + 0, 529, 0, 74, 75, 0, 31, 76, 0, 77, + 72, 73, 0, 530, 0, 0, 273, 274, 74, 75, + 31, 0, 76, 0, 77, 275, 0, 498, 276, 0, + 277, 145, 570, 499, 43, 44, 498, 0, 0, 0, + 0, 146, 0, 531, 533, 147, 532, 0, 0, 0, + 498, 220, 0, 497, 148, 0, 149, 531, 533, 0, + 204, 0, 497, 0, 0, 220, 0, 150, 0, 151, + 56, 0, 0, 0, 204, 0, 497, 152, 0, 0, + 153, 57, 0, 0, 0, 145, 154, 0, 72, 73, + 0, 0, 155, 0, 0, 146, 74, 75, 0, 147, + 76, 0, 77, 0, 0, 0, 0, 156, 148, 0, + 149, 0, 0, 302, 0, 0, 0, 0, 0, 0, + 0, 150, 0, 151, 56, 0, 0, 0, 0, 0, + 0, 152, 0, 0, 153, 57, 0, 0, 0, 0, + 154, 0, 0, 0, 0, 0, 155, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 145, 156, 0, 0, 0, 0, 0, 0, 0, 0, + 146, 0, 0, 0, 147, 0, 0, 0, 0, 0, + 0, 0, 0, 148, 0, 149, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 150, 0, 151, 56, + 0, 26, 27, 28, 0, 0, 152, 0, 0, 153, + 57, 0, 30, 0, 0, 154, 0, 0, 0, 31, + 0, 155, 0, 32, 33, 0, 34, 0, 0, 0, + 35, 0, 36, 37, 38, 0, 156, 40, 0, 0, + 0, 41, 0, 42, 0, 0, 0, 0, 0, 0, + 0, 0, 27, 28, 0, 45, 43, 44, 0, 46, + 0, 47, 30, 49, 0, 50, 0, 0, 0, 31, + 39, 48, 29, 32, 33, 0, 34, 0, 0, 0, + 0, 0, 0, 37, 0, 0, 0, 40, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 45, 43, 44, 0, 46, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 39, 48, 29, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 26, 27, 28, 0, 0, + 0, 0, 0, 0, 0, 0, 30, 0, 0, 0, + 0, 0, 0, 31, 0, 0, 0, 32, 33, 0, + 34, 0, 0, 0, 35, 0, 36, 37, 38, 0, + 0, 40, 0, 0, 0, 41, 0, 42, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 45, + 43, 44, 0, 46, 0, 47, 0, 49, 0, 50, + 0, 0, 0, 0, 39, 48, 29, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, -116, + 0, 0, 0, 26, 27, 28, 0, 0, 0, 0, + 0, 0, 0, 0, 30, 0, 0, 0, 0, 0, + 0, 31, 0, 0, 0, 32, 33, 0, 34, 0, + 0, 0, 35, 0, 36, 37, 38, 0, 0, 40, + 0, 0, 0, 41, 0, 42, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 45, 43, 44, + 0, 46, 0, 47, 0, 49, 0, 50, 0, 0, + 0, 0, 39, 48, 29, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 26, 27, 28, + 0, 0, 0, 0, 0, 0, 0, 0, 30, 0, + 0, 0, 0, 0, 0, 31, 0, 0, 0, 32, + 33, 0, 34, 0, 0, 0, 35, 0, 36, 37, + 38, 0, 0, 40, 0, 0, 0, 41, 0, 42, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 45, 43, 44, 0, 46, 0, 47, 0, 49, + 265, 50, 0, 0, 0, 0, 39, 48, 29, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 469, 0, 0, 26, 27, 28, 0, 0, 0, + 0, 0, 0, 0, 0, 30, 0, 0, 0, 0, + 0, 0, 31, 0, 0, 0, 32, 33, 0, 34, + 0, 0, 0, 35, 0, 36, 37, 38, 0, 0, + 40, 0, 0, 0, 41, 0, 42, 0, 0, 470, + 0, 0, 0, 0, 0, 0, 0, 0, 45, 43, + 44, 0, 46, 0, 47, 0, 49, 0, 50, 0, + 0, 0, 0, 39, 48, 29, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 477, 0, + 0, 26, 27, 28, 0, 0, 0, 0, 0, 0, + 0, 0, 30, 0, 0, 0, 0, 0, 0, 31, + 0, 0, 0, 32, 33, 0, 34, 0, 0, 0, + 35, 0, 36, 37, 38, 0, 0, 40, 0, 0, + 0, 41, 0, 42, 0, 0, 478, 0, 0, 0, + 0, 0, 0, 0, 0, 45, 43, 44, 0, 46, + 0, 47, 0, 49, 0, 50, 0, 0, 0, 0, + 39, 48, 29, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 477, 0, 0, 26, 27, + 28, 0, 0, 0, 0, 0, 0, 0, 0, 30, + 0, 0, 0, 0, 0, 0, 31, 0, 0, 0, + 32, 33, 0, 34, 0, 0, 0, 35, 0, 36, + 37, 38, 0, 0, 40, 0, 0, 0, 41, 0, + 42, 0, 0, 480, 0, 0, 0, 0, 0, 0, + 0, 0, 45, 43, 44, 0, 46, 0, 47, 0, + 49, 0, 50, 0, 0, 0, 0, 39, 48, 29, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 215, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 87, 88, 0, 0, 0, - 0, 0, 0, 0, 0, 90, 0, 0, 0, 0, - 0, 0, 8, 0, 0, 0, 91, 92, 0, 93, - 0, 0, 0, 0, 0, 0, 96, 0, 0, 0, - 99, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 102, 9, - 12, 0, 103, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 98, 105, 89, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 86, 87, 88, 0, 0, - 0, 0, 0, 0, 0, 0, 90, 0, 0, 0, - 0, 0, 0, 8, 0, 0, 0, 91, 92, 0, - 93, 0, 0, 0, 94, 0, 95, 96, 97, 0, - 0, 99, 0, 0, 0, 100, 0, 101, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 102, - 9, 12, 0, 103, 0, 104, 0, 106, 0, 107, - 0, 0, 0, 0, 98, 105, 89, 0, 0, 0, - 0, 0, 0, 0, 0, 0, -113, 0, 0, 0, - 86, 87, 88, 0, 0, 0, 0, 0, 0, 0, - 0, 90, 0, 0, 0, 0, 0, 0, 8, 0, - 0, 0, 91, 92, 0, 93, 0, 0, 0, 94, - 0, 95, 96, 97, 0, 0, 99, 0, 0, 0, - 100, 0, 101, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 102, 9, 12, 0, 103, 0, - 104, 0, 106, 0, 107, 0, 0, 0, 0, 98, - 105, 89, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 86, 87, 88, 0, 0, 0, 0, 0, 0, - 0, 0, 90, 0, 0, 0, 0, 0, 0, 8, - 0, 0, 0, 91, 92, 0, 93, 0, 0, 0, - 94, 0, 95, 96, 97, 0, 0, 99, 0, 0, - 0, 100, 0, 101, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 102, 9, 12, 0, 103, - 0, 104, 0, 106, 321, 107, 0, 0, 0, 0, - 98, 105, 89, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 514, 0, 0, 86, 87, 88, 0, 0, - 0, 0, 0, 0, 0, 0, 90, 0, 0, 0, - 0, 0, 0, 8, 0, 0, 0, 91, 92, 0, - 93, 0, 0, 0, 94, 0, 95, 96, 97, 0, - 0, 99, 0, 0, 0, 100, 0, 101, 0, 0, - 515, 0, 0, 0, 0, 0, 0, 0, 0, 102, - 9, 12, 0, 103, 0, 104, 0, 106, 0, 107, - 0, 0, 0, 0, 98, 105, 89, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 514, 0, 0, 86, - 87, 88, 0, 0, 0, 0, 0, 0, 0, 0, - 90, 0, 0, 0, 0, 0, 0, 8, 0, 0, - 0, 91, 92, 0, 93, 0, 0, 0, 94, 0, - 95, 96, 97, 0, 0, 99, 0, 0, 0, 100, - 0, 101, 0, 0, 520, 0, 0, 0, 0, 0, - 0, 0, 0, 102, 9, 12, 0, 103, 0, 104, - 0, 106, 0, 107, 0, 0, 0, 0, 98, 105, - 89, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 522, 0, 0, 86, 87, 88, 0, 0, 0, 0, - 0, 0, 0, 0, 90, 0, 0, 0, 0, 0, - 0, 8, 0, 0, 0, 91, 92, 0, 93, 0, - 0, 0, 94, 0, 95, 96, 97, 0, 0, 99, - 0, 0, 0, 100, 0, 101, 0, 0, 523, 0, - 0, 0, 0, 0, 0, 0, 0, 102, 9, 12, - 0, 103, 0, 104, 0, 106, 0, 107, 0, 0, - 0, 0, 98, 105, 89, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 522, 0, 0, 86, 87, 88, - 0, 0, 0, 0, 0, 0, 0, 0, 90, 0, - 0, 0, 0, 0, 0, 8, 0, 0, 0, 91, - 92, 0, 93, 0, 0, 0, 94, 0, 95, 96, - 97, 0, 0, 99, 0, 0, 0, 100, 0, 101, - 0, 0, 525, 0, 0, 0, 0, 0, 0, 0, - 0, 102, 9, 12, 0, 103, 0, 104, 0, 106, - 0, 107, 0, 0, 0, 0, 98, 105, 89, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 514, 0, - 0, 86, 87, 88, 0, 0, 0, 0, 0, 0, - 0, 0, 90, 0, 0, 0, 0, 0, 0, 8, - 0, 0, 0, 91, 92, 0, 93, 0, 0, 0, - 94, 0, 95, 96, 97, 0, 0, 99, 0, 0, - 0, 100, 0, 101, 0, 0, 515, 0, 0, 11, - 0, 0, 0, 0, 0, 102, 9, 12, 0, 103, - 0, 104, 0, 106, 0, 107, 0, 0, 0, 0, - 98, 105, 89, 0, 0, 10, 0, 0, 0, 0, - 0, 0, 86, 87, 88, 0, 0, 0, 0, 0, - 0, 0, 0, 90, 0, 0, 0, 0, 0, 0, - 8, 269, 0, 0, 562, 563, 0, 93, 0, 0, - 0, 94, 0, 95, 96, 97, 0, 0, 99, 0, - 0, 0, 100, 0, 101, 0, 0, 0, 0, 0, - 0, 0, 273, 0, 0, 0, 102, 9, 12, 0, - 103, 0, 104, 0, 106, 0, 107, 0, 0, 0, - 0, 98, 105, 89, 0, 264, 0, 564, 0, 0, - 0, 0, 0, 160, 161, 162, 0, 0, 164, 166, - 167, 0, 0, 168, 0, 169, 0, 0, 0, 171, - 172, 173, 0, 0, 0, 0, 0, 0, 8, 174, - 175, 176, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 177, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 180, 0, - 0, 0, 0, 0, 0, 9, 12, 181, 182, 183, - 0, 185, 186, 187, 188, 189, 190, 0, 0, 178, - 184, 170, 163, 165, 179, 0, 0, 0, 0, 0, - 0, 160, 161, 162, 0, 0, 164, 166, 167, 0, - 0, 168, 0, 169, 0, 0, 0, 171, 172, 173, - 0, 0, 0, 0, 0, 0, 443, 174, 175, 176, + 0, 0, 469, 0, 0, 26, 27, 28, 0, 0, + 0, 0, 0, 0, 0, 0, 30, 0, 0, 0, + 0, 0, 0, 31, 0, 0, 0, 32, 33, 0, + 34, 0, 0, 0, 35, 0, 36, 37, 38, 0, + 0, 40, 0, 0, 0, 41, 0, 42, 0, 0, + 475, 0, 0, 0, 0, 0, 0, 0, 0, 45, + 43, 44, 0, 46, 0, 47, 0, 49, 0, 50, + 0, 0, 0, 0, 39, 48, 29, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, + 27, 28, 0, 0, 0, 0, 0, 0, 0, 0, + 30, 0, 0, 0, 0, 0, 0, 31, 211, 0, + 0, 579, 580, 0, 34, 0, 0, 0, 35, 0, + 36, 37, 38, 0, 0, 40, 0, 0, 0, 41, + 0, 42, 0, 0, 0, 0, 0, 0, 0, 215, + 0, 0, 0, 45, 43, 44, 0, 46, 0, 47, + 0, 49, 0, 50, 0, 0, 0, 0, 39, 48, + 29, 0, 206, 0, 581, 0, 0, 0, 0, 0, + 0, 0, 0, 469, 0, 0, 26, 27, 28, 0, + 0, 0, 0, 0, 0, 0, 0, 30, 0, 0, + 0, 0, 0, 0, 31, 0, 0, 0, 32, 33, + 0, 34, 0, 0, 0, 35, 0, 36, 37, 38, + 0, 0, 40, 0, 0, 0, 41, 0, 42, 0, + 0, 470, 0, 0, 498, 0, 0, 0, 0, 0, + 45, 43, 44, 0, 46, 0, 47, 0, 49, 0, + 50, 0, 0, 0, 0, 39, 48, 29, 0, 0, + 497, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 103, 104, 105, 0, 0, 107, 109, 110, 0, 0, + 111, 0, 112, 0, 0, 0, 114, 115, 116, 0, + 0, 0, 0, 0, 0, 31, 117, 118, 119, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 120, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 177, 0, 0, 0, 444, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 180, 0, 0, 0, - 0, 0, 448, 445, 447, 181, 182, 183, 0, 185, - 186, 187, 188, 189, 190, 0, 0, 178, 184, 170, - 163, 165, 179, 0, 0, 0, 0, 0, 0, 160, - 161, 162, 0, 0, 164, 166, 167, 0, 0, 168, - 0, 169, 0, 0, 0, 171, 172, 173, 0, 0, - 0, 0, 0, 0, 443, 174, 175, 176, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 177, 0, - 0, 0, 444, 0, 0, 0, 0, 0, 0, 0, - 446, 0, 0, 0, 180, 0, 0, 0, 0, 0, - 448, 445, 447, 181, 182, 183, 0, 185, 186, 187, - 188, 189, 190, 0, 0, 178, 184, 170, 163, 165, - 179, 0, 0, 0, 0, 0, 0, 262, 0, 0, - 0, 0, 263, 0, 86, 87, 88, 265, 0, 0, - 0, 0, 0, 0, 266, 90, 0, 0, 0, 0, - 0, 0, 268, 269, 0, 0, 270, 92, 0, 93, - 0, 0, 0, 94, 0, 95, 96, 97, 0, 0, - 99, 0, 0, 0, 100, 0, 101, 0, 0, 0, - 0, 0, 272, 0, 273, 0, 0, 0, 102, 271, - 274, 275, 103, 276, 104, 277, 106, 49, 107, 278, - 279, 0, 0, 98, 105, 89, 43, 264, 0, 0, - 0, 0, 0, 0, 0, 262, 0, 0, 0, 0, - 263, 0, 86, 87, 88, 265, 0, 0, 0, 0, - 0, 0, 266, 267, 0, 0, 0, 0, 0, 0, - 268, 269, 0, 0, 270, 92, 0, 93, 0, 0, - 0, 94, 0, 95, 96, 97, 0, 0, 99, 0, - 0, 0, 100, 0, 101, 0, 0, 0, 0, 0, - 272, 0, 273, 0, 0, 0, 102, 271, 274, 275, - 103, 276, 104, 277, 106, 49, 107, 278, 279, 0, - 0, 98, 105, 89, 43, 264, 0, 0, 0, 0, - 0, 0, 0, 568, 161, 162, 0, 0, 570, 166, - 572, 87, 88, 573, 0, 169, 0, 0, 0, 171, - 575, 576, 0, 0, 0, 0, 0, 0, 577, 578, - 175, 176, 270, 92, 0, 93, 0, 0, 0, 94, - 0, 95, 579, 97, 0, 0, 581, 0, 0, 0, - 100, 0, 101, 0, 0, 0, 0, 0, 583, 0, - 273, 0, 0, 0, 585, 582, 584, 586, 587, 588, - 104, 590, 591, 592, 593, 594, 595, 0, 0, 580, - 589, 574, 569, 571, 179, 0, 0, 0, 0, 0, - 0, 411, 161, 162, 0, 0, 413, 166, 415, 87, - 88, 416, 0, 169, 0, 0, 0, 171, 418, 419, - 0, 0, 0, 0, 0, 0, 420, 421, 175, 176, - 270, 92, 0, 93, 0, 0, 0, 94, 0, 95, - 422, 97, 0, 0, 424, 0, 0, 0, 100, 0, - 101, 0, -259, 0, 0, 0, 426, 0, 273, 0, - 0, 0, 428, 425, 427, 429, 430, 431, 104, 433, - 434, 435, 436, 437, 438, 0, 0, 423, 432, 417, - 412, 414, 179, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 123, 0, 0, 0, 0, + 0, 0, 43, 44, 124, 125, 126, 0, 128, 129, + 130, 131, 132, 133, 0, 0, 121, 127, 113, 106, + 108, 122, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 103, 104, 105, 0, 0, 107, 109, 110, 0, + 0, 111, 0, 112, 0, 0, 0, 114, 115, 116, + 0, 0, 0, 0, 0, 0, 387, 117, 118, 119, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 120, 0, 0, 0, 388, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 123, 0, 0, 0, + 0, 0, 392, 389, 391, 124, 125, 126, 0, 128, + 129, 130, 131, 132, 133, 0, 0, 121, 127, 113, + 106, 108, 122, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 103, 104, 105, 0, 0, 107, 109, 110, + 0, 0, 111, 0, 112, 0, 0, 0, 114, 115, + 116, 0, 0, 0, 0, 0, 0, 387, 117, 118, + 119, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 120, 0, 0, 0, 388, 0, 0, 0, 0, + 0, 0, 0, 390, 0, 0, 0, 123, 0, 0, + 0, 0, 0, 392, 389, 391, 124, 125, 126, 0, + 128, 129, 130, 131, 132, 133, 0, 0, 121, 127, + 113, 106, 108, 122, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 203, 0, 0, 0, 0, 205, 0, + 26, 27, 28, 207, 0, 0, 0, 0, 0, 0, + 208, 30, 0, 0, 0, 0, 0, 0, 210, 211, + 0, 0, 212, 33, 0, 34, 0, 0, 0, 35, + 0, 36, 37, 38, 0, 0, 40, 0, 0, 0, + 41, 0, 42, 0, 0, 0, 0, 0, 214, 0, + 215, 0, 0, 0, 45, 213, 216, 217, 46, 218, + 47, 219, 49, 220, 50, 221, 222, 0, 0, 39, + 48, 29, 204, 206, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 203, 0, 0, 0, 0, 205, + 0, 26, 27, 28, 207, 0, 0, 0, 0, 0, + 0, 208, 209, 0, 0, 0, 0, 0, 0, 210, + 211, 0, 0, 212, 33, 0, 34, 0, 0, 0, + 35, 0, 36, 37, 38, 0, 0, 40, 0, 0, + 0, 41, 0, 42, 0, 0, 0, 0, 0, 214, + 0, 215, 0, 0, 0, 45, 213, 216, 217, 46, + 218, 47, 219, 49, 220, 50, 221, 222, 0, 0, + 39, 48, 29, 204, 206, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 585, 104, 105, 0, 0, + 587, 109, 589, 27, 28, 590, 0, 112, 0, 0, + 0, 114, 592, 593, 0, 0, 0, 0, 0, 0, + 594, 595, 118, 119, 212, 33, 0, 34, 0, 0, + 0, 35, 0, 36, 596, 38, 0, 0, 598, 0, + 0, 0, 41, 0, 42, 0, 0, 0, 0, 0, + 600, 0, 215, 0, 0, 0, 602, 599, 601, 603, + 604, 605, 47, 607, 608, 609, 610, 611, 612, 0, + 0, 597, 606, 591, 586, 588, 122, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 355, 104, 105, 0, + 0, 357, 109, 359, 27, 28, 360, 0, 112, 0, + 0, 0, 114, 362, 363, 0, 0, 0, 0, 0, + 0, 364, 365, 118, 119, 212, 33, 0, 34, 0, + 0, 0, 35, 0, 36, 366, 38, 0, 0, 368, + 0, 0, 0, 41, 0, 42, 0, -262, 0, 0, + 0, 370, 0, 215, 0, 0, 0, 372, 369, 371, + 373, 374, 375, 47, 377, 378, 379, 380, 381, 382, + 0, 0, 367, 376, 361, 356, 358, 122, 0, 0, + 0, 0, 0, 0, 0, 0, 0, - 506, 499, 504, 300, 73, 510, 288, 524, 203, 521, - 610, 36, 508, 370, 216, 60, 352, 29, 389, 199, - 567, 26, 260, 239, 241, 33, 288, 300, 486, 222, - 489, 229, 604, 534, 18, 235, 293, 540, 303, 550, - 489, 552, 547, 497, 475, 235, 486, 482, 403, 399, - 479, 191, 361, 549, 288, 483, 224, 467, 357, 293, - 359, 465, 386, 452, 460, 495, 235, 401, 500, 197, - 384, 300, 194, 486, 450, 489, 442, 440, 397, 526, - 352, 511, 485, 370, 7, 352, 37, 352, 7, 14, - 604, 352, 111, 239, 233, 111, 111, 501, 111, 157, - 0, 146, 139, 454, 111, 0, 455, 111, 141, 454, - 111, 140, 455, 7, 111, 601, 233, 388, 0, 519, - 153, 111, 111, 518, 260, 454, 159, 145, 455, 111, - 355, 501, 0, 151, 352, 353, 111, 382, 502, 260, - 111, 380, 111, 0, 119, 142, 111, 111, 501, 532, - 111, 111, 533, 502, 111, 111, 118, 502, 287, 111, - 0, 379, 111, 0, 0, 121, 614, 111, 394, 531, - 111, 111, 111, 218, 111, 336, 338, 335, 111, 334, - 233, 111, 111, 391, 528, 111, 337, 529, 111, 316, - 530, 111, 111, 111, 320, 111, 111, 148, 149, 147, - 135, 143, 111, 197, 197, 111, 111, 144, 0, 231, - 457, 111, 111, 123, 120, 157, 596, 128, 598, 111, - 111, 0, 221, 111, 320, 320, 112, 328, 323, 111, - 348, 0, 111, 348, 320, 320, 339, 320, 320, 341, - 348, 511, 159, 228, 111, 320, 111, 0, 111, 320, - 0, 320, 376, 320, 0, 369, 0, 345, 348, 363, - 348, 343, 350, 320, 111, 320, 7, 53, 0, 320, - 554, 559, 556, 558, 560, 557, 561, 0, 0, 0, - 347, 366, 367, 0, 42, 55, 111, 0, 0, 0, - 0, 320, 0, 340, 0, 0, 0, 0, 0, 0, + 165, 543, 163, 430, 409, 512, 303, 301, 386, 394, + 504, 411, 557, 455, 305, 515, 519, 430, 404, 551, + 569, 144, 176, 296, 13, 489, 314, 384, 182, 244, + 201, 180, 296, 433, 567, 237, 481, 247, 439, 232, + 170, 566, 341, 244, 176, 430, 345, 564, 343, 429, + 433, 584, 333, 423, 328, 176, 330, 296, 332, 237, + 441, 347, 426, 396, 466, 454, 232, 443, 452, 237, + 244, 461, 548, 232, 450, 419, 444, 134, 427, 522, + 479, 476, 54, 0, 0, 433, 84, 0, 142, 100, + 496, 0, 618, 201, 496, 137, 523, 496, 500, 157, + 201, 0, 0, 140, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 398, 102, 54, 399, 0, 54, + 82, 54, 54, 83, 174, 54, 282, 174, 140, 54, + 54, 445, 54, 54, 401, 86, 140, 87, 314, 54, + 54, 66, 172, 54, 281, 89, 180, 54, 54, 446, + 260, 54, 54, 280, 174, 264, 296, 159, 54, 54, + 54, 96, 445, 85, 279, 54, 54, 54, 446, 54, + 278, 54, 88, 54, 448, 71, 474, 90, 54, 91, + 473, 64, 54, 54, 446, 488, 54, 398, 445, 296, + 399, 54, 296, 455, 231, 54, 338, 63, 54, 54, + 62, 61, 54, 54, 54, 55, 484, 162, 54, 92, + 485, 54, 54, 398, 323, 100, 399, 78, 0, 613, + 297, 615, 54, 94, 483, 54, 54, 487, 486, 0, + 292, 54, 0, 292, 335, 264, 264, 0, 264, 0, + 54, 102, 169, 466, 287, 264, 292, 0, 0, 267, + 0, 264, 313, 324, 54, 311, 326, 292, 54, 264, + 54, 285, 264, 264, 0, 264, 54, 465, 294, 289, + 0, 264, 0, 54, 0, 307, 296, 54, 264, 291, + 272, 292, 264, 310, 283, 54, 264, 496, 537, 0, + 264, 571, 284, 576, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 320, 528, 538, 0, 0, 573, 575, + 577, 574, 578, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 299, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 496, 537, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, - 53, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 42, 55, 0, + 0, 0, 0, 0, 0, 528, 538, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -983,170 +609,179 @@ const int QmlJSGrammar::action_info [] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0}; + 0, 0, 0, 0}; const int QmlJSGrammar::action_check [] = { - 78, 48, 29, 60, 8, 78, 60, 48, 2, 1, - 55, 78, 1, 20, 29, 33, 36, 33, 5, 33, - 5, 7, 5, 7, 61, 7, 7, 36, 36, 7, - 7, 61, 55, 36, 55, 7, 16, 8, 60, 7, - 31, 36, 55, 7, 7, 33, 36, 2, 60, 7, - 17, 48, 2, 7, 33, 7, 7, 55, 7, 61, - 36, 36, 8, 7, 7, 7, 36, 36, 7, 7, - 36, 36, 33, 7, 36, 7, 36, 1, 88, 36, - 17, 7, 7, 36, 7, 33, 60, 7, 33, 36, - 1, 8, 33, 29, 2, 88, 36, 15, 8, 8, - -1, 60, 8, 76, 8, 8, 36, 8, 36, 36, - 66, 8, 8, 48, 8, 33, -1, -1, 6, -1, - 10, -1, 8, 7, 8, 8, 8, 8, 8, 60, - -1, 60, 20, -1, -1, 50, -1, -1, 60, 54, - 61, 62, 61, 62, 8, 78, -1, 61, 62, 40, - 56, 8, 56, -1, 61, 62, -1, 60, -1, 60, - 51, 12, 56, 60, 60, 55, 61, 62, 0, 61, - 62, 40, 61, 62, 60, 42, 56, 60, 60, 60, - 29, 7, 51, 61, 62, 40, 53, 61, 62, 61, - 62, 50, 40, 61, 62, 54, 51, 61, 61, 62, - 29, 15, 29, 51, 61, 62, 57, 29, 15, 15, - 29, 8, 63, 29, 8, 7, 29, 66, 67, 29, - 34, 29, 36, 15, 29, 12, 89, 34, 34, 36, - 36, 7, 12, 29, 29, 61, 62, 66, 67, 66, - 67, 33, -1, 29, 66, 67, 29, 66, 67, -1, - 66, 67, 8, 66, 67, 29, 66, 67, 66, 67, - 25, 8, 27, 29, 61, 62, 29, 61, 62, 74, - 57, 66, 67, 38, 29, -1, 63, 57, 74, 29, - 85, 29, 8, 63, -1, 61, 62, 29, 74, 85, - -1, 74, 66, 67, 61, 62, -1, -1, -1, 85, - 66, 67, 85, 66, 67, 61, 62, 33, -1, 29, - -1, 66, 67, 29, 61, 62, 66, 67, 66, 67, - 36, -1, 89, 15, 66, 67, 29, 25, -1, 27, - 18, 19, -1, 36, -1, 61, 62, -1, 18, 19, - 38, 61, 62, -1, 29, -1, 66, 67, -1, -1, - 66, 67, 29, -1, 29, 47, -1, 45, 46, 23, - 24, -1, -1, 66, 67, 45, 46, -1, 32, 61, - 62, 35, 29, 37, 59, 29, -1, -1, -1, -1, - -1, 66, 67, -1, 61, 62, 61, 62, -1, 66, - 67, 66, 67, 29, 18, 19, -1, 89, -1, -1, - 85, 29, 59, -1, -1, -1, -1, 61, 62, 66, - 67, -1, 66, 67, -1, 23, 24, -1, 29, -1, - -1, 45, 46, 31, 32, 61, 62, 35, 85, 37, - 66, 67, -1, 61, 62, 23, 24, -1, 66, 67, - -1, 10, -1, 31, 32, -1, -1, 35, 59, 37, - 23, 24, -1, 22, 65, 66, 67, -1, 31, 32, - 29, -1, 35, -1, 37, -1, 10, -1, 23, 24, - -1, -1, -1, -1, 85, -1, -1, 32, 22, -1, - 35, -1, 37, -1, -1, 29, 55, -1, -1, -1, - 59, -1, -1, -1, -1, -1, -1, 66, 67, -1, - -1, -1, -1, -1, -1, 74, -1, -1, -1, -1, - -1, 55, -1, -1, 83, 59, 85, -1, -1, 3, - -1, -1, 66, 67, -1, -1, -1, -1, -1, 13, - 74, -1, -1, 17, -1, -1, -1, 23, 24, 83, - -1, 85, 26, -1, 28, 31, 32, 31, -1, 35, - -1, 37, -1, -1, -1, 39, -1, 41, 42, -1, - -1, -1, -1, -1, -1, 49, -1, -1, 52, 53, - -1, -1, -1, -1, 58, -1, -1, -1, -1, -1, - 64, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 79, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 3, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 13, -1, -1, -1, - 17, -1, -1, -1, -1, -1, -1, -1, -1, 26, - -1, 28, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 39, -1, 41, 42, -1, -1, -1, -1, - -1, -1, 49, -1, -1, 52, 53, -1, -1, -1, - -1, 58, -1, -1, -1, -1, -1, 64, -1, -1, + 7, 36, 36, 7, 55, 7, 33, 7, 36, 7, + 55, 8, 36, 7, 36, 16, 36, 7, 60, 7, + 33, 7, 33, 55, 36, 7, 36, 60, 7, 20, + 55, 5, 7, 5, 29, 8, 29, 36, 7, 17, + 36, 33, 29, 60, 33, 60, 7, 5, 7, 88, + 7, 36, 36, 33, 7, 7, 33, 66, 7, 7, + 36, 1, 8, 2, 78, 36, 7, 1, 36, 7, + 78, 8, 2, 78, 1, 8, 36, 60, 33, 8, + 61, 7, 48, 7, 48, 88, 48, 31, 7, 36, + 33, 61, 17, 60, 36, 60, 2, 60, 8, 55, + 36, 36, 2, 1, 36, 8, 60, 8, 7, 8, + -1, 8, 8, 8, 8, 6, 61, 48, 8, 8, + 40, 8, 10, 8, 40, 8, 76, 78, 50, 20, + 8, 51, 54, 61, 62, 51, 15, -1, 61, 62, + 61, 62, 50, 61, 62, 8, 54, 61, 62, 61, + 62, 7, 61, 62, 33, 29, 29, 60, 12, 60, + 56, 56, 29, 60, 40, 7, 60, 55, 61, 62, + 60, 56, 61, 60, 40, 51, 0, 60, 42, 61, + 62, 25, 60, 27, 29, 51, 61, 62, 8, 53, + 61, 62, 29, 56, 38, 12, 8, 29, 8, 29, + 74, 74, 25, 57, 27, 61, 62, 74, -1, 63, + 29, 85, 85, 8, -1, 38, -1, -1, 85, 61, + 62, 66, 67, 29, -1, 61, 62, 29, -1, 66, + 67, 29, 12, -1, 66, 67, 29, -1, 29, -1, + 57, 61, 62, 25, 74, 27, 63, 66, 67, 61, + 62, 61, 62, 89, 29, 85, 38, 25, 29, 27, + 66, 67, 61, 62, 66, 67, 61, 62, 66, 67, + 38, 7, 29, 66, 67, 66, 67, 57, 29, 15, + 25, 15, 27, 63, 15, 25, 25, 27, 27, 8, + 89, 66, 67, 38, -1, 66, 67, 33, 38, 38, + 34, 29, 36, 34, 25, 36, 27, 29, -1, 66, + 67, 25, 25, 27, 27, 66, 67, 38, 25, 25, + 27, 27, 18, 19, 38, 38, 90, 91, 92, 29, + -1, 38, 38, 25, 29, 27, -1, 8, 66, 67, + -1, -1, 61, 62, 66, 67, 38, 29, -1, 45, + 46, -1, -1, -1, 36, 18, 19, 29, -1, 15, + 18, 19, 33, 29, 36, -1, 66, 67, -1, -1, + -1, 66, 67, -1, 15, -1, -1, -1, 34, -1, + 36, -1, 45, 46, 66, 67, -1, 45, 46, -1, + 61, 62, -1, 59, 66, 67, 23, 24, -1, -1, + 66, 67, 23, 24, 29, 32, 47, -1, 35, -1, + 37, 32, -1, 29, 35, -1, 37, 23, 24, 85, + 61, 62, -1, -1, 29, -1, 32, 29, -1, 35, + -1, 37, -1, -1, -1, -1, 61, 62, 29, 18, + 19, 66, 67, 23, 24, 61, 62, -1, 89, -1, + 66, 67, 32, 29, 59, 35, 29, 37, -1, 61, + 62, 66, 67, -1, 66, 67, 45, 46, -1, -1, + 61, 62, -1, -1, -1, 66, 67, -1, -1, -1, + 85, -1, -1, -1, -1, 61, 62, 10, 61, 62, + 66, 67, -1, 66, 67, 23, 24, 29, -1, 22, + -1, 10, -1, 31, 32, -1, 29, 35, -1, 37, + 23, 24, -1, 22, -1, -1, 23, 24, 31, 32, + 29, -1, 35, -1, 37, 32, -1, 59, 35, -1, + 37, 3, 55, 65, 66, 67, 59, -1, -1, -1, + -1, 13, -1, 66, 67, 17, 55, -1, -1, -1, + 59, 74, -1, 85, 26, -1, 28, 66, 67, -1, + 83, -1, 85, -1, -1, 74, -1, 39, -1, 41, + 42, -1, -1, -1, 83, -1, 85, 49, -1, -1, + 52, 53, -1, -1, -1, 3, 58, -1, 23, 24, + -1, -1, 64, -1, -1, 13, 31, 32, -1, 17, + 35, -1, 37, -1, -1, -1, -1, 79, 26, -1, + 28, -1, -1, 31, -1, -1, -1, -1, -1, -1, + -1, 39, -1, 41, 42, -1, -1, -1, -1, -1, + -1, 49, -1, -1, 52, 53, -1, -1, -1, -1, + 58, -1, -1, -1, -1, -1, 64, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 79, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 12, 13, -1, -1, -1, - -1, -1, -1, -1, -1, 22, -1, -1, -1, -1, - -1, -1, 29, -1, -1, -1, 33, 34, -1, 36, - -1, -1, -1, -1, -1, -1, 43, -1, -1, -1, - 47, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 65, 66, - 67, -1, 69, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 80, 81, 82, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 11, 12, 13, -1, -1, - -1, -1, -1, -1, -1, -1, 22, -1, -1, -1, - -1, -1, -1, 29, -1, -1, -1, 33, 34, -1, - 36, -1, -1, -1, 40, -1, 42, 43, 44, -1, - -1, 47, -1, -1, -1, 51, -1, 53, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 65, - 66, 67, -1, 69, -1, 71, -1, 73, -1, 75, - -1, -1, -1, -1, 80, 81, 82, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 7, -1, -1, -1, - 11, 12, 13, -1, -1, -1, -1, -1, -1, -1, - -1, 22, -1, -1, -1, -1, -1, -1, 29, -1, - -1, -1, 33, 34, -1, 36, -1, -1, -1, 40, - -1, 42, 43, 44, -1, -1, 47, -1, -1, -1, - 51, -1, 53, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 65, 66, 67, -1, 69, -1, - 71, -1, 73, -1, 75, -1, -1, -1, -1, 80, - 81, 82, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 11, 12, 13, -1, -1, -1, -1, -1, -1, - -1, -1, 22, -1, -1, -1, -1, -1, -1, 29, - -1, -1, -1, 33, 34, -1, 36, -1, -1, -1, - 40, -1, 42, 43, 44, -1, -1, 47, -1, -1, + 3, 79, -1, -1, -1, -1, -1, -1, -1, -1, + 13, -1, -1, -1, 17, -1, -1, -1, -1, -1, + -1, -1, -1, 26, -1, 28, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 39, -1, 41, 42, + -1, 11, 12, 13, -1, -1, 49, -1, -1, 52, + 53, -1, 22, -1, -1, 58, -1, -1, -1, 29, + -1, 64, -1, 33, 34, -1, 36, -1, -1, -1, + 40, -1, 42, 43, 44, -1, 79, 47, -1, -1, -1, 51, -1, 53, -1, -1, -1, -1, -1, -1, + -1, -1, 12, 13, -1, 65, 66, 67, -1, 69, + -1, 71, 22, 73, -1, 75, -1, -1, -1, 29, + 80, 81, 82, 33, 34, -1, 36, -1, -1, -1, + -1, -1, -1, 43, -1, -1, -1, 47, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 65, 66, 67, -1, 69, - -1, 71, -1, 73, 74, 75, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 80, 81, 82, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 8, -1, -1, 11, 12, 13, -1, -1, + -1, -1, -1, -1, -1, 11, 12, 13, -1, -1, -1, -1, -1, -1, -1, -1, 22, -1, -1, -1, -1, -1, -1, 29, -1, -1, -1, 33, 34, -1, 36, -1, -1, -1, 40, -1, 42, 43, 44, -1, -1, 47, -1, -1, -1, 51, -1, 53, -1, -1, - 56, -1, -1, -1, -1, -1, -1, -1, -1, 65, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 65, 66, 67, -1, 69, -1, 71, -1, 73, -1, 75, -1, -1, -1, -1, 80, 81, 82, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 8, -1, -1, 11, - 12, 13, -1, -1, -1, -1, -1, -1, -1, -1, - 22, -1, -1, -1, -1, -1, -1, 29, -1, -1, - -1, 33, 34, -1, 36, -1, -1, -1, 40, -1, - 42, 43, 44, -1, -1, 47, -1, -1, -1, 51, - -1, 53, -1, -1, 56, -1, -1, -1, -1, -1, - -1, -1, -1, 65, 66, 67, -1, 69, -1, 71, - -1, 73, -1, 75, -1, -1, -1, -1, 80, 81, - 82, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 8, -1, -1, 11, 12, 13, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 7, + -1, -1, -1, 11, 12, 13, -1, -1, -1, -1, -1, -1, -1, -1, 22, -1, -1, -1, -1, -1, -1, 29, -1, -1, -1, 33, 34, -1, 36, -1, -1, -1, 40, -1, 42, 43, 44, -1, -1, 47, - -1, -1, -1, 51, -1, 53, -1, -1, 56, -1, + -1, -1, -1, 51, -1, 53, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 65, 66, 67, -1, 69, -1, 71, -1, 73, -1, 75, -1, -1, -1, -1, 80, 81, 82, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 8, -1, -1, 11, 12, 13, + -1, -1, -1, -1, -1, -1, -1, 11, 12, 13, -1, -1, -1, -1, -1, -1, -1, -1, 22, -1, -1, -1, -1, -1, -1, 29, -1, -1, -1, 33, 34, -1, 36, -1, -1, -1, 40, -1, 42, 43, 44, -1, -1, 47, -1, -1, -1, 51, -1, 53, - -1, -1, 56, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 65, 66, 67, -1, 69, -1, 71, -1, 73, - -1, 75, -1, -1, -1, -1, 80, 81, 82, -1, + 74, 75, -1, -1, -1, -1, 80, 81, 82, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 8, -1, -1, 11, 12, 13, -1, -1, -1, + -1, -1, -1, -1, -1, 22, -1, -1, -1, -1, + -1, -1, 29, -1, -1, -1, 33, 34, -1, 36, + -1, -1, -1, 40, -1, 42, 43, 44, -1, -1, + 47, -1, -1, -1, 51, -1, 53, -1, -1, 56, + -1, -1, -1, -1, -1, -1, -1, -1, 65, 66, + 67, -1, 69, -1, 71, -1, 73, -1, 75, -1, + -1, -1, -1, 80, 81, 82, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 8, -1, -1, 11, 12, 13, -1, -1, -1, -1, -1, -1, -1, -1, 22, -1, -1, -1, -1, -1, -1, 29, -1, -1, -1, 33, 34, -1, 36, -1, -1, -1, 40, -1, 42, 43, 44, -1, -1, 47, -1, -1, - -1, 51, -1, 53, -1, -1, 56, -1, -1, 59, + -1, 51, -1, 53, -1, -1, 56, -1, -1, -1, -1, -1, -1, -1, -1, 65, 66, 67, -1, 69, -1, 71, -1, 73, -1, 75, -1, -1, -1, -1, - 80, 81, 82, -1, -1, 85, -1, -1, -1, -1, - -1, -1, 11, 12, 13, -1, -1, -1, -1, -1, - -1, -1, -1, 22, -1, -1, -1, -1, -1, -1, - 29, 30, -1, -1, 33, 34, -1, 36, -1, -1, - -1, 40, -1, 42, 43, 44, -1, -1, 47, -1, - -1, -1, 51, -1, 53, -1, -1, -1, -1, -1, - -1, -1, 61, -1, -1, -1, 65, 66, 67, -1, - 69, -1, 71, -1, 73, -1, 75, -1, -1, -1, - -1, 80, 81, 82, -1, 84, -1, 86, -1, -1, - -1, -1, -1, 4, 5, 6, -1, -1, 9, 10, - 11, -1, -1, 14, -1, 16, -1, -1, -1, 20, - 21, 22, -1, -1, -1, -1, -1, -1, 29, 30, - 31, 32, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 43, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 59, -1, - -1, -1, -1, -1, -1, 66, 67, 68, 69, 70, - -1, 72, 73, 74, 75, 76, 77, -1, -1, 80, - 81, 82, 83, 84, 85, -1, -1, -1, -1, -1, + 80, 81, 82, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 8, -1, -1, 11, 12, + 13, -1, -1, -1, -1, -1, -1, -1, -1, 22, + -1, -1, -1, -1, -1, -1, 29, -1, -1, -1, + 33, 34, -1, 36, -1, -1, -1, 40, -1, 42, + 43, 44, -1, -1, 47, -1, -1, -1, 51, -1, + 53, -1, -1, 56, -1, -1, -1, -1, -1, -1, + -1, -1, 65, 66, 67, -1, 69, -1, 71, -1, + 73, -1, 75, -1, -1, -1, -1, 80, 81, 82, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 8, -1, -1, 11, 12, 13, -1, -1, + -1, -1, -1, -1, -1, -1, 22, -1, -1, -1, + -1, -1, -1, 29, -1, -1, -1, 33, 34, -1, + 36, -1, -1, -1, 40, -1, 42, 43, 44, -1, + -1, 47, -1, -1, -1, 51, -1, 53, -1, -1, + 56, -1, -1, -1, -1, -1, -1, -1, -1, 65, + 66, 67, -1, 69, -1, 71, -1, 73, -1, 75, + -1, -1, -1, -1, 80, 81, 82, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 11, + 12, 13, -1, -1, -1, -1, -1, -1, -1, -1, + 22, -1, -1, -1, -1, -1, -1, 29, 30, -1, + -1, 33, 34, -1, 36, -1, -1, -1, 40, -1, + 42, 43, 44, -1, -1, 47, -1, -1, -1, 51, + -1, 53, -1, -1, -1, -1, -1, -1, -1, 61, + -1, -1, -1, 65, 66, 67, -1, 69, -1, 71, + -1, 73, -1, 75, -1, -1, -1, -1, 80, 81, + 82, -1, 84, -1, 86, -1, -1, -1, -1, -1, + -1, -1, -1, 8, -1, -1, 11, 12, 13, -1, + -1, -1, -1, -1, -1, -1, -1, 22, -1, -1, + -1, -1, -1, -1, 29, -1, -1, -1, 33, 34, + -1, 36, -1, -1, -1, 40, -1, 42, 43, 44, + -1, -1, 47, -1, -1, -1, 51, -1, 53, -1, + -1, 56, -1, -1, 59, -1, -1, -1, -1, -1, + 65, 66, 67, -1, 69, -1, 71, -1, 73, -1, + 75, -1, -1, -1, -1, 80, 81, 82, -1, -1, + 85, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 4, 5, 6, -1, -1, 9, 10, 11, -1, -1, + 14, -1, 16, -1, -1, -1, 20, 21, 22, -1, + -1, -1, -1, -1, -1, 29, 30, 31, 32, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 43, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 59, -1, -1, -1, -1, + -1, -1, 66, 67, 68, 69, 70, -1, 72, 73, + 74, 75, 76, 77, -1, -1, 80, 81, 82, 83, + 84, 85, -1, -1, -1, -1, -1, -1, -1, -1, -1, 4, 5, 6, -1, -1, 9, 10, 11, -1, -1, 14, -1, 16, -1, -1, -1, 20, 21, 22, -1, -1, -1, -1, -1, -1, 29, 30, 31, 32, @@ -1155,89 +790,94 @@ const int QmlJSGrammar::action_check [] = { -1, -1, -1, -1, -1, -1, 59, -1, -1, -1, -1, -1, 65, 66, 67, 68, 69, 70, -1, 72, 73, 74, 75, 76, 77, -1, -1, 80, 81, 82, - 83, 84, 85, -1, -1, -1, -1, -1, -1, 4, - 5, 6, -1, -1, 9, 10, 11, -1, -1, 14, - -1, 16, -1, -1, -1, 20, 21, 22, -1, -1, - -1, -1, -1, -1, 29, 30, 31, 32, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 43, -1, - -1, -1, 47, -1, -1, -1, -1, -1, -1, -1, - 55, -1, -1, -1, 59, -1, -1, -1, -1, -1, - 65, 66, 67, 68, 69, 70, -1, 72, 73, 74, - 75, 76, 77, -1, -1, 80, 81, 82, 83, 84, - 85, -1, -1, -1, -1, -1, -1, 4, -1, -1, - -1, -1, 9, -1, 11, 12, 13, 14, -1, -1, - -1, -1, -1, -1, 21, 22, -1, -1, -1, -1, - -1, -1, 29, 30, -1, -1, 33, 34, -1, 36, - -1, -1, -1, 40, -1, 42, 43, 44, -1, -1, - 47, -1, -1, -1, 51, -1, 53, -1, -1, -1, - -1, -1, 59, -1, 61, -1, -1, -1, 65, 66, - 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, - 77, -1, -1, 80, 81, 82, 83, 84, -1, -1, - -1, -1, -1, -1, -1, 4, -1, -1, -1, -1, - 9, -1, 11, 12, 13, 14, -1, -1, -1, -1, - -1, -1, 21, 22, -1, -1, -1, -1, -1, -1, - 29, 30, -1, -1, 33, 34, -1, 36, -1, -1, - -1, 40, -1, 42, 43, 44, -1, -1, 47, -1, - -1, -1, 51, -1, 53, -1, -1, -1, -1, -1, - 59, -1, 61, -1, -1, -1, 65, 66, 67, 68, - 69, 70, 71, 72, 73, 74, 75, 76, 77, -1, - -1, 80, 81, 82, 83, 84, -1, -1, -1, -1, - -1, -1, -1, 4, 5, 6, -1, -1, 9, 10, - 11, 12, 13, 14, -1, 16, -1, -1, -1, 20, + 83, 84, 85, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 4, 5, 6, -1, -1, 9, 10, 11, + -1, -1, 14, -1, 16, -1, -1, -1, 20, 21, + 22, -1, -1, -1, -1, -1, -1, 29, 30, 31, + 32, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 43, -1, -1, -1, 47, -1, -1, -1, -1, + -1, -1, -1, 55, -1, -1, -1, 59, -1, -1, + -1, -1, -1, 65, 66, 67, 68, 69, 70, -1, + 72, 73, 74, 75, 76, 77, -1, -1, 80, 81, + 82, 83, 84, 85, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 4, -1, -1, -1, -1, 9, -1, + 11, 12, 13, 14, -1, -1, -1, -1, -1, -1, 21, 22, -1, -1, -1, -1, -1, -1, 29, 30, - 31, 32, 33, 34, -1, 36, -1, -1, -1, 40, + -1, -1, 33, 34, -1, 36, -1, -1, -1, 40, -1, 42, 43, 44, -1, -1, 47, -1, -1, -1, 51, -1, 53, -1, -1, -1, -1, -1, 59, -1, 61, -1, -1, -1, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, -1, -1, 80, - 81, 82, 83, 84, 85, -1, -1, -1, -1, -1, - -1, 4, 5, 6, -1, -1, 9, 10, 11, 12, - 13, 14, -1, 16, -1, -1, -1, 20, 21, 22, - -1, -1, -1, -1, -1, -1, 29, 30, 31, 32, - 33, 34, -1, 36, -1, -1, -1, 40, -1, 42, - 43, 44, -1, -1, 47, -1, -1, -1, 51, -1, - 53, -1, 55, -1, -1, -1, 59, -1, 61, -1, - -1, -1, 65, 66, 67, 68, 69, 70, 71, 72, - 73, 74, 75, 76, 77, -1, -1, 80, 81, 82, - 83, 84, 85, -1, -1, -1, -1, -1, -1, + 81, 82, 83, 84, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 4, -1, -1, -1, -1, 9, + -1, 11, 12, 13, 14, -1, -1, -1, -1, -1, + -1, 21, 22, -1, -1, -1, -1, -1, -1, 29, + 30, -1, -1, 33, 34, -1, 36, -1, -1, -1, + 40, -1, 42, 43, 44, -1, -1, 47, -1, -1, + -1, 51, -1, 53, -1, -1, -1, -1, -1, 59, + -1, 61, -1, -1, -1, 65, 66, 67, 68, 69, + 70, 71, 72, 73, 74, 75, 76, 77, -1, -1, + 80, 81, 82, 83, 84, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 4, 5, 6, -1, -1, + 9, 10, 11, 12, 13, 14, -1, 16, -1, -1, + -1, 20, 21, 22, -1, -1, -1, -1, -1, -1, + 29, 30, 31, 32, 33, 34, -1, 36, -1, -1, + -1, 40, -1, 42, 43, 44, -1, -1, 47, -1, + -1, -1, 51, -1, 53, -1, -1, -1, -1, -1, + 59, -1, 61, -1, -1, -1, 65, 66, 67, 68, + 69, 70, 71, 72, 73, 74, 75, 76, 77, -1, + -1, 80, 81, 82, 83, 84, 85, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 4, 5, 6, -1, + -1, 9, 10, 11, 12, 13, 14, -1, 16, -1, + -1, -1, 20, 21, 22, -1, -1, -1, -1, -1, + -1, 29, 30, 31, 32, 33, 34, -1, 36, -1, + -1, -1, 40, -1, 42, 43, 44, -1, -1, 47, + -1, -1, -1, 51, -1, 53, -1, 55, -1, -1, + -1, 59, -1, 61, -1, -1, -1, 65, 66, 67, + 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, + -1, -1, 80, 81, 82, 83, 84, 85, -1, -1, + -1, -1, -1, -1, -1, -1, -1, - 68, 16, 15, 68, 15, 68, 6, 31, 64, 31, - 31, 5, 15, 6, 31, 21, 15, 6, 6, 31, - 12, 6, 68, 6, 6, 6, 6, 68, 15, 31, - 16, 15, 6, 6, 6, 6, 6, 15, 15, 6, - 16, 6, 21, 6, 93, 6, 15, 78, 68, 15, - 90, 15, 68, 21, 6, 15, 31, 15, 68, 6, - 15, 68, 15, 68, 68, 95, 6, 68, 16, 31, - 68, 68, 31, 15, 31, 16, 32, 31, 68, 15, - 15, 31, 78, 6, 6, 15, 8, 15, 6, 7, - 6, 15, 41, 6, 43, 41, 41, 43, 41, 6, - -1, 46, 45, 35, 41, -1, 38, 41, 45, 35, - 41, 45, 38, 6, 41, 8, 43, 68, -1, 27, - 51, 41, 41, 31, 68, 35, 33, 46, 38, 41, - 65, 43, -1, 53, 15, 65, 41, 65, 43, 68, - 41, 65, 41, -1, 43, 46, 41, 41, 43, 43, - 41, 41, 43, 43, 41, 41, 43, 43, 102, 41, - -1, 84, 41, -1, -1, 44, 82, 41, 97, 43, - 41, 41, 41, 55, 41, 46, 46, 46, 41, 46, - 43, 41, 41, 96, 43, 41, 46, 43, 41, 41, - 43, 41, 41, 41, 46, 41, 41, 47, 47, 47, - 46, 46, 41, 31, 31, 41, 41, 46, -1, 37, - 37, 41, 41, 49, 43, 6, 6, 47, 8, 41, - 41, -1, 57, 41, 46, 46, 44, 48, 50, 41, - 41, -1, 41, 41, 46, 46, 48, 46, 46, 48, - 41, 31, 33, 34, 41, 46, 41, -1, 41, 46, - -1, 46, 63, 46, -1, 63, -1, 52, 41, 56, - 41, 54, 63, 46, 41, 46, 6, 7, -1, 46, - 10, 15, 16, 17, 18, 19, 20, -1, -1, -1, - 63, 58, 63, -1, 24, 25, 41, -1, -1, -1, - -1, 46, -1, 48, -1, -1, -1, -1, -1, -1, + 33, 23, 33, 3, 2, 9, 3, 2, 34, 33, + 9, 3, 3, 9, 2, 9, 9, 3, 2, 9, + 9, 66, 9, 3, 3, 2, 9, 33, 9, 2, + 2, 9, 3, 18, 9, 9, 3, 3, 96, 9, + 3, 23, 2, 2, 9, 3, 2, 23, 3, 79, + 18, 15, 9, 91, 2, 9, 3, 3, 2, 9, + 9, 2, 79, 2, 33, 2, 9, 18, 3, 9, + 2, 33, 3, 9, 2, 94, 18, 3, 3, 8, + 33, 33, 43, -1, -1, 18, 47, -1, 33, 9, + 9, -1, 11, 2, 9, 33, 11, 9, 10, 33, + 2, -1, -1, 33, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 37, 35, 43, 40, -1, 43, + 47, 43, 43, 47, 45, 43, 48, 45, 33, 43, + 43, 45, 43, 43, 39, 48, 33, 48, 9, 43, + 43, 51, 39, 43, 48, 48, 9, 43, 43, 45, + 43, 43, 43, 48, 45, 48, 3, 57, 43, 43, + 43, 53, 45, 48, 48, 43, 43, 43, 45, 43, + 48, 43, 48, 43, 3, 49, 29, 49, 43, 49, + 33, 46, 43, 43, 45, 45, 43, 37, 45, 3, + 40, 43, 3, 9, 103, 43, 98, 45, 43, 43, + 45, 45, 43, 43, 43, 46, 45, 59, 43, 49, + 45, 43, 43, 37, 85, 9, 40, 48, -1, 9, + 67, 11, 43, 55, 45, 43, 43, 45, 45, -1, + 43, 43, -1, 43, 97, 48, 48, -1, 48, -1, + 43, 35, 36, 33, 56, 48, 43, -1, -1, 52, + -1, 48, 65, 67, 43, 65, 67, 43, 43, 48, + 43, 50, 48, 48, -1, 48, 43, 83, 65, 54, + -1, 48, -1, 43, -1, 58, 3, 43, 48, 65, + 50, 43, 48, 60, 50, 43, 48, 9, 10, -1, + 48, 13, 50, 3, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 65, 26, 27, -1, -1, 18, 19, + 20, 21, 22, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 67, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 9, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 6, - 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 24, 25, -1, + -1, -1, -1, -1, -1, 26, 27, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, @@ -1245,5 +885,5 @@ const int QmlJSGrammar::action_check [] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1}; + -1, -1, -1, -1}; diff --git a/src/declarative/qml/parser/qmljsgrammar_p.h b/src/declarative/qml/parser/qmljsgrammar_p.h index 1590274..da42f8c 100644 --- a/src/declarative/qml/parser/qmljsgrammar_p.h +++ b/src/declarative/qml/parser/qmljsgrammar_p.h @@ -59,8 +59,8 @@ class QmlJSGrammar public: enum { EOF_SYMBOL = 0, - REDUCE_HERE = 91, - SHIFT_THERE = 90, + REDUCE_HERE = 94, + SHIFT_THERE = 93, T_AND = 1, T_AND_AND = 2, T_AND_EQ = 3, @@ -85,6 +85,9 @@ public: T_EQ_EQ = 18, T_EQ_EQ_EQ = 19, T_FALSE = 82, + T_FEED_JS_EXPRESSION = 92, + T_FEED_JS_STATEMENT = 91, + T_FEED_UI_PROGRAM = 90, T_FINALLY = 20, T_FOR = 21, T_FUNCTION = 22, @@ -151,26 +154,20 @@ public: T_XOR = 78, T_XOR_EQ = 79, - ACCEPT_STATE = 615, - RULE_COUNT = 338, - STATE_COUNT = 616, - TERMINAL_COUNT = 92, - NON_TERMINAL_COUNT = 104, + ACCEPT_STATE = 621, + RULE_COUNT = 341, + STATE_COUNT = 622, + TERMINAL_COUNT = 95, + NON_TERMINAL_COUNT = 105, - GOTO_INDEX_OFFSET = 616, - GOTO_INFO_OFFSET = 2139, - GOTO_CHECK_OFFSET = 2139 + GOTO_INDEX_OFFSET = 622, + GOTO_INFO_OFFSET = 2247, + GOTO_CHECK_OFFSET = 2247 }; static const char *const spell []; static const int lhs []; static const int rhs []; - -#ifndef QLALR_NO_QMLJSGRAMMAR_DEBUG_INFO - static const int rule_index []; - static const int rule_info []; -#endif // QLALR_NO_QMLJSGRAMMAR_DEBUG_INFO - static const int goto_default []; static const int action_default []; static const int action_index []; diff --git a/src/declarative/qml/parser/qmljsparser.cpp b/src/declarative/qml/parser/qmljsparser.cpp index a13b425..08a424e 100644 --- a/src/declarative/qml/parser/qmljsparser.cpp +++ b/src/declarative/qml/parser/qmljsparser.cpp @@ -1,7 +1,5 @@ // This file was generated by qlalr - DO NOT EDIT! -#line 95 "qmljs.g" - /**************************************************************************** ** ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). @@ -53,8 +51,6 @@ #include "qmljsnodepool_p.h" -#line 349 "qmljs.g" - #include "qmljsparser_p.h" #include @@ -147,14 +143,16 @@ AST::UiQualifiedId *Parser::reparseAsQualifiedId(AST::ExpressionNode *expr) return 0; } -bool Parser::parse() +bool Parser::parse(int startToken) { Lexer *lexer = driver->lexer(); bool hadErrors = false; int yytoken = -1; int action = 0; - first_token = last_token = 0; + token_buffer[0].token = startToken; + first_token = &token_buffer[0]; + last_token = &token_buffer[1]; tos = -1; program = 0; @@ -197,36 +195,40 @@ bool Parser::parse() switch (r) { -#line 498 "qmljs.g" - case 0: { - program = makeAstNode (driver->nodePool(), sym(1).UiImportList, - sym(2).UiObjectMemberList->finish()); - sym(1).UiProgram = program; + sym(1).Node = sym(2).Node; + program = sym(1).Node; } break; -#line 508 "qmljs.g" +case 1: { + sym(1).Node = sym(2).Node; + program = sym(1).Node; +} break; case 2: { - sym(1).Node = sym(1).UiImportList->finish(); + sym(1).Node = sym(2).Node; + program = sym(1).Node; } break; -#line 515 "qmljs.g" - case 3: { - sym(1).Node = makeAstNode (driver->nodePool(), sym(1).UiImport); + sym(1).UiProgram = makeAstNode (driver->nodePool(), sym(1).UiImportList, + sym(2).UiObjectMemberList->finish()); +} break; + +case 5: { + sym(1).Node = sym(1).UiImportList->finish(); } break; -#line 522 "qmljs.g" +case 6: { + sym(1).Node = makeAstNode (driver->nodePool(), sym(1).UiImport); +} break; -case 4: { +case 7: { sym(1).Node = makeAstNode (driver->nodePool(), sym(1).UiImportList, sym(2).UiImport); } break; -#line 531 "qmljs.g" - -case 6: { +case 9: { AST::UiImport *node = makeAstNode(driver->nodePool(), sym(2).sval); node->importToken = loc(1); node->fileNameToken = loc(2); @@ -234,9 +236,7 @@ case 6: { sym(1).Node = node; } break; -#line 543 "qmljs.g" - -case 8: { +case 11: { AST::UiImport *node = makeAstNode(driver->nodePool(), sym(2).sval); node->importId = sym(4).sval; node->importToken = loc(1); @@ -247,9 +247,7 @@ case 8: { sym(1).Node = node; } break; -#line 558 "qmljs.g" - -case 10: { +case 13: { AST::UiImport *node = makeAstNode(driver->nodePool(), sym(2).UiQualifiedId->finish()); node->importToken = loc(1); node->fileNameToken = loc(2); @@ -257,9 +255,7 @@ case 10: { sym(1).Node = node; } break; -#line 570 "qmljs.g" - -case 12: { +case 15: { AST::UiImport *node = makeAstNode(driver->nodePool(), sym(2).UiQualifiedId->finish()); node->importToken = loc(1); node->fileNameToken = loc(2); @@ -268,9 +264,7 @@ case 12: { sym(1).Node = node; } break; -#line 583 "qmljs.g" - -case 14: { +case 17: { AST::UiImport *node = makeAstNode(driver->nodePool(), sym(2).UiQualifiedId->finish()); node->importId = sym(5).sval; node->importToken = loc(1); @@ -282,9 +276,7 @@ case 14: { sym(1).Node = node; } break; -#line 599 "qmljs.g" - -case 16: { +case 19: { AST::UiImport *node = makeAstNode(driver->nodePool(), sym(2).UiQualifiedId->finish()); node->importId = sym(4).sval; node->importToken = loc(1); @@ -295,76 +287,56 @@ case 16: { sym(1).Node = node; } break; -#line 613 "qmljs.g" - -case 17: { +case 20: { sym(1).Node = 0; } break; -#line 620 "qmljs.g" - -case 18: { +case 21: { sym(1).Node = makeAstNode (driver->nodePool(), sym(1).UiObjectMember); } break; -#line 627 "qmljs.g" - -case 19: { +case 22: { sym(1).Node = makeAstNode (driver->nodePool(), sym(1).UiObjectMember); } break; -#line 634 "qmljs.g" - -case 20: { +case 23: { AST::UiObjectMemberList *node = makeAstNode (driver->nodePool(), sym(1).UiObjectMemberList, sym(2).UiObjectMember); sym(1).Node = node; } break; -#line 643 "qmljs.g" - -case 21: { +case 24: { sym(1).Node = makeAstNode (driver->nodePool(), sym(1).UiObjectMember); } break; -#line 650 "qmljs.g" - -case 22: { +case 25: { AST::UiArrayMemberList *node = makeAstNode (driver->nodePool(), sym(1).UiArrayMemberList, sym(3).UiObjectMember); node->commaToken = loc(2); sym(1).Node = node; } break; -#line 660 "qmljs.g" - -case 23: { +case 26: { AST::UiObjectInitializer *node = makeAstNode (driver->nodePool(), (AST::UiObjectMemberList*)0); node->lbraceToken = loc(1); node->rbraceToken = loc(2); sym(1).Node = node; } break; -#line 670 "qmljs.g" - -case 24: { +case 27: { AST::UiObjectInitializer *node = makeAstNode (driver->nodePool(), sym(2).UiObjectMemberList->finish()); node->lbraceToken = loc(1); node->rbraceToken = loc(3); sym(1).Node = node; } break; -#line 680 "qmljs.g" - -case 25: { +case 28: { AST::UiObjectDefinition *node = makeAstNode (driver->nodePool(), sym(1).UiQualifiedId->finish(), sym(2).UiObjectInitializer); sym(1).Node = node; } break; -#line 691 "qmljs.g" - -case 27: { +case 30: { AST::UiArrayBinding *node = makeAstNode (driver->nodePool(), sym(1).UiQualifiedId->finish(), sym(4).UiArrayMemberList->finish()); node->colonToken = loc(2); @@ -373,25 +345,19 @@ case 27: { sym(1).Node = node; } break; -#line 703 "qmljs.g" - -case 28: { +case 31: { AST::StringLiteral *node = makeAstNode (driver->nodePool(), sym(1).sval); node->literalToken = loc(1); sym(1).Node = node; } break; -#line 713 "qmljs.g" - -case 30: { +case 33: { AST::ExpressionStatement *node = makeAstNode (driver->nodePool(), sym(1).Expression); node->semicolonToken = loc(2); sym(1).Node = node; } break; -#line 723 "qmljs.g" - -case 31: { +case 34: { if (AST::UiQualifiedId *qualifiedId = reparseAsQualifiedId(sym(3).Expression)) { AST::UiObjectBinding *node = makeAstNode (driver->nodePool(), sym(1).UiQualifiedId->finish(), qualifiedId, sym(4).UiObjectInitializer); @@ -406,21 +372,7 @@ case 31: { return false; // ### recover } } break; - -#line 742 "qmljs.g" -case 32: -#line 745 "qmljs.g" -case 33: -#line 748 "qmljs.g" -case 34: -#line 751 "qmljs.g" -case 35: -#line 754 "qmljs.g" -case 36: -#line 757 "qmljs.g" -case 37: -#line 759 "qmljs.g" - +case 35:case 36:case 37:case 38:case 39:case 40: { AST::UiScriptBinding *node = makeAstNode (driver->nodePool(), sym(1).UiQualifiedId->finish(), sym(3).Statement); @@ -428,49 +380,35 @@ case 37: sym(1).Node = node; } break; -#line 769 "qmljs.g" - -case 38: +case 41: -#line 773 "qmljs.g" - -case 39: { +case 42: { sym(1).sval = driver->intern(lexer->characterBuffer(), lexer->characterCount()); break; } -#line 783 "qmljs.g" - -case 41: { +case 44: { sym(1).Node = 0; } break; -#line 790 "qmljs.g" - -case 42: { +case 45: { sym(1).Node = sym(1).UiParameterList->finish (); } break; -#line 797 "qmljs.g" - -case 43: { +case 46: { AST::UiParameterList *node = makeAstNode (driver->nodePool(), sym(1).sval, sym(2).sval); node->identifierToken = loc(2); sym(1).Node = node; } break; -#line 806 "qmljs.g" - -case 44: { +case 47: { AST::UiParameterList *node = makeAstNode (driver->nodePool(), sym(1).UiParameterList, sym(3).sval, sym(4).sval); node->commaToken = loc(2); node->identifierToken = loc(4); sym(1).Node = node; } break; -#line 816 "qmljs.g" - -case 45: { +case 48: { AST::UiPublicMember *node = makeAstNode (driver->nodePool(), (NameId *)0, sym(2).sval); node->type = AST::UiPublicMember::Signal; node->propertyToken = loc(1); @@ -480,9 +418,7 @@ case 45: { sym(1).Node = node; } break; -#line 829 "qmljs.g" - -case 46: { +case 49: { AST::UiPublicMember *node = makeAstNode (driver->nodePool(), (NameId *)0, sym(2).sval); node->type = AST::UiPublicMember::Signal; node->propertyToken = loc(1); @@ -491,9 +427,7 @@ case 46: { sym(1).Node = node; } break; -#line 842 "qmljs.g" - -case 48: { +case 51: { AST::UiPublicMember *node = makeAstNode (driver->nodePool(), sym(2).sval, sym(3).sval); node->propertyToken = loc(1); node->typeToken = loc(2); @@ -502,9 +436,7 @@ case 48: { sym(1).Node = node; } break; -#line 855 "qmljs.g" - -case 50: { +case 53: { AST::UiPublicMember *node = makeAstNode (driver->nodePool(), sym(3).sval, sym(4).sval); node->isDefaultMember = true; node->defaultToken = loc(1); @@ -515,9 +447,7 @@ case 50: { sym(1).Node = node; } break; -#line 870 "qmljs.g" - -case 52: { +case 55: { AST::UiPublicMember *node = makeAstNode (driver->nodePool(), sym(2).sval, sym(3).sval, sym(5).Expression); node->propertyToken = loc(1); @@ -528,9 +458,7 @@ case 52: { sym(1).Node = node; } break; -#line 885 "qmljs.g" - -case 54: { +case 57: { AST::UiPublicMember *node = makeAstNode (driver->nodePool(), sym(3).sval, sym(4).sval, sym(6).Expression); node->isDefaultMember = true; @@ -543,104 +471,76 @@ case 54: { sym(1).Node = node; } break; -#line 901 "qmljs.g" - -case 55: { +case 58: { sym(1).Node = makeAstNode(driver->nodePool(), sym(1).Node); } break; -#line 908 "qmljs.g" - -case 56: { +case 59: { sym(1).Node = makeAstNode(driver->nodePool(), sym(1).Node); } break; - -#line 915 "qmljs.g" -case 57: -#line 918 "qmljs.g" - -case 58: +case 60: +case 61: { AST::UiQualifiedId *node = makeAstNode (driver->nodePool(), driver->intern(lexer->characterBuffer(), lexer->characterCount())); node->identifierToken = loc(1); sym(1).Node = node; } break; -#line 930 "qmljs.g" - -case 60: { +case 63: { QString s = QLatin1String(QmlJSGrammar::spell[T_PROPERTY]); sym(1).sval = driver->intern(s.constData(), s.length()); break; } -#line 939 "qmljs.g" - -case 61: { +case 64: { QString s = QLatin1String(QmlJSGrammar::spell[T_SIGNAL]); sym(1).sval = driver->intern(s.constData(), s.length()); break; } -#line 952 "qmljs.g" - -case 62: { +case 65: { AST::ThisExpression *node = makeAstNode (driver->nodePool()); node->thisToken = loc(1); sym(1).Node = node; } break; -#line 961 "qmljs.g" - -case 63: { +case 66: { AST::IdentifierExpression *node = makeAstNode (driver->nodePool(), sym(1).sval); node->identifierToken = loc(1); sym(1).Node = node; } break; -#line 970 "qmljs.g" - -case 64: { +case 67: { AST::NullExpression *node = makeAstNode (driver->nodePool()); node->nullToken = loc(1); sym(1).Node = node; } break; -#line 979 "qmljs.g" - -case 65: { +case 68: { AST::TrueLiteral *node = makeAstNode (driver->nodePool()); node->trueToken = loc(1); sym(1).Node = node; } break; -#line 988 "qmljs.g" - -case 66: { +case 69: { AST::FalseLiteral *node = makeAstNode (driver->nodePool()); node->falseToken = loc(1); sym(1).Node = node; } break; -#line 997 "qmljs.g" - -case 67: { +case 70: { AST::NumericLiteral *node = makeAstNode (driver->nodePool(), sym(1).dval, lexer->flags); node->literalToken = loc(1); sym(1).Node = node; } break; -#line 1006 "qmljs.g" - -case 68: { +case 71: { AST::StringLiteral *node = makeAstNode (driver->nodePool(), sym(1).sval); node->literalToken = loc(1); sym(1).Node = node; } break; -#line 1018 "qmljs.g" - -case 69: { +case 72: { bool rx = lexer->scanRegExp(Lexer::NoPrefix); if (!rx) { diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, location(lexer), lexer->errorMessage())); @@ -651,9 +551,7 @@ case 69: { sym(1).Node = node; } break; -#line 1035 "qmljs.g" - -case 70: { +case 73: { bool rx = lexer->scanRegExp(Lexer::EqualPrefix); if (!rx) { diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, location(lexer), lexer->errorMessage())); @@ -664,36 +562,28 @@ case 70: { sym(1).Node = node; } break; -#line 1049 "qmljs.g" - -case 71: { +case 74: { AST::ArrayLiteral *node = makeAstNode (driver->nodePool(), (AST::Elision *) 0); node->lbracketToken = loc(1); node->rbracketToken = loc(2); sym(1).Node = node; } break; -#line 1059 "qmljs.g" - -case 72: { +case 75: { AST::ArrayLiteral *node = makeAstNode (driver->nodePool(), sym(2).Elision->finish()); node->lbracketToken = loc(1); node->rbracketToken = loc(3); sym(1).Node = node; } break; -#line 1069 "qmljs.g" - -case 73: { +case 76: { AST::ArrayLiteral *node = makeAstNode (driver->nodePool(), sym(2).ElementList->finish ()); node->lbracketToken = loc(1); node->rbracketToken = loc(3); sym(1).Node = node; } break; -#line 1079 "qmljs.g" - -case 74: { +case 77: { AST::ArrayLiteral *node = makeAstNode (driver->nodePool(), sym(2).ElementList->finish (), (AST::Elision *) 0); node->lbracketToken = loc(1); @@ -702,9 +592,7 @@ case 74: { sym(1).Node = node; } break; -#line 1091 "qmljs.g" - -case 75: { +case 78: { AST::ArrayLiteral *node = makeAstNode (driver->nodePool(), sym(2).ElementList->finish (), sym(4).Elision->finish()); node->lbracketToken = loc(1); @@ -713,9 +601,7 @@ case 75: { sym(1).Node = node; } break; -#line 1110 "qmljs.g" - -case 76: { +case 79: { AST::ObjectLiteral *node = 0; if (sym(2).Node) node = makeAstNode (driver->nodePool(), @@ -727,9 +613,7 @@ case 76: { sym(1).Node = node; } break; -#line 1125 "qmljs.g" - -case 77: { +case 80: { AST::ObjectLiteral *node = makeAstNode (driver->nodePool(), sym(2).PropertyNameAndValueList->finish ()); node->lbraceToken = loc(1); @@ -737,89 +621,67 @@ case 77: { sym(1).Node = node; } break; -#line 1136 "qmljs.g" - -case 78: { +case 81: { AST::NestedExpression *node = makeAstNode(driver->nodePool(), sym(2).Expression); node->lparenToken = loc(1); node->rparenToken = loc(3); sym(1).Node = node; } break; -#line 1146 "qmljs.g" - -case 79: { +case 82: { AST::UiQualifiedId *node = makeAstNode (driver->nodePool(), sym(1).sval); node->identifierToken = loc(1); sym(1).Node = node; } break; -#line 1155 "qmljs.g" - -case 80: { +case 83: { AST::UiQualifiedId *node = makeAstNode (driver->nodePool(), sym(1).UiQualifiedId, sym(3).sval); node->identifierToken = loc(3); sym(1).Node = node; } break; -#line 1164 "qmljs.g" - -case 81: { +case 84: { sym(1).Node = makeAstNode (driver->nodePool(), (AST::Elision *) 0, sym(1).Expression); } break; -#line 1171 "qmljs.g" - -case 82: { +case 85: { sym(1).Node = makeAstNode (driver->nodePool(), sym(1).Elision->finish(), sym(2).Expression); } break; -#line 1178 "qmljs.g" - -case 83: { +case 86: { AST::ElementList *node = makeAstNode (driver->nodePool(), sym(1).ElementList, (AST::Elision *) 0, sym(3).Expression); node->commaToken = loc(2); sym(1).Node = node; } break; -#line 1188 "qmljs.g" - -case 84: { +case 87: { AST::ElementList *node = makeAstNode (driver->nodePool(), sym(1).ElementList, sym(3).Elision->finish(), sym(4).Expression); node->commaToken = loc(2); sym(1).Node = node; } break; -#line 1198 "qmljs.g" - -case 85: { +case 88: { AST::Elision *node = makeAstNode (driver->nodePool()); node->commaToken = loc(1); sym(1).Node = node; } break; -#line 1207 "qmljs.g" - -case 86: { +case 89: { AST::Elision *node = makeAstNode (driver->nodePool(), sym(1).Elision); node->commaToken = loc(2); sym(1).Node = node; } break; -#line 1216 "qmljs.g" - -case 87: { +case 90: { AST::PropertyNameAndValueList *node = makeAstNode (driver->nodePool(), sym(1).PropertyName, sym(3).Expression); node->colonToken = loc(2); sym(1).Node = node; } break; -#line 1226 "qmljs.g" - -case 88: { +case 91: { AST::PropertyNameAndValueList *node = makeAstNode (driver->nodePool(), sym(1).PropertyNameAndValueList, sym(3).PropertyName, sym(5).Expression); node->commaToken = loc(2); @@ -827,196 +689,116 @@ case 88: { sym(1).Node = node; } break; -#line 1237 "qmljs.g" - -case 89: { +case 92: { AST::IdentifierPropertyName *node = makeAstNode (driver->nodePool(), sym(1).sval); node->propertyNameToken = loc(1); sym(1).Node = node; } break; - -#line 1246 "qmljs.g" -case 90: -#line 1249 "qmljs.g" - -case 91: { +case 93: +case 94: { AST::IdentifierPropertyName *node = makeAstNode (driver->nodePool(), driver->intern(lexer->characterBuffer(), lexer->characterCount())); node->propertyNameToken = loc(1); sym(1).Node = node; } break; -#line 1258 "qmljs.g" - -case 92: { +case 95: { AST::StringLiteralPropertyName *node = makeAstNode (driver->nodePool(), sym(1).sval); node->propertyNameToken = loc(1); sym(1).Node = node; } break; -#line 1267 "qmljs.g" - -case 93: { +case 96: { AST::NumericLiteralPropertyName *node = makeAstNode (driver->nodePool(), sym(1).dval); node->propertyNameToken = loc(1); sym(1).Node = node; } break; -#line 1276 "qmljs.g" - -case 94: { +case 97: { AST::IdentifierPropertyName *node = makeAstNode (driver->nodePool(), sym(1).sval); node->propertyNameToken = loc(1); sym(1).Node = node; } break; -#line 1285 "qmljs.g" - -case 95: - -#line 1289 "qmljs.g" - -case 96: - -#line 1293 "qmljs.g" - -case 97: - -#line 1297 "qmljs.g" - case 98: -#line 1301 "qmljs.g" - case 99: -#line 1305 "qmljs.g" - case 100: -#line 1309 "qmljs.g" - case 101: -#line 1313 "qmljs.g" - case 102: -#line 1317 "qmljs.g" - case 103: -#line 1321 "qmljs.g" - case 104: -#line 1325 "qmljs.g" - case 105: -#line 1329 "qmljs.g" - case 106: -#line 1333 "qmljs.g" - case 107: -#line 1337 "qmljs.g" - case 108: -#line 1341 "qmljs.g" - case 109: -#line 1345 "qmljs.g" - case 110: -#line 1349 "qmljs.g" - case 111: -#line 1353 "qmljs.g" - case 112: -#line 1357 "qmljs.g" - case 113: -#line 1361 "qmljs.g" - case 114: -#line 1365 "qmljs.g" - case 115: -#line 1369 "qmljs.g" - case 116: -#line 1373 "qmljs.g" - case 117: -#line 1377 "qmljs.g" - case 118: -#line 1381 "qmljs.g" - case 119: -#line 1385 "qmljs.g" - case 120: -#line 1389 "qmljs.g" - case 121: -#line 1393 "qmljs.g" - case 122: -#line 1397 "qmljs.g" - case 123: -#line 1401 "qmljs.g" - case 124: -#line 1405 "qmljs.g" - case 125: + +case 126: + +case 127: + +case 128: { sym(1).sval = driver->intern(lexer->characterBuffer(), lexer->characterCount()); } break; -#line 1419 "qmljs.g" - -case 130: { +case 133: { AST::ArrayMemberExpression *node = makeAstNode (driver->nodePool(), sym(1).Expression, sym(3).Expression); node->lbracketToken = loc(2); node->rbracketToken = loc(4); sym(1).Node = node; } break; -#line 1429 "qmljs.g" - -case 131: { +case 134: { AST::FieldMemberExpression *node = makeAstNode (driver->nodePool(), sym(1).Expression, sym(3).sval); node->dotToken = loc(2); node->identifierToken = loc(3); sym(1).Node = node; } break; -#line 1439 "qmljs.g" - -case 132: { +case 135: { AST::NewMemberExpression *node = makeAstNode (driver->nodePool(), sym(2).Expression, sym(4).ArgumentList); node->newToken = loc(1); node->lparenToken = loc(3); @@ -1024,500 +806,384 @@ case 132: { sym(1).Node = node; } break; -#line 1452 "qmljs.g" - -case 134: { +case 137: { AST::NewExpression *node = makeAstNode (driver->nodePool(), sym(2).Expression); node->newToken = loc(1); sym(1).Node = node; } break; -#line 1461 "qmljs.g" - -case 135: { +case 138: { AST::CallExpression *node = makeAstNode (driver->nodePool(), sym(1).Expression, sym(3).ArgumentList); node->lparenToken = loc(2); node->rparenToken = loc(4); sym(1).Node = node; } break; -#line 1471 "qmljs.g" - -case 136: { +case 139: { AST::CallExpression *node = makeAstNode (driver->nodePool(), sym(1).Expression, sym(3).ArgumentList); node->lparenToken = loc(2); node->rparenToken = loc(4); sym(1).Node = node; } break; -#line 1481 "qmljs.g" - -case 137: { +case 140: { AST::ArrayMemberExpression *node = makeAstNode (driver->nodePool(), sym(1).Expression, sym(3).Expression); node->lbracketToken = loc(2); node->rbracketToken = loc(4); sym(1).Node = node; } break; -#line 1491 "qmljs.g" - -case 138: { +case 141: { AST::FieldMemberExpression *node = makeAstNode (driver->nodePool(), sym(1).Expression, sym(3).sval); node->dotToken = loc(2); node->identifierToken = loc(3); sym(1).Node = node; } break; -#line 1501 "qmljs.g" - -case 139: { +case 142: { sym(1).Node = 0; } break; -#line 1508 "qmljs.g" - -case 140: { +case 143: { sym(1).Node = sym(1).ArgumentList->finish(); } break; -#line 1515 "qmljs.g" - -case 141: { +case 144: { sym(1).Node = makeAstNode (driver->nodePool(), sym(1).Expression); } break; -#line 1522 "qmljs.g" - -case 142: { +case 145: { AST::ArgumentList *node = makeAstNode (driver->nodePool(), sym(1).ArgumentList, sym(3).Expression); node->commaToken = loc(2); sym(1).Node = node; } break; -#line 1535 "qmljs.g" - -case 146: { +case 149: { AST::PostIncrementExpression *node = makeAstNode (driver->nodePool(), sym(1).Expression); node->incrementToken = loc(2); sym(1).Node = node; } break; -#line 1544 "qmljs.g" - -case 147: { +case 150: { AST::PostDecrementExpression *node = makeAstNode (driver->nodePool(), sym(1).Expression); node->decrementToken = loc(2); sym(1).Node = node; } break; -#line 1555 "qmljs.g" - -case 149: { +case 152: { AST::DeleteExpression *node = makeAstNode (driver->nodePool(), sym(2).Expression); node->deleteToken = loc(1); sym(1).Node = node; } break; -#line 1564 "qmljs.g" - -case 150: { +case 153: { AST::VoidExpression *node = makeAstNode (driver->nodePool(), sym(2).Expression); node->voidToken = loc(1); sym(1).Node = node; } break; -#line 1573 "qmljs.g" - -case 151: { +case 154: { AST::TypeOfExpression *node = makeAstNode (driver->nodePool(), sym(2).Expression); node->typeofToken = loc(1); sym(1).Node = node; } break; -#line 1582 "qmljs.g" - -case 152: { +case 155: { AST::PreIncrementExpression *node = makeAstNode (driver->nodePool(), sym(2).Expression); node->incrementToken = loc(1); sym(1).Node = node; } break; -#line 1591 "qmljs.g" - -case 153: { +case 156: { AST::PreDecrementExpression *node = makeAstNode (driver->nodePool(), sym(2).Expression); node->decrementToken = loc(1); sym(1).Node = node; } break; -#line 1600 "qmljs.g" - -case 154: { +case 157: { AST::UnaryPlusExpression *node = makeAstNode (driver->nodePool(), sym(2).Expression); node->plusToken = loc(1); sym(1).Node = node; } break; -#line 1609 "qmljs.g" - -case 155: { +case 158: { AST::UnaryMinusExpression *node = makeAstNode (driver->nodePool(), sym(2).Expression); node->minusToken = loc(1); sym(1).Node = node; } break; -#line 1618 "qmljs.g" - -case 156: { +case 159: { AST::TildeExpression *node = makeAstNode (driver->nodePool(), sym(2).Expression); node->tildeToken = loc(1); sym(1).Node = node; } break; -#line 1627 "qmljs.g" - -case 157: { +case 160: { AST::NotExpression *node = makeAstNode (driver->nodePool(), sym(2).Expression); node->notToken = loc(1); sym(1).Node = node; } break; -#line 1638 "qmljs.g" - -case 159: { +case 162: { AST::BinaryExpression *node = makeAstNode (driver->nodePool(), sym(1).Expression, QSOperator::Mul, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -#line 1648 "qmljs.g" - -case 160: { +case 163: { AST::BinaryExpression *node = makeAstNode (driver->nodePool(), sym(1).Expression, QSOperator::Div, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -#line 1658 "qmljs.g" - -case 161: { +case 164: { AST::BinaryExpression *node = makeAstNode (driver->nodePool(), sym(1).Expression, QSOperator::Mod, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -#line 1670 "qmljs.g" - -case 163: { +case 166: { AST::BinaryExpression *node = makeAstNode (driver->nodePool(), sym(1).Expression, QSOperator::Add, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -#line 1680 "qmljs.g" - -case 164: { +case 167: { AST::BinaryExpression *node = makeAstNode (driver->nodePool(), sym(1).Expression, QSOperator::Sub, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -#line 1692 "qmljs.g" - -case 166: { +case 169: { AST::BinaryExpression *node = makeAstNode (driver->nodePool(), sym(1).Expression, QSOperator::LShift, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -#line 1702 "qmljs.g" - -case 167: { +case 170: { AST::BinaryExpression *node = makeAstNode (driver->nodePool(), sym(1).Expression, QSOperator::RShift, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -#line 1712 "qmljs.g" - -case 168: { +case 171: { AST::BinaryExpression *node = makeAstNode (driver->nodePool(), sym(1).Expression, QSOperator::URShift, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -#line 1724 "qmljs.g" - -case 170: { +case 173: { AST::BinaryExpression *node = makeAstNode (driver->nodePool(), sym(1).Expression, QSOperator::Lt, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -#line 1734 "qmljs.g" - -case 171: { +case 174: { AST::BinaryExpression *node = makeAstNode (driver->nodePool(), sym(1).Expression, QSOperator::Gt, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -#line 1744 "qmljs.g" - -case 172: { +case 175: { AST::BinaryExpression *node = makeAstNode (driver->nodePool(), sym(1).Expression, QSOperator::Le, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -#line 1754 "qmljs.g" - -case 173: { +case 176: { AST::BinaryExpression *node = makeAstNode (driver->nodePool(), sym(1).Expression, QSOperator::Ge, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -#line 1764 "qmljs.g" - -case 174: { +case 177: { AST::BinaryExpression *node = makeAstNode (driver->nodePool(), sym(1).Expression, QSOperator::InstanceOf, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -#line 1774 "qmljs.g" - -case 175: { +case 178: { AST::BinaryExpression *node = makeAstNode (driver->nodePool(), sym(1).Expression, QSOperator::In, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -#line 1786 "qmljs.g" - -case 177: { +case 180: { AST::BinaryExpression *node = makeAstNode (driver->nodePool(), sym(1).Expression, QSOperator::Lt, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -#line 1796 "qmljs.g" - -case 178: { +case 181: { AST::BinaryExpression *node = makeAstNode (driver->nodePool(), sym(1).Expression, QSOperator::Gt, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -#line 1806 "qmljs.g" - -case 179: { +case 182: { AST::BinaryExpression *node = makeAstNode (driver->nodePool(), sym(1).Expression, QSOperator::Le, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -#line 1816 "qmljs.g" - -case 180: { +case 183: { AST::BinaryExpression *node = makeAstNode (driver->nodePool(), sym(1).Expression, QSOperator::Ge, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -#line 1826 "qmljs.g" - -case 181: { +case 184: { AST::BinaryExpression *node = makeAstNode (driver->nodePool(), sym(1).Expression, QSOperator::InstanceOf, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -#line 1838 "qmljs.g" - -case 183: { +case 186: { AST::BinaryExpression *node = makeAstNode (driver->nodePool(), sym(1).Expression, QSOperator::Equal, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -#line 1848 "qmljs.g" - -case 184: { +case 187: { AST::BinaryExpression *node = makeAstNode (driver->nodePool(), sym(1).Expression, QSOperator::NotEqual, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -#line 1858 "qmljs.g" - -case 185: { +case 188: { AST::BinaryExpression *node = makeAstNode (driver->nodePool(), sym(1).Expression, QSOperator::StrictEqual, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -#line 1868 "qmljs.g" - -case 186: { +case 189: { AST::BinaryExpression *node = makeAstNode (driver->nodePool(), sym(1).Expression, QSOperator::StrictNotEqual, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -#line 1880 "qmljs.g" - -case 188: { +case 191: { AST::BinaryExpression *node = makeAstNode (driver->nodePool(), sym(1).Expression, QSOperator::Equal, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -#line 1890 "qmljs.g" - -case 189: { +case 192: { AST::BinaryExpression *node = makeAstNode (driver->nodePool(), sym(1).Expression, QSOperator::NotEqual, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -#line 1900 "qmljs.g" - -case 190: { +case 193: { AST::BinaryExpression *node = makeAstNode (driver->nodePool(), sym(1).Expression, QSOperator::StrictEqual, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -#line 1910 "qmljs.g" - -case 191: { +case 194: { AST::BinaryExpression *node = makeAstNode (driver->nodePool(), sym(1).Expression, QSOperator::StrictNotEqual, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -#line 1922 "qmljs.g" - -case 193: { +case 196: { AST::BinaryExpression *node = makeAstNode (driver->nodePool(), sym(1).Expression, QSOperator::BitAnd, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -#line 1934 "qmljs.g" - -case 195: { +case 198: { AST::BinaryExpression *node = makeAstNode (driver->nodePool(), sym(1).Expression, QSOperator::BitAnd, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -#line 1946 "qmljs.g" - -case 197: { +case 200: { AST::BinaryExpression *node = makeAstNode (driver->nodePool(), sym(1).Expression, QSOperator::BitXor, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -#line 1958 "qmljs.g" - -case 199: { +case 202: { AST::BinaryExpression *node = makeAstNode (driver->nodePool(), sym(1).Expression, QSOperator::BitXor, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -#line 1970 "qmljs.g" - -case 201: { +case 204: { AST::BinaryExpression *node = makeAstNode (driver->nodePool(), sym(1).Expression, QSOperator::BitOr, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -#line 1982 "qmljs.g" - -case 203: { +case 206: { AST::BinaryExpression *node = makeAstNode (driver->nodePool(), sym(1).Expression, QSOperator::BitOr, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -#line 1994 "qmljs.g" - -case 205: { +case 208: { AST::BinaryExpression *node = makeAstNode (driver->nodePool(), sym(1).Expression, QSOperator::And, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -#line 2006 "qmljs.g" - -case 207: { +case 210: { AST::BinaryExpression *node = makeAstNode (driver->nodePool(), sym(1).Expression, QSOperator::And, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -#line 2018 "qmljs.g" - -case 209: { +case 212: { AST::BinaryExpression *node = makeAstNode (driver->nodePool(), sym(1).Expression, QSOperator::Or, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -#line 2030 "qmljs.g" - -case 211: { +case 214: { AST::BinaryExpression *node = makeAstNode (driver->nodePool(), sym(1).Expression, QSOperator::Or, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -#line 2042 "qmljs.g" - -case 213: { +case 216: { AST::ConditionalExpression *node = makeAstNode (driver->nodePool(), sym(1).Expression, sym(3).Expression, sym(5).Expression); node->questionToken = loc(2); @@ -1525,9 +1191,7 @@ case 213: { sym(1).Node = node; } break; -#line 2055 "qmljs.g" - -case 215: { +case 218: { AST::ConditionalExpression *node = makeAstNode (driver->nodePool(), sym(1).Expression, sym(3).Expression, sym(5).Expression); node->questionToken = loc(2); @@ -1535,160 +1199,112 @@ case 215: { sym(1).Node = node; } break; -#line 2068 "qmljs.g" - -case 217: { +case 220: { AST::BinaryExpression *node = makeAstNode (driver->nodePool(), sym(1).Expression, sym(2).ival, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -#line 2080 "qmljs.g" - -case 219: { +case 222: { AST::BinaryExpression *node = makeAstNode (driver->nodePool(), sym(1).Expression, sym(2).ival, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -#line 2090 "qmljs.g" - -case 220: { +case 223: { sym(1).ival = QSOperator::Assign; } break; -#line 2097 "qmljs.g" - -case 221: { +case 224: { sym(1).ival = QSOperator::InplaceMul; } break; -#line 2104 "qmljs.g" - -case 222: { +case 225: { sym(1).ival = QSOperator::InplaceDiv; } break; -#line 2111 "qmljs.g" - -case 223: { +case 226: { sym(1).ival = QSOperator::InplaceMod; } break; -#line 2118 "qmljs.g" - -case 224: { +case 227: { sym(1).ival = QSOperator::InplaceAdd; } break; -#line 2125 "qmljs.g" - -case 225: { +case 228: { sym(1).ival = QSOperator::InplaceSub; } break; -#line 2132 "qmljs.g" - -case 226: { +case 229: { sym(1).ival = QSOperator::InplaceLeftShift; } break; -#line 2139 "qmljs.g" - -case 227: { +case 230: { sym(1).ival = QSOperator::InplaceRightShift; } break; -#line 2146 "qmljs.g" - -case 228: { +case 231: { sym(1).ival = QSOperator::InplaceURightShift; } break; -#line 2153 "qmljs.g" - -case 229: { +case 232: { sym(1).ival = QSOperator::InplaceAnd; } break; -#line 2160 "qmljs.g" - -case 230: { +case 233: { sym(1).ival = QSOperator::InplaceXor; } break; -#line 2167 "qmljs.g" - -case 231: { +case 234: { sym(1).ival = QSOperator::InplaceOr; } break; -#line 2176 "qmljs.g" - -case 233: { +case 236: { AST::Expression *node = makeAstNode (driver->nodePool(), sym(1).Expression, sym(3).Expression); node->commaToken = loc(2); sym(1).Node = node; } break; -#line 2185 "qmljs.g" - -case 234: { +case 237: { sym(1).Node = 0; } break; -#line 2196 "qmljs.g" - -case 237: { +case 240: { AST::Expression *node = makeAstNode (driver->nodePool(), sym(1).Expression, sym(3).Expression); node->commaToken = loc(2); sym(1).Node = node; } break; -#line 2205 "qmljs.g" - -case 238: { +case 241: { sym(1).Node = 0; } break; -#line 2231 "qmljs.g" - -case 255: { +case 258: { AST::Block *node = makeAstNode (driver->nodePool(), sym(2).StatementList); node->lbraceToken = loc(1); node->rbraceToken = loc(3); sym(1).Node = node; } break; -#line 2241 "qmljs.g" - -case 256: { +case 259: { sym(1).Node = makeAstNode (driver->nodePool(), sym(1).Statement); } break; -#line 2248 "qmljs.g" - -case 257: { +case 260: { sym(1).Node = makeAstNode (driver->nodePool(), sym(1).StatementList, sym(2).Statement); } break; -#line 2255 "qmljs.g" - -case 258: { +case 261: { sym(1).Node = 0; } break; -#line 2262 "qmljs.g" - -case 259: { +case 262: { sym(1).Node = sym(1).StatementList->finish (); } break; -#line 2270 "qmljs.g" - -case 261: { +case 264: { AST::VariableStatement *node = makeAstNode (driver->nodePool(), sym(2).VariableDeclarationList->finish (/*readOnly=*/sym(1).ival == T_CONST)); node->declarationKindToken = loc(1); @@ -1696,106 +1312,76 @@ case 261: { sym(1).Node = node; } break; -#line 2281 "qmljs.g" - -case 262: { +case 265: { sym(1).ival = T_CONST; } break; -#line 2288 "qmljs.g" - -case 263: { +case 266: { sym(1).ival = T_VAR; } break; -#line 2295 "qmljs.g" - -case 264: { +case 267: { sym(1).Node = makeAstNode (driver->nodePool(), sym(1).VariableDeclaration); } break; -#line 2302 "qmljs.g" - -case 265: { +case 268: { AST::VariableDeclarationList *node = makeAstNode (driver->nodePool(), sym(1).VariableDeclarationList, sym(3).VariableDeclaration); node->commaToken = loc(2); sym(1).Node = node; } break; -#line 2312 "qmljs.g" - -case 266: { +case 269: { sym(1).Node = makeAstNode (driver->nodePool(), sym(1).VariableDeclaration); } break; -#line 2319 "qmljs.g" - -case 267: { +case 270: { sym(1).Node = makeAstNode (driver->nodePool(), sym(1).VariableDeclarationList, sym(3).VariableDeclaration); } break; -#line 2326 "qmljs.g" - -case 268: { +case 271: { AST::VariableDeclaration *node = makeAstNode (driver->nodePool(), sym(1).sval, sym(2).Expression); node->identifierToken = loc(1); sym(1).Node = node; } break; -#line 2335 "qmljs.g" - -case 269: { +case 272: { AST::VariableDeclaration *node = makeAstNode (driver->nodePool(), sym(1).sval, sym(2).Expression); node->identifierToken = loc(1); sym(1).Node = node; } break; -#line 2344 "qmljs.g" - -case 270: { +case 273: { // ### TODO: AST for initializer sym(1) = sym(2); } break; -#line 2352 "qmljs.g" - -case 271: { +case 274: { sym(1).Node = 0; } break; -#line 2361 "qmljs.g" - -case 273: { +case 276: { // ### TODO: AST for initializer sym(1) = sym(2); } break; -#line 2369 "qmljs.g" - -case 274: { +case 277: { sym(1).Node = 0; } break; -#line 2378 "qmljs.g" - -case 276: { +case 279: { AST::EmptyStatement *node = makeAstNode (driver->nodePool()); node->semicolonToken = loc(1); sym(1).Node = node; } break; -#line 2388 "qmljs.g" - -case 278: { +case 281: { AST::ExpressionStatement *node = makeAstNode (driver->nodePool(), sym(1).Expression); node->semicolonToken = loc(2); sym(1).Node = node; } break; -#line 2397 "qmljs.g" - -case 279: { +case 282: { AST::IfStatement *node = makeAstNode (driver->nodePool(), sym(3).Expression, sym(5).Statement, sym(7).Statement); node->ifToken = loc(1); node->lparenToken = loc(2); @@ -1804,9 +1390,7 @@ case 279: { sym(1).Node = node; } break; -#line 2409 "qmljs.g" - -case 280: { +case 283: { AST::IfStatement *node = makeAstNode (driver->nodePool(), sym(3).Expression, sym(5).Statement); node->ifToken = loc(1); node->lparenToken = loc(2); @@ -1814,9 +1398,7 @@ case 280: { sym(1).Node = node; } break; -#line 2422 "qmljs.g" - -case 282: { +case 285: { AST::DoWhileStatement *node = makeAstNode (driver->nodePool(), sym(2).Statement, sym(5).Expression); node->doToken = loc(1); node->whileToken = loc(3); @@ -1826,9 +1408,7 @@ case 282: { sym(1).Node = node; } break; -#line 2435 "qmljs.g" - -case 283: { +case 286: { AST::WhileStatement *node = makeAstNode (driver->nodePool(), sym(3).Expression, sym(5).Statement); node->whileToken = loc(1); node->lparenToken = loc(2); @@ -1836,9 +1416,7 @@ case 283: { sym(1).Node = node; } break; -#line 2446 "qmljs.g" - -case 284: { +case 287: { AST::ForStatement *node = makeAstNode (driver->nodePool(), sym(3).Expression, sym(5).Expression, sym(7).Expression, sym(9).Statement); node->forToken = loc(1); @@ -1849,9 +1427,7 @@ case 284: { sym(1).Node = node; } break; -#line 2460 "qmljs.g" - -case 285: { +case 288: { AST::LocalForStatement *node = makeAstNode (driver->nodePool(), sym(4).VariableDeclarationList->finish (/*readOnly=*/false), sym(6).Expression, sym(8).Expression, sym(10).Statement); @@ -1864,9 +1440,7 @@ case 285: { sym(1).Node = node; } break; -#line 2476 "qmljs.g" - -case 286: { +case 289: { AST:: ForEachStatement *node = makeAstNode (driver->nodePool(), sym(3).Expression, sym(5).Expression, sym(7).Statement); node->forToken = loc(1); @@ -1876,9 +1450,7 @@ case 286: { sym(1).Node = node; } break; -#line 2489 "qmljs.g" - -case 287: { +case 290: { AST::LocalForEachStatement *node = makeAstNode (driver->nodePool(), sym(4).VariableDeclaration, sym(6).Expression, sym(8).Statement); node->forToken = loc(1); @@ -1889,18 +1461,14 @@ case 287: { sym(1).Node = node; } break; -#line 2504 "qmljs.g" - -case 289: { +case 292: { AST::ContinueStatement *node = makeAstNode (driver->nodePool()); node->continueToken = loc(1); node->semicolonToken = loc(2); sym(1).Node = node; } break; -#line 2515 "qmljs.g" - -case 291: { +case 294: { AST::ContinueStatement *node = makeAstNode (driver->nodePool(), sym(2).sval); node->continueToken = loc(1); node->identifierToken = loc(2); @@ -1908,18 +1476,14 @@ case 291: { sym(1).Node = node; } break; -#line 2527 "qmljs.g" - -case 293: { +case 296: { AST::BreakStatement *node = makeAstNode (driver->nodePool()); node->breakToken = loc(1); node->semicolonToken = loc(2); sym(1).Node = node; } break; -#line 2538 "qmljs.g" - -case 295: { +case 298: { AST::BreakStatement *node = makeAstNode (driver->nodePool(), sym(2).sval); node->breakToken = loc(1); node->identifierToken = loc(2); @@ -1927,18 +1491,14 @@ case 295: { sym(1).Node = node; } break; -#line 2550 "qmljs.g" - -case 297: { +case 300: { AST::ReturnStatement *node = makeAstNode (driver->nodePool(), sym(2).Expression); node->returnToken = loc(1); node->semicolonToken = loc(3); sym(1).Node = node; } break; -#line 2560 "qmljs.g" - -case 298: { +case 301: { AST::WithStatement *node = makeAstNode (driver->nodePool(), sym(3).Expression, sym(5).Statement); node->withToken = loc(1); node->lparenToken = loc(2); @@ -1946,9 +1506,7 @@ case 298: { sym(1).Node = node; } break; -#line 2571 "qmljs.g" - -case 299: { +case 302: { AST::SwitchStatement *node = makeAstNode (driver->nodePool(), sym(3).Expression, sym(5).CaseBlock); node->switchToken = loc(1); node->lparenToken = loc(2); @@ -1956,122 +1514,90 @@ case 299: { sym(1).Node = node; } break; -#line 2582 "qmljs.g" - -case 300: { +case 303: { AST::CaseBlock *node = makeAstNode (driver->nodePool(), sym(2).CaseClauses); node->lbraceToken = loc(1); node->rbraceToken = loc(3); sym(1).Node = node; } break; -#line 2592 "qmljs.g" - -case 301: { +case 304: { AST::CaseBlock *node = makeAstNode (driver->nodePool(), sym(2).CaseClauses, sym(3).DefaultClause, sym(4).CaseClauses); node->lbraceToken = loc(1); node->rbraceToken = loc(5); sym(1).Node = node; } break; -#line 2602 "qmljs.g" - -case 302: { +case 305: { sym(1).Node = makeAstNode (driver->nodePool(), sym(1).CaseClause); } break; -#line 2609 "qmljs.g" - -case 303: { +case 306: { sym(1).Node = makeAstNode (driver->nodePool(), sym(1).CaseClauses, sym(2).CaseClause); } break; -#line 2616 "qmljs.g" - -case 304: { +case 307: { sym(1).Node = 0; } break; -#line 2623 "qmljs.g" - -case 305: { +case 308: { sym(1).Node = sym(1).CaseClauses->finish (); } break; -#line 2630 "qmljs.g" - -case 306: { +case 309: { AST::CaseClause *node = makeAstNode (driver->nodePool(), sym(2).Expression, sym(4).StatementList); node->caseToken = loc(1); node->colonToken = loc(3); sym(1).Node = node; } break; -#line 2640 "qmljs.g" - -case 307: { +case 310: { AST::DefaultClause *node = makeAstNode (driver->nodePool(), sym(3).StatementList); node->defaultToken = loc(1); node->colonToken = loc(2); sym(1).Node = node; } break; - -#line 2650 "qmljs.g" -case 308: -#line 2653 "qmljs.g" - -case 309: { +case 311: +case 312: { AST::LabelledStatement *node = makeAstNode (driver->nodePool(), driver->intern(lexer->characterBuffer(), lexer->characterCount()), sym(3).Statement); node->identifierToken = loc(1); node->colonToken = loc(2); sym(1).Node = node; } break; -#line 2663 "qmljs.g" - -case 310: { +case 313: { AST::LabelledStatement *node = makeAstNode (driver->nodePool(), sym(1).sval, sym(3).Statement); node->identifierToken = loc(1); node->colonToken = loc(2); sym(1).Node = node; } break; -#line 2674 "qmljs.g" - -case 312: { +case 315: { AST::ThrowStatement *node = makeAstNode (driver->nodePool(), sym(2).Expression); node->throwToken = loc(1); node->semicolonToken = loc(3); sym(1).Node = node; } break; -#line 2684 "qmljs.g" - -case 313: { +case 316: { AST::TryStatement *node = makeAstNode (driver->nodePool(), sym(2).Statement, sym(3).Catch); node->tryToken = loc(1); sym(1).Node = node; } break; -#line 2693 "qmljs.g" - -case 314: { +case 317: { AST::TryStatement *node = makeAstNode (driver->nodePool(), sym(2).Statement, sym(3).Finally); node->tryToken = loc(1); sym(1).Node = node; } break; -#line 2702 "qmljs.g" - -case 315: { +case 318: { AST::TryStatement *node = makeAstNode (driver->nodePool(), sym(2).Statement, sym(3).Catch, sym(4).Finally); node->tryToken = loc(1); sym(1).Node = node; } break; -#line 2711 "qmljs.g" - -case 316: { +case 319: { AST::Catch *node = makeAstNode (driver->nodePool(), sym(3).sval, sym(5).Block); node->catchToken = loc(1); node->lparenToken = loc(2); @@ -2080,26 +1606,20 @@ case 316: { sym(1).Node = node; } break; -#line 2723 "qmljs.g" - -case 317: { +case 320: { AST::Finally *node = makeAstNode (driver->nodePool(), sym(2).Block); node->finallyToken = loc(1); sym(1).Node = node; } break; -#line 2733 "qmljs.g" - -case 319: { +case 322: { AST::DebuggerStatement *node = makeAstNode (driver->nodePool()); node->debuggerToken = loc(1); node->semicolonToken = loc(2); sym(1).Node = node; } break; -#line 2743 "qmljs.g" - -case 320: { +case 323: { AST::FunctionDeclaration *node = makeAstNode (driver->nodePool(), sym(2).sval, sym(4).FormalParameterList, sym(7).FunctionBody); node->functionToken = loc(1); node->identifierToken = loc(2); @@ -2110,9 +1630,7 @@ case 320: { sym(1).Node = node; } break; -#line 2757 "qmljs.g" - -case 321: { +case 324: { AST::FunctionExpression *node = makeAstNode (driver->nodePool(), sym(2).sval, sym(4).FormalParameterList, sym(7).FunctionBody); node->functionToken = loc(1); if (sym(2).sval) @@ -2124,85 +1642,59 @@ case 321: { sym(1).Node = node; } break; -#line 2772 "qmljs.g" - -case 322: { +case 325: { AST::FormalParameterList *node = makeAstNode (driver->nodePool(), sym(1).sval); node->identifierToken = loc(1); sym(1).Node = node; } break; -#line 2781 "qmljs.g" - -case 323: { +case 326: { AST::FormalParameterList *node = makeAstNode (driver->nodePool(), sym(1).FormalParameterList, sym(3).sval); node->commaToken = loc(2); node->identifierToken = loc(3); sym(1).Node = node; } break; -#line 2791 "qmljs.g" - -case 324: { +case 327: { sym(1).Node = 0; } break; -#line 2798 "qmljs.g" - -case 325: { +case 328: { sym(1).Node = sym(1).FormalParameterList->finish (); } break; -#line 2805 "qmljs.g" - -case 326: { +case 329: { sym(1).Node = 0; } break; -#line 2814 "qmljs.g" - -case 328: { +case 331: { sym(1).Node = makeAstNode (driver->nodePool(), sym(1).SourceElements->finish ()); } break; -#line 2829 "qmljs.g" - -case 329: { +case 332: { sym(1).Node = makeAstNode (driver->nodePool(), sym(1).SourceElement); } break; -#line 2836 "qmljs.g" - -case 330: { +case 333: { sym(1).Node = makeAstNode (driver->nodePool(), sym(1).SourceElements, sym(2).SourceElement); } break; -#line 2843 "qmljs.g" - -case 331: { +case 334: { sym(1).Node = makeAstNode (driver->nodePool(), sym(1).Statement); } break; -#line 2850 "qmljs.g" - -case 332: { +case 335: { sym(1).Node = makeAstNode (driver->nodePool(), sym(1).FunctionDeclaration); } break; -#line 2857 "qmljs.g" - -case 333: { +case 336: { sym(1).sval = 0; } break; -#line 2866 "qmljs.g" - -case 335: { +case 338: { sym(1).Node = 0; } break; -#line 2874 "qmljs.g" - } // switch action = nt_action(state_stack[tos], lhs[r] - TERMINAL_COUNT); } // if @@ -2293,7 +1785,8 @@ case 335: { } for (int tk = 1; tk < TERMINAL_COUNT; ++tk) { - if (tk == T_AUTOMATIC_SEMICOLON) + if (tk == T_AUTOMATIC_SEMICOLON || tk == T_FEED_UI_PROGRAM || + tk == T_FEED_JS_STATEMENT || tk == T_FEED_JS_EXPRESSION) continue; int a = t_action(errorState, tk); diff --git a/src/declarative/qml/parser/qmljsparser_p.h b/src/declarative/qml/parser/qmljsparser_p.h index e4ca20a..9273039 100644 --- a/src/declarative/qml/parser/qmljsparser_p.h +++ b/src/declarative/qml/parser/qmljsparser_p.h @@ -1,7 +1,5 @@ // This file was generated by qlalr - DO NOT EDIT! -#line 148 "qmljs.g" - /**************************************************************************** ** ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). @@ -128,10 +126,29 @@ public: Parser(Engine *engine); ~Parser(); - bool parse(); + // parse a UI program + bool parse() { return parse(T_FEED_UI_PROGRAM); } + bool parseStatement() { return parse(T_FEED_JS_STATEMENT); } + bool parseExpression() { return parse(T_FEED_JS_EXPRESSION); } + + AST::UiProgram *ast() const + { return AST::cast(program); } + + AST::Statement *statement() const + { + if (! program) + return 0; - AST::UiProgram *ast() - { return program; } + return program->statementCast(); + } + + AST::ExpressionNode *expression() const + { + if (! program) + return 0; + + return program->expressionCast(); + } QList diagnosticMessages() const { return diagnostic_messages; } @@ -156,6 +173,8 @@ public: { return diagnosticMessage().loc.startColumn; } protected: + bool parse(int startToken); + void reallocateStack(); inline Value &sym(int index) @@ -174,7 +193,7 @@ protected: int *state_stack; AST::SourceLocation *location_stack; - AST::UiProgram *program; + AST::Node *program; // error recovery enum { TOKEN_BUFFER_SIZE = 3 }; @@ -200,15 +219,9 @@ protected: -#line 1015 "qmljs.g" - -#define J_SCRIPT_REGEXPLITERAL_RULE1 69 - -#line 1032 "qmljs.g" - -#define J_SCRIPT_REGEXPLITERAL_RULE2 70 +#define J_SCRIPT_REGEXPLITERAL_RULE1 72 -#line 2994 "qmljs.g" +#define J_SCRIPT_REGEXPLITERAL_RULE2 73 QT_END_NAMESPACE -- cgit v0.12 From bcae9d84fb5dd2bdc5a5298c8841702505a02867 Mon Sep 17 00:00:00 2001 From: Roberto Raggi Date: Wed, 15 Jul 2009 13:39:05 +0200 Subject: Rewrite QML expressions as closures --- src/declarative/qml/qmlexpression.cpp | 173 +++++++++++++++++++++++++++------- src/declarative/qml/qmlexpression_p.h | 4 + 2 files changed, 143 insertions(+), 34 deletions(-) diff --git a/src/declarative/qml/qmlexpression.cpp b/src/declarative/qml/qmlexpression.cpp index 84352b8..4fe7d0c 100644 --- a/src/declarative/qml/qmlexpression.cpp +++ b/src/declarative/qml/qmlexpression.cpp @@ -43,6 +43,10 @@ #include "qmlexpression_p.h" #include "qmlengine_p.h" #include "qmlcontext_p.h" +#include "rewriter/textwriter_p.h" +#include "parser/qmljslexer_p.h" +#include "parser/qmljsparser_p.h" +#include "parser/qmljsnodepool_p.h" #include "QtCore/qdebug.h" Q_DECLARE_METATYPE(QList); @@ -51,18 +55,109 @@ QT_BEGIN_NAMESPACE DEFINE_BOOL_CONFIG_OPTION(qmlDebugger, QML_DEBUGGER) +namespace { + +using namespace QmlJS; + +class RewriteBinding: protected AST::Visitor +{ + unsigned _position; + TextWriter *_writer; + +public: + QString operator()(const QString &code) + { + Engine engine; + NodePool pool(QString(), &engine); + Lexer lexer(&engine); + Parser parser(&engine); + lexer.setCode(code, 0); + parser.parseStatement(); + return rewrite(code, 0, parser.statement()); + } + +protected: + using AST::Visitor::visit; + + void accept(AST::Node *node) + { + AST::Node::acceptChild(node, this); + } + + QString rewrite(QString code, unsigned position, AST::Statement *node) + { + TextWriter w; + _writer = &w; + _position = position; + + accept(node); + + unsigned startOfStatement = node->firstSourceLocation().begin() - _position; + unsigned endOfStatement = node->lastSourceLocation().end() - _position; + + _writer->replace(startOfStatement, 0, QLatin1String("function() {\n")); + _writer->replace(endOfStatement, 0, QLatin1String("\n}")); + + w.write(&code); + + return code; + } + + virtual bool visit(AST::Block *ast) + { + for (AST::StatementList *it = ast->statements; it; it = it->next) { + if (! it->next) { + // we need to rewrite only the last statement of a block. + accept(it->statement); + } + } + + return false; + } + + virtual bool visit(AST::ExpressionStatement *ast) + { + unsigned startOfExpressionStatement = ast->firstSourceLocation().begin() - _position; + _writer->replace(startOfExpressionStatement, 0, QLatin1String("return ")); + + return false; + } + + virtual bool visit(AST::NumericLiteral *node) + { + if (node->suffix != AST::NumericLiteral::noSuffix) { + const int suffixLength = AST::NumericLiteral::suffixLength[node->suffix]; + const char *suffixSpell = AST::NumericLiteral::suffixSpell[node->suffix]; + QString pre; + pre += QLatin1String("qmlNumberFrom"); + pre += QChar(QLatin1Char(suffixSpell[0])).toUpper(); + pre += QLatin1String(&suffixSpell[1]); + pre += QLatin1Char('('); + _writer->replace(node->literalToken.begin() - _position, 0, pre); + _writer->replace(node->literalToken.end() - _position - suffixLength, + suffixLength, + QLatin1String(")")); + } + + return false; + } +}; + +} // end of anonymous namespace + + QmlExpressionPrivate::QmlExpressionPrivate(QmlExpression *b) -: q(b), ctxt(0), sseData(0), proxy(0), me(0), trackChange(false), line(-1), id(0), log(0) +: q(b), ctxt(0), expressionFunctionValid(false), sseData(0), proxy(0), me(0), trackChange(false), line(-1), id(0), log(0) { } QmlExpressionPrivate::QmlExpressionPrivate(QmlExpression *b, void *expr, QmlRefCount *rc) -: q(b), ctxt(0), sse((const char *)expr, rc), sseData(0), proxy(0), me(0), trackChange(true), line(-1), id(0), log(0) +: q(b), ctxt(0), expressionFunctionValid(false), sse((const char *)expr, rc), sseData(0), proxy(0), me(0), trackChange(true), line(-1), id(0), log(0) { } QmlExpressionPrivate::QmlExpressionPrivate(QmlExpression *b, const QString &expr) -: q(b), ctxt(0), expression(expr), sseData(0), proxy(0), me(0), trackChange(true), line(-1), id(0), log(0) +: q(b), ctxt(0), expression(expr), expressionFunctionValid(false), sseData(0), proxy(0), me(0), trackChange(true), line(-1), id(0), log(0) { } @@ -77,7 +172,7 @@ QmlExpressionPrivate::~QmlExpressionPrivate() /*! Create an invalid QmlExpression. - As the expression will not have an associated QmlContext, this will be a + As the expression will not have an associated QmlContext, this will be a null expression object and its value will always be an invalid QVariant. */ QmlExpression::QmlExpression() @@ -86,7 +181,7 @@ QmlExpression::QmlExpression() } /*! \internal */ -QmlExpression::QmlExpression(QmlContext *ctxt, void *expr, +QmlExpression::QmlExpression(QmlContext *ctxt, void *expr, QmlRefCount *rc, QObject *me) : d(new QmlExpressionPrivate(this, expr, rc)) { @@ -105,7 +200,7 @@ QmlExpression::QmlExpression(QmlContext *ctxt, void *expr, If specified, the \a scope object's properties will also be in scope during the expression's execution. */ -QmlExpression::QmlExpression(QmlContext *ctxt, const QString &expression, +QmlExpression::QmlExpression(QmlContext *ctxt, const QString &expression, QObject *scope) : d(new QmlExpressionPrivate(this, expression)) { @@ -177,13 +272,15 @@ void QmlExpression::setExpression(const QString &expression) delete d->proxy; d->proxy = 0; d->expression = expression; + d->expressionFunctionValid = false; + d->expressionFunction = QScriptValue(); d->sse.clear(); } /*! Called by QmlExpression each time the expression value changes from the - last time it was evaluated. The expression must have been evaluated at + last time it was evaluated. The expression must have been evaluated at least once (by calling QmlExpression::value()) before this callback will be made. @@ -226,16 +323,24 @@ QVariant QmlExpressionPrivate::evalQtScript() ctxtPriv->defaultObjects.insert(ctxtPriv->highPriorityCount, me); QScriptEngine *scriptEngine = engine->scriptEngine(); - QScriptValueList oldScopeChain = + QScriptValueList oldScopeChain = scriptEngine->currentContext()->scopeChain(); for (int i = 0; i < oldScopeChain.size(); ++i) scriptEngine->currentContext()->popScope(); - for (int i = ctxtPriv->scopeChain.size() - 1; i > -1; --i) + for (int i = ctxtPriv->scopeChain.size() - 1; i > -1; --i) scriptEngine->currentContext()->pushScope(ctxtPriv->scopeChain.at(i)); - - QScriptValue svalue = - scriptEngine->evaluate(expression, fileName.toString(), line); + + if (!expressionFunctionValid) { + RewriteBinding rewriteBinding; + + const QString code = rewriteBinding(expression); + expressionFunction = scriptEngine->evaluate(code, fileName.toString(), line); + expressionFunctionValid = true; + } + + QScriptValue svalue = expressionFunction.call(); + if (scriptEngine->hasUncaughtException()) { if (scriptEngine->uncaughtException().isError()){ @@ -262,7 +367,7 @@ QVariant QmlExpressionPrivate::evalQtScript() QList list; for (int ii = 0; ii < length; ++ii) { QScriptValue arrayItem = svalue.property(ii); - QObject *d = + QObject *d = qvariant_cast(arrayItem.data().toVariant()); if (d) { list << d; @@ -272,11 +377,11 @@ QVariant QmlExpressionPrivate::evalQtScript() } rv = QVariant::fromValue(list); } - } else if (svalue.isObject() && + } else if (svalue.isObject() && !svalue.isNumber() && !svalue.isString() && - !svalue.isDate() && - !svalue.isError() && + !svalue.isDate() && + !svalue.isError() && !svalue.isFunction() && !svalue.isNull() && !svalue.isQMetaObject() && @@ -290,19 +395,19 @@ QVariant QmlExpressionPrivate::evalQtScript() rv = var; } } - if (rv.isNull()) + if (rv.isNull()) rv = svalue.toVariant(); - for (int i = 0; i < ctxtPriv->scopeChain.size(); ++i) + for (int i = 0; i < ctxtPriv->scopeChain.size(); ++i) scriptEngine->currentContext()->popScope(); - for (int i = oldScopeChain.size() - 1; i > -1; --i) + for (int i = oldScopeChain.size() - 1; i > -1; --i) scriptEngine->currentContext()->pushScope(oldScopeChain.at(i)); return rv; } /*! - Returns the value of the expression, or an invalid QVariant if the + Returns the value of the expression, or an invalid QVariant if the expression is invalid or has an error. */ QVariant QmlExpression::value() @@ -358,12 +463,12 @@ QVariant QmlExpression::value() d->proxy, changedIndex); } else { const QMetaObject *metaObj = prop.object->metaObject(); - QMetaProperty metaProp = + QMetaProperty metaProp = metaObj->property(prop.coreIndex); - QString warn = QLatin1String("Expression depends on non-NOTIFYable property: ") + - QLatin1String(metaObj->className()) + - QLatin1String("::") + + QString warn = QLatin1String("Expression depends on non-NOTIFYable property: ") + + QLatin1String(metaObj->className()) + + QLatin1String("::") + QLatin1String(metaProp.name()); log.addWarning(warn); } @@ -386,10 +491,10 @@ QVariant QmlExpression::value() } const QMetaObject *metaObj = prop.object->metaObject(); - QMetaProperty metaProp = + QMetaProperty metaProp = metaObj->property(prop.coreIndex); - qWarning().nospace() << " " << metaObj->className() + qWarning().nospace() << " " << metaObj->className() << "::" << metaProp.name(); } } @@ -438,14 +543,14 @@ bool QmlExpression::trackChange() const /*! Set whether changes are tracked in the expression's value to \a trackChange. - If true, the QmlExpression will monitor properties involved in the + If true, the QmlExpression will monitor properties involved in the expression's evaluation, and call QmlExpression::valueChanged() if they have changed. This allows an application to ensure that any value associated with the result of the expression remains up to date. If false, the QmlExpression will not montitor properties involved in the expression's evaluation, and QmlExpression::valueChanged() will never be - called. This is more efficient if an application wants a "one off" + called. This is more efficient if an application wants a "one off" evaluation of the expression. By default, trackChange is true. @@ -468,7 +573,7 @@ void QmlExpression::setSourceLocation(const QUrl &fileName, int line) /*! Returns the expression's scope object, if provided, otherwise 0. - In addition to data provided by the expression's QmlContext, the scope + In addition to data provided by the expression's QmlContext, the scope object's properties are also in scope during the expression's evaluation. */ QObject *QmlExpression::scopeObject() const @@ -498,13 +603,13 @@ quint32 QmlExpression::id() const more convenient in an application, QmlExpressionObject can be used instead. QmlExpressionObject behaves identically to QmlExpression, except that the - QmlExpressionObject::value() method is a slot, and the + QmlExpressionObject::value() method is a slot, and the QmlExpressionObject::valueChanged() callback is a signal. */ /*! Create a QmlExpression with the specified \a parent. - As the expression will not have an associated QmlContext, this will be a + As the expression will not have an associated QmlContext, this will be a null expression object and its value will always be an invalid QVariant. */ QmlExpressionObject::QmlExpressionObject(QObject *parent) @@ -531,7 +636,7 @@ QmlExpressionObject::QmlExpressionObject(QmlContext *ctxt, void *d, QmlRefCount } /*! - Returns the value of the expression, or an invalid QVariant if the + Returns the value of the expression, or an invalid QVariant if the expression is invalid or has an error. */ QVariant QmlExpressionObject::value() @@ -543,8 +648,8 @@ QVariant QmlExpressionObject::value() \fn void QmlExpressionObject::valueChanged() Emitted each time the expression value changes from the last time it was - evaluated. The expression must have been evaluated at least once (by - calling QmlExpressionObject::value()) before this signal will be emitted. + evaluated. The expression must have been evaluated at least once (by + calling QmlExpressionObject::value()) before this signal will be emitted. */ void QmlExpressionPrivate::addLog(const QmlExpressionLog &l) diff --git a/src/declarative/qml/qmlexpression_p.h b/src/declarative/qml/qmlexpression_p.h index 5883125..09745a3 100644 --- a/src/declarative/qml/qmlexpression_p.h +++ b/src/declarative/qml/qmlexpression_p.h @@ -55,6 +55,7 @@ #include "qmlbasicscript_p.h" #include "qmlexpression.h" +#include QT_BEGIN_NAMESPACE @@ -73,6 +74,9 @@ public: QmlExpression *q; QmlContext *ctxt; QString expression; + bool expressionFunctionValid; + QScriptValue expressionFunction; + QmlBasicScript sse; void *sseData; QmlExpressionBindProxy *proxy; -- cgit v0.12 From 6263185ab45f533efea6c8f397092afb625cd929 Mon Sep 17 00:00:00 2001 From: Alan Alpert Date: Thu, 16 Jul 2009 10:07:10 +1000 Subject: Remove emitingEditingFinished from QLineControl Doesn't seem to hurt anything, and it was ugly API. --- src/gui/widgets/qlinecontrol.cpp | 2 -- src/gui/widgets/qlinecontrol_p.h | 5 +---- src/gui/widgets/qlineedit.cpp | 18 ++++-------------- 3 files changed, 5 insertions(+), 20 deletions(-) diff --git a/src/gui/widgets/qlinecontrol.cpp b/src/gui/widgets/qlinecontrol.cpp index ba85182..97f4a45 100644 --- a/src/gui/widgets/qlinecontrol.cpp +++ b/src/gui/widgets/qlinecontrol.cpp @@ -1497,9 +1497,7 @@ void QLineControl::processKeyEvent(QKeyEvent* event) if (event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return) { if (hasAcceptableInput() || fixup()) { emit accepted(); - m_emitingEditingFinished = true; emit editingFinished(); - m_emitingEditingFinished = false; } if (inlineCompletionAccepted) event->accept(); diff --git a/src/gui/widgets/qlinecontrol_p.h b/src/gui/widgets/qlinecontrol_p.h index 68ff66b..1e5c144 100644 --- a/src/gui/widgets/qlinecontrol_p.h +++ b/src/gui/widgets/qlinecontrol_p.h @@ -78,8 +78,7 @@ class Q_GUI_EXPORT QLineControl : public QObject public: QLineControl(const QString &txt = QString()) - : m_emitingEditingFinished(0), - m_cursor(0), m_preeditCursor(0), m_layoutDirection(Qt::LeftToRight), + : m_cursor(0), m_preeditCursor(0), m_layoutDirection(Qt::LeftToRight), m_hideCursor(false), m_separator(0), m_readOnly(0), m_dragEnabled(0), m_echoMode(0), m_textDirty(0), m_selDirty(0), m_validInput(1), m_blinkPeriod(0), m_blinkTimer(0), m_deleteAllTimer(0), @@ -230,8 +229,6 @@ public: bool processEvent(QEvent *ev); - bool m_emitingEditingFinished; //Needed in QLineEdit FocusOut event - private: void init(const QString &txt); void removeSelectedText(); diff --git a/src/gui/widgets/qlineedit.cpp b/src/gui/widgets/qlineedit.cpp index 6deb196..e0f5bc9 100644 --- a/src/gui/widgets/qlineedit.cpp +++ b/src/gui/widgets/qlineedit.cpp @@ -1393,15 +1393,10 @@ bool QLineEdit::event(QEvent * e) } else if (e->type() == QEvent::LeaveEditFocus) { d->setCursorVisible(false); d->control->setCursorBlinkPeriod(0); - if (!d->control->emitingEditingFinished) { - if (d->control->hasAcceptableInput() || d->control->fixup()) { - d->control->emitingEditingFinished = true; - emit editingFinished(); - d->control->emitingEditingFinished = false; - } - } + if (d->control->hasAcceptableInput() || d->control->fixup()) + emit editingFinished(); } - return; + return true; } #endif return QWidget::event(e); @@ -1727,13 +1722,8 @@ void QLineEdit::focusOutEvent(QFocusEvent *e) #endif if (reason != Qt::PopupFocusReason || !(QApplication::activePopupWidget() && QApplication::activePopupWidget()->parentWidget() == this)) { - if (!d->control->m_emitingEditingFinished) { - if (hasAcceptableInput() || d->control->fixup()) { - d->control->m_emitingEditingFinished = true; + if (hasAcceptableInput() || d->control->fixup()) emit editingFinished(); - d->control->m_emitingEditingFinished = false; - } - } #ifdef QT3_SUPPORT emit lostFocus(); #endif -- cgit v0.12 From 6eb1e397491c2d73aa40f3273cb20b371efad35a Mon Sep 17 00:00:00 2001 From: Alan Alpert Date: Thu, 16 Jul 2009 10:14:47 +1000 Subject: Initial commit of QFxLineEdit QLineControl is integrated here, so no more need for qfxlineedit branch --- src/declarative/fx/fx.pri | 3 + src/declarative/fx/qfxlineedit.cpp | 543 +++++++++++++++++++++++++++++++++++++ src/declarative/fx/qfxlineedit.h | 193 +++++++++++++ src/declarative/fx/qfxlineedit_p.h | 106 ++++++++ 4 files changed, 845 insertions(+) create mode 100644 src/declarative/fx/qfxlineedit.cpp create mode 100644 src/declarative/fx/qfxlineedit.h create mode 100644 src/declarative/fx/qfxlineedit_p.h diff --git a/src/declarative/fx/fx.pri b/src/declarative/fx/fx.pri index 0c26356..50bdc98 100644 --- a/src/declarative/fx/fx.pri +++ b/src/declarative/fx/fx.pri @@ -35,6 +35,8 @@ HEADERS += \ fx/qfxrepeater_p.h \ fx/qfxscalegrid.h \ fx/qfxshadowfilter.h \ + fx/qfxlineedit.h \ + fx/qfxlineedit_p.h \ fx/qfxtextedit.h \ fx/qfxtextedit_p.h \ fx/qfxtext.h \ @@ -70,6 +72,7 @@ SOURCES += \ fx/qfxrepeater.cpp \ fx/qfxscalegrid.cpp \ fx/qfxshadowfilter.cpp \ + fx/qfxlineedit.cpp \ fx/qfxtext.cpp \ fx/qfxtextedit.cpp \ fx/qfxtransform.cpp \ diff --git a/src/declarative/fx/qfxlineedit.cpp b/src/declarative/fx/qfxlineedit.cpp new file mode 100644 index 0000000..d23c325 --- /dev/null +++ b/src/declarative/fx/qfxlineedit.cpp @@ -0,0 +1,543 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qfxlineedit.h" +#include "qfxlineedit_p.h" +#include +#include +#include + +QT_BEGIN_NAMESPACE +QML_DEFINE_TYPE(QFxLineEdit,LineEdit); +QML_DEFINE_TYPE(QIntValidator,QIntValidator); + +QFxLineEdit::QFxLineEdit(QFxItem* parent) + : QFxPaintedItem(*(new QFxLineEditPrivate), parent) +{ + Q_D(QFxLineEdit); + d->init(); +} + +/* + \internal +*/ +QFxLineEdit::QFxLineEdit(QFxLineEditPrivate &dd, QFxItem* parent) + : QFxPaintedItem(dd, parent) +{ + Q_D(QFxLineEdit); + d->init(); +} + +QFxLineEdit::~QFxLineEdit() +{ +} + +QString QFxLineEdit::text() const +{ + Q_D(const QFxLineEdit); + return d->control->text(); +} + +void QFxLineEdit::setText(const QString &s) +{ + Q_D(QFxLineEdit); + if(s == text()) + return; + d->control->setText(s); + //emit textChanged(); +} + +QmlFont *QFxLineEdit::font() +{ + Q_D(QFxLineEdit); + return d->font; +} + +QColor QFxLineEdit::color() const +{ + Q_D(const QFxLineEdit); + return d->color; +} + +void QFxLineEdit::setColor(const QColor &c) +{ + Q_D(QFxLineEdit); + d->color = c; +} + +/* +QFxText::TextStyle QFxLineEdit::style() const +{ + Q_D(const QFxLineEdit); + return d->style; +} + +void QFxLineEdit::setStyle(QFxText::TextStyle style) +{ + Q_D(QFxLineEdit); + d->style = style; +} + +QColor QFxLineEdit::styleColor() const +{ + Q_D(const QFxLineEdit); + return d->styleColor; +} + +void QFxLineEdit::setStyleColor(const QColor &c) +{ + Q_D(QFxLineEdit); + d->styleColor = c; +} +*/ + +QFxText::HAlignment QFxLineEdit::hAlign() const +{ + Q_D(const QFxLineEdit); + return d->hAlign; +} + +void QFxLineEdit::setHAlign(QFxText::HAlignment align) +{ + Q_D(QFxLineEdit); + d->hAlign = align; +} + +QFxText::VAlignment QFxLineEdit::vAlign() const +{ + Q_D(const QFxLineEdit); + return d->vAlign; +} + +void QFxLineEdit::setVAlign(QFxText::VAlignment align) +{ + Q_D(QFxLineEdit); + d->vAlign = align; +} + +//### Should this also toggle cursor visibility? +bool QFxLineEdit::isReadOnly() const +{ + Q_D(const QFxLineEdit); + return d->control->isReadOnly(); +} + +void QFxLineEdit::setReadOnly(bool ro) +{ + Q_D(QFxLineEdit); + d->control->setReadOnly(ro); +} + +int QFxLineEdit::maxLength() const +{ + Q_D(const QFxLineEdit); + return d->control->maxLength(); +} + +void QFxLineEdit::setMaxLength(int ml) +{ + Q_D(QFxLineEdit); + d->control->setMaxLength(ml); +} + +int QFxLineEdit::cursorPosition() const +{ + Q_D(const QFxLineEdit); + return d->control->cursor(); +} +void QFxLineEdit::setCursorPosition(int cp) +{ + Q_D(QFxLineEdit); + d->control->moveCursor(cp); +} + +int QFxLineEdit::selectionLength() const +{ + Q_D(const QFxLineEdit); + return d->control->selectionEnd() - d->control->selectionStart(); +} + +void QFxLineEdit::setSelectionLength(int len) +{ + Q_D(QFxLineEdit); + d->control->setSelection(d->control->cursor(), len); +} + +QString QFxLineEdit::selectedText() const +{ + Q_D(const QFxLineEdit); + return d->control->selectedText(); +} + +bool QFxLineEdit::isAwesome() const +{ + Q_D(const QFxLineEdit); + return d->awesome; +} + +#include //Can be removed along wit the property +void QFxLineEdit::setAwesome(bool a) +{ + Q_D(QFxLineEdit); + d->awesome = a; + if(a){ + setColor(QColor(0,0,255)); + rainbowRedraw(); + } +} + +QObject* QFxLineEdit::validator() const +{ + Q_D(const QFxLineEdit); + //###const cast isn't good, but needed for property system? + //###same should be said about using QObject* as the property type + return const_cast(d->control->validator()); +} + +void QFxLineEdit::setValidator(QObject* v) +{ + Q_D(QFxLineEdit); + QValidator* valid = qobject_cast(v); + if(!valid) + return; + d->control->setValidator(valid); + if(!d->control->hasAcceptableInput()){ + d->oldValidity = false; + emit acceptableInputChanged(); + } +} + +QString QFxLineEdit::inputMask() const +{ + Q_D(const QFxLineEdit); + return d->control->inputMask(); +} + +void QFxLineEdit::setInputMask(const QString &im) +{ + Q_D(QFxLineEdit); + d->control->setInputMask(im); +} + +bool QFxLineEdit::hasAcceptableInput() const +{ + Q_D(const QFxLineEdit); + return d->control->hasAcceptableInput(); +} + +uint QFxLineEdit::echoMode() const +{ + Q_D(const QFxLineEdit); + return d->control->echoMode(); +} + +void QFxLineEdit::setEchoMode(uint echo) +{ + Q_D(QFxLineEdit); + d->control->setEchoMode(echo); +} + +QmlComponent* QFxLineEdit::cursorDelegate() const +{ + Q_D(const QFxLineEdit); + return d->cursorComponent; +} + +void QFxLineEdit::setCursorDelegate(QmlComponent* c) +{ + Q_D(QFxLineEdit); + if(d->cursorComponent) + delete d->cursorComponent; + d->cursorComponent = c; + d->startCreatingCursor(); +} + +void QFxLineEditPrivate::startCreatingCursor() +{ + Q_Q(QFxLineEdit); + if(!cursorComponent){ + q->disconnect(control, SIGNAL(cursorPositionChanged(int, int)), + q, SLOT(moveCursor())); + return; + } + q->connect(control, SIGNAL(cursorPositionChanged(int, int)), + q, SLOT(moveCursor())); + if(cursorComponent->isReady()){ + q->createCursor(); + }else if(cursorComponent->isLoading()){ + q->connect(cursorComponent, SIGNAL(statusChanged(int)), + q, SLOT(createCursor())); + }else{//isError + qWarning() << "You could really use the error checking for QFxLineEdit. We'll implement it soon."; + } +} + +void QFxLineEdit::createCursor() +{ + Q_D(QFxLineEdit); + //Handle isError too + if(!d->cursorComponent->isReady()) + return; + + if(d->cursorItem) + delete d->cursorItem; + d->cursorItem = qobject_cast(d->cursorComponent->create()); + if(!d->cursorItem){ + qWarning() << "You could really use the error reporting for QFxLineEdit. We'll implement it soon."; + return; + } + + d->cursorItem->setItemParent(this); + d->cursorItem->setX(d->control->cursorToX()); + d->cursorItem->setHeight(d->control->height()); +} + +void QFxLineEdit::moveCursor() +{ + Q_D(QFxLineEdit); + if(!d->cursorItem) + return; + d->cursorItem->setX(d->control->cursorToX() - d->hscroll); +} + +/* +int QFxLineEdit::scrollDuration() const +{ + Q_D(const QFxLineEdit); + return d->scrollDur; +} + +void QFxLineEdit::setScrollDuration(int s) +{ + Q_D(QFxLineEdit); + d->scrollDur = s; + //Need to update cur anims as well +} +*/ +int QFxLineEdit::xToPos(int x) +{ + Q_D(const QFxLineEdit); + return d->control->xToPos(x - d->hscroll); +} + +void QFxLineEdit::focusChanged(bool hasFocus) +{ + Q_D(QFxLineEdit); + if(d->focused && !hasFocus){ + d->focused = false; + d->control->setCursorBlinkPeriod(0); + updateAll();//Only need the cursor rect + }else{ + d->focused = hasFocus; + updateAll();//Only need the cursor rect + } +} + +void QFxLineEdit::keyPressEvent(QKeyEvent* ev) +{ + Q_D(QFxLineEdit); + d->control->processKeyEvent(ev); +} + +void QFxLineEdit::mousePressEvent(QGraphicsSceneMouseEvent *event) +{ + Q_D(QFxLineEdit); + setFocus(true); + d->control->setCursorBlinkPeriod(QApplication::cursorFlashTime()); + d->focused = true; + d->control->processEvent(event); + //event->accept(); +} + +bool QFxLineEdit::event(QEvent* ev) +{ + Q_D(QFxLineEdit); + //Anything we don't deal with ourselves, pass to the control + switch(ev->type()){ + case QEvent::GraphicsSceneMousePress: + break; + default: + return d->control->processEvent(ev); + } + return false; +} + +void QFxLineEdit::geometryChanged(const QRectF &newGeometry, + const QRectF &oldGeometry) +{ + if (newGeometry.width() != oldGeometry.width()) + updateSize(); + QFxPaintedItem::geometryChanged(newGeometry, oldGeometry); +} + +void QFxLineEdit::drawContents(QPainter *p, const QRect &r) +{ + Q_D(QFxLineEdit); + p->setRenderHint(QPainter::TextAntialiasing, true); + p->save(); + p->setPen(QPen(d->color)); + int flags = QLineControl::DrawText; + if(!isReadOnly() && d->focused && !d->cursorItem) + flags |= QLineControl::DrawCursor; + if (d->control->hasSelectedText()) + flags |= QLineControl::DrawSelections; + + //TODO: Clean up this cut'n'pasted section from QLineEdit + QRect lineRect(r); + + int cix = qRound(d->control->cursorToX()); + + // horizontal scrolling. d->hscroll is the left indent from the beginning + // of the text line to the left edge of lineRect. we update this value + // depending on the delta from the last paint event; in effect this means + // the below code handles all scrolling based on the textline (widthUsed, + // minLB, minRB), the line edit rect (lineRect) and the cursor position + // (cix). + QFontMetrics fm = QApplication::fontMetrics(); + int minLB = qMax(0, -fm.minLeftBearing()); + int minRB = qMax(0, -fm.minRightBearing()); + int widthUsed = d->control->width() + minRB; + if ((minLB + widthUsed) <= lineRect.width()) { + // text fits in lineRect; use hscroll for alignment + d->hscroll = 0; + d->hscroll -= minLB; + } else if (cix - d->hscroll >= lineRect.width()) { + // text doesn't fit, cursor is to the right of lineRect (scroll right) + d->hscroll = cix - lineRect.width() + 1; + } else if (cix - d->hscroll < 0 && d->hscroll < widthUsed) { + // text doesn't fit, cursor is to the left of lineRect (scroll left) + d->hscroll = cix; + } + // the y offset is there to keep the baseline constant in case we have script changes in the text. + QPoint topLeft = lineRect.topLeft() - QPoint(d->hscroll, d->control->ascent() - fm.ascent()); + + if(d->hscroll != d->oldScroll) + moveCursor(); + + d->control->draw(p, topLeft, r, flags); + + d->oldScroll = d->hscroll; + p->restore(); +} + +void QFxLineEditPrivate::init() +{ + Q_Q(QFxLineEdit); + control->setCursorWidth(1); + control->setPasswordCharacter('*'); + control->setLayoutDirection(Qt::LeftToRight); + control->setSelection(0,0); + q->setSmooth(true); + q->setAcceptedMouseButtons(Qt::LeftButton); + q->setOptions(QFxLineEdit::AcceptsInputMethods | QFxLineEdit::SimpleItem + | QFxLineEdit::HasContents | QFxLineEdit::MouseEvents); + q->connect(control, SIGNAL(cursorPositionChanged(int,int)), + q, SIGNAL(cursorPositionChanged())); + q->connect(control, SIGNAL(selectionChanged()), + q, SLOT(selectionChanged())); + q->connect(control, SIGNAL(textChanged(const QString &)), + q, SLOT(q_textChanged())); + q->connect(control, SIGNAL(accepted()), + q, SIGNAL(accepted())); + q->connect(control, SIGNAL(updateNeeded(const QRect &)), + // q, SLOT(dirtyCache(const QRect &))); + q, SLOT(updateAll())); + q->connect(control, SIGNAL(cursorPositionChanged(int,int)), + q, SLOT(updateAll())); + q->connect(control, SIGNAL(selectionChanged()), + q, SLOT(updateAll())); + if(!font) + font = new QmlFont(); + q->updateSize(); + oldValidity = control->hasAcceptableInput(); + oldSelectLength = q->selectionLength(); +} + +void QFxLineEdit::selectionChanged() +{ + Q_D(QFxLineEdit); + emit selectedTextChanged(); + if(selectionLength() != d->oldSelectLength){ + d->oldSelectLength = selectionLength(); + emit selectionLengthChanged(); + } +} + +void QFxLineEdit::q_textChanged() +{ + Q_D(QFxLineEdit); + updateAll(); + emit textChanged(); + if(hasAcceptableInput() != d->oldValidity){ + d->oldValidity = hasAcceptableInput(); + emit acceptableInputChanged(); + } +} + +//### Please replace this function with proper updating +void QFxLineEdit::updateAll() +{ + clearCache(); + updateSize(); + update(); +} + +void QFxLineEdit::updateSize() +{ + Q_D(QFxLineEdit); + setImplicitHeight(d->control->height()); + //d->control->width() is max width, not current width + QFontMetrics fm = QFontMetrics(d->font->font()); + setImplicitWidth(fm.boundingRect(d->control->text()).width()+1); + setContentsSize(QSize(width(), height())); +} + +void QFxLineEdit::rainbowRedraw() +{ + Q_D(QFxLineEdit); + if(!d->awesome) + return; + setColor(QColor::fromHsv((d->color.hue() + 5)%360, d->color.saturation(), d->color.value())); + updateAll(); + QTimer::singleShot(50, this, SLOT(rainbowRedraw())); +} +QT_END_NAMESPACE + diff --git a/src/declarative/fx/qfxlineedit.h b/src/declarative/fx/qfxlineedit.h new file mode 100644 index 0000000..04dbee3 --- /dev/null +++ b/src/declarative/fx/qfxlineedit.h @@ -0,0 +1,193 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QFXLINEEDIT_H +#define QFXLINEEDIT_H + +#include "qfxtext.h" +#include "qfxpainteditem.h" +#include +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Declarative) + +class QFxLineEditPrivate; +class QValidator; +class Q_DECLARATIVE_EXPORT QFxLineEdit : public QFxPaintedItem +{ + Q_OBJECT + + Q_PROPERTY(QString text READ text WRITE setText NOTIFY textChanged) + Q_PROPERTY(QmlFont *font READ font) + Q_PROPERTY(QColor color READ color WRITE setColor) + /* + Q_PROPERTY(QFxText::TextStyle style READ style WRITE setStyle) + Q_PROPERTY(QColor styleColor READ styleColor WRITE setStyleColor) + Q_PROPERTY(QFxText::HAlignment hAlign READ hAlign WRITE setHAlign) + Q_PROPERTY(QFxText::VAlignment vAlign READ vAlign WRITE setVAlign) + */ + + Q_PROPERTY(bool readOnly READ isReadOnly WRITE setReadOnly); + Q_PROPERTY(int maxLength READ maxLength WRITE setMaxLength); + Q_PROPERTY(int cursorPosition READ cursorPosition WRITE setCursorPosition NOTIFY cursorPositionChanged); + Q_PROPERTY(int selectionLength READ selectionLength WRITE setSelectionLength NOTIFY selectionLengthChanged); + Q_PROPERTY(QString selectedText READ selectedText NOTIFY selectedTextChanged); + + Q_PROPERTY(QObject* validator READ validator WRITE setValidator); + Q_PROPERTY(QString inputMask READ inputMask WRITE setInputMask); + Q_PROPERTY(bool acceptableInput READ hasAcceptableInput NOTIFY acceptableInputChanged); + Q_PROPERTY(uint echoMode READ echoMode WRITE setEchoMode); + + Q_PROPERTY(QmlComponent *cursorDelegate READ cursorDelegate WRITE setCursorDelegate); + /* + Q_PROPERTY(int scrollDuration READ scrollDuration SET setScrollDuration NOTIFY scrollDurationChanged); + */ + //### Requested by Aaron K.(Remove before release?) + Q_PROPERTY(bool awesome READ isAwesome WRITE setAwesome); +public: + QFxLineEdit(QFxItem* parent=0); + ~QFxLineEdit(); + + QString text() const; + void setText(const QString &); + + QmlFont *font(); + + QColor color() const; + void setColor(const QColor &c); + + //### Should we have this function or x variants of properties? + Q_INVOKABLE int xToPos(int x); + + /* + QFxText::TextStyle style() const; + void setStyle(QFxText::TextStyle style); + + QColor styleColor() const; + void setStyleColor(const QColor &c); + */ + + QFxText::HAlignment hAlign() const; + void setHAlign(QFxText::HAlignment align); + + QFxText::VAlignment vAlign() const; + void setVAlign(QFxText::VAlignment align); + + bool isReadOnly() const; + void setReadOnly(bool); + + int maxLength() const; + void setMaxLength(int ml); + + int cursorPosition() const; + void setCursorPosition(int cp); + + int selectionLength() const; + void setSelectionLength(int len); + + QString selectedText() const; + + QObject * validator() const; + void setValidator(QObject* v); + + QString inputMask() const; + void setInputMask(const QString &im); + + uint echoMode() const; + void setEchoMode(uint echo); + + QmlComponent* cursorDelegate() const; + void setCursorDelegate(QmlComponent*); + + /* + int scrollDuration() const; + void setScrollDuration(int); + */ + + bool hasAcceptableInput() const; + + bool isAwesome() const; + void setAwesome(bool a); + + void drawContents(QPainter *p,const QRect &r); +Q_SIGNALS: + void textChanged(); + void cursorPositionChanged(); + void selectionLengthChanged(); + void selectedTextChanged(); + void accepted(); + void acceptableInputChanged(); + +protected: + QFxLineEdit(QFxLineEditPrivate &dd, QFxItem *parent); + virtual void geometryChanged(const QRectF &newGeometry, + const QRectF &oldGeometry); + + void mousePressEvent(QGraphicsSceneMouseEvent *event); + void keyPressEvent(QKeyEvent* ev); + bool event(QEvent *e); + + void focusChanged(bool hasFocus); + +private slots: + void updateSize(); + void q_textChanged(); + void selectionChanged(); + void updateAll(); + void createCursor(); + void moveCursor(); + void rainbowRedraw(); + +private: + Q_DECLARE_PRIVATE(QFxLineEdit); +}; + +QT_END_NAMESPACE + +QML_DECLARE_TYPE(QFxLineEdit) +QML_DECLARE_TYPE(QIntValidator) + +QT_END_HEADER +#endif // QFXLINEEDIT_H diff --git a/src/declarative/fx/qfxlineedit_p.h b/src/declarative/fx/qfxlineedit_p.h new file mode 100644 index 0000000..8ee5cca --- /dev/null +++ b/src/declarative/fx/qfxlineedit_p.h @@ -0,0 +1,106 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QFXLINEEDIT_P_H +#define QFXLINEEDIT_P_H + +#include "qfxlineedit.h" +#include "qml.h" +#include "qfxpainteditem_p.h" +#include "private/qlinecontrol_p.h" +#include +// +// 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. + +QT_BEGIN_NAMESPACE + +class QFxLineEditPrivate : public QFxPaintedItemPrivate +{ + Q_DECLARE_PUBLIC(QFxLineEdit); +public: + QFxLineEditPrivate() : control(new QLineControl(QString())), + font(0), color((QRgb)0), style(QFxText::Normal), + hAlign(QFxText::AlignLeft), vAlign(QFxText::AlignTop), + styleColor((QRgb)0), oldScroll(0), hscroll(0), + focused(false), awesome(false) + { + } + + ~QFxLineEditPrivate() + { + } + + void init(); + void startCreatingCursor(); + + QLineControl* control; + + QmlFont *font; + QColor color; + QFxText::TextStyle style; + QColor styleColor; + QFxText::HAlignment hAlign; + QFxText::VAlignment vAlign; + QPointer cursorComponent; + QPointer cursorItem; + + int oldSelectLength; + int oldHeight; + int oldWidth; + bool oldValidity; + int hscroll; + int oldScroll; + bool focused; + bool awesome; + +}; + +QT_END_NAMESPACE + +#endif + -- cgit v0.12 From 87c97621a1b6ff958d773559f5c39db010c9b073 Mon Sep 17 00:00:00 2001 From: Alan Alpert Date: Thu, 16 Jul 2009 11:08:06 +1000 Subject: Fixes bugs with particles Fixed: Particle count changes had a noticable delay Fixed: Changing from zero to non-zero didn't work --- src/declarative/extra/qfxparticles.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/declarative/extra/qfxparticles.cpp b/src/declarative/extra/qfxparticles.cpp index 3130f06..e1c5bbe 100644 --- a/src/declarative/extra/qfxparticles.cpp +++ b/src/declarative/extra/qfxparticles.cpp @@ -473,8 +473,9 @@ void QFxParticlesPrivate::tick(int time) } } } - while(particles.count() < count && particles.count() < percCount && streamWidth--) - createParticle(time); + while(particles.count() < count && + (!stream || (particles.count() < percCount && streamWidth--))) + createParticle(time); } lastAdvTime = time; @@ -704,11 +705,13 @@ void QFxParticles::setCount(int cnt) { Q_D(QFxParticles); if (cnt != d->count) { - if (!d->count && d->clock.state() != QAbstractAnimation::Running) - d->clock.start(); // infinity?? + int oldCount = d->count; d->count = cnt; d->addParticleTime = 0; d->addParticleCount = d->particles.count(); + if (!oldCount && d->clock.state() != QAbstractAnimation::Running){ + d->clock.start(); // infinity?? + } update(); } } -- cgit v0.12 From befae051c1f80d66f459f375279f36047017c194 Mon Sep 17 00:00:00 2001 From: Alan Alpert Date: Thu, 16 Jul 2009 11:09:49 +1000 Subject: Update SameGame particles Remove count:1 hack, make particles the right color. --- demos/declarative/samegame/content/BoomBlock.qml | 23 ++++++++++++++++++--- .../declarative/samegame/content/pics/blueStar.png | Bin 0 -> 2684 bytes .../samegame/content/pics/greenStar.png | Bin 0 -> 2675 bytes .../declarative/samegame/content/pics/redStar.png | Bin 0 -> 2676 bytes 4 files changed, 20 insertions(+), 3 deletions(-) create mode 100644 demos/declarative/samegame/content/pics/blueStar.png create mode 100644 demos/declarative/samegame/content/pics/greenStar.png create mode 100644 demos/declarative/samegame/content/pics/redStar.png diff --git a/demos/declarative/samegame/content/BoomBlock.qml b/demos/declarative/samegame/content/BoomBlock.qml index 68e0e1a..0d05772 100644 --- a/demos/declarative/samegame/content/BoomBlock.qml +++ b/demos/declarative/samegame/content/BoomBlock.qml @@ -9,19 +9,36 @@ Item { id:block y: Follow { source: targetY; spring: 1.2; damping: 0.1 } Image { id: img - source: {if(type==0){"pics/redStone.png";}else if(type==1){"pics/blueStone.png";}else{"pics/greenStone.png";}} + source: { + if(type == 0){ + "pics/redStone.png"; + } else if(type == 1) { + "pics/blueStone.png"; + } else { + "pics/greenStone.png"; + } + } opacity: 0 opacity: Behavior { NumberAnimation { properties:"opacity"; duration: 200 } } anchors.fill: parent } Particles { id: particles width:1; height:1; anchors.centeredIn: parent; opacity: 0 - lifeSpan: 100000; source: "pics/star.png"; count:1; streamIn: false + lifeSpan: 1000000000; count:0; streamIn: false angle: 0; angleDeviation: 360; velocity: 100; velocityDeviation:30 + source: { + if(type == 0){ + "pics/redStar.png"; + } else if (type == 1) { + "pics/blueStar.png"; + } else { + "pics/greenStar.png"; + } + } } states: [ - State{ name: "SpawnState"; when: spawning == true && dying == false + State{ name: "AliveState"; when: spawning == true && dying == false SetProperties { target: img; opacity: 1 } }, State{ name: "DeathState"; when: dying == true diff --git a/demos/declarative/samegame/content/pics/blueStar.png b/demos/declarative/samegame/content/pics/blueStar.png new file mode 100644 index 0000000..822dc53 Binary files /dev/null and b/demos/declarative/samegame/content/pics/blueStar.png differ diff --git a/demos/declarative/samegame/content/pics/greenStar.png b/demos/declarative/samegame/content/pics/greenStar.png new file mode 100644 index 0000000..1abbcf0 Binary files /dev/null and b/demos/declarative/samegame/content/pics/greenStar.png differ diff --git a/demos/declarative/samegame/content/pics/redStar.png b/demos/declarative/samegame/content/pics/redStar.png new file mode 100644 index 0000000..b18834f Binary files /dev/null and b/demos/declarative/samegame/content/pics/redStar.png differ -- cgit v0.12 From 8e31e21bb4fc5630706cd21a4a74251c41563adb Mon Sep 17 00:00:00 2001 From: Yann Bodson Date: Thu, 16 Jul 2009 11:13:27 +1000 Subject: Do not segfault when index == -1. --- src/declarative/extra/qmlfolderlistmodel.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/declarative/extra/qmlfolderlistmodel.cpp b/src/declarative/extra/qmlfolderlistmodel.cpp index acee5e1..4a71109 100644 --- a/src/declarative/extra/qmlfolderlistmodel.cpp +++ b/src/declarative/extra/qmlfolderlistmodel.cpp @@ -161,7 +161,9 @@ void QmlFolderListModel::classComplete() bool QmlFolderListModel::isFolder(int index) const { Q_D(const QmlFolderListModel); - return d->model.isDir(d->model.index(index, 0, d->folderIndex)); + if (index != -1) + return d->model.isDir(d->model.index(index, 0, d->folderIndex)); + return false; } void QmlFolderListModel::refresh() -- cgit v0.12 From 17f3d0d2389619109a80c54240903a1534a86358 Mon Sep 17 00:00:00 2001 From: Yann Bodson Date: Thu, 16 Jul 2009 11:15:24 +1000 Subject: Add QmlPalette::darker() and QmlPalette::lighter(). --- src/declarative/util/qmlpalette.cpp | 10 ++++++++++ src/declarative/util/qmlpalette.h | 3 +++ 2 files changed, 13 insertions(+) diff --git a/src/declarative/util/qmlpalette.cpp b/src/declarative/util/qmlpalette.cpp index eda0ded..40cfa71 100644 --- a/src/declarative/util/qmlpalette.cpp +++ b/src/declarative/util/qmlpalette.cpp @@ -151,6 +151,16 @@ QColor QmlPalette::highlightedText() const return d->palette.color(d->group, QPalette::HighlightedText); } +QColor QmlPalette::lighter(const QColor& color) const +{ + return color.lighter(); +} + +QColor QmlPalette::darker(const QColor& color) const +{ + return color.darker(); +} + void QmlPalette::setColorGroup(QPalette::ColorGroup colorGroup) { Q_D(QmlPalette); diff --git a/src/declarative/util/qmlpalette.h b/src/declarative/util/qmlpalette.h index 1401ad1..7f26f9a 100644 --- a/src/declarative/util/qmlpalette.h +++ b/src/declarative/util/qmlpalette.h @@ -101,6 +101,9 @@ public: bool virtual eventFilter(QObject *watched, QEvent *event); bool virtual event(QEvent *event); + Q_INVOKABLE QColor lighter(const QColor&) const; + Q_INVOKABLE QColor darker(const QColor&) const; + Q_SIGNALS: void paletteChanged(); }; -- cgit v0.12 From effc7e9c521b230f5a7dccfa195011ec0c791bd2 Mon Sep 17 00:00:00 2001 From: Yann Bodson Date: Thu, 16 Jul 2009 11:17:29 +1000 Subject: Improve loader example Use system palette and icons. --- examples/declarative/loader/Browser.qml | 62 +++++++++++++++++------- examples/declarative/loader/images/fileopen.png | Bin 0 -> 953 bytes examples/declarative/loader/images/up.png | Bin 0 -> 662 bytes examples/declarative/loader/loader.qrc | 2 + examples/declarative/loader/main.cpp | 2 + 5 files changed, 49 insertions(+), 17 deletions(-) create mode 100644 examples/declarative/loader/images/fileopen.png create mode 100644 examples/declarative/loader/images/up.png diff --git a/examples/declarative/loader/Browser.qml b/examples/declarative/loader/Browser.qml index 280273b..aec373b 100644 --- a/examples/declarative/loader/Browser.qml +++ b/examples/declarative/loader/Browser.qml @@ -2,6 +2,7 @@ Rect { id: Root width: parent.width height: parent.height + color: activePalette.base FolderListModel { id: folders nameFilters: [ "*.qml" ] @@ -13,12 +14,26 @@ Rect { Rect { id: Wrapper width: Root.width - height: NameText.height + height: 32 + color: activePalette.base + Rect { + id: Highlight; visible: false + anchors.fill: parent + gradient: Gradient { + GradientStop { id: t1; position: 0.0; color: activePalette.highlight } + GradientStop { id: t2; position: 1.0; color: activePalette.lighter(activePalette.highlight) } + } + } + Item { + width: 32; height: 32 + Image { source: "images/fileopen.png"; anchors.centeredIn: parent; visible: folders.isFolder(index)} + } Text { id: NameText - text: fileName - font.bold: true - font.size: 12 + anchors.fill: parent; vAlign: "AlignVCenter" + text: fileName; anchors.leftMargin: 32 + font.size: 10 + color: activePalette.windowText } MouseRegion { id: Mouse @@ -35,7 +50,8 @@ Rect { State { name: "pressed" when: Mouse.pressed - SetProperties { target: Wrapper; color: "#bbbbbb" } + SetProperties { target: Highlight; visible: true } + SetProperties { target: NameText; color: activePalette.highlightedText } } ] } @@ -48,19 +64,8 @@ Rect { } } - Rect { - id: UpButton - width: 30 - height: UpText.height - color: "grey" - MouseRegion { anchors.fill: parent; onClicked: folders.folder = up(folders.folder) } - Text { id: UpText; text: "Up" } - } - - Text { anchors.left: UpButton.right; text: folders.folder } - ListView { - anchors.top: UpButton.bottom + anchors.top: TitleBar.bottom anchors.left: parent.left anchors.right: parent.right anchors.bottom: parent.bottom @@ -68,4 +73,27 @@ Rect { delegate: FolderDelegate clip: true } + + Rect { + id: TitleBar + width: parent.width + height: 32 + color: activePalette.button; pen.color: activePalette.mid + + Rect { + id: UpButton + width: 30 + height: TitleBar.height + pen.color: activePalette.mid; color: "transparent" + MouseRegion { anchors.fill: parent; onClicked: folders.folder = up(folders.folder) } + Image { anchors.centeredIn: parent; source: "images/up.png" } + } + + Text { + anchors.left: UpButton.right; anchors.right: parent.right; height: parent.height + anchors.leftMargin: 4; anchors.rightMargin: 4 + text: folders.folder; color: activePalette.buttonText + elide: "ElideLeft"; hAlign: "AlignRight"; vAlign: "AlignVCenter" + } + } } diff --git a/examples/declarative/loader/images/fileopen.png b/examples/declarative/loader/images/fileopen.png new file mode 100644 index 0000000..4aaf149 Binary files /dev/null and b/examples/declarative/loader/images/fileopen.png differ diff --git a/examples/declarative/loader/images/up.png b/examples/declarative/loader/images/up.png new file mode 100644 index 0000000..b05f802 Binary files /dev/null and b/examples/declarative/loader/images/up.png differ diff --git a/examples/declarative/loader/loader.qrc b/examples/declarative/loader/loader.qrc index 1f0925f..bdbcd5c 100644 --- a/examples/declarative/loader/loader.qrc +++ b/examples/declarative/loader/loader.qrc @@ -2,5 +2,7 @@ loader.qml Browser.qml + images/fileopen.png + images/up.png diff --git a/examples/declarative/loader/main.cpp b/examples/declarative/loader/main.cpp index 23125ce..aa86f8f 100644 --- a/examples/declarative/loader/main.cpp +++ b/examples/declarative/loader/main.cpp @@ -5,6 +5,7 @@ #include #include #include +#include "qmlpalette.h" QFxView *canvas = 0; @@ -61,6 +62,7 @@ int main(int argc, char *argv[]) canvas = new QFxView; QmlContext *ctxt = canvas->rootContext(); ctxt->setContextProperty("qmlLauncher", launcher); + ctxt->setContextProperty("activePalette", new QmlPalette); canvas->setUrl(QUrl("qrc:/loader.qml")); canvas->execute(); canvas->show(); -- cgit v0.12 From 84637da766fe1e3a4b4240601a6002f94f1b07c9 Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Thu, 16 Jul 2009 11:45:33 +1000 Subject: Fix crash on object destruction --- src/declarative/qml/qmlbasicscript.cpp | 9 ++++++--- src/declarative/qml/qmlcontext.cpp | 11 +++++++++-- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/src/declarative/qml/qmlbasicscript.cpp b/src/declarative/qml/qmlbasicscript.cpp index 478491f..d6d6625 100644 --- a/src/declarative/qml/qmlbasicscript.cpp +++ b/src/declarative/qml/qmlbasicscript.cpp @@ -181,6 +181,9 @@ static QVariant toObjectOrVariant(const QVariant &v) static QVariant fetch_value(QObject *o, int idx, int type) { + if (!o) + return QVariant(); + switch(type) { case QVariant::String: { @@ -823,7 +826,7 @@ QVariant QmlBasicScript::run(QmlContext *context, void *voidCache, CacheState *c QObject *obj = contextPrivate->defaultObjects.at(0); stack.push(fetch_value(obj, instr.constant.idx, instr.constant.type)); - if (instr.constant.notify != 0) + if (obj && instr.constant.notify != 0) enginePrivate->capturedProperties << QmlEnginePrivate::CapturedProperty(obj, instr.constant.idx, instr.constant.notify); state = Reset; @@ -835,7 +838,7 @@ QVariant QmlBasicScript::run(QmlContext *context, void *voidCache, CacheState *c QObject *obj = contextPrivate->defaultObjects.at(1); stack.push(fetch_value(obj, instr.constant.idx, instr.constant.type)); - if (instr.constant.notify != 0) + if (obj && instr.constant.notify != 0) enginePrivate->capturedProperties << QmlEnginePrivate::CapturedProperty(obj, instr.constant.idx, instr.constant.notify); state = Reset; @@ -848,7 +851,7 @@ QVariant QmlBasicScript::run(QmlContext *context, void *voidCache, CacheState *c QObject *obj = qvariant_cast(o); stack.push(fetch_value(obj, instr.constant.idx, instr.constant.type)); - if (instr.constant.notify != 0) + if (obj && instr.constant.notify != 0) enginePrivate->capturedProperties << QmlEnginePrivate::CapturedProperty(obj, instr.constant.idx, instr.constant.notify); state = Reset; diff --git a/src/declarative/qml/qmlcontext.cpp b/src/declarative/qml/qmlcontext.cpp index b605869..440f4b8 100644 --- a/src/declarative/qml/qmlcontext.cpp +++ b/src/declarative/qml/qmlcontext.cpp @@ -86,8 +86,15 @@ void QmlContextPrivate::destroyed(QObject *obj) } } - for (int ii = 0; ii < notifies.count(); ++ii) { - QMetaObject::activate(q, notifies[ii] + notifyIndex, 0); + // There is no need to emit these notifications if our parent is in the + // process of being deleted (which is *probably* why obj has been destroyed + // anyway), as we're about to get deleted which will invalidate all the + // expressions that could depend on us + QObject *parent = q->parent(); + if (!parent || !QObjectPrivate::get(parent)->wasDeleted) { + for (int ii = 0; ii < notifies.count(); ++ii) { + QMetaObject::activate(q, notifies[ii] + notifyIndex, 0); + } } } -- cgit v0.12