diff --git a/src/colorpicker.cpp b/src/colorpicker.cpp index 69773dc..ba5db17 100644 --- a/src/colorpicker.cpp +++ b/src/colorpicker.cpp @@ -1,179 +1,179 @@ /* Copyright (C) 2003-2008 Cies Breijs This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "colorpicker.h" #include "interpreter/translator.h" // for getting the translated ArgumentSeparator #include #include #include #include #include #include #include #include #include #include #include #include #include #include ColorPicker::ColorPicker(QWidget* parent) : QDialog(parent) { setWindowTitle(i18n("Color Picker")); setModal(false); QVBoxLayout *mainLayout = new QVBoxLayout; setLayout(mainLayout); QWidget* baseWidget = new QWidget(this); mainLayout->addWidget(baseWidget); QVBoxLayout* baseLayout = new QVBoxLayout; baseLayout->setMargin(0); baseWidget->setLayout( baseLayout ); QGridLayout* gridLayout = new QGridLayout; baseLayout->addLayout(gridLayout); redSlider = new QSlider(Qt::Horizontal, this); redSlider->setMaximum(255); redSpin = new QSpinBox(this); redSpin->setMaximum(255); QLabel* redLabel = new QLabel(i18n("Amount red:")); redLabel->setBuddy(redSpin); gridLayout->addWidget(redLabel, 0, 0); gridLayout->addWidget(redSlider, 0, 1); gridLayout->addWidget(redSpin, 0, 2); connect(redSlider, &QSlider::valueChanged, redSpin, &QSpinBox::setValue); connect(redSpin, static_cast(&QSpinBox::valueChanged), redSlider, &QSlider::setValue); connect(redSpin, static_cast(&QSpinBox::valueChanged), this, &ColorPicker::redChanged); greenSlider = new QSlider(Qt::Horizontal, this); greenSlider->setMaximum(255); greenSpin = new QSpinBox(this); greenSpin->setMaximum(255); QLabel* greenLabel = new QLabel(i18n("Amount green:")); greenLabel->setBuddy(greenSpin); gridLayout->addWidget(greenLabel, 1, 0); gridLayout->addWidget(greenSlider, 1, 1); gridLayout->addWidget(greenSpin, 1, 2); connect(greenSlider, &QSlider::valueChanged, greenSpin, &QSpinBox::setValue); connect(greenSpin, static_cast(&QSpinBox::valueChanged), greenSlider, &QSlider::setValue); connect(greenSpin, static_cast(&QSpinBox::valueChanged), this, &ColorPicker::greenChanged); blueSlider = new QSlider(Qt::Horizontal, this); blueSlider->setMaximum(255); blueSpin = new QSpinBox(this); blueSpin->setMaximum(255); QLabel* blueLabel = new QLabel(i18n("Amount blue:")); blueLabel->setBuddy(blueSpin); gridLayout->addWidget(blueLabel, 2, 0); gridLayout->addWidget(blueSlider, 2, 1); gridLayout->addWidget(blueSpin, 2, 2); connect(blueSlider, &QSlider::valueChanged, blueSpin, &QSpinBox::setValue); connect(blueSpin, static_cast(&QSpinBox::valueChanged), blueSlider, &QSlider::setValue); connect(blueSpin, static_cast(&QSpinBox::valueChanged), this, &ColorPicker::blueChanged); baseLayout->addSpacing(20); colorPatch = new ColorPatch(this); colorPatch->setMinimumWidth(100); colorPatch->setMinimumHeight(60); baseLayout->addWidget(colorPatch); baseLayout->addSpacing(20); QHBoxLayout* resultLayout = new QHBoxLayout; resultLayout->addStretch(); baseLayout->addLayout(resultLayout); resultBox = new QLineEdit(this); resultBox->setReadOnly(true); resultBox->setFont(QFontDatabase::systemFont(QFontDatabase::FixedFont)); - int width = QFontMetrics(QFontDatabase::systemFont(QFontDatabase::FixedFont)).boundingRect("255, 255, 255_000").width(); + int width = QFontMetrics(QFontDatabase::systemFont(QFontDatabase::FixedFont)).boundingRect(QStringLiteral("255, 255, 255_000")).width(); resultBox->setMinimumWidth(width); resultBox->setMaximumWidth(width); resultLayout->addWidget(resultBox); - QPushButton* copyButton = new QPushButton(QIcon::fromTheme("edit-copy"), i18n("&Copy to clipboard"), baseWidget); + QPushButton* copyButton = new QPushButton(QIcon::fromTheme(QStringLiteral("edit-copy")), i18n("&Copy to clipboard"), baseWidget); mainLayout->addWidget(copyButton); resultLayout->addWidget(copyButton); connect(copyButton, &QPushButton::clicked, this, &ColorPicker::copyProxy); - QPushButton* pasteButton = new QPushButton(QIcon::fromTheme("edit-paste"), i18n("&Paste to editor"), baseWidget); + QPushButton* pasteButton = new QPushButton(QIcon::fromTheme(QStringLiteral("edit-paste")), i18n("&Paste to editor"), baseWidget); mainLayout->addWidget(pasteButton); resultLayout->addWidget(pasteButton); connect(pasteButton, &QPushButton::clicked, this, &ColorPicker::pasteProxy); QDialogButtonBox *buttonBox = new QDialogButtonBox(); QWidget *mainWidget = new QWidget(this); mainLayout->addWidget(mainWidget); QPushButton *user1Button = new QPushButton; buttonBox->addButton(user1Button, QDialogButtonBox::ActionRole); connect(buttonBox, &QDialogButtonBox::accepted, this, &ColorPicker::accept); connect(buttonBox, &QDialogButtonBox::rejected, this, &ColorPicker::reject); mainLayout->addWidget(buttonBox); user1Button->setDefault(true); KGuiItem::assign(user1Button, KStandardGuiItem::close()); connect(user1Button, &QPushButton::clicked, this, &ColorPicker::hide); resultLayout->addStretch(); updateResult(0, 0, 0); } void ColorPicker::redChanged(int value) { updateResult(value, greenSlider->value(), blueSlider->value()); } void ColorPicker::greenChanged(int value) { updateResult(redSlider->value(), value, blueSlider->value()); } void ColorPicker::blueChanged(int value) { updateResult(redSlider->value(), greenSlider->value(), value); } void ColorPicker::updateResult(int r, int g, int b) { - QString separator(Translator::instance()->default2localized(QString(","))); - resultBox->setText(QString("%2%1 %3%1 %4 \n").arg(separator).arg(r).arg(g).arg(b)); + QString separator(Translator::instance()->default2localized(QStringLiteral(","))); + resultBox->setText(QStringLiteral("%2%1 %3%1 %4 \n").arg(separator).arg(r).arg(g).arg(b)); colorPatch->setColor(QColor(r, g, b)); colorPatch->repaint(); } void ColorPicker::copyProxy() { QApplication::clipboard()->setText(resultBox->text()); } void ColorPicker::pasteProxy() { emit pasteText(resultBox->text()); } diff --git a/src/console.cpp b/src/console.cpp index bee2141..4266f36 100644 --- a/src/console.cpp +++ b/src/console.cpp @@ -1,103 +1,103 @@ /* Copyright (C) 2003-2009 Cies Breijs This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "console.h" #include "editor.h" // only for the error highlight color value #include #include #include #include #include #include #include Console::Console(QWidget* parent) : QWidgetAction(parent) { baseWidget = new QWidget(parent); QHBoxLayout* baseLayout = new QHBoxLayout(); baseLayout->setMargin(0); baseWidget->setLayout(baseLayout); comboBox = new QComboBox(baseWidget); comboBox->setEditable(true); comboBox->setMinimumWidth(200); comboBox->setDuplicatesEnabled(true); comboBox->setFont(QFontDatabase::systemFont(QFontDatabase::FixedFont)); comboBox->setToolTip(i18n("Write a command here and press enter...")); comboBox->setWhatsThis(i18n("Console: quickly run single commands -- write a command here and press enter.")); QLabel* consoleLabel = new QLabel(i18n("Console:"), baseWidget); consoleLabel->setBuddy(comboBox); consoleLabel->setWhatsThis(comboBox->whatsThis()); baseLayout->addWidget(consoleLabel); baseLayout->addWidget(comboBox); setDefaultWidget(baseWidget); connect(comboBox->lineEdit(), &QLineEdit::returnPressed, this, &Console::run); connect(comboBox, &QComboBox::editTextChanged, this, &Console::clearMarkings); } void Console::disable() { comboBox->setEnabled(false); } void Console::enable() { comboBox->setEnabled(true); } void Console::clearMarkings() { comboBox->setToolTip(i18n("Write a command here and press enter...")); - comboBox->setStyleSheet(""); + comboBox->setStyleSheet(QLatin1String("")); comboBox->setFont(QFontDatabase::systemFont(QFontDatabase::FixedFont)); } void Console::run() { QString errorMessage = emit execute(comboBox->currentText()); if (errorMessage.isNull()) { comboBox->clearEditText(); return; } showError(errorMessage); } void Console::showError(const QString& msg) { comboBox->setStyleSheet("QComboBox:editable{background:" + ERROR_HIGHLIGHT_COLOR.name() + ";}"); comboBox->setFont(QFontDatabase::systemFont(QFontDatabase::FixedFont)); QString toolTipText(i18n("

ERROR: %1

", msg)); comboBox->setToolTip(toolTipText); } void Console::executeActionTriggered() { QLineEdit* lineEdit = comboBox->lineEdit(); if (!lineEdit) return; QKeyEvent event(QEvent::KeyPress, Qt::Key_Return, Qt::NoModifier, QChar('\n')); QApplication::sendEvent(lineEdit, &event); } diff --git a/src/directiondialog.cpp b/src/directiondialog.cpp index d1f66d1..0631b58 100644 --- a/src/directiondialog.cpp +++ b/src/directiondialog.cpp @@ -1,423 +1,423 @@ /* Copyright (C) 2007 Niels Slot This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "directiondialog.h" #include using std::atan; #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include //BEGIN DirectionCanvas widget DirectionCanvas::DirectionCanvas(QWidget* parent) : QWidget(parent) { setFocusPolicy(Qt::ClickFocus); setMinimumSize(230, 200); setBackgroundRole(QPalette::Base); setAutoFillBackground(true); - turtle.load(QString(":turtle.svg")); - greyTurtle.load(QString(":turtle_grey.svg")); + turtle.load(QStringLiteral(":turtle.svg")); + greyTurtle.load(QStringLiteral(":turtle_grey.svg")); deg = 0; previousDeg = 0; greyTurtleEnabled = true; } void DirectionCanvas::enableGreyTurtle(bool enable) { greyTurtleEnabled = enable; update(); } void DirectionCanvas::paintEvent(QPaintEvent *event) { Q_UNUSED(event); int side = qMin(width(), height()); QPainter painter(this); painter.setRenderHint(QPainter::Antialiasing); painter.save(); // Place us in the middle of the widget painter.translate(width() / 2, height() / 2); // Scale the widget to a square of 200 by 200 painter.scale(side / 200.0, side / 200.0); // Draw the ellipse. With a nice border of 10 painter.drawEllipse(-80, -80, 160, 160); // Draw the lines in the circle painter.save(); for (int i = 0; i < 4; i++) { painter.drawLine(0, -80, 0, 80); painter.rotate(45); } painter.restore(); - painter.drawText(-100, -98, 200, 200, Qt::AlignHCenter|Qt::AlignTop, "0"); - painter.drawText(-100, -100, 200, 200, Qt::AlignHCenter|Qt::AlignBottom, "180"); - painter.drawText(-100, -100, 203, 200, Qt::AlignRight|Qt::AlignVCenter, "90"); - painter.drawText(-109, -100, 200, 200, Qt::AlignLeft|Qt::AlignVCenter, "270"); + painter.drawText(-100, -98, 200, 200, Qt::AlignHCenter|Qt::AlignTop, QStringLiteral("0")); + painter.drawText(-100, -100, 200, 200, Qt::AlignHCenter|Qt::AlignBottom, QStringLiteral("180")); + painter.drawText(-100, -100, 203, 200, Qt::AlignRight|Qt::AlignVCenter, QStringLiteral("90")); + painter.drawText(-109, -100, 200, 200, Qt::AlignLeft|Qt::AlignVCenter, QStringLiteral("270")); painter.save(); // the gray turtle if (greyTurtleEnabled) { painter.rotate(previousDeg); painter.setPen(Qt::blue); painter.drawLine(0, -80, 0, 0); QRectF greyTurtleRect(-25, -25, 50, 50); greyTurtle.render(&painter, greyTurtleRect); painter.restore(); painter.save(); } // the more healthy looking one painter.rotate(deg); painter.setPen(Qt::red); painter.drawLine(0, -80, 0, 0); QRectF turtleRect(-25, -25, 50, 50); turtle.render(&painter, turtleRect); painter.restore(); painter.restore(); // Draw the widget's border painter.setPen(palette().dark().color()); painter.setBrush(Qt::NoBrush); painter.drawRect(QRect(0, 0, width() - 1, height() - 1)); } void DirectionCanvas::mouseMoveEvent(QMouseEvent *event) { mousePressEvent(event); } void DirectionCanvas::mousePressEvent(QMouseEvent *event) { // Only act upon left and right mouse button clicks, // then translate the X and Y coordinates so that // (0, 0) is in the middle of the widget, sent the // signals and update the widget. if (event->buttons() & Qt::LeftButton) { deg = translateMouseCoords(event->x() - (width() / 2), event->y() - (height() / 2)); update(); emit degreeChanged(deg); } else if (event->buttons() & Qt::RightButton) { previousDeg = translateMouseCoords(event->x() - (width() / 2), event->y() - (height() / 2)); emit previousDegreeChanged(previousDeg); update(); } } void DirectionCanvas::updateDirections(double previousDeg, double deg) { this->deg = deg; this->previousDeg = previousDeg; update(); } double DirectionCanvas::translateMouseCoords(double trans_x, double trans_y) { // We now have 4 squares. One four every corner. // With a cross in the middle. // For every square we calculate a different tangent // therefore we have to add of subtract a number of degrees double result = 0; if (trans_x >= 0 && trans_y >= 0) { // Right down double arc_tan = trans_y / trans_x; result = 90 + (atan(arc_tan)) * (180/M_PI); } else if (trans_x <= 0 && trans_y >= 0) { // Left down trans_x = trans_x * -1; double arc_tan = trans_y / trans_x; result = 270 - (atan(arc_tan)) * (180/M_PI); } else if (trans_x >= 0 && trans_y <= 0) { // Right up trans_y = trans_y * -1; double arc_tan = trans_y / trans_x; result = 90 - (atan(arc_tan)) * (180/M_PI); } else if (trans_x <= 0 && trans_y <= 0) { // Left up trans_x = trans_x * -1; trans_y = trans_y * -1; double arc_tan = trans_y / trans_x; result = 270 + (atan(arc_tan)) * (180/M_PI); } return result; } //END DirectionCanvas widget DirectionDialog::DirectionDialog(double deg, QWidget* parent) : QDialog(parent) { skipValueChangedEvent = false; while (deg < 0 || deg > 359) { if (deg < 0) deg = deg + 360; else if (deg > 359) deg = deg - 360; } translator = Translator::instance(); setWindowTitle(i18n("Direction Chooser")); setModal(false); QVBoxLayout *mainLayout = new QVBoxLayout(this); QWidget *mainWidget = new QWidget(this); mainLayout->addWidget(mainWidget); QWidget* baseWidget = new QWidget(this); mainLayout->addWidget(baseWidget); QVBoxLayout* baseLayout = new QVBoxLayout; baseLayout->setMargin(0); baseWidget->setLayout( baseLayout ); QHBoxLayout* degreeChooserLayout = new QHBoxLayout; baseLayout->addLayout(degreeChooserLayout); canvas = new DirectionCanvas(baseWidget); mainLayout->addWidget(canvas); connect(canvas, &DirectionCanvas::degreeChanged, this, &DirectionDialog::updateDegrees); connect(canvas, &DirectionCanvas::previousDegreeChanged, this, &DirectionDialog::updatePreviousDegrees); degreeChooserLayout->addWidget(canvas); QWidget* rightWidget = new QWidget(baseWidget); mainLayout->addWidget(rightWidget); degreeChooserLayout->addWidget(rightWidget); QVBoxLayout* rightLayout = new QVBoxLayout(rightWidget); // command picker QLabel* commandPickerLabel = new QLabel(rightWidget); commandPickerLabel->setText(i18n("Command &type:")); commandPickerLabel->setScaledContents(true); rightLayout->addWidget(commandPickerLabel); commandPicker = new QComboBox(rightWidget); - commandPicker->insertItem(Turnleft, translator->default2localized("turnleft")); - commandPicker->insertItem(Turnright, translator->default2localized("turnright")); - commandPicker->insertItem(Direction, translator->default2localized("direction")); + commandPicker->insertItem(Turnleft, translator->default2localized(QStringLiteral("turnleft"))); + commandPicker->insertItem(Turnright, translator->default2localized(QStringLiteral("turnright"))); + commandPicker->insertItem(Direction, translator->default2localized(QStringLiteral("direction"))); rightLayout->addWidget(commandPicker); commandPickerLabel->setBuddy(commandPicker); connect(commandPicker, static_cast(&QComboBox::currentIndexChanged), this, &DirectionDialog::changeCommand); rightLayout->addStretch(); // direction QLabel* previousDirectionLabel = new QLabel(rightWidget); previousDirectionLabel->setText(i18n("&Previous direction:")); previousDirectionLabel->setScaledContents(true); rightLayout->addWidget(previousDirectionLabel); previousDirectionSpin = new QSpinBox(rightWidget); // Use -360 to 720 instead of 0 to 360 // If 0 to 360 is used, then wrap-around goes from 360 to 0 (which isn't really a step at all) // Instead use larger range and then convert it into the 0 to 359 range whenever it is changed. previousDirectionSpin->setRange(-360, 720); previousDirectionSpin->setWrapping(true); previousDirectionSpin->setSingleStep(10); previousDirectionSpin->setValue(static_cast(deg)); rightLayout->addWidget(previousDirectionSpin); previousDirectionLabel->setBuddy(previousDirectionSpin); connect(previousDirectionSpin, static_cast(&QSpinBox::valueChanged), this, &DirectionDialog::directionChanged); // previous direction QLabel* directionLabel = new QLabel(rightWidget); directionLabel->setText(i18n("&New direction:")); rightLayout->addWidget(directionLabel); directionSpin = new QSpinBox(rightWidget); // Use -360 to 720 instead of 0 to 360 // If 0 to 360 is used, then wrap-around goes from 360 to 0 (which isn't really a step at all) // Instead use larger range and then convert it into the 0 to 359 range whenever it is changed. directionSpin->setRange(-360, 720); directionSpin->setWrapping(true); directionSpin->setSingleStep(10); directionSpin->setValue(static_cast(deg)); rightLayout->addWidget(directionSpin); directionLabel->setBuddy(directionSpin); connect(directionSpin, static_cast(&QSpinBox::valueChanged), this, &DirectionDialog::directionChanged); baseLayout->addSpacing(20); // commandBox and copy/paste buttons QHBoxLayout *pasteRowLayout = new QHBoxLayout; baseLayout->addLayout(pasteRowLayout); pasteRowLayout->addStretch(); commandBox = new QLineEdit(rightWidget); commandBox->setReadOnly(true); commandBox->setFont(QFontDatabase::systemFont(QFontDatabase::FixedFont)); - commandBox->setMinimumWidth(commandBox->fontMetrics().boundingRect("000000000_360").width()); + commandBox->setMinimumWidth(commandBox->fontMetrics().boundingRect(QStringLiteral("000000000_360")).width()); pasteRowLayout->addWidget(commandBox); - QPushButton* copyButton = new QPushButton(QIcon::fromTheme("edit-copy"), i18n("&Copy to clipboard"), baseWidget); + QPushButton* copyButton = new QPushButton(QIcon::fromTheme(QStringLiteral("edit-copy")), i18n("&Copy to clipboard"), baseWidget); mainLayout->addWidget(copyButton); pasteRowLayout->addWidget(copyButton); connect(copyButton, &QPushButton::clicked, this, &DirectionDialog::copyProxy); - QPushButton* pasteButton = new QPushButton(QIcon::fromTheme("edit-paste"), i18n("&Paste to editor"), baseWidget); + QPushButton* pasteButton = new QPushButton(QIcon::fromTheme(QStringLiteral("edit-paste")), i18n("&Paste to editor"), baseWidget); mainLayout->addWidget(pasteButton); pasteRowLayout->addWidget(pasteButton); connect(pasteButton, &QPushButton::clicked, this, &DirectionDialog::pasteProxy); pasteRowLayout->addStretch(); baseLayout->addSpacing(10); QDialogButtonBox *buttonBox = new QDialogButtonBox(); QPushButton *user1Button = new QPushButton; buttonBox->addButton(user1Button, QDialogButtonBox::ActionRole); connect(buttonBox, &QDialogButtonBox::accepted, this, &DirectionDialog::accept); connect(buttonBox, &QDialogButtonBox::rejected, this, &DirectionDialog::reject); mainLayout->addWidget(buttonBox); user1Button->setDefault(true); KGuiItem::assign(user1Button, KStandardGuiItem::close()); connect(user1Button, &QPushButton::clicked, this, &DirectionDialog::close); changeCommand(0); show(); } void DirectionDialog::directionChanged(int value) { Q_UNUSED(value); // if value is outside of the 0 to 359 range, then move it into that range if (previousDirectionSpin->value() < 0) { previousDirectionSpin->setValue(previousDirectionSpin->value() + 360); } else if (previousDirectionSpin->value() >= 360) { previousDirectionSpin->setValue(previousDirectionSpin->value() - 360); } // if value is outside of the 0 to 359 range, then move it into that range if (directionSpin->value() < 0) { directionSpin->setValue(directionSpin->value() + 360); } else if (directionSpin->value() >= 360) { directionSpin->setValue(directionSpin->value() - 360); } // Don't update the canvas when we just updated the direction spinbox. // (only update when the users changes the spinbox) if (skipValueChangedEvent) { skipValueChangedEvent = false; return; } updateCanvas(); updateCommandBox(); } void DirectionDialog::updateCanvas() { // Get the things we need, then update the canvas. int previousDir = previousDirectionSpin->value(); int dir = directionSpin->value(); canvas->updateDirections(previousDir, dir); } void DirectionDialog::changeCommand(int command) { currentCommand = command; if (currentCommand == Direction) { previousDirectionSpin->setEnabled(false); canvas->enableGreyTurtle(false); } else { previousDirectionSpin->setEnabled(true); canvas->enableGreyTurtle(true); } updateCanvas(); updateCommandBox(); } void DirectionDialog::updateDegrees(double deg) { // The canvas has changed, update the spinbox and command-LineEdit skipValueChangedEvent = true; directionSpin->setValue(static_cast(round(deg))); updateCommandBox(); } void DirectionDialog::updatePreviousDegrees(double deg) { // The canvas has changed, update the spinbox and commandBox skipValueChangedEvent = true; previousDirectionSpin->setValue(static_cast(round(deg))); updateCommandBox(); } void DirectionDialog::updateCommandBox() { // Generate a new value for the commandBox. QString output; int degree = 0; switch (currentCommand) { case Turnleft: - output.append(translator->default2localized("turnleft")); + output.append(translator->default2localized(QStringLiteral("turnleft"))); degree = 360 - (directionSpin->value() - previousDirectionSpin->value()); break; case Turnright: - output.append(translator->default2localized("turnright")); + output.append(translator->default2localized(QStringLiteral("turnright"))); degree = directionSpin->value() - previousDirectionSpin->value(); break; case Direction: - output.append(translator->default2localized("direction")); + output.append(translator->default2localized(QStringLiteral("direction"))); degree = directionSpin->value(); break; } if (degree < 0) { degree += 360; } else if (degree >= 360) { degree -= 360; } - output.append(QString(" %1\n").arg(degree)); + output.append(QStringLiteral(" %1\n").arg(degree)); commandBox->setText(output); } void DirectionDialog::copyProxy() { QApplication::clipboard()->setText(commandBox->text()); } void DirectionDialog::pasteProxy() { emit pasteText(commandBox->text()); } diff --git a/src/editor.cpp b/src/editor.cpp index 0af59b9..e4f0622 100644 --- a/src/editor.cpp +++ b/src/editor.cpp @@ -1,473 +1,473 @@ /* Copyright (C) 2003-2008 Cies Breijs This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "editor.h" #include "interpreter/token.h" #include "interpreter/tokenizer.h" #include #include #include #include #include #include #include #include #include #include #include #include static const int CURSOR_WIDTH = 2; // in pixels static const int TAB_WIDTH = 2; // in character widths Editor::Editor(QWidget *parent) : QFrame(parent) { setFrameStyle(QFrame::StyledPanel | QFrame::Sunken); setLineWidth(CURSOR_WIDTH); setCurrentUrl(); currentRow = 1; currentCol = 1; // setup the main view editor = new TextEdit(this); editor->document()->setDefaultFont(QFontDatabase::systemFont(QFontDatabase::FixedFont)); editor->setFrameStyle(QFrame::NoFrame); editor->installEventFilter(this); editor->setLineWrapMode(QTextEdit::WidgetWidth); - editor->setTabStopWidth(editor->fontMetrics().boundingRect("0").width() * TAB_WIDTH); + editor->setTabStopWidth(editor->fontMetrics().boundingRect(QStringLiteral("0")).width() * TAB_WIDTH); editor->setAcceptRichText(false); setFocusProxy(editor); connect(editor->document(), &QTextDocument::contentsChange, this, &Editor::textChanged); connect(editor->document(), &QTextDocument::modificationChanged, this, &Editor::setModified); connect(editor, &TextEdit::cursorPositionChanged, this, &Editor::updateOnCursorPositionChange); // setup the line number pane numbers = new LineNumbers(this, editor); numbers->setFont(editor->document()->defaultFont()); numbers->setWidth(1); connect(editor->document()->documentLayout(), SIGNAL(update(QRectF)), numbers, SLOT(update())); connect(editor->verticalScrollBar(), SIGNAL(valueChanged(int)), numbers, SLOT(update())); // let the line numbers and the editor coexist box = new QHBoxLayout(this); box->setSpacing(0); box->setMargin(0); box->addWidget(numbers); box->addWidget(editor); // calculate the bg color for the highlighted line QColor bgColor = this->palette().brush(this->backgroundRole()).color(); highlightedLineBackgroundColor.setHsv( LINE_HIGHLIGHT_COLOR.hue(), bgColor.saturation() + EXTRA_SATURATION, bgColor.value()); // our syntax highlighter (this does not do any markings) highlighter = new Highlighter(editor->document()); // create a find dialog fdialog = new KFindDialog(); fdialog->setSupportsRegularExpressionFind(false); fdialog->setHasSelection(false); fdialog->setHasCursor(false); // sets some more default values newFile(); tokenizer = new Tokenizer(); } Editor::~Editor() { delete highlighter; delete tokenizer; } void Editor::enable() { editor->viewport()->setEnabled(true); editor->setReadOnly(false); } void Editor::disable() { editor->viewport()->setEnabled(false); editor->setReadOnly(true); } void Editor::setContent(const QString& s) { editor->document()->setPlainText(s); editor->document()->setModified(false); } void Editor::openExample(const QString& example, const QString& exampleName) { if (newFile()) { setContent(example); editor->document()->setModified(false); setCurrentUrl(QUrl::fromLocalFile(exampleName)); } } void Editor::textChanged(int pos, int removed, int added) { Q_UNUSED(pos); if (removed == 0 && added == 0) return; // save some cpu cycles removeMarkings(); // removes the character markings if there are any int lineCount = 1; for (QTextBlock block = editor->document()->begin(); block.isValid(); block = block.next()) lineCount++; numbers->setWidth(qMax(1, 1 + static_cast(std::floor(std::log10(static_cast(lineCount) - 1))))); emit contentChanged(); } bool Editor::newFile() { if (maybeSave()) { editor->document()->clear(); setCurrentUrl(); return true; } return false; } bool Editor::openFile(const QUrl &_url) { QUrl url = _url; if (maybeSave()) { if (url.isEmpty()) { url = QFileDialog::getOpenFileUrl(this, i18n("Open"), QUrl(), - QString("%1 (*.turtle);;%2 (*)").arg(i18n("Turtle code files")).arg(i18n("All files")) + QStringLiteral("%1 (*.turtle);;%2 (*)").arg(i18n("Turtle code files")).arg(i18n("All files")) ); } if (!url.isEmpty()) { KIO::StoredTransferJob *job = KIO::storedGet(url); if (job->exec()) { QByteArray data = job->data(); QBuffer buffer(&data); if (!buffer.open(QIODevice::ReadOnly | QIODevice::Text)) { return false; // can't happen } QTextStream in(&buffer); // check for our magic identifier QString s; s = in.readLine(); if (s != KTURTLE_MAGIC_1_0) { KMessageBox::error(this, i18n("The file you try to open is not a valid KTurtle script, or is incompatible with this version of KTurtle.\nCannot open %1", url.toDisplayString(QUrl::PreferLocalFile))); return false; } QString localizedScript = Translator::instance()->localizeScript(in.readAll()); setContent(localizedScript); setCurrentUrl(url); editor->document()->setModified(false); emit fileOpened(url); return true; } else { KMessageBox::error(this, job->errorString()); return false; } } } // statusbar "Nothing opened" return false; } bool Editor::saveFile(const QUrl &targetUrl) { QUrl url(targetUrl); bool result = false; if (url.isEmpty() && currentUrl().isEmpty()) { result = saveFileAs(); } else { if (url.isEmpty()) url = currentUrl(); QTemporaryFile tmp; // only used for network export tmp.setAutoRemove(false); tmp.open(); QString filename = url.isLocalFile() ? url.toLocalFile() : tmp.fileName(); QSaveFile *savefile = new QSaveFile(filename); if (savefile->open(QIODevice::WriteOnly)) { QTextStream outputStream(savefile); // store commands in their generic @(...) notation format, to be translatable when reopened // this allows sharing of scripts written in different languages Tokenizer tokenizer; tokenizer.initialize(editor->document()->toPlainText()); const QStringList localizedLooks(Translator::instance()->allLocalizedLooks()); QString unstranslated; Token* t; bool pendingEOL = false; // to avoid writing a final EOL token while ((t = tokenizer.getToken())->type() != Token::EndOfInput) { if (pendingEOL) { unstranslated.append('\n'); pendingEOL = false; } if (localizedLooks.contains(t->look())) { QString defaultLook(Translator::instance()->defaultLook(t->look())); - unstranslated.append(QString("@(%1)").arg(defaultLook)); + unstranslated.append(QStringLiteral("@(%1)").arg(defaultLook)); } else { if (t->type() == Token::EndOfLine) pendingEOL = true; else unstranslated.append(t->look()); } } outputStream << KTURTLE_MAGIC_1_0 << '\n'; outputStream << unstranslated; outputStream.flush(); if (savefile->commit()) { result = true; if (!url.isLocalFile()) { KIO::StoredTransferJob *job = KIO::storedPut(savefile, url, -1, nullptr); if (!job->exec()) { result = false; KMessageBox::error(this, i18n("Could not save file.")); } } } else { // Error. result = false; KMessageBox::error(this, i18n("Could not save file.")); } if (result) { setCurrentUrl(url); editor->document()->setModified(false); // MainWindow will add us to the recent file list emit fileSaved(url); } } delete savefile; } return result; } bool Editor::saveFileAs() { QUrl url = QFileDialog::getSaveFileUrl(this, i18n("Save As"), QUrl(), - QString("%1 (*.turtle);;%2 (*)").arg(i18n("Turtle code files")).arg(i18n("All files")) + QStringLiteral("%1 (*.turtle);;%2 (*)").arg(i18n("Turtle code files")).arg(i18n("All files")) ); if (url.isEmpty()) return false; bool result = saveFile(url); return result; } bool Editor::maybeSave() { if (!editor->document()->isModified()) return true; int result = KMessageBox::warningContinueCancel(this, i18n("The program you are currently working on is not saved. " "By continuing you may lose the changes you have made."), i18n("Unsaved File"), KGuiItem(i18n("&Discard Changes")), KStandardGuiItem::cancel(), i18n("&Discard Changes")); if (result == KMessageBox::Continue) return true; return false; } void Editor::setModified(bool b) { editor->document()->setModified(b); emit modificationChanged(); } // TODO: improve find to be able to search within a selection void Editor::find() { // find selection, etc if (editor->textCursor().hasSelection()) { QString selectedText = editor->textCursor().selectedText(); // If the selection is too big, then we don't want to automatically // populate the search text box with the selection text if (selectedText.length() < 30) { fdialog->setPattern(selectedText); } } if (fdialog->exec() == QDialog::Accepted && !fdialog->pattern().isEmpty()) { long kOpts = fdialog->options(); QTextDocument::FindFlags qOpts = nullptr; if (kOpts & KFind::CaseSensitive) { qOpts |= QTextDocument::FindCaseSensitively; } if (kOpts & KFind::FindBackwards) { qOpts |= QTextDocument::FindBackward; } if (kOpts & KFind::WholeWordsOnly) { qOpts |= QTextDocument::FindWholeWords; } editor->find(fdialog->pattern(), qOpts); } } void Editor::findNext() { if (!fdialog->pattern().isEmpty()) { long kOpts = fdialog->options(); QTextDocument::FindFlags qOpts = nullptr; if (kOpts & KFind::CaseSensitive) { qOpts |= QTextDocument::FindCaseSensitively; } if (kOpts & KFind::FindBackwards) { qOpts |= QTextDocument::FindBackward; } if (kOpts & KFind::WholeWordsOnly) { qOpts |= QTextDocument::FindWholeWords; } editor->find(fdialog->pattern(), qOpts); } } void Editor::findPrev() { if(!fdialog->pattern().isEmpty()) { long kOpts = fdialog->options(); QTextDocument::FindFlags qOpts = nullptr; if (kOpts & KFind::CaseSensitive) { qOpts |= QTextDocument::FindCaseSensitively; } // search in the opposite direction as findNext() if (!(kOpts & KFind::FindBackwards)) { qOpts |= QTextDocument::FindBackward; } if (kOpts & KFind::WholeWordsOnly) { qOpts |= QTextDocument::FindWholeWords; } editor->find(fdialog->pattern(), qOpts); } } void Editor::setCurrentUrl(const QUrl &url) { m_currentUrl = url; emit contentNameChanged(m_currentUrl.fileName()); } void Editor::setOverwriteMode(bool b) { editor->setOverwriteMode(b); - editor->setCursorWidth(b ? editor->fontMetrics().boundingRect("0").width() : 2); + editor->setCursorWidth(b ? editor->fontMetrics().boundingRect(QStringLiteral("0")).width() : 2); } void Editor::updateOnCursorPositionChange() { // convert the absolute pos into a row/col pair, and set current line aswell QString s = editor->toPlainText(); int pos = editor->textCursor().position(); int row = 1; int last_break = -1; int next_break = 0; for (int i = 0; i < s.length(); i++) { if (s.at(i) == '\n' && i < pos) { last_break = i; row++; } else if (s.at(i) == '\n' && i >= pos) { next_break = i; break; } } if (next_break == 0) next_break = s.length(); if (currentRow != row) { currentRow = row; highlightCurrentLine(); editor->highlightCurrentLine(); } currentCol = pos - last_break; currentLine = s.mid(last_break+1, next_break-last_break-1); emit cursorPositionChanged(); } Token* Editor::currentToken() { tokenizer->initialize(currentLine); Token* token = tokenizer->getToken(); while (token->type() != Token::EndOfInput) { if (currentCol >= token->startCol() && currentCol <= token->endCol()) return token; delete token; token = tokenizer->getToken(); } delete token; return nullptr; } void Editor::insertPlainText(const QString& txt) { editor->textCursor().insertText(txt); } void Editor::paintEvent(QPaintEvent *event) { QRect rect = editor->currentLineRect(); rect.setWidth(this->width() - EDITOR_MARGIN); // don't draw too much rect.translate(0, EDITOR_MARGIN); // small hack to nicely align the line highlighting //QColor bgColor = this->palette().brush(this->backgroundRole()).color(); QPainter painter(this); const QBrush brush(highlightedLineBackgroundColor); painter.fillRect(rect, brush); painter.end(); QFrame::paintEvent(event); } QString Editor::toHtml(const QString& title, const QString& lang) { Tokenizer* tokenizer = new Tokenizer(); tokenizer->initialize(editor->document()->toPlainText()); QString html = QString(); QTextCharFormat* format; Token* token = tokenizer->getToken(); while (token->type() != Token::EndOfInput) { QString escaped; switch (token->type()) { - case Token::EndOfLine: escaped = "
"; break; - case Token::WhiteSpace: escaped = ""; for (int n = 0; n < token->look().length(); n++) { escaped += " "; } break; + case Token::EndOfLine: escaped = QStringLiteral("
"); break; + case Token::WhiteSpace: escaped = QLatin1String(""); for (int n = 0; n < token->look().length(); n++) { escaped += QLatin1String(" "); } break; default: escaped = token->look().toHtmlEscaped(); break; } format = highlighter->tokenToFormat(token); if (format) { bool bold = format->fontWeight() > 50; - html += QString("%3") + html += QStringLiteral("%3") .arg(format->foreground().color().name()) .arg(bold ? " font-weight: bold;" : "") .arg(escaped); } else { html += escaped; } token = tokenizer->getToken(); } delete tokenizer; return QString("" "" "%2" "%3").arg(lang).arg(title).arg(html); } // bool Editor::eventFilter(QObject *obj, QEvent *event) // { // if (obj != editor) return QFrame::eventFilter(obj, event); // // if (event->type() == QEvent::ToolTip) { // QHelpEvent *helpEvent = static_cast(event); // // QTextCursor cursor = editor->cursorForPosition(helpEvent->pos()); // cursor.movePosition(QTextCursor::StartOfWord, QTextCursor::MoveAnchor); // cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor); // // QString word = cursor.selectedText(); // emit mouseHover(word); // emit mouseHover(helpEvent->pos(), word); // // // QToolTip::showText(helpEvent->globalPos(), word); // For testing // } // // return false; // } diff --git a/src/editor.h b/src/editor.h index 98b139d..240c851 100644 --- a/src/editor.h +++ b/src/editor.h @@ -1,296 +1,296 @@ /* Copyright (C) 2003-2008 Cies Breijs This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _EDITOR_H_ #define _EDITOR_H_ #include #include #include #include #include #include #include #include "highlighter.h" #include "interpreter/token.h" #include "interpreter/tokenizer.h" #include "interpreter/treenode.h" class QHBoxLayout; static const QColor LINE_HIGHLIGHT_COLOR(239, 247, 255); static const QColor WORD_HIGHLIGHT_COLOR(255, 255, 156); static const QColor ERROR_HIGHLIGHT_COLOR(255, 200, 200); static const int EXTRA_SATURATION = 30; // used for drawing the highlighted background static const int EDITOR_MARGIN = 2; // some margin that can't be set to zero, yet painters should know it static const int CURSOR_RECT_MARGIN = 5; // another margin that cannot be traced static const int LINENUMBER_SPACING = 2; // sets the margin for the line numbers -const QString KTURTLE_MAGIC_1_0 = "kturtle-script-v1.0"; +const QString KTURTLE_MAGIC_1_0 = QStringLiteral("kturtle-script-v1.0"); //BEGIN LineNumbers class class LineNumbers : public QWidget { Q_OBJECT public: LineNumbers(QWidget *parent, QTextEdit *te) : QWidget(parent), editor(te), maxWidth(0) {} ~LineNumbers() Q_DECL_OVERRIDE {} void setFont(const QFont& f) { QWidget::setFont(f); } void setWidth(int w) { if (w == maxWidth) return; // save some cpu cycles maxWidth = w; - QString s(""); - for (; w > 0; w--) s += "0"; + QString s; + for (; w > 0; w--) s += QStringLiteral("0"); setFixedWidth(fontMetrics().boundingRect(s).width() + 2*LINENUMBER_SPACING); } void paintEvent(QPaintEvent*) Q_DECL_OVERRIDE { QAbstractTextDocumentLayout* layout = editor->document()->documentLayout(); int contentsY = editor->verticalScrollBar()->value(); qreal pageBottom = contentsY + editor->viewport()->height(); const QFontMetrics fm = fontMetrics(); const int ascent = fontMetrics().ascent() + 1; // height = ascent + descent + 1 int lineCount = 1; QPainter painter(this); for (QTextBlock block = editor->document()->begin(); block.isValid(); block = block.next(), ++lineCount) { const QRectF boundingRect = layout->blockBoundingRect(block); QPointF position = boundingRect.topLeft(); if (position.y() + boundingRect.height() < contentsY) continue; if (position.y() > pageBottom) break; const QString txt = QString::number(lineCount); painter.drawText(width() - fm.boundingRect(txt).width() - LINENUMBER_SPACING, qRound(position.y()) - contentsY + ascent, txt); } painter.end(); } private: QTextEdit *editor; int maxWidth; }; //END class LineNumbers //BEGIN QTextEdit sub-class class TextEdit : public QTextEdit { Q_OBJECT public: explicit TextEdit(QWidget* parent = nullptr) : QTextEdit(parent) {} void markCurrentWord(int startRow, int startCol, int endRow, int endCol) { currentWord.setCoords(startRow, startCol, endRow, endCol); viewport()->update(); } void removeCurrentWordMark() { currentWord = QRect(); viewport()->update(); } void markCurrentError(int startRow, int startCol, int endRow, int endCol) { currentError.setCoords(startRow, startCol, endRow, endCol); viewport()->update(); } void removeCurrentErrorMark() { currentError = QRect(); viewport()->update(); } void highlightCurrentLine() { viewport()->update(); } QRect currentLineRect() { // this method is also used for highlighting the background of the numbers QTextCursor cursor = textCursor(); cursor.movePosition(QTextCursor::StartOfBlock); QRect rect = cursorRect(cursor); cursor.movePosition(QTextCursor::EndOfBlock); rect |= cursorRect(cursor); // get the bounding rectangle of both rects rect.setX(0); rect.setWidth(viewport()->width()); return rect; } protected: void paintEvent(QPaintEvent *event) Q_DECL_OVERRIDE { QPainter painter(viewport()); painter.fillRect(currentLineRect(), QBrush(LINE_HIGHLIGHT_COLOR)); if (!currentWord.isNull()) foreach (const QRect &rect, coordsToRects(currentWord)) painter.fillRect(rect, QBrush(WORD_HIGHLIGHT_COLOR)); if (!currentError.isNull()) foreach (const QRect &rect, coordsToRects(currentError)) painter.fillRect(rect, QBrush(ERROR_HIGHLIGHT_COLOR)); painter.end(); QTextEdit::paintEvent(event); } private: QVector coordsToRects(QRect coords) { // this methods calculate the viewport rectangles that cover a (multi-line) word or error // after switching the tokenizer to use the QTextDocument we might optimize this methods int startRow, startCol, endRow, endCol; coords.getCoords(&startRow, &startCol, &endRow, &endCol); QTextCursor cursor(document()); cursor.movePosition(QTextCursor::Start); QTextCursor endCursor(cursor); cursor.movePosition(QTextCursor::NextBlock, QTextCursor::MoveAnchor, startRow - 1); cursor.movePosition(QTextCursor::NextCharacter, QTextCursor::MoveAnchor, startCol - 1); endCursor.movePosition(QTextCursor::NextBlock, QTextCursor::MoveAnchor, endRow - 1); endCursor.movePosition(QTextCursor::NextCharacter, QTextCursor::MoveAnchor, endCol - 1); QRect rect = cursorRect(cursor).adjusted(CURSOR_RECT_MARGIN, 0, 0, 0); cursor.movePosition(QTextCursor::EndOfLine); QVector rects; while (cursor < endCursor) { cursor.movePosition(QTextCursor::PreviousCharacter); - rects << (rect | cursorRect(cursor).adjusted(0, 0, fontMetrics().boundingRect("0").width() - CURSOR_RECT_MARGIN, 0)); + rects << (rect | cursorRect(cursor).adjusted(0, 0, fontMetrics().boundingRect(QStringLiteral("0")).width() - CURSOR_RECT_MARGIN, 0)); cursor.movePosition(QTextCursor::Down); cursor.movePosition(QTextCursor::StartOfLine); rect = cursorRect(cursor).adjusted(CURSOR_RECT_MARGIN, 0, 0, 0); cursor.movePosition(QTextCursor::EndOfLine); } rects << (rect | cursorRect(endCursor).adjusted(0, 0, -CURSOR_RECT_MARGIN, 0)); return rects; } // stores the start/end row/col of currentWord and currentError in the coods of 2 rectangles QRect currentWord, currentError; }; //END QTextEdit sub-class class Editor : public QFrame { Q_OBJECT public: explicit Editor(QWidget *parent = nullptr); ~Editor(); QTextEdit* view() const { return editor; } QTextDocument* document() const { return editor->document(); } void enable(); void disable(); const QUrl ¤tUrl() { return m_currentUrl; } void setCurrentUrl(const QUrl &url = QUrl()); bool maybeSave(); bool isModified() { return editor->document()->isModified(); } QString content() { return editor->document()->toPlainText(); } QString toHtml(const QString& title, const QString& lang); int row() { return currentRow; } int col() { return currentCol; } Token* currentToken(); void removeMarkings() { editor->removeCurrentWordMark(); editor->removeCurrentErrorMark(); } public slots: bool newFile(); bool openFile(const QUrl &url = QUrl()); void openExample(const QString& example, const QString& exampleName); bool saveFile(const QUrl &url = QUrl()); bool saveFileAs(); void toggleLineNumbers(bool b) { numbers->setVisible(b); } void setModified(bool); void setOverwriteMode(bool b); void markCurrentWord(TreeNode* node) { editor->markCurrentWord( node->token()->startRow(), node->token()->startCol(), node->token()->endRow(), node->token()->endCol()); } void markCurrentError(int startRow, int startCol, int endRow, int endCol) { editor->markCurrentError(startRow, startCol, endRow, endCol); } void find(); void findNext(); void findPrev(); void insertPlainText(const QString& txt); void rehighlight() { highlighter->rehighlight(); } signals: void contentNameChanged(const QString&); void fileOpened(const QUrl&); void fileSaved(const QUrl&); void modificationChanged(); void contentChanged(); void cursorPositionChanged(); protected slots: void textChanged(int pos, int added, int removed); // void cursorPositionChanged(); protected: void paintEvent(QPaintEvent *event) Q_DECL_OVERRIDE; private slots: void updateOnCursorPositionChange(); void highlightCurrentLine() { this->update(); } private: void setContent(const QString&); TextEdit *editor; // TODO why pointers? Highlighter *highlighter; // TODO could this class become a singleton? (shared with the inspector, errdlg) Tokenizer *tokenizer; // TODO could this class become a singleton? (shared with the highlighter, interpreter) LineNumbers *numbers; QHBoxLayout *box; // TODO is this relly needed? KFindDialog *fdialog; QUrl m_currentUrl; // contains url to the currently load file or the exampleName QColor highlightedLineBackgroundColor; // the bg color of the current line's line number space QString currentLine; int currentRow; int currentCol; }; #endif // _EDITOR_H_ diff --git a/src/errordialog.cpp b/src/errordialog.cpp index 736eaec..fe30c9b 100644 --- a/src/errordialog.cpp +++ b/src/errordialog.cpp @@ -1,163 +1,163 @@ /* Copyright (C) 2003-2008 Cies Breijs This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "errordialog.h" #include #include #include #include #include #include #include #include #include #include ErrorDialog::ErrorDialog(QWidget* parent) : QDialog(parent) { errorList = nullptr; setWindowTitle(i18n("Errors")); setModal(false); QVBoxLayout *mainLayout = new QVBoxLayout; setLayout(mainLayout); QWidget *mainWidget = new QWidget(this); mainLayout->addWidget(mainWidget); QWidget *baseWidget = new QWidget(this); mainLayout->addWidget(baseWidget); baseLayout = new QVBoxLayout(baseWidget); mainLayout->addWidget(baseWidget); label = new QLabel(baseWidget); mainLayout->addWidget(label); label->setText(i18n("In this list you find the error(s) that resulted from running your code.\nGood luck!")); // \nYou can select an error and click the 'Help on Error' button for help. label->setScaledContents(true); baseLayout->addWidget(label); spacer = new QSpacerItem(10, 10, QSizePolicy::Minimum, QSizePolicy::Fixed); baseLayout->addItem(spacer); errorTable = new QTableWidget(baseWidget); mainLayout->addWidget(errorTable); errorTable->setSelectionMode(QAbstractItemView::SingleSelection); errorTable->setSelectionBehavior(QAbstractItemView::SelectRows); errorTable->horizontalHeader()->setDefaultAlignment(Qt::AlignLeft); errorTable->setShowGrid(false); errorTable->setColumnCount(3); QStringList horizontalHeaderTexts; horizontalHeaderTexts << i18n("line") << i18n("description") << i18n("code"); errorTable->setHorizontalHeaderLabels(horizontalHeaderTexts); errorTable->setEditTriggers(QAbstractItemView::NoEditTriggers); baseLayout->addWidget(errorTable); m_buttonBox = new QDialogButtonBox(QDialogButtonBox::Help); QPushButton *user1Button = new QPushButton; m_buttonBox->addButton(user1Button, QDialogButtonBox::ActionRole); connect(m_buttonBox, &QDialogButtonBox::accepted, this, &ErrorDialog::accept); connect(m_buttonBox, &QDialogButtonBox::rejected, this, &ErrorDialog::reject); connect(m_buttonBox, &QDialogButtonBox::helpRequested, this, &ErrorDialog::helpRequested); mainLayout->addWidget(m_buttonBox); KGuiItem::assign(user1Button, KGuiItem(i18n("Hide Errors"))); // setButtonGuiItem(User1, i18n("Help on &Error")); // TODO context help in the error dialog user1Button->setDefault(true); clear(); } void ErrorDialog::clear() { disable(); errorList = nullptr; errorTable->clearContents(); // put a friendly 'nothing to see here' notice in the empty table errorTable->setRowCount(1); QTableWidgetItem* emptyItem = new QTableWidgetItem(i18n("No errors occurred yet.")); QFont emptyFont(QFontDatabase::systemFont(QFontDatabase::GeneralFont)); emptyFont.setItalic(true); emptyItem->setFont(emptyFont); errorTable->setItem(0, 1, emptyItem); errorTable->resizeColumnsToContents(); // errorTable->setColumnWidth(0, errorTable->fontMetrics().width("88888")); // errorTable->setColumnWidth(2, errorTable->fontMetrics().width("88888")); // errorTable->setColumnWidth(1, errorTable->width() - errorTable->verticalHeader()->width() - errorTable->columnWidth(0) - errorTable->columnWidth(2)); } void ErrorDialog::enable() { Q_ASSERT (errorList); errorTable->setEnabled(true); m_buttonBox->button(QDialogButtonBox::Help)->setEnabled(true); connect(errorTable, &QTableWidget::itemSelectionChanged, this, &ErrorDialog::selectedErrorChangedProxy); errorTable->selectRow(0); } void ErrorDialog::disable() { disconnect(errorTable, &QTableWidget::itemSelectionChanged, this, &ErrorDialog::selectedErrorChangedProxy); errorTable->setEnabled(false); m_buttonBox->button(QDialogButtonBox::Help)->setEnabled(false); errorTable->clearSelection(); } void ErrorDialog::setErrorList(ErrorList *list) { errorList = list; errorTable->setRowCount(errorList->size()); int row = 0; foreach (const ErrorMessage &error, *errorList) { int col = 0; QStringList itemTexts; itemTexts << QString::number(error.token().startRow()) << error.text() << QString::number(error.code()); foreach (const QString &itemText, itemTexts) { errorTable->setItem(row, col, new QTableWidgetItem(itemText)); col++; } row++; } errorTable->clearSelection(); errorTable->resizeColumnsToContents(); enable(); } void ErrorDialog::selectedErrorChangedProxy() { Q_ASSERT (errorList); const Token* t = &errorList->at(errorTable->selectedItems().first()->row()).token(); emit currentlySelectedError(t->startRow(), t->startCol(), t->endRow(), t->endCol()); // //qDebug() << "EMITTED: " << t->startRow() << ", " << t->startCol() << ", " << t->endRow() << ", " << t->endCol(); } void ErrorDialog::helpRequested() { - KHelpClient::invokeHelp("reference", "kturtle"); + KHelpClient::invokeHelp(QStringLiteral("reference"), QStringLiteral("kturtle")); } diff --git a/src/inspector.cpp b/src/inspector.cpp index 5b58aa4..83babd1 100644 --- a/src/inspector.cpp +++ b/src/inspector.cpp @@ -1,319 +1,319 @@ /* Copyright (C) 2003-2008 Cies Breijs This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "inspector.h" #include "interpreter/translator.h" // for getting the translated ArgumentSeparator #include #include #include #include #include #include #include #include Inspector::Inspector(QWidget *parent) : QFrame(parent) { mainLayout = new QHBoxLayout(this); mainLayout->setSpacing(0); mainLayout->setMargin(0); tabWidget = new QTabWidget(this); variableTab = new QWidget(); variableLayout = new QHBoxLayout(variableTab); variableTable = new QTableWidget(variableTab); variableTable->setAlternatingRowColors(true); variableLayout->addWidget(variableTable); tabWidget->addTab(variableTab, i18n("Variables")); functionTab = new QWidget(); functionLayout = new QHBoxLayout(functionTab); functionTable = new QTableWidget(functionTab); functionTable->setAlternatingRowColors(true); functionLayout->addWidget(functionTable); tabWidget->addTab(functionTab, i18n("Functions")); treeTab = new QWidget(); treeLayout = new QHBoxLayout(treeTab); treeView = new QTreeWidget(treeTab); treeView->header()->setVisible(false); treeLayout->addWidget(treeView); tabWidget->addTab(treeTab, i18n("Tree")); mainLayout->addWidget(tabWidget); // our syntax highlighter (this does not do any markings) highlighter = new Highlighter(); // // the maps used when marking table/tree items later // variableMap = new QHash(); // functionMap = new QHash(); // treeMap = new QHash(); currentlyMarkedTreeItem = nullptr; disable(); clear(); } Inspector::~Inspector() { delete highlighter; } void Inspector::disable() { variableTable->setEnabled(false); functionTable->setEnabled(false); treeView->setEnabled(false); // enabling happened when the inspector gets filled with data } void Inspector::clear() { clearAllMarks(); // Question: is the code duplication below enough // for a subclass-of-QTableWidget based approach? variableMap.clear(); variableTableEmpty = true; variableTable->clear(); QStringList headers; headers << i18n("name") << i18n("value") << i18n("type"); variableTable->setColumnCount(3); variableTable->setHorizontalHeaderLabels(headers); variableTable->setSelectionMode(QAbstractItemView::SingleSelection); variableTable->setSelectionBehavior(QAbstractItemView::SelectRows); variableTable->horizontalHeader()->setDefaultAlignment(Qt::AlignLeft); variableTable->verticalHeader()->setVisible(false); variableTable->setShowGrid(false); variableTable->setRowCount(1); QTableWidgetItem* emptyItem; emptyItem = new QTableWidgetItem(i18n("No variables")); variableTable->setItem(0, 0, emptyItem); variableTable->resizeColumnsToContents(); functionMap.clear(); functionTableEmpty = true; functionTable->clear(); headers.clear(); headers << i18n("name") << i18n("parameters"); functionTable->setColumnCount(2); functionTable->setHorizontalHeaderLabels(headers); functionTable->setSelectionMode(QAbstractItemView::SingleSelection); functionTable->setSelectionBehavior(QAbstractItemView::SelectRows); functionTable->horizontalHeader()->setDefaultAlignment(Qt::AlignLeft); functionTable->verticalHeader()->setVisible(false); functionTable->setShowGrid(false); functionTable->setRowCount(1); emptyItem = new QTableWidgetItem(i18n("No learned functions")); functionTable->setItem(0, 0, emptyItem); functionTable->resizeColumnsToContents(); // Treeview gets cleared in updateTree() disable(); } void Inspector::updateVariable(const QString& name, const Value& value) { // Check if the variable has already been added to the table int row = findVariable(name); if (row == -1) { // We are dealing with a new variable if (variableTableEmpty) { // Check whether we have to add a new row variableTableEmpty = false; } else { variableTable->insertRow(0); } row = 0; } QTableWidgetItem* nameItem; nameItem = new QTableWidgetItem(name); nameItem->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); QTextCharFormat* format = highlighter->formatForStatement(name); nameItem->setFont(format->font()); nameItem->setForeground(format->foreground()); variableTable->setItem(row, 0, nameItem); variableMap[name] = nameItem; QTableWidgetItem* valueItem; valueItem = new QTableWidgetItem(value.string()); valueItem->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); // TODO variable coloring when tokens are available in the inspector! // format = highlighter->formatForStatement(value.string()); // valueItem->setFont(format->font()); // valueItem->setForeground(format->foreground()); QTableWidgetItem* typeItem; switch (value.type()) { case Value::Empty: { typeItem = new QTableWidgetItem(i18nc("undefined type of a variable","empty")); QFont font = typeItem->font(); font.setItalic(true); typeItem->setFont(font); } break; case Value::Bool: typeItem = new QTableWidgetItem(i18n("boolean")); break; case Value::Number: typeItem = new QTableWidgetItem(i18n("number")); break; case Value::String: typeItem = new QTableWidgetItem(i18n("string")); break; default: // should never happen - typeItem = new QTableWidgetItem("ERROR! please report to KTurtle developers"); + typeItem = new QTableWidgetItem(QStringLiteral("ERROR! please report to KTurtle developers")); break; } typeItem->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); variableTable->setItem(row, 1, valueItem); variableTable->setItem(row, 2, typeItem); variableTable->sortItems(0); variableTable->resizeColumnsToContents(); variableTable->setEnabled(true); } void Inspector::updateFunction(const QString& name, const QStringList& parameters) { // When there is already a the 'Nothing to show' line re-use that one and don't add another if (functionTableEmpty) { functionTableEmpty = false; } else { functionTable->insertRow(0); } QTableWidgetItem* nameItem = new QTableWidgetItem(name); nameItem->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); functionTable->setItem(0, 0, nameItem); functionMap[name] = nameItem; QTableWidgetItem* paramItem; if (parameters.empty()) { paramItem = new QTableWidgetItem(i18n("None")); QFont font = paramItem->font(); font.setItalic(true); paramItem->setFont(font); } else { - QString paramList = parameters.join(Translator::instance()->default2localized(QString(","))); + QString paramList = parameters.join(Translator::instance()->default2localized(QStringLiteral(","))); paramItem = new QTableWidgetItem(paramList); } paramItem->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); functionTable->setItem(0, 1, paramItem); functionTable->sortItems(0); functionTable->resizeColumnsToContents(); functionTable->setEnabled(true); } void Inspector::updateTree(TreeNode* rootNode) { treeMap.clear(); treeView->clear(); QTreeWidgetItem* rootItem = walkTree(rootNode); foreach (QTreeWidgetItem* item, rootItem->takeChildren()) { treeView->addTopLevelItem(item); } delete rootItem; treeView->expandAll(); treeView->setEnabled(true); } QTreeWidgetItem* Inspector::walkTree(TreeNode* node) { QTreeWidgetItem* result = new QTreeWidgetItem(); result->setText(0, node->token()->look()); QTextCharFormat* format = highlighter->tokenToFormat(node->token()); if (format) { result->setForeground(0, format->foreground()); QFont font(QFontDatabase::systemFont(QFontDatabase::FixedFont)); font.setBold(format->font().bold()); result->setFont(0, font); } treeMap[node] = result; if (node->hasChildren()) { for (uint i = 0; i < node->childCount(); i++) { result->addChild(walkTree(node->child(i))); } } return result; } int Inspector::findVariable(const QString& name) { QTableWidgetItem* item = variableMap[name]; if (!item) return -1; return item->row(); // old implementation before we had a variableMap // // This function will search for a specified variable and return the row number of this variable. // QList matches = variableTable->findItems(name, Qt::MatchExactly); // QList::iterator i; // for (i = matches.begin(); i != matches.end(); ++i) { // if ((*i)->column() == 0) // only check the first column // return (*i)->row(); // } // return -1; } void Inspector::markVariable(const QString& name) { Q_UNUSED(name); //qDebug() << variableMap[name]->row(); } void Inspector::markFunction(const QString& name) { Q_UNUSED(name); //qDebug() << functionMap[name]->row(); } void Inspector::markTreeNode(TreeNode* node) { // //qDebug() << treeMap[node]->text(0); clearTreeMark(); currentlyMarkedTreeItem = treeMap[node]; previousTreeBackground = currentlyMarkedTreeItem->background(0); currentlyMarkedTreeItem->setBackground(0, QBrush(WORD_HIGHLIGHT_COLOR)); } void Inspector::clearTreeMark() { if (!currentlyMarkedTreeItem) return; currentlyMarkedTreeItem->setBackground(0, previousTreeBackground); currentlyMarkedTreeItem = nullptr; } void Inspector::clearAllMarks() { clearTreeMark(); } diff --git a/src/interpreter/echoer.h b/src/interpreter/echoer.h index ce143fb..2b34ac9 100644 --- a/src/interpreter/echoer.h +++ b/src/interpreter/echoer.h @@ -1,155 +1,155 @@ /* Copyright (C) 2003-2006 Cies Breijs This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _ECHOER_H_ #define _ECHOER_H_ #include "executer.h" #include /** * @short Echoes signals to a QTextStream * * Just echos the signals it gets. * Useful for creating UnitTests. * * @author Cies Breijs */ class Echoer : public QObject { Q_OBJECT public: /** * Default Constructor */ explicit Echoer(QObject* parent = 0) { setParent(parent); } /** * Default Destructor */ virtual ~Echoer() {} /** * Connects all its slots to the signals of the Executer */ void connectAllSlots(Executer* executer) { // these connect calls connect all the Executers signals to this class' slots //BEGIN GENERATED echoer_connect_h CODE /* The code between the line that start with "//BEGIN GENERATED" and "//END GENERATED" * is generated by "generate.rb" according to the definitions specified in * "definitions.rb". Please make all changes in the "definitions.rb" file, since all * all change you make here will be overwritten the next time "generate.rb" is run. * Thanks for looking at the code! */ - connect(executer, SIGNAL(reset()), - SLOT(reset())); - connect(executer, SIGNAL(clear()), - SLOT(clear())); - connect(executer, SIGNAL(center()), - SLOT(center())); - connect(executer, SIGNAL(go(double, double)), - SLOT(go(double, double))); - connect(executer, SIGNAL(goX(double)), - SLOT(goX(double))); - connect(executer, SIGNAL(goY(double)), - SLOT(goY(double))); - connect(executer, SIGNAL(forward(double)), - SLOT(forward(double))); - connect(executer, SIGNAL(backward(double)), - SLOT(backward(double))); - connect(executer, SIGNAL(direction(double)), - SLOT(direction(double))); - connect(executer, SIGNAL(turnLeft(double)), - SLOT(turnLeft(double))); - connect(executer, SIGNAL(turnRight(double)), - SLOT(turnRight(double))); - connect(executer, SIGNAL(penWidth(double)), - SLOT(penWidth(double))); - connect(executer, SIGNAL(penUp()), - SLOT(penUp())); - connect(executer, SIGNAL(penDown()), - SLOT(penDown())); - connect(executer, SIGNAL(penColor(double, double, double)), - SLOT(penColor(double, double, double))); - connect(executer, SIGNAL(canvasColor(double, double, double)), - SLOT(canvasColor(double, double, double))); - connect(executer, SIGNAL(canvasSize(double, double)), - SLOT(canvasSize(double, double))); - connect(executer, SIGNAL(spriteShow()), - SLOT(spriteShow())); - connect(executer, SIGNAL(spriteHide()), - SLOT(spriteHide())); - connect(executer, SIGNAL(print(const QString&)), - SLOT(print(const QString&))); - connect(executer, SIGNAL(fontSize(double)), - SLOT(fontSize(double))); + connect(executer, &Executer::reset, + this, &Echoer::reset); + connect(executer, &Executer::clear, + this, &Echoer::clear); + connect(executer, &Executer::center, + this, &Echoer::center); + connect(executer, &Executer::go, + this, &Echoer::go); + connect(executer, &Executer::goX, + this, &Echoer::goX); + connect(executer, &Executer::goY, + this, &Echoer::goY); + connect(executer, &Executer::forward, + this, &Echoer::forward); + connect(executer, &Executer::backward, + this, &Echoer::backward); + connect(executer, &Executer::direction, + this, &Echoer::direction); + connect(executer, &Executer::turnLeft, + this, &Echoer::turnLeft); + connect(executer, &Executer::turnRight, + this, &Echoer::turnRight); + connect(executer, &Executer::penWidth, + this, &Echoer::penWidth); + connect(executer, &Executer::penUp, + this, &Echoer::penUp); + connect(executer, &Executer::penDown, + this, &Echoer::penDown); + connect(executer, &Executer::penColor, + this, &Echoer::penColor); + connect(executer, &Executer::canvasColor, + this, &Echoer::canvasColor); + connect(executer, &Executer::canvasSize, + this, &Echoer::canvasSize); + connect(executer, &Executer::spriteShow, + this, &Echoer::spriteShow); + connect(executer, &Executer::spriteHide, + this, &Echoer::spriteHide); + connect(executer, &Executer::print, + this, &Echoer::print); + connect(executer, &Executer::fontSize, + this, &Echoer::fontSize); //END GENERATED echoer_connect_h CODE } public slots: // the generated code is a set of slots that are covering all the Executers signals... //BEGIN GENERATED echoer_slots_h CODE /* The code between the line that start with "//BEGIN GENERATED" and "//END GENERATED" * is generated by "generate.rb" according to the definitions specified in * "definitions.rb". Please make all changes in the "definitions.rb" file, since all * all change you make here will be overwritten the next time "generate.rb" is run. * Thanks for looking at the code! */ void reset() { qDebug() << "SIG> " << "reset" << "(" << ")"; } void clear() { qDebug() << "SIG> " << "clear" << "(" << ")"; } void center() { qDebug() << "SIG> " << "center" << "(" << ")"; } void go(double arg0, double arg1) { qDebug() << "SIG> " << "go" << "(" << arg0 << "," << arg1 << ")"; } void goX(double arg0) { qDebug() << "SIG> " << "goX" << "(" << arg0 << ")"; } void goY(double arg0) { qDebug() << "SIG> " << "goY" << "(" << arg0 << ")"; } void forward(double arg0) { qDebug() << "SIG> " << "forward" << "(" << arg0 << ")"; } void backward(double arg0) { qDebug() << "SIG> " << "backward" << "(" << arg0 << ")"; } void direction(double arg0) { qDebug() << "SIG> " << "direction" << "(" << arg0 << ")"; } void turnLeft(double arg0) { qDebug() << "SIG> " << "turnLeft" << "(" << arg0 << ")"; } void turnRight(double arg0) { qDebug() << "SIG> " << "turnRight" << "(" << arg0 << ")"; } void penWidth(double arg0) { qDebug() << "SIG> " << "penWidth" << "(" << arg0 << ")"; } void penUp() { qDebug() << "SIG> " << "penUp" << "(" << ")"; } void penDown() { qDebug() << "SIG> " << "penDown" << "(" << ")"; } void penColor(double arg0, double arg1, double arg2) { qDebug() << "SIG> " << "penColor" << "(" << arg0 << "," << arg1 << "," << arg2 << ")"; } void canvasColor(double arg0, double arg1, double arg2) { qDebug() << "SIG> " << "canvasColor" << "(" << arg0 << "," << arg1 << "," << arg2 << ")"; } void canvasSize(double arg0, double arg1) { qDebug() << "SIG> " << "canvasSize" << "(" << arg0 << "," << arg1 << ")"; } void spriteShow() { qDebug() << "SIG> " << "spriteShow" << "(" << ")"; } void spriteHide() { qDebug() << "SIG> " << "spriteHide" << "(" << ")"; } void print(const QString& arg0) { qDebug() << "SIG> " << "print" << "(" << qPrintable(arg0) << ")"; } void fontSize(double arg0) { qDebug() << "SIG> " << "fontSize" << "(" << arg0 << ")"; } //END GENERATED echoer_slots_h CODE }; #endif // _ECHOER_H_ diff --git a/src/interpreter/errormsg.h b/src/interpreter/errormsg.h index c42dab4..78c381c 100644 --- a/src/interpreter/errormsg.h +++ b/src/interpreter/errormsg.h @@ -1,107 +1,107 @@ /* Copyright (C) 2003-2006 Cies Breijs This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _ERRORMSG_H_ #define _ERRORMSG_H_ #include "token.h" #include #include #include /** * @short An object for an error message. * * Basically it is a aggregation of a QString (the message text), a Token (the Token * that is related to the error) and a code (a simple integer). * * ErrorMessages are created by the Parser and the Executer. * * @TODO investigate if it will be better to replace this class by a struct for speed. * * @author Cies Breijs */ class ErrorMessage { public: ErrorMessage() {} ErrorMessage(const QString&, const Token& t, int code); ~ErrorMessage() {} const QString& text() const { return _errorText; } const Token& token() const { return _errorToken; } int code() const { return _errorCode; } bool operator==(const ErrorMessage&) const; ErrorMessage& operator=(const ErrorMessage& n); private: QString _errorText; Token _errorToken; int _errorCode; }; /** * @short The simple subclass of QList to represent list of ErrorMessages. */ class ErrorList : public QList { public: QStringList asStringList() { QStringList result; ErrorList::iterator error; int i = 1; for (error = this->begin(); error != this->end(); ++error) { - result.append(QString("%1: %2 [by %3 on line %4], code %5") + result.append(QStringLiteral("%1: %2 [by %3 on line %4], code %5") .arg(i) .arg((*error).text()) .arg((*error).token().look()) .arg((*error).token().startRow()) .arg((*error).code())); i++; } return result; } void addError(const QString& s, const Token& t, int code) { ErrorMessage error = ErrorMessage(s, t, code); addError(error); } void addError(ErrorMessage error) { if (!this->contains(error)) this->append(error); // //qDebug() << // QString("ErrorList::addError(): %1 [by %2 on line %3], code %4") // .arg(error.text()) // .arg(error.token().look()) // .arg(error.token().startRow()) // .arg(error.code()); } }; #endif // _ERRORMSG_H_ diff --git a/src/interpreter/executer.cpp b/src/interpreter/executer.cpp index c071cf2..9dae953 100644 --- a/src/interpreter/executer.cpp +++ b/src/interpreter/executer.cpp @@ -1,1102 +1,1102 @@ /* Copyright (C) 2003-2006 Cies Breijs This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ // This file is originally written by Walter Scheppers, but almost // every aspect of it is slightly changed by Cies Breijs. #include "executer.h" #include #include #include // for wait #include #include #include #include void Executer::initialize(TreeNode* tree, ErrorList* _errorList) { rootNode = tree; newScope = rootNode; currentNode = rootNode; finished = !currentNode->hasChildren(); // set finished to false unless the tree is empty errorList = _errorList; breaking = false; returning = false; waiting = false; returnValue = nullptr; executeCurrent = false; functionTable.clear(); globalVariableTable.clear(); while (!functionStack.isEmpty()) { // In the ForTo loop, we can assign the globalVariableTable to an entry in the functionStack // we shouldn't delete this variableTable, so check for it. VariableTable* variableTable = functionStack.pop().variableTable; if(variableTable!=&globalVariableTable) delete variableTable; } } void Executer::execute() { //Do we have to do anything? if (finished || waiting) return; if(executeCurrent) { // executeCurrent is used to make sure the currentNode will be executed // this way the tree will not be walked before the execution... executeCurrent = false; execute(currentNode); return; } if(returning) { //We are returning from a function call // Handle returning in the top-level (not inside a function) as // gracefully as possible. // See: https://bugs.kde.org/show_bug.cgi?id=300949 if (functionStack.isEmpty()) { addError(i18n("Cannot return outside a function. "), *(currentNode->token()), 0); finished = true; return; } // Take the last called function from the function stack CalledFunction calledFunction = functionStack.pop(); // Delete the local variables of the called function delete calledFunction.variableTable; currentNode = calledFunction.function; if (returnValue == nullptr) currentNode->setNullValue(); // Handle an empty return value else currentNode->setValue(returnValue); execute(currentNode); return; } if (newScope == nullptr) { TreeNode* currentParent = currentNode->parent(); currentNode = currentNode->nextSibling(); if(currentNode == nullptr) { //running off sibling list currentNode = currentParent; if(currentNode == rootNode) { finished = true; return; } // printExe(); // debugging thing execute(currentNode); return; } }else{ // We're entering a new scope // skip ahead to frist child (if any) else we will not get into the scope if(newScope->hasChildren()) currentNode = newScope->firstChild(); else currentNode = newScope; newScope = nullptr; } while (currentNode->hasChildren() && currentNode->token()->type() != Token::Scope) currentNode = currentNode->firstChild(); // printExe(); // debugging thing execute(currentNode); } void Executer::execute(TreeNode* node) { if (finished) return; // emit a signal for GUI Token* t = node->token(); // //qDebug() << "emitting token: '" << t->look() << "' - (" << t->startRow() << "," << t->startCol() << " - " << t->endRow() << "," << t->endCol() << ")"; // don't report scopes (their are not really executed) if (t->type() != Token::Scope) emit currentlyExecuting(node); // this method executes one node at the time // if (currentNode->token()->type() != Token::Scope) //qDebug() << "1234567890!!!!!"; switch (node->token()->type()) { //BEGIN GENERATED executer_switch_cpp CODE /* The code between the line that start with "//BEGIN GENERATED" and "//END GENERATED" * is generated by "generate.rb" according to the definitions specified in * "definitions.rb". Please make all changes in the "definitions.rb" file, since all * all change you make here will be overwritten the next time "generate.rb" is run. * Thanks for looking at the code! */ case Token::Root : executeRoot(node); break; case Token::Scope : executeScope(node); break; case Token::Variable : executeVariable(node); break; case Token::FunctionCall : executeFunctionCall(node); break; case Token::String : /* a constant; do nothing */ break; case Token::Number : /* a constant; do nothing */ break; case Token::True : /* a constant; do nothing */ break; case Token::False : /* a constant; do nothing */ break; case Token::Exit : executeExit(node); break; case Token::If : executeIf(node); break; case Token::Else : executeElse(node); break; case Token::Repeat : executeRepeat(node); break; case Token::While : executeWhile(node); break; case Token::For : executeFor(node); break; case Token::ForTo : executeForTo(node); break; case Token::Break : executeBreak(node); break; case Token::Return : executeReturn(node); break; case Token::Wait : executeWait(node); break; case Token::Assert : executeAssert(node); break; case Token::And : executeAnd(node); break; case Token::Or : executeOr(node); break; case Token::Not : executeNot(node); break; case Token::Equals : executeEquals(node); break; case Token::NotEquals : executeNotEquals(node); break; case Token::GreaterThan : executeGreaterThan(node); break; case Token::LessThan : executeLessThan(node); break; case Token::GreaterOrEquals : executeGreaterOrEquals(node); break; case Token::LessOrEquals : executeLessOrEquals(node); break; case Token::Addition : executeAddition(node); break; case Token::Substracton : executeSubstracton(node); break; case Token::Multiplication : executeMultiplication(node); break; case Token::Division : executeDivision(node); break; case Token::Power : executePower(node); break; case Token::Assign : executeAssign(node); break; case Token::Learn : executeLearn(node); break; case Token::ArgumentList : executeArgumentList(node); break; case Token::Reset : executeReset(node); break; case Token::Clear : executeClear(node); break; case Token::Center : executeCenter(node); break; case Token::Go : executeGo(node); break; case Token::GoX : executeGoX(node); break; case Token::GoY : executeGoY(node); break; case Token::Forward : executeForward(node); break; case Token::Backward : executeBackward(node); break; case Token::Direction : executeDirection(node); break; case Token::TurnLeft : executeTurnLeft(node); break; case Token::TurnRight : executeTurnRight(node); break; case Token::PenWidth : executePenWidth(node); break; case Token::PenUp : executePenUp(node); break; case Token::PenDown : executePenDown(node); break; case Token::PenColor : executePenColor(node); break; case Token::CanvasColor : executeCanvasColor(node); break; case Token::CanvasSize : executeCanvasSize(node); break; case Token::SpriteShow : executeSpriteShow(node); break; case Token::SpriteHide : executeSpriteHide(node); break; case Token::Print : executePrint(node); break; case Token::FontSize : executeFontSize(node); break; case Token::Random : executeRandom(node); break; case Token::GetX : executeGetX(node); break; case Token::GetY : executeGetY(node); break; case Token::Message : executeMessage(node); break; case Token::Ask : executeAsk(node); break; case Token::Pi : executePi(node); break; case Token::Tan : executeTan(node); break; case Token::Sin : executeSin(node); break; case Token::Cos : executeCos(node); break; case Token::ArcTan : executeArcTan(node); break; case Token::ArcSin : executeArcSin(node); break; case Token::ArcCos : executeArcCos(node); break; case Token::Sqrt : executeSqrt(node); break; case Token::Round : executeRound(node); break; case Token::GetDirection : executeGetDirection(node); break; case Token::Mod : executeMod(node); break; //END GENERATED executer_switch_cpp CODE default: //qDebug() << "Unrecognizd Token type (" << node->token()->type() << ", " << node->token()->look() << ") -- THIS SHOULDN'T HAPPEN!"; break; } } VariableTable* Executer::currentVariableTable() { if (functionStack.isEmpty()) return &globalVariableTable; else return functionStack.top().variableTable; } bool Executer::checkParameterQuantity(TreeNode* node, uint quantity, int errorCode) { // //qDebug() << "called"; uint nodeSize = node->childCount(); if (quantity == 0) { if (nodeSize == 0) return true; // thats easy! addError(i18n("The %1 command accepts no parameters.", node->token()->look()), *node->token(), errorCode); return false; } // // CHECK THIS OUT LATER // if (nodeSize != 0) // when all parameters are forgotten the parser puts a Unknown/tokEOL param, catch this: // if (node->firstChild()->getToken().type == tokEOL) nodeSize = 0; if (nodeSize != quantity) { if (nodeSize < quantity) { addError(i18np("The %2 command was called with %3 but needs 1 parameter.", "The %2 command was called with %3 but needs %1 parameters.", quantity, node->token()->look(), nodeSize), *node->token(), errorCode); } else { addError(i18np("The %2 command was called with %3 but only accepts 1 parameter.", "The %2 command was called with %3 but only accepts %1 parameters.", quantity, node->token()->look(), nodeSize), *node->token(), errorCode); } return false; } return true; // if all tests passed } bool Executer::checkParameterType(TreeNode* node, int valueType, int errorCode) { // //qDebug() << "called"; uint quantity = node->childCount(); TreeNode* currentChild = node->firstChild(); while (currentChild != nullptr) { if (currentChild->value()->type() != valueType) { switch (valueType) { case Value::String: if (quantity == 1) addError(i18n("The %1 command only accepts a string as its parameter.", node->token()->look()), *node->token(), errorCode); else addError(i18n("The %1 command only accepts strings as its parameters.", node->token()->look()), *node->token(), errorCode); break; case Value::Number: if (quantity == 1) addError(i18n("The %1 command only accepts a number as its parameter.", node->token()->look()), *node->token(), errorCode); else addError(i18n("The %1 command only accepts numbers as its parameters.", node->token()->look()), *node->token(), errorCode); break; case Value::Bool: if (quantity == 1) addError(i18n("The %1 command only accepts an answer as its parameter.", node->token()->look()), *node->token(), errorCode); else addError(i18n("The %1 command only accepts answers as its parameters.", node->token()->look()), *node->token(), errorCode); break; } return false; } currentChild = node->nextChild(); } return true; // if all tests passed } void Executer::addError(const QString& s, const Token& t, int code) { // //qDebug() << qPrintable(s) << " (runtime error)"; errorList->addError(s, t, code); } //BEGIN GENERATED executer_cpp CODE /* The code between the line that start with "//BEGIN GENERATED" and "//END GENERATED" * is generated by "generate.rb" according to the definitions specified in * "definitions.rb". Please make all changes in the "definitions.rb" file, since all * all change you make here will be overwritten the next time "generate.rb" is run. * Thanks for looking at the code! */ void Executer::executeRoot(TreeNode* node) { // //qDebug() << "called"; node = node; // stop the warnings // this is a stud } void Executer::executeScope(TreeNode* node) { // //qDebug() << "called"; // catch loops, they need to be managed... int parentTokenType = node->parent()->token()->type(); if (parentTokenType == Token::If || parentTokenType == Token::Repeat || parentTokenType == Token::While || // parentTokenType == Token::ForIn || parentTokenType == Token::ForTo) { currentNode = node->parent(); executeCurrent = true; return; } if(parentTokenType == Token::Learn) { //We have the end of a Learn, so we should return returning = true; returnValue = nullptr; return; } newScope = node; } void Executer::executeVariable(TreeNode* node) { // //qDebug() << "called"; bool aValueIsNeeded = true; // no need to look up when assigning (in a for loop statement) if ((node->parent()->token()->type() == Token::ForTo) && (node->parent()->child(0)==node)) return; // we need to executeVariables in assignments for things like $x=$y to work if (node->parent()->token()->type() == Token::Assign) { // Test if we are in the LHS of the assignment if (node == node->parent()->child(0)) { // In this case we do not need to be initialized, we will get a value in executeAssign aValueIsNeeded = false; } } if (!functionStack.isEmpty() && functionStack.top().variableTable->contains(node->token()->look())) { // //qDebug() << "exists locally"; node->setValue( (*functionStack.top().variableTable)[node->token()->look()] ); } else if (globalVariableTable.contains(node->token()->look())) { // //qDebug() << "exists globally"; node->setValue(globalVariableTable[node->token()->look()]); } else if (aValueIsNeeded) { addError(i18n("The variable '%1' was used without first being assigned to a value", node->token()->look()), *node->token(), 0); } } void Executer::executeFunctionCall(TreeNode* node) { // //qDebug() << "called"; if (node->parent()->token()->type() == Token::Learn) { // in case we're defining a function currentNode = node->parent(); executeCurrent = true; return; } if (returning) { // if the function is already executed and returns now returnValue = nullptr; returning = false; // //qDebug() << "==> functionReturned!"; return; } if (!functionTable.contains(node->token()->look())) { addError(i18n("An unknown function named '%1' was called", node->token()->look()), *node->token(), 0); return; } CalledFunction c; c.function = node; c.variableTable = new VariableTable(); functionStack.push(c); // //qDebug() << "==> functionCalled!"; TreeNode* learnNode = functionTable[node->token()->look()]; // if the parameter numbers are not equal... if (node->childCount() != learnNode->child(1)->childCount()) { addError( i18n("The function '%1' was called with %2, while it should be called with %3", node->token()->look(), i18ncp("The function '%1' was called with %2, while it should be called with %3", "1 parameter", "%1 parameters", node->childCount()), i18ncp("The function '%1' was called with %2, while it should be called with %3", "1 parameter", "%1 parameters", learnNode->child(1)->childCount()) ), *node->token(), 0); return; } for (uint i = 0; i < node->childCount(); i++) { functionStack.top().variableTable->insert(learnNode->child(1)->child(i)->token()->look(), node->child(i)->value()); // //qDebug() << "inserted variable " << learnNode->child(1)->child(i)->token()->look() << " on function stack"; } newScope = learnNode->child(2); } void Executer::executeExit(TreeNode* node) { // //qDebug() << "called"; node = node; // stop the warnings finished = true; } void Executer::executeIf(TreeNode* node) { // //qDebug() << "called"; - QString id = QString("__%1_%2").arg(node->token()->look()).arg(reinterpret_cast(node)); + QString id = QStringLiteral("__%1_%2").arg(node->token()->look()).arg(reinterpret_cast(node)); if (currentVariableTable()->contains(id)) { currentVariableTable()->remove(id); return; } if (node->child(0)->value()->boolean()) { // store a empty Value just to know we executed once currentVariableTable()->insert(id, Value()); newScope = node->child(1); } else { if (node->childCount() >= 3) { currentVariableTable()->insert(id, Value()); newScope = node->child(2); // execute the else part } } } void Executer::executeElse(TreeNode* node) { // //qDebug() << "called"; execute(node->child(0)); // execute the scope, that's all... } void Executer::executeRepeat(TreeNode* node) { // //qDebug() << "called"; - QString id = QString("__%1_%2").arg(node->token()->look()).arg(reinterpret_cast(node)); + QString id = QStringLiteral("__%1_%2").arg(node->token()->look()).arg(reinterpret_cast(node)); if(breaking) { breaking = false; currentVariableTable()->remove(id); return; } // the iteration state is stored on the variable table if (currentVariableTable()->contains(id)) { int currentCount = static_cast(round((*currentVariableTable())[id].number())); if (currentCount > 0) { (*currentVariableTable())[id].setNumber(currentCount - 1); } else { currentVariableTable()->remove(id); return; } } else { if(static_cast(round(node->child(0)->value()->number()))<=0) // handle 'repeat 0' return; currentVariableTable()->insert(id, Value(round(node->child(0)->value()->number()) - 1.0)); } newScope = node->child(1); } void Executer::executeWhile(TreeNode* node) { // //qDebug() << "called"; // first time this gets called the expression is already executed // after one iteration the expression is not automatically re-executed. // so we do the following on every call to executeWhile: // exec scope, exec expression, exec scope, exec expression, ... - QString id = QString("__%1_%2").arg(node->token()->look()).arg(reinterpret_cast(node)); + QString id = QStringLiteral("__%1_%2").arg(node->token()->look()).arg(reinterpret_cast(node)); if (breaking) { // We hit a break command while executing the scope breaking = false; // Not breaking anymore currentVariableTable()->remove(id); // remove the value (cleanup) return; // Move to the next sibbling } if (currentVariableTable()->contains(id)) { newScope = node; // re-execute the expression currentVariableTable()->remove(id); return; } currentVariableTable()->insert(id, Value()); // store a empty Value just to know we executed once if (node->child(0)->value()->boolean()) newScope = node->child(1); // (re-)execute the scope else currentVariableTable()->remove(id); // clean-up, keep currenNode on currentNode so the next sibling we be run next } void Executer::executeFor(TreeNode* node) { // //qDebug() << "called"; qCritical("Executer::executeFor(): should have been translated to Token::ForTo by the parser"); node = node; // stop the warnings } void Executer::executeForTo(TreeNode* node) { // //qDebug() << "called"; // first time this gets called the expressions are already executed // after one iteration the expression is not re-executed. // so we do: exec scope, exec expressions, exec scope, exec expressions, ... //TODO: We have the cleanup part twice (after breaking and after the last iteration // perhaps clean it up by putting in in one place? bool firstIteration = false; if (functionStack.isEmpty() || functionStack.top().function != node) { // if this for loop is called for the first time... CalledFunction c; c.function = node; // TODO: Find a better solution then this for nested for loops //c.variableTable = new VariableTable(); c.variableTable = currentVariableTable(); functionStack.push(c); currentVariableTable()->insert(node->child(0)->token()->look(), Value(node->child(1)->value()->number())); firstIteration = true; } - QString id = QString("__%1_%2").arg(node->token()->look()).arg(reinterpret_cast(node)); + QString id = QStringLiteral("__%1_%2").arg(node->token()->look()).arg(reinterpret_cast(node)); if(breaking) { breaking = false; //delete functionStack.top().variableTable; functionStack.pop(); // if we don't delete the functionStack's varibleTable any more // do remove the for loops id.. currentVariableTable()->remove(id); return; } if (currentVariableTable()->contains(id)) { newScope = node; // re-execute the expressions currentVariableTable()->remove(id); return; } currentVariableTable()->insert(id, Value()); // store a empty Value just to know we executed once double currentCount = (*currentVariableTable())[node->child(0)->token()->look()].number(); double startCondition = node->child(1)->value()->number(); double endCondition = node->child(2)->value()->number(); double step = node->child(3)->value()->number(); if ((startCondition < endCondition && currentCount + step <= endCondition) || (startCondition > endCondition && currentCount + step >= endCondition && step<0) || //negative loop sanity check, is it implemented? (startCondition ==endCondition && firstIteration) ) { // for expressions like for $n=1 to 1 if (!firstIteration) (*currentVariableTable())[node->child(0)->token()->look()].setNumber(currentCount + step); newScope = node->child(4); // (re-)execute the scope } else { // cleaning up after last iteration... //delete functionStack.top().variableTable; functionStack.pop(); // if we don't delete the functionStack's varibleTable any more // do remove the for loops id.. currentVariableTable()->remove(id); } } void Executer::executeBreak(TreeNode* node) { // //qDebug() << "called"; if (!checkParameterQuantity(node, 0, 20000+Token::Break*100+90)) return; breaking = true; // Check for the first parent which is a repeat, while of for loop. // If found, switch the newScope to them so they can break. QList tokenTypes; tokenTypes.append(Token::Repeat); tokenTypes.append(Token::While); tokenTypes.append(Token::ForTo); TreeNode* ns = getParentOfTokenTypes(node, &tokenTypes); if(ns!=nullptr) newScope = ns; //else // We could add an error right HERE // At the moment we just ignore a break when we couldn't // find a matching parent } void Executer::executeReturn(TreeNode* node) { // //qDebug() << "called"; if(node->childCount()>0) returnValue = node->child(0)->value(); else returnValue = nullptr; returning = true; } void Executer::executeWait(TreeNode* node) { // //qDebug() << "called"; if (!checkParameterQuantity(node, 1, 20000+Token::Wait*100+90)) return; if (!checkParameterType(node, Value::Number, 20000+Token::Wait*100+91) ) return; waiting = true; - QTimer::singleShot(static_cast(1000*node->child(0)->value()->number()), this, SLOT(stopWaiting())); + QTimer::singleShot(static_cast(1000*node->child(0)->value()->number()), this, &Executer::stopWaiting); } void Executer::executeAssert(TreeNode* node) { // //qDebug() << "called"; if (!checkParameterQuantity(node, 1, 20000+Token::Wait*100+90)) return; if (!checkParameterType(node, Value::Bool, 20000+Token::Wait*100+91) ) return; if (!node->child(0)->value()->boolean()) addError(i18n("ASSERT failed"), *node->token(), 0); } void Executer::executeAnd(TreeNode* node) { // //qDebug() << "called"; //Niels: See 'Not' if(node->childCount()!=2) { addError(i18n("'And' needs two variables"), *node->token(), 0); return; } node->value()->setBool(node->child(0)->value()->boolean() && node->child(1)->value()->boolean()); } void Executer::executeOr(TreeNode* node) { // //qDebug() << "called"; //Niels: See 'Not' if(node->childCount()!=2) { addError(i18n("'Or' needs two variables"), *node->token(), 0); return; } node->value()->setBool(node->child(0)->value()->boolean() || node->child(1)->value()->boolean()); } void Executer::executeNot(TreeNode* node) { // //qDebug() << "called"; // OLD-TODO: maybe add some error handling here... //Niels: Ok, now we check if the node has children. Should we also check whether the child value is a boolean? if(node->childCount()!=1) { addError(i18n("I need something to do a not on"), *node->token(), 0); return; } node->value()->setBool(!node->child(0)->value()->boolean()); } void Executer::executeEquals(TreeNode* node) { // //qDebug() << "called"; if(node->childCount()!=2) { addError(i18n("I cannot do a '==' without 2 variables"), *node->token(), 0); return; } node->value()->setBool(*node->child(0)->value() == node->child(1)->value()); } void Executer::executeNotEquals(TreeNode* node) { // //qDebug() << "called"; if(node->childCount()!=2) { addError(i18n("I cannot do a '!=' without 2 variables"), *node->token(), 0); return; } node->value()->setBool(*node->child(0)->value() != node->child(1)->value()); } void Executer::executeGreaterThan(TreeNode* node) { // //qDebug() << "called"; if(node->childCount()!=2) { addError(i18n("I cannot do a '>' without 2 variables"), *node->token(), 0); return; } node->value()->setBool(*node->child(0)->value() > node->child(1)->value()); } void Executer::executeLessThan(TreeNode* node) { // //qDebug() << "called"; if(node->childCount()!=2) { addError(i18n("I cannot do a '<' without 2 variables"), *node->token(), 0); return; } node->value()->setBool(*node->child(0)->value() < node->child(1)->value()); } void Executer::executeGreaterOrEquals(TreeNode* node) { // //qDebug() << "called"; if(node->childCount()!=2) { addError(i18n("I cannot do a '>=' without 2 variables"), *node->token(), 0); return; } node->value()->setBool(*node->child(0)->value() >= node->child(1)->value()); } void Executer::executeLessOrEquals(TreeNode* node) { // //qDebug() << "called"; if(node->childCount()!=2) { addError(i18n("I cannot do a '<=' without 2 variables"), *node->token(), 0); return; } node->value()->setBool(*node->child(0)->value() <= node->child(1)->value()); } void Executer::executeAddition(TreeNode* node) { // //qDebug() << "called"; if(node->childCount()!=2) { addError(i18n("You need two numbers or string to do an addition"), *node->token(), 0); return; } if (node->child(0)->value()->type() == Value::Number && node->child(1)->value()->type() == Value::Number) { node->value()->setNumber(node->child(0)->value()->number() + node->child(1)->value()->number()); } else { node->value()->setString(node->child(0)->value()->string().append(node->child(1)->value()->string())); } } void Executer::executeSubstracton(TreeNode* node) { // //qDebug() << "called"; if(node->childCount()!=2) { addError(i18n("You need two numbers to subtract"), *node->token(), 0); return; } if (node->child(0)->value()->type() == Value::Number && node->child(1)->value()->type() == Value::Number) { node->value()->setNumber(node->child(0)->value()->number() - node->child(1)->value()->number()); } else { if (node->child(0)->value()->type() != Value::Number) addError(i18n("You tried to subtract from a non-number, '%1'", node->child(0)->token()->look()), *node->token(), 0); if (node->child(1)->value()->type() != Value::Number) addError(i18n("You tried to subtract a non-number, '%1'", node->child(1)->token()->look()), *node->token(), 0); } } void Executer::executeMultiplication(TreeNode* node) { // //qDebug() << "called"; if(node->childCount()!=2) { addError(i18n("You need two numbers to multiplicate"), *node->token(), 0); return; } if (node->child(0)->value()->type() == Value::Number && node->child(1)->value()->type() == Value::Number) { node->value()->setNumber(node->child(0)->value()->number() * node->child(1)->value()->number()); } else { if (node->child(0)->value()->type() != Value::Number) addError(i18n("You tried to multiplicate a non-number, '%1'", node->child(0)->token()->look()), *node->token(), 0); if (node->child(1)->value()->type() != Value::Number) addError(i18n("You tried to multiplicate by a non-number, '%1'", node->child(1)->token()->look()), *node->token(), 0); } } void Executer::executeDivision(TreeNode* node) { // //qDebug() << "called"; if(node->childCount()!=2) { addError(i18n("You need two numbers to divide"), *node->token(), 0); return; } if (node->child(0)->value()->type() == Value::Number && node->child(1)->value()->type() == Value::Number) { if(node->child(1)->value()->number()==0) { addError(i18n("You tried to divide by zero"), *node->token(), 0); return; } node->value()->setNumber(node->child(0)->value()->number() / node->child(1)->value()->number()); } else { if (node->child(0)->value()->type() != Value::Number) addError(i18n("You tried to divide a non-number, '%1'", node->child(0)->token()->look()), *node->token(), 0); if (node->child(1)->value()->type() != Value::Number) addError(i18n("You tried to divide by a non-number, '%1'", node->child(1)->token()->look()), *node->token(), 0); } } void Executer::executePower(TreeNode* node) { // //qDebug() << "called"; if(node->childCount()!=2) { addError(i18n("You need two numbers to raise a power"), *node->token(), 0); return; } if (node->child(0)->value()->type() == Value::Number && node->child(1)->value()->type() == Value::Number) { node->value()->setNumber(pow(node->child(0)->value()->number(), node->child(1)->value()->number())); double result = pow(node->child(0)->value()->number(), node->child(1)->value()->number()); int error = errno; if(error==ERANGE) { node->value()->setNumber(0); addError(i18n("The result of an exponentiation was too large"), *node->token(), 0); }else{ node->value()->setNumber(result); } } else { if (node->child(0)->value()->type() != Value::Number) addError(i18n("You tried to raise a non-number to a power, '%1'", node->child(0)->token()->look()), *node->token(), 0); if (node->child(1)->value()->type() != Value::Number) addError(i18n("You tried to raise the power of a non-number, '%1'", node->child(1)->token()->look()), *node->token(), 0); } } void Executer::executeAssign(TreeNode* node) { // //qDebug() << "called"; if(node->childCount()!=2) { addError(i18n("You need one variable and a value or variable to do a '='"), *node->token(), 0); return; } if (!functionStack.isEmpty() && !globalVariableTable.contains(node->child(0)->token()->look())) // &&functionStack.top().variableTable->contains(node->token()->look())) { // //qDebug() << "function scope"; functionStack.top().variableTable->insert(node->child(0)->token()->look(), node->child(1)->value()); } else { // inserts unless already exists then replaces globalVariableTable.insert(node->child(0)->token()->look(), node->child(1)->value()); } // //qDebug() << "variableTable updated!"; emit variableTableUpdated(node->child(0)->token()->look(), node->child(1)->value()); } void Executer::executeLearn(TreeNode* node) { // //qDebug() << "called"; if(functionTable.contains(node->child(0)->token()->look())) { addError(i18n("The function '%1' is already defined.", node->child(0)->token()->look()), *node->token(), 0); return; } functionTable.insert(node->child(0)->token()->look(), node); // //qDebug() << "functionTable updated!"; QStringList parameters; for (uint i = 0; i < node->child(1)->childCount(); i++) parameters << node->child(1)->child(i)->token()->look(); emit functionTableUpdated(node->child(0)->token()->look(), parameters); } void Executer::executeArgumentList(TreeNode* node) { // //qDebug() << "called"; node = node; // stop the warnings // this is a stud } void Executer::executeReset(TreeNode* node) { // //qDebug() << "called"; if (!checkParameterQuantity(node, 0, 20000+Token::Reset*100+90)) return; emit reset(); } void Executer::executeClear(TreeNode* node) { // //qDebug() << "called"; if (!checkParameterQuantity(node, 0, 20000+Token::Clear*100+90)) return; emit clear(); } void Executer::executeCenter(TreeNode* node) { // //qDebug() << "called"; if (!checkParameterQuantity(node, 0, 20000+Token::Center*100+90)) return; emit center(); } void Executer::executeGo(TreeNode* node) { // //qDebug() << "called"; if (!checkParameterQuantity(node, 2, 20000+Token::Go*100+90) || !checkParameterType(node, Value::Number, 20000+Token::Go*100+91)) return; emit go(node->child(0)->value()->number(), node->child(1)->value()->number()); } void Executer::executeGoX(TreeNode* node) { // //qDebug() << "called"; if (!checkParameterQuantity(node, 1, 20000+Token::GoX*100+90) || !checkParameterType(node, Value::Number, 20000+Token::GoX*100+91)) return; emit goX(node->child(0)->value()->number()); } void Executer::executeGoY(TreeNode* node) { // //qDebug() << "called"; if (!checkParameterQuantity(node, 1, 20000+Token::GoY*100+90) || !checkParameterType(node, Value::Number, 20000+Token::GoY*100+91)) return; emit goY(node->child(0)->value()->number()); } void Executer::executeForward(TreeNode* node) { // //qDebug() << "called"; if (!checkParameterQuantity(node, 1, 20000+Token::Forward*100+90) || !checkParameterType(node, Value::Number, 20000+Token::Forward*100+91)) return; emit forward(node->child(0)->value()->number()); } void Executer::executeBackward(TreeNode* node) { // //qDebug() << "called"; if (!checkParameterQuantity(node, 1, 20000+Token::Backward*100+90) || !checkParameterType(node, Value::Number, 20000+Token::Backward*100+91)) return; emit backward(node->child(0)->value()->number()); } void Executer::executeDirection(TreeNode* node) { // //qDebug() << "called"; if (!checkParameterQuantity(node, 1, 20000+Token::Direction*100+90) || !checkParameterType(node, Value::Number, 20000+Token::Direction*100+91)) return; emit direction(node->child(0)->value()->number()); } void Executer::executeTurnLeft(TreeNode* node) { // //qDebug() << "called"; if (!checkParameterQuantity(node, 1, 20000+Token::TurnLeft*100+90) || !checkParameterType(node, Value::Number, 20000+Token::TurnLeft*100+91)) return; emit turnLeft(node->child(0)->value()->number()); } void Executer::executeTurnRight(TreeNode* node) { // //qDebug() << "called"; if (!checkParameterQuantity(node, 1, 20000+Token::TurnRight*100+90) || !checkParameterType(node, Value::Number, 20000+Token::TurnRight*100+91)) return; emit turnRight(node->child(0)->value()->number()); } void Executer::executePenWidth(TreeNode* node) { // //qDebug() << "called"; if (!checkParameterQuantity(node, 1, 20000+Token::PenWidth*100+90) || !checkParameterType(node, Value::Number, 20000+Token::PenWidth*100+91)) return; emit penWidth(node->child(0)->value()->number()); } void Executer::executePenUp(TreeNode* node) { // //qDebug() << "called"; if (!checkParameterQuantity(node, 0, 20000+Token::PenUp*100+90)) return; emit penUp(); } void Executer::executePenDown(TreeNode* node) { // //qDebug() << "called"; if (!checkParameterQuantity(node, 0, 20000+Token::PenDown*100+90)) return; emit penDown(); } void Executer::executePenColor(TreeNode* node) { // //qDebug() << "called"; if (!checkParameterQuantity(node, 3, 20000+Token::PenColor*100+90) || !checkParameterType(node, Value::Number, 20000+Token::PenColor*100+91)) return; emit penColor(node->child(0)->value()->number(), node->child(1)->value()->number(), node->child(2)->value()->number()); } void Executer::executeCanvasColor(TreeNode* node) { // //qDebug() << "called"; if (!checkParameterQuantity(node, 3, 20000+Token::CanvasColor*100+90) || !checkParameterType(node, Value::Number, 20000+Token::CanvasColor*100+91)) return; emit canvasColor(node->child(0)->value()->number(), node->child(1)->value()->number(), node->child(2)->value()->number()); } void Executer::executeCanvasSize(TreeNode* node) { // //qDebug() << "called"; if (!checkParameterQuantity(node, 2, 20000+Token::CanvasSize*100+90) || !checkParameterType(node, Value::Number, 20000+Token::CanvasSize*100+91)) return; emit canvasSize(node->child(0)->value()->number(), node->child(1)->value()->number()); } void Executer::executeSpriteShow(TreeNode* node) { // //qDebug() << "called"; if (!checkParameterQuantity(node, 0, 20000+Token::SpriteShow*100+90)) return; emit spriteShow(); } void Executer::executeSpriteHide(TreeNode* node) { // //qDebug() << "called"; if (!checkParameterQuantity(node, 0, 20000+Token::SpriteHide*100+90)) return; emit spriteHide(); } void Executer::executePrint(TreeNode* node) { // //qDebug() << "called"; if (!checkParameterQuantity(node, 1, 20000+Token::Print*100+90)) return; // //qDebug() << "Printing: '" << node->child(0)->value()->string() << "'"; emit print(node->child(0)->value()->string()); } void Executer::executeFontSize(TreeNode* node) { // //qDebug() << "called"; if (!checkParameterQuantity(node, 1, 20000+Token::FontSize*100+90) || !checkParameterType(node, Value::Number, 20000+Token::FontSize*100+91)) return; emit fontSize(node->child(0)->value()->number()); } void Executer::executeRandom(TreeNode* node) { // //qDebug() << "called"; if (!checkParameterQuantity(node, 2, 20000+Token::Random*100+90)) return; TreeNode* nodeX = node->child(0); // getting TreeNode* nodeY = node->child(1); if (!checkParameterType(node, Value::Number, 20000+Token::Random*100+91)) return; double x = nodeX->value()->number(); double y = nodeY->value()->number(); double r = static_cast(KRandom::random()) / RAND_MAX; node->value()->setNumber(r * (y - x) + x); } void Executer::executeGetX(TreeNode* node) { // //qDebug() << "called"; if (!checkParameterQuantity(node, 0, 20000+Token::GetX*100+90)) return; double value = 0; emit getX(value); node->value()->setNumber(value); } void Executer::executeGetY(TreeNode* node) { // //qDebug() << "called"; if (!checkParameterQuantity(node, 0, 20000+Token::GetY*100+90)) return; double value = 0; emit getY(value); node->value()->setNumber(value); } void Executer::executeMessage(TreeNode* node) { // //qDebug() << "called"; if (!checkParameterQuantity(node, 1, 20000+Token::Message*100+90)) return; emit message(node->child(0)->value()->string()); } void Executer::executeAsk(TreeNode* node) { // //qDebug() << "called"; if (!checkParameterQuantity(node, 1, 20000+Token::Ask*100+90)) return; QString value = node->child(0)->value()->string(); emit ask(value); bool convertOk; double d = value.toDouble(&convertOk); if(convertOk) node->value()->setNumber(d); else node->value()->setString(value); } void Executer::executePi(TreeNode* node) { // //qDebug() << "called"; node->value()->setNumber(M_PI); } void Executer::executeTan(TreeNode* node) { // //qDebug() << "called"; if (!checkParameterQuantity(node, 1, 20000+Token::Tan*100+90)) return; double deg = node->child(0)->value()->number(); node->value()->setNumber(tan(qDegreesToRadians(deg))); } void Executer::executeSin(TreeNode* node) { // //qDebug() << "called"; if (!checkParameterQuantity(node, 1, 20000+Token::Sin*100+90)) return; double deg = node->child(0)->value()->number(); node->value()->setNumber(sin(qDegreesToRadians(deg))); } void Executer::executeCos(TreeNode* node) { // //qDebug() << "called"; if (!checkParameterQuantity(node, 1, 20000+Token::Cos*100+90)) return; double deg = node->child(0)->value()->number(); node->value()->setNumber(cos(qDegreesToRadians(deg))); } void Executer::executeArcTan(TreeNode* node) { // //qDebug() << "called"; if (!checkParameterQuantity(node, 1, 20000+Token::ArcTan*100+90)) return; double deg = node->child(0)->value()->number(); node->value()->setNumber(qRadiansToDegrees(atan(deg))); } void Executer::executeArcSin(TreeNode* node) { // //qDebug() << "called"; if (!checkParameterQuantity(node, 1, 20000+Token::ArcSin*100+90)) return; double deg = node->child(0)->value()->number(); node->value()->setNumber(qRadiansToDegrees(asin(deg))); } void Executer::executeArcCos(TreeNode* node) { // //qDebug() << "called"; if (!checkParameterQuantity(node, 1, 20000+Token::ArcCos*100+90)) return; double deg = node->child(0)->value()->number(); node->value()->setNumber(qRadiansToDegrees(acos(deg))); } void Executer::executeSqrt(TreeNode* node) { // //qDebug() << "called"; if (!checkParameterQuantity(node, 1, 20000+Token::Sqrt*100+90)) return; double val = node->child(0)->value()->number(); if(val<0) { addError(i18n("Can't do a sqrt of a negative number"), *node->child(0)->token(), 0); node->value()->setNumber(0); return; } node->value()->setNumber(sqrt(val)); } void Executer::executeRound(TreeNode* node) { // //qDebug() << "called"; if (!checkParameterQuantity(node, 1, 20000+Token::Round*100+90)) return; double val = node->child(0)->value()->number(); node->value()->setNumber(round(val)); } void Executer::executeGetDirection(TreeNode* node) { // //qDebug() << "called"; if (!checkParameterQuantity(node, 0, 20000+Token::GetDirection*100+90)) return; double value = 0; emit getDirection(value); node->value()->setNumber(value); } void Executer::executeMod(TreeNode* node) { // //qDebug() << "called"; if (!checkParameterQuantity(node, 2, 20000+Token::Mod*100+90)) return; TreeNode* nodeX = node->child(0); // getting TreeNode* nodeY = node->child(1); if (!checkParameterType(node, Value::Number, 20000+Token::Mod*100+91)) return; double x = nodeX->value()->number(); double y = nodeY->value()->number(); double m = (static_cast(round(x)) % static_cast(round(y))); node->value()->setNumber(m); } //END GENERATED executer_cpp CODE TreeNode* Executer::getParentOfTokenTypes(TreeNode* child, QList* types) { foreach(int type, *types) { if(child->parent()->token()->type()==type) return child->parent(); else if(child->parent()->token()->type()==Token::Root) return nullptr; } return getParentOfTokenTypes(child->parent(), types); } void Executer::printExe() { // if (currentNode->token()->type() != Token::Scope) // //qDebug() << "EXE> " << qPrintable(currentNode->token()->look()); } diff --git a/src/interpreter/gui_connect.inc b/src/interpreter/gui_connect.inc index 14678f6..0f527bb 100644 --- a/src/interpreter/gui_connect.inc +++ b/src/interpreter/gui_connect.inc @@ -1,83 +1,83 @@ /* Copyright (C) 2003-2006 Cies Breijs This program is free software; you can redistribute it and/or modify it under the terms of version 2 of the GNU General Public License as published by the Free Software Foundation. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ //BEGIN GENERATED gui_connect_inc CODE /* The code between the line that start with "//BEGIN GENERATED" and "//END GENERATED" * is generated by "generate.rb" according to the definitions specified in * "definitions.rb". Please make all changes in the "definitions.rb" file, since all * all change you make here will be overwritten the next time "generate.rb" is run. * Thanks for looking at the code! */ - connect(executer, SIGNAL(reset()), - canvas, SLOT(slotReset())); - connect(executer, SIGNAL(clear()), - canvas, SLOT(slotClear())); - connect(executer, SIGNAL(center()), - canvas, SLOT(slotCenter())); - connect(executer, SIGNAL(go(double, double)), - canvas, SLOT(slotGo(double, double))); - connect(executer, SIGNAL(goX(double)), - canvas, SLOT(slotGoX(double))); - connect(executer, SIGNAL(goY(double)), - canvas, SLOT(slotGoY(double))); - connect(executer, SIGNAL(forward(double)), - canvas, SLOT(slotForward(double))); - connect(executer, SIGNAL(backward(double)), - canvas, SLOT(slotBackward(double))); - connect(executer, SIGNAL(direction(double)), - canvas, SLOT(slotDirection(double))); - connect(executer, SIGNAL(turnLeft(double)), - canvas, SLOT(slotTurnLeft(double))); - connect(executer, SIGNAL(turnRight(double)), - canvas, SLOT(slotTurnRight(double))); - connect(executer, SIGNAL(penWidth(double)), - canvas, SLOT(slotPenWidth(double))); - connect(executer, SIGNAL(penUp()), - canvas, SLOT(slotPenUp())); - connect(executer, SIGNAL(penDown()), - canvas, SLOT(slotPenDown())); - connect(executer, SIGNAL(penColor(double, double, double)), - canvas, SLOT(slotPenColor(double, double, double))); - connect(executer, SIGNAL(canvasColor(double, double, double)), - canvas, SLOT(slotCanvasColor(double, double, double))); - connect(executer, SIGNAL(canvasSize(double, double)), - canvas, SLOT(slotCanvasSize(double, double))); - connect(executer, SIGNAL(spriteShow()), - canvas, SLOT(slotSpriteShow())); - connect(executer, SIGNAL(spriteHide()), - canvas, SLOT(slotSpriteHide())); - connect(executer, SIGNAL(print(const QString&)), - canvas, SLOT(slotPrint(const QString&))); - connect(executer, SIGNAL(fontSize(double)), - canvas, SLOT(slotFontSize(double))); + connect(executer, &Executer::reset, + canvas, &Canvas::slotReset); + connect(executer, &Executer::clear, + canvas, &Canvas::slotClear); + connect(executer, &Executer::center, + canvas, &Canvas::slotCenter); + connect(executer, &Executer::go, + canvas, &Canvas::slotGo); + connect(executer, &Executer::goX, + canvas, &Canvas::slotGoX); + connect(executer, &Executer::goY, + canvas, &Canvas::slotGoY); + connect(executer, &Executer::forward, + canvas, &Canvas::slotForward); + connect(executer, &Executer::backward, + canvas, &Canvas::slotBackward); + connect(executer, &Executer::direction, + canvas, &Canvas::slotDirection); + connect(executer, &Executer::turnLeft, + canvas, &Canvas::slotTurnLeft); + connect(executer, &Executer::turnRight, + canvas, &Canvas::slotTurnRight); + connect(executer, &Executer::penWidth, + canvas, &Canvas::slotPenWidth); + connect(executer, &Executer::penUp, + canvas, &Canvas::slotPenUp); + connect(executer, &Executer::penDown, + canvas, &Canvas::slotPenDown); + connect(executer, &Executer::penColor, + canvas, &Canvas::slotPenColor); + connect(executer, &Executer::canvasColor, + canvas, &Canvas::slotCanvasColor); + connect(executer, &Executer::canvasSize, + canvas, &Canvas::slotCanvasSize); + connect(executer, &Executer::spriteShow, + canvas, &Canvas::slotSpriteShow); + connect(executer, &Executer::spriteHide, + canvas, &Canvas::slotSpriteHide); + connect(executer, &Executer::print, + canvas, &Canvas::slotPrint); + connect(executer, &Executer::fontSize, + canvas, &Canvas::slotFontSize); //END GENERATED gui_connect_inc CODE - connect(executer, SIGNAL(getX(double&)), - canvas, SLOT(getX(double&))); - connect(executer, SIGNAL(getY(double&)), - canvas, SLOT(getY(double&))); - connect(executer, SIGNAL(getDirection(double&)), - canvas, SLOT(getDirection(double&))); - connect(executer, SIGNAL(message(const QString&)), - this, SLOT(slotMessageDialog(const QString&))); - connect(executer, SIGNAL(ask(QString&)), - this, SLOT(slotInputDialog(QString&))); + connect(executer, &Executer::getX, + canvas, &Canvas::getX); + connect(executer, &Executer::getY, + canvas, &Canvas::getY); + connect(executer, &Executer::getDirection, + canvas, &Canvas::getDirection); + connect(executer, &Executer::message, + this, &MainWindow::slotMessageDialog); + connect(executer, &Executer::ask, + this, &MainWindow::slotInputDialog); diff --git a/src/interpreter/interpreter.cpp b/src/interpreter/interpreter.cpp index be1dfd9..55e96e5 100644 --- a/src/interpreter/interpreter.cpp +++ b/src/interpreter/interpreter.cpp @@ -1,138 +1,138 @@ /* Copyright (C) 2003-2006 Cies Breijs This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "interpreter.h" #include "interpreteradaptor.h" #include #include #include #include "errormsg.h" #include "executer.h" #include "parser.h" #include "tokenizer.h" #include "translator.h" Interpreter::Interpreter(QObject* parent, bool testing) : QObject(parent), m_testing(testing) { if (testing) { new InterpreterAdaptor(this); QDBusConnection dbus = QDBusConnection::sessionBus(); - dbus.registerObject("/Interpreter", this); + dbus.registerObject(QStringLiteral("/Interpreter"), this); } errorList = new ErrorList(); tokenizer = new Tokenizer(); parser = new Parser(testing); executer = new Executer(testing); m_state = Uninitialized; } Interpreter::~Interpreter() { errorList->clear(); delete errorList; delete tokenizer; delete parser; delete executer; } void Interpreter::initialize(const QString& inString) { errorList->clear(); tokenizer->initialize(inString); m_state = Initialized; } void Interpreter::interpret() { switch (m_state) { case Uninitialized: qCritical("Interpreter::interpret(): called without being initialized"); return; case Initialized: parser->initialize(tokenizer, errorList); m_state = Parsing; // //qDebug() << "Initialized the parser, parsing the code..."; emit parsing(); break; case Parsing: parser->parse(); if (encounteredErrors()) { m_state = Aborted; // //qDebug() << "Error encountered while parsing:"; // const QStringList lines = errorList->asStringList(); // foreach (const QString &line, lines) //qDebug() << line; // //qDebug() << "Parsing was unsuccessful."; return; } if (parser->isFinished()) { // //qDebug() << "Finished parsing.\n"; TreeNode* tree = parser->getRootNode(); emit treeUpdated(tree); // //qDebug() << "Node tree as returned by parser:"; // parser->printTree(); // //qDebug() << ""; executer->initialize(tree, errorList); m_state = Executing; // //qDebug() << "Initialized the executer, executing the node tree..."; emit executing(); return; } break; case Executing: executer->execute(); if (executer->isFinished()) { // //qDebug() << "Finished executing.\n"; if (encounteredErrors()) { // //qDebug() << "Execution returned " << errorList->count() << " error(s):"; // const QStringList lines = errorList->asStringList(); // foreach (const QString &line, lines) // //qDebug() << line; } else { // //qDebug() << "No errors encountered."; } m_state = Finished; emit finished(); return; } break; case Finished: qCritical("Interpreter::interpret(): called while already finished"); return; } } diff --git a/src/interpreter/parser.cpp b/src/interpreter/parser.cpp index f92a94b..2f25263 100644 --- a/src/interpreter/parser.cpp +++ b/src/interpreter/parser.cpp @@ -1,991 +1,991 @@ /* Copyright (C) 2003-2006 Cies Breijs This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "parser.h" #include #include Parser::~Parser() { } void Parser::initialize(Tokenizer* _tokenizer, ErrorList* _errorList) { tokenizer = _tokenizer; errorList = _errorList; - rootNode = new TreeNode(new Token(Token::Root, "root", 0, 0, 0, 0)); + rootNode = new TreeNode(new Token(Token::Root, QStringLiteral("root"), 0, 0, 0, 0)); currentScope = rootNode; newScope = nullptr; finished = false; nextToken(); } void Parser::parse() { if (finished) return; // //qDebug() << "Parser::parse() -- main parse loop called"; TreeNode* resultNode = parseStatement(); // parse the next statement if (resultNode == nullptr) { // no statement was found addError(i18n("Expected a command, instead got '%1'", currentToken->look()), *currentToken, 0); return; } if (resultNode->token()->type() == Token::ScopeClose || resultNode->token()->type() == Token::EndOfInput) { delete resultNode; } else { currentScope->appendChild(resultNode); } if (newScope != nullptr) { currentScope = newScope; newScope = nullptr; } } void Parser::nextToken() { // get the next relevant token, and store it in currentToken // skip spaces and comments: currentToken = tokenizer->getToken(); // //qDebug() << "########### got token: " << currentToken->look(); while (currentToken->type() == Token::WhiteSpace || currentToken->type() == Token::Comment) { delete currentToken; currentToken = tokenizer->getToken(); // //qDebug() << "########### got token: " << currentToken->look(); } if (currentToken->type() == Token::Error) addError(i18n("Could not understand '%1'", currentToken->look()), *currentToken, 100); // QString out = QString("Parser::nextToken(): \"%5\" [%6] @ (%1,%2)-(%3,%4)") // .arg(currentToken->startRow()) // .arg(currentToken->startCol()) // .arg(currentToken->endRow()) // .arg(currentToken->endCol()) // .arg(currentToken->look()) // .arg(currentToken->type()); // //qDebug() << "Parser::nextToken():" << currentToken->look() << " [" << currentToken->type() << "] on line" << currentToken->startRow(); if (currentToken->type() == Token::EndOfInput) finished = true; } bool Parser::skipToken(int expectedTokenType) { // if the expectedTokenType matches the currentToken's type, dispose the currentToken and get a new one if (currentToken->type() == expectedTokenType) { delete currentToken; nextToken(); return true; } return false; } bool Parser::skipToken(int expectedTokenType, Token& byToken) { // TODO have byToken, and "errorHappenedHereToken" //TODO: Translate the following QStrings? if (skipToken(expectedTokenType)) return true; switch (expectedTokenType) { case Token::ArgumentSeparator: addError(i18n("A comma was expected here..."), byToken, 0); break; case Token::EndOfInput: addError(i18n("Did not expect '%1', instead expected the line to end after %2", currentToken->look(), byToken.look()), byToken, 0); break; case Token::Assign: addError(i18n("Expected an assignment, '=', after the variable '%1'", byToken.look()), byToken, 0); break; case Token::ParenthesisClose: addError(i18n("Did not expect '%1', instead expected a closing parenthesis, ')'", currentToken->look()), byToken, 0); break; case Token::To: addError(i18n("Expected 'to' after 'for'"), byToken, 0); break; case Token::FunctionCall: addError(i18n("Expected a name for a command after 'learn' command"), byToken, 0); break; } return false; } void Parser::addError(const QString& s, const Token& t, int code) { // if (m_testing) // //qDebug() << "ERR> " << qPrintable(s) << " (parse error)"; errorList->addError(s, t, code); } void Parser::printTree() const { const char* prefix = m_testing ? "NTR> " : ""; foreach (const QString &line, rootNode->toString().split('\n', QString::SkipEmptyParts)) { qDebug() << prefix << qPrintable(line.trimmed()); } } TreeNode* Parser::parseStatement() { // in addition to whitespace and comments (skipped by nextToken()), also skip newlines before statements while (currentToken->type() == Token::EndOfLine) { delete currentToken; nextToken(); } if (finished) return new TreeNode(currentToken); // TODO check if all scopes are closed before returning + throw error switch (currentToken->type()) { //BEGIN GENERATED parser_statements_cpp CODE /* The code between the line that start with "//BEGIN GENERATED" and "//END GENERATED" * is generated by "generate.rb" according to the definitions specified in * "definitions.rb". Please make all changes in the "definitions.rb" file, since all * all change you make here will be overwritten the next time "generate.rb" is run. * Thanks for looking at the code! */ case Token::Variable : return parseVariable(); case Token::FunctionCall : return parseFunctionCall(); case Token::ScopeOpen : return parseScopeOpen(); case Token::ScopeClose : return parseScopeClose(); case Token::Exit : return parseExit(); case Token::If : return parseIf(); case Token::Repeat : return parseRepeat(); case Token::While : return parseWhile(); case Token::For : return parseFor(); case Token::Break : return parseBreak(); case Token::Return : return parseReturn(); case Token::Wait : return parseWait(); case Token::Assert : return parseAssert(); case Token::Learn : return parseLearn(); case Token::Reset : return parseReset(); case Token::Clear : return parseClear(); case Token::Center : return parseCenter(); case Token::Go : return parseGo(); case Token::GoX : return parseGoX(); case Token::GoY : return parseGoY(); case Token::Forward : return parseForward(); case Token::Backward : return parseBackward(); case Token::Direction : return parseDirection(); case Token::TurnLeft : return parseTurnLeft(); case Token::TurnRight : return parseTurnRight(); case Token::PenWidth : return parsePenWidth(); case Token::PenUp : return parsePenUp(); case Token::PenDown : return parsePenDown(); case Token::PenColor : return parsePenColor(); case Token::CanvasColor : return parseCanvasColor(); case Token::CanvasSize : return parseCanvasSize(); case Token::SpriteShow : return parseSpriteShow(); case Token::SpriteHide : return parseSpriteHide(); case Token::Print : return parsePrint(); case Token::FontSize : return parseFontSize(); case Token::Random : return parseRandom(); case Token::GetX : return parseGetX(); case Token::GetY : return parseGetY(); case Token::Message : return parseMessage(); case Token::Ask : return parseAsk(); case Token::Pi : return parsePi(); case Token::Tan : return parseTan(); case Token::Sin : return parseSin(); case Token::Cos : return parseCos(); case Token::ArcTan : return parseArcTan(); case Token::ArcSin : return parseArcSin(); case Token::ArcCos : return parseArcCos(); case Token::Sqrt : return parseSqrt(); case Token::Round : return parseRound(); case Token::GetDirection : return parseGetDirection(); case Token::Mod : return parseMod(); //END GENERATED parser_statements_cpp CODE case Token::Error : return new TreeNode(currentToken); default : { //Token type is something else... ////qDebug() << "Parser::parseStatement(): I don't know this Token type."; ////qDebug() << "Look: " << currentToken->look() << " type: " << currentToken->type(); addError(i18n("You cannot put '%1' here.", currentToken->look()), *currentToken, 0); finished = true; return new TreeNode(currentToken); } } } TreeNode* Parser::parseFactor() { // //qDebug() << "Parser::parseFactor()"; Token* rememberedToken; TreeNode* node; switch (currentToken->type()) { case Token::ParenthesisOpen: rememberedToken = currentToken; nextToken(); node = parseExpression(); skipToken(Token::ParenthesisClose, *rememberedToken); break; case Token::FunctionCall: node = parseFunctionCall(); break; case Token::Variable: node = new TreeNode(currentToken); nextToken(); break; case Token::String: node = new TreeNode(currentToken); { // extra scope to localize the QString 'str' QString str = currentToken->look(); if (!currentToken->look().endsWith('\"')) { - str += "\""; + str += QLatin1String("\""); addError(i18n("Text string was not properly closed, expected a double quote, ' \" ', to close the string."), *currentToken, 0); } node->value()->setString(str.mid(1, str.length() - 2)); } nextToken(); break; case Token::Number: node = new TreeNode(currentToken); { bool ok = true; double num = currentToken->look().toDouble(&ok); if (ok) { node->value()->setNumber(num); nextToken(); } else { qCritical("Parser::parseFactor(): could not parse a number"); } } break; case Token::True: node = new TreeNode(currentToken); node->value()->setBool(true); nextToken(); break; case Token::False: node = new TreeNode(currentToken); node->value()->setBool(false); nextToken(); break; // case Token::Run: // node = ExternalRun(); // break; // // case tokInputWindow: // node = InputWindow(); // break; // // case tokRandom: // node = Random(); // break; // // case Token::EndOfLine: // node = new TreeNode(currentToken); // break; default: // TODO maybe precheck if this is a statement that returns something node = parseStatement(); break; // default: // QString s = currentToken->look(); // if ( s.isEmpty() || currentToken->type() == Token::EndOfInput ) // { // // Error(currentToken, i18n("INTERNAL ERROR NR %1: please sent this Logo script to KTurtle developers").arg(1), 1020); // // if this error occurs the see the Parser::Repeat for the good solution using 'preservedToken' // } // else // { // // Error(currentToken, i18n("Cannot understand '%1', expected an expression after the '%2' command").arg(s).arg(preservedToken->look()), 1020); // } // node = new TreeNode(currentToken); // nextToken(); // break; } return node; } TreeNode* Parser::parseSignedFactor() { // //qDebug() << "Parser::parseSignedFactor()"; // see if there is a plus, minus or 'not' in front of a factor Token* rememberedToken; TreeNode* node; switch (currentToken->type()) { case Token::Addition: nextToken(); return parseFactor(); break; case Token::Substracton: rememberedToken = currentToken; nextToken(); node = parseFactor(); if (node->token()->type() == Token::Number) { // in case of just a constant (-3) situation node->value()->setNumber(-1 * node->value()->number()); return node; } else { // in case of a variable or other situation (-$a) TreeNode* minusNode = new TreeNode(rememberedToken); minusNode->appendChild(node); return minusNode; } break; case Token::Not: rememberedToken = currentToken; nextToken(); node = parseFactor(); { // extra scope needed to localize not_Node TreeNode* notNode = new TreeNode(rememberedToken); notNode->appendChild(node); return notNode; } break; default: // no 'sign', no problem; just had to check if there was any... continue with the real work: return parseFactor(); break; } } TreeNode* Parser::parseTerm() { // //qDebug() << "Parser::parseTerm()"; TreeNode* termNode = parseSignedFactor(); TreeNode* pos = termNode; TreeNode* left = nullptr; TreeNode* right = nullptr; while ( (currentToken->type() == Token::Multiplication) || (currentToken->type() == Token::Division) || (currentToken->type() == Token::Power) ) { // while we find a multiplicative operator do... left = pos; pos = new TreeNode(currentToken); pos->appendChild(left); nextToken(); right = parseSignedFactor(); if (right != nullptr) pos->appendChild(right); termNode = pos; } return termNode; } TreeNode* Parser::parseExpression() { // //qDebug() << "Parser::parseExpression()"; TreeNode* expressionNode = parseTerm(); TreeNode* pos = expressionNode; TreeNode* left = nullptr; TreeNode* right = nullptr; Token* prevToken = nullptr; while ((currentToken->type() == Token::Addition) || (currentToken->type() == Token::Substracton) || (currentToken->type() == Token::GreaterThan) || (currentToken->type() == Token::GreaterOrEquals) || (currentToken->type() == Token::LessThan) || (currentToken->type() == Token::LessOrEquals) || (currentToken->type() == Token::Equals) || (currentToken->type() == Token::NotEquals) || (currentToken->type() == Token::Or) || (currentToken->type() == Token::And)) { left = pos; pos = new TreeNode(currentToken); pos->appendChild(left); prevToken = currentToken; nextToken(); if(prevToken->type() == Token::And || prevToken->type() == Token::Or) right = parseExpression(); else right = parseTerm(); if (right != nullptr) pos->appendChild(right); expressionNode = pos; } return expressionNode; } void Parser::appendArguments(TreeNode* node) { // appends the nodes of arguments to the node, does not do any type/quantity checking. // this because it's also used for the user defined 'functionCall' where we don't know type nor quantity // we also don't know if this node is (part of) an argument itself if (currentToken->type() == Token::EndOfLine || currentToken->type() == Token::EndOfInput || currentToken->type() == Token::ArgumentSeparator || currentToken->type() == Token::ParenthesisClose || currentToken->type() == Token::ScopeOpen || currentToken->type() == Token::ScopeClose) return; node->appendChild(parseExpression()); // append the first parameter while (skipToken(Token::ArgumentSeparator)) { // pushes through the comma if (currentToken->type() == Token::EndOfLine || currentToken->type() == Token::EndOfInput) return; // catch forgotten expressions (go 10,) node->appendChild(parseExpression()); } } //BEGIN GENERATED parser_cpp CODE /* The code between the line that start with "//BEGIN GENERATED" and "//END GENERATED" * is generated by "generate.rb" according to the definitions specified in * "definitions.rb". Please make all changes in the "definitions.rb" file, since all * all change you make here will be overwritten the next time "generate.rb" is run. * Thanks for looking at the code! */ TreeNode* Parser::parseVariable() { // This is called to the variable is the first token on a line. // There has to be an assignment token right after it... TreeNode* variableNode = new TreeNode(currentToken); nextToken(); Token* remeberedToken = new Token(*currentToken); skipToken(Token::Assign, *variableNode->token()); TreeNode* assignNode = new TreeNode(remeberedToken); assignNode->appendChild(variableNode); // the LHV; the symbol assignNode->appendChild(parseExpression()); // the RHV; the expression return assignNode; } TreeNode* Parser::parseFunctionCall() { TreeNode* node = new TreeNode(currentToken); node->token()->setType(Token::FunctionCall); nextToken(); appendArguments(node); return node; } TreeNode* Parser::parseScopeOpen() { - TreeNode* scopeNode = new TreeNode(new Token(Token::Scope, "{...}", currentToken->startRow(), currentToken->startCol(), 0, 0)); + TreeNode* scopeNode = new TreeNode(new Token(Token::Scope, QStringLiteral("{...}"), currentToken->startRow(), currentToken->startCol(), 0, 0)); delete currentToken; nextToken(); // cannot change the currentScope to this scope cauz we still have to work in the currentScope // so we set the newScope, which the currentScope will become after parsing the current statement newScope = scopeNode; return scopeNode; } TreeNode* Parser::parseScopeClose() { TreeNode* node = new TreeNode(currentToken); int endRow = currentToken->endRow(); int endCol = currentToken->endCol(); nextToken(); while (currentToken->type() == Token::EndOfLine) { // allow newlines before else delete currentToken; nextToken(); } if (currentScope->parent() && currentScope->parent()->token()->type() == Token::If && currentToken->type() == Token::Else) { currentScope->parent()->appendChild(parseElse()); } if (currentScope != rootNode) { // find the parent scope of this scope, and make it current TreeNode* parentScope = currentScope; do { parentScope = parentScope->parent(); } while (parentScope != rootNode && parentScope->token()->type() != Token::Scope); currentScope->token()->setEndRow(endRow); currentScope->token()->setEndCol(endCol); currentScope = parentScope; } return node; } TreeNode* Parser::parseExit() { TreeNode* node = new TreeNode(currentToken); nextToken(); skipToken(Token::EndOfLine, *node->token()); return node; } TreeNode* Parser::parseIf() { TreeNode* node = new TreeNode(currentToken); nextToken(); node->appendChild(parseExpression()); if (currentToken->type() == Token::ScopeOpen) { node->appendChild(parseScopeOpen()); // if followed by a scope } return node; } TreeNode* Parser::parseElse() { nextToken(); if (currentToken->type() == Token::ScopeOpen) { return parseScopeOpen(); // if followed by a scope } return parseStatement(); // if followed by single statement } TreeNode* Parser::parseRepeat() { TreeNode* node = new TreeNode(currentToken); nextToken(); node->appendChild(parseExpression()); if (currentToken->type() == Token::ScopeOpen) { node->appendChild(parseScopeOpen()); // if followed by a scope } else { node->appendChild(parseStatement()); // if followed by single statement } return node; } TreeNode* Parser::parseWhile() { TreeNode* node = new TreeNode(currentToken); nextToken(); node->appendChild(parseExpression()); if (currentToken->type() == Token::ScopeOpen) { node->appendChild(parseScopeOpen()); // if followed by a scope } else { node->appendChild(parseStatement()); // if followed by single statement } return node; } TreeNode* Parser::parseFor() { TreeNode* node = new TreeNode(currentToken); nextToken(); Token* firstToken = currentToken; nextToken(); if (firstToken->type() == Token::Variable && currentToken->type() == Token::Assign) { node->token()->setType(Token::ForTo); node->appendChild(new TreeNode(firstToken)); nextToken(); node->appendChild(parseExpression()); skipToken(Token::To, *node->token()); node->appendChild(parseExpression()); if (currentToken->type() == Token::Step) { nextToken(); node->appendChild(parseExpression()); } else { - TreeNode* step = new TreeNode(new Token(Token::Number, "1", 0,0,0,0)); + TreeNode* step = new TreeNode(new Token(Token::Number, QStringLiteral("1"), 0,0,0,0)); step->setValue(Value(1.0)); node->appendChild(step); } // } else if (currentToken->type() == Token::In) { // // @TODO something for a for-in loop } else { addError(i18n("'for' was called wrongly"), *node->token(), 0); finished = true; // abort after this error return node; } if (currentToken->type() == Token::ScopeOpen) { node->appendChild(parseScopeOpen()); // if followed by a scope } else { node->appendChild(parseStatement()); // if followed by single statement } return node; } TreeNode* Parser::parseBreak() { TreeNode* node = new TreeNode(currentToken); nextToken(); skipToken(Token::EndOfLine, *node->token()); return node; } TreeNode* Parser::parseReturn() { TreeNode* node = new TreeNode(currentToken); nextToken(); appendArguments(node); skipToken(Token::EndOfLine, *node->token()); return node; } TreeNode* Parser::parseWait() { TreeNode* node = new TreeNode(currentToken); nextToken(); appendArguments(node); skipToken(Token::EndOfLine, *node->token()); return node; } TreeNode* Parser::parseAssert() { TreeNode* node = new TreeNode(currentToken); nextToken(); appendArguments(node); skipToken(Token::EndOfLine, *node->token()); return node; } TreeNode* Parser::parseLearn() { TreeNode* node = new TreeNode(currentToken); nextToken(); node->appendChild(new TreeNode(new Token(*currentToken))); skipToken(Token::FunctionCall, *node->token()); - TreeNode* argumentList = new TreeNode(new Token(Token::ArgumentList, "arguments", 0, 0, 0, 0)); + TreeNode* argumentList = new TreeNode(new Token(Token::ArgumentList, QStringLiteral("arguments"), 0, 0, 0, 0)); while (currentToken->type() == Token::Variable) { // cannot just call appendArguments here because we're only appending Token::Variable tokens argumentList->appendChild(new TreeNode(currentToken)); nextToken(); if (currentToken->type() != Token::ArgumentSeparator) break; nextToken(); } node->appendChild(argumentList); //Skip all the following EndOfLine's while (currentToken->type() == Token::EndOfLine) { delete currentToken; nextToken(); } if (currentToken->type() == Token::ScopeOpen) { node->appendChild(parseScopeOpen()); // if followed by a scope } else { addError(i18n("Expected a scope after the 'learn' command"), *node->token(), 0); } return node; } TreeNode* Parser::parseReset() { TreeNode* node = new TreeNode(currentToken); nextToken(); skipToken(Token::EndOfLine, *node->token()); return node; } TreeNode* Parser::parseClear() { TreeNode* node = new TreeNode(currentToken); nextToken(); skipToken(Token::EndOfLine, *node->token()); return node; } TreeNode* Parser::parseCenter() { TreeNode* node = new TreeNode(currentToken); nextToken(); skipToken(Token::EndOfLine, *node->token()); return node; } TreeNode* Parser::parseGo() { TreeNode* node = new TreeNode(currentToken); nextToken(); appendArguments(node); skipToken(Token::EndOfLine, *node->token()); return node; } TreeNode* Parser::parseGoX() { TreeNode* node = new TreeNode(currentToken); nextToken(); appendArguments(node); skipToken(Token::EndOfLine, *node->token()); return node; } TreeNode* Parser::parseGoY() { TreeNode* node = new TreeNode(currentToken); nextToken(); appendArguments(node); skipToken(Token::EndOfLine, *node->token()); return node; } TreeNode* Parser::parseForward() { TreeNode* node = new TreeNode(currentToken); nextToken(); appendArguments(node); skipToken(Token::EndOfLine, *node->token()); return node; } TreeNode* Parser::parseBackward() { TreeNode* node = new TreeNode(currentToken); nextToken(); appendArguments(node); skipToken(Token::EndOfLine, *node->token()); return node; } TreeNode* Parser::parseDirection() { TreeNode* node = new TreeNode(currentToken); nextToken(); appendArguments(node); skipToken(Token::EndOfLine, *node->token()); return node; } TreeNode* Parser::parseTurnLeft() { TreeNode* node = new TreeNode(currentToken); nextToken(); appendArguments(node); skipToken(Token::EndOfLine, *node->token()); return node; } TreeNode* Parser::parseTurnRight() { TreeNode* node = new TreeNode(currentToken); nextToken(); appendArguments(node); skipToken(Token::EndOfLine, *node->token()); return node; } TreeNode* Parser::parsePenWidth() { TreeNode* node = new TreeNode(currentToken); nextToken(); appendArguments(node); skipToken(Token::EndOfLine, *node->token()); return node; } TreeNode* Parser::parsePenUp() { TreeNode* node = new TreeNode(currentToken); nextToken(); skipToken(Token::EndOfLine, *node->token()); return node; } TreeNode* Parser::parsePenDown() { TreeNode* node = new TreeNode(currentToken); nextToken(); skipToken(Token::EndOfLine, *node->token()); return node; } TreeNode* Parser::parsePenColor() { TreeNode* node = new TreeNode(currentToken); nextToken(); appendArguments(node); skipToken(Token::EndOfLine, *node->token()); return node; } TreeNode* Parser::parseCanvasColor() { TreeNode* node = new TreeNode(currentToken); nextToken(); appendArguments(node); skipToken(Token::EndOfLine, *node->token()); return node; } TreeNode* Parser::parseCanvasSize() { TreeNode* node = new TreeNode(currentToken); nextToken(); appendArguments(node); skipToken(Token::EndOfLine, *node->token()); return node; } TreeNode* Parser::parseSpriteShow() { TreeNode* node = new TreeNode(currentToken); nextToken(); skipToken(Token::EndOfLine, *node->token()); return node; } TreeNode* Parser::parseSpriteHide() { TreeNode* node = new TreeNode(currentToken); nextToken(); skipToken(Token::EndOfLine, *node->token()); return node; } TreeNode* Parser::parsePrint() { TreeNode* node = new TreeNode(currentToken); nextToken(); appendArguments(node); skipToken(Token::EndOfLine, *node->token()); return node; } TreeNode* Parser::parseFontSize() { TreeNode* node = new TreeNode(currentToken); nextToken(); appendArguments(node); skipToken(Token::EndOfLine, *node->token()); return node; } TreeNode* Parser::parseRandom() { TreeNode* node = new TreeNode(currentToken); nextToken(); appendArguments(node); skipToken(Token::EndOfLine, *node->token()); return node; } TreeNode* Parser::parseGetX() { TreeNode* node = new TreeNode(currentToken); nextToken(); skipToken(Token::EndOfLine, *node->token()); return node; } TreeNode* Parser::parseGetY() { TreeNode* node = new TreeNode(currentToken); nextToken(); skipToken(Token::EndOfLine, *node->token()); return node; } TreeNode* Parser::parseMessage() { TreeNode* node = new TreeNode(currentToken); nextToken(); appendArguments(node); skipToken(Token::EndOfLine, *node->token()); return node; } TreeNode* Parser::parseAsk() { TreeNode* node = new TreeNode(currentToken); nextToken(); appendArguments(node); skipToken(Token::EndOfLine, *node->token()); return node; } TreeNode* Parser::parsePi() { TreeNode* node = new TreeNode(currentToken); nextToken(); skipToken(Token::EndOfLine, *node->token()); return node; } TreeNode* Parser::parseTan() { TreeNode* node = new TreeNode(currentToken); nextToken(); appendArguments(node); skipToken(Token::EndOfLine, *node->token()); return node; } TreeNode* Parser::parseSin() { TreeNode* node = new TreeNode(currentToken); nextToken(); appendArguments(node); skipToken(Token::EndOfLine, *node->token()); return node; } TreeNode* Parser::parseCos() { TreeNode* node = new TreeNode(currentToken); nextToken(); appendArguments(node); skipToken(Token::EndOfLine, *node->token()); return node; } TreeNode* Parser::parseArcTan() { TreeNode* node = new TreeNode(currentToken); nextToken(); appendArguments(node); skipToken(Token::EndOfLine, *node->token()); return node; } TreeNode* Parser::parseArcSin() { TreeNode* node = new TreeNode(currentToken); nextToken(); appendArguments(node); skipToken(Token::EndOfLine, *node->token()); return node; } TreeNode* Parser::parseArcCos() { TreeNode* node = new TreeNode(currentToken); nextToken(); appendArguments(node); skipToken(Token::EndOfLine, *node->token()); return node; } TreeNode* Parser::parseSqrt() { TreeNode* node = new TreeNode(currentToken); nextToken(); appendArguments(node); skipToken(Token::EndOfLine, *node->token()); return node; } TreeNode* Parser::parseRound() { TreeNode* node = new TreeNode(currentToken); nextToken(); appendArguments(node); skipToken(Token::EndOfLine, *node->token()); return node; } TreeNode* Parser::parseGetDirection() { TreeNode* node = new TreeNode(currentToken); nextToken(); skipToken(Token::EndOfLine, *node->token()); return node; } TreeNode* Parser::parseMod() { TreeNode* node = new TreeNode(currentToken); nextToken(); appendArguments(node); skipToken(Token::EndOfLine, *node->token()); return node; } //END GENERATED parser_cpp CODE diff --git a/src/interpreter/token.cpp b/src/interpreter/token.cpp index 1185f6a..723a1fd 100644 --- a/src/interpreter/token.cpp +++ b/src/interpreter/token.cpp @@ -1,204 +1,204 @@ /* Copyright (C) 2003-2009 Cies Breijs This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "token.h" Token::Token() : _type(Token::NotSet), - _look(""), + _look(QLatin1String("")), _startRow(0), _startCol(0), _endRow(0), _endCol(0) { } Token::Token(int type, const QString& look, int startRow, int startCol, int endRow, int endCol) : _type(type), _look(look), _startRow(startRow), _startCol(startCol), _endRow(endRow), _endCol(endCol) { } bool Token::operator==(const Token& n) const { if (n.type() == _type || n.look() == _look || n.startRow() == _startRow || n.startCol() == _startCol || n.endRow() == _endRow || n.endCol() == _endCol) return true; return false; } Token& Token::operator=(const Token& n) { _type = n.type(); _look = n.look(); _startRow = n.startRow(); _startCol = n.startCol(); _endRow = n.endRow(); _endCol = n.endCol(); return *this; } int Token::typeToCategory(int type) { switch (type) { //BEGIN GENERATED token_switch_cpp CODE /* The code between the line that start with "//BEGIN GENERATED" and "//END GENERATED" * is generated by "generate.rb" according to the definitions specified in * "definitions.rb". Please make all changes in the "definitions.rb" file, since all * all change you make here will be overwritten the next time "generate.rb" is run. * Thanks for looking at the code! */ case Mod: case Sin: case GoX: case GoY: case FontSize: case GetDirection: case Cos: case CanvasColor: case Tan: case Backward: case CanvasSize: case TurnRight: case Pi: case Forward: case Message: case Random: case Sqrt: case Go: case ArcSin: case Ask: case Assert: case PenUp: case Print: case Clear: case ArcCos: case SpriteHide: case TurnLeft: case PenWidth: case Direction: case ArcTan: case SpriteShow: case Center: case Round: case GetX: case GetY: case PenColor: case PenDown: case Reset: return CommandCategory; case Else: case Break: case Return: case While: case Step: case For: case Wait: case ForTo: case Repeat: case To: case Exit: case If: return ControllerCommandCategory; case Number: return NumberCategory; case ParenthesisOpen: case ParenthesisClose: return ParenthesisCategory; case True: case False: return TrueFalseCategory; case FunctionCall: return FunctionCallCategory; case GreaterThan: case LessOrEquals: case Equals: case LessThan: case GreaterOrEquals: case NotEquals: return ExpressionCategory; case ArgumentSeparator: return ArgumentSeparatorCategory; case Power: case Substracton: case Multiplication: case Division: case Addition: return MathOperatorCategory; case Comment: return CommentCategory; case Assign: return AssignmentCategory; case Or: case And: case Not: return BooleanOperatorCategory; case Scope: case ScopeOpen: case ScopeClose: return ScopeCategory; case Variable: return VariableCategory; case StringDelimiter: case String: return StringCategory; case Learn: return LearnCommandCategory; //END GENERATED token_switch_cpp CODE } return UnknownCategory; } diff --git a/src/interpreter/tokenizer.cpp b/src/interpreter/tokenizer.cpp index e967e58..d0ff804 100644 --- a/src/interpreter/tokenizer.cpp +++ b/src/interpreter/tokenizer.cpp @@ -1,215 +1,215 @@ /* Copyright (C) 2003-2009 Cies Breijs This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "tokenizer.h" #include void Tokenizer::initialize(const QString& inString) { translator = Translator::instance(); inputString = inString + '\n'; // the certainty of a hard break at the end makes parsing much easier at = 0; row = 1; col = 1; prevCol = 1; atEnd = false; } Token* Tokenizer::getToken() { int startRow = row; int startCol = col; QChar c = getChar(); // get and store the next character from the string // catch the end of the input string if (atEnd) - return new Token(Token::EndOfInput, "END", row, col, row, col); + return new Token(Token::EndOfInput, QStringLiteral("END"), row, col, row, col); int cType = translator->look2type(c); // since we need to know it often we store it // catch spaces if (isSpace(c)) { QString look; do { look += (isTab(c) ? " " : " "); c = getChar(); } while (isSpace(c) && !atEnd); ungetChar(); return new Token(Token::WhiteSpace, look, startRow, startCol, row, col); } // catch EndOfLine's if (isBreak(c)) { - return new Token(Token::EndOfLine, "\\n", startRow, startCol, startRow+1, 1); + return new Token(Token::EndOfLine, QStringLiteral("\\n"), startRow, startCol, startRow+1, 1); } // catch comments if (cType == Token::Comment) { QString look; do { look += c; c = getChar(); } while (!isBreak(c) && !atEnd); ungetChar(); return new Token(Token::Comment, look, startRow, startCol, row, col); } // catch strings if (cType == Token::StringDelimiter) { QString look = QString(c); do { c = getChar(); look += c; - } while (!(translator->look2type(c) == Token::StringDelimiter && look.right(2) != "\\\"") && + } while (!(translator->look2type(c) == Token::StringDelimiter && look.right(2) != QLatin1String("\\\"")) && !isBreak(c) && !atEnd); return new Token(Token::String, look, startRow, startCol, row, col); } // catch variables if (cType == Token::VariablePrefix) { QString look; do { look += c; c = getChar(); } while (isWordChar(c) || c.category() == QChar::Number_DecimalDigit || c == '_'); ungetChar(); return new Token(Token::Variable, look, startRow, startCol, row, col); } // catch words (known commands or function calls) if (isWordChar(c)) { // first char has to be a letter QString look; do { look += c; c = getChar(); } while (isWordChar(c) || c.isDigit() || c == '_'); // next chars ungetChar(); int type = translator->look2type(look); if (type == Token::Unknown) type = Token::FunctionCall; return new Token(type, look, startRow, startCol, row, col); } // catch numbers if (c.isDigit() || cType == Token::DecimalSeparator) { bool hasDot = false; int localType = cType; QString look; do { if (localType == Token::DecimalSeparator) hasDot = true; look += c; c = getChar(); localType = translator->look2type(c); } while (c.isDigit() || (localType == Token::DecimalSeparator && !hasDot)); ungetChar(); // if all we got is a dot then this is not a number, so return an Error token here if (translator->look2type(look) == Token::DecimalSeparator) return new Token(Token::Error, look, startRow, startCol, row, col); return new Token(Token::Number, look, startRow, startCol, row, col); } // catch previously uncatched 'double charactered tokens' (tokens that ar not in letters, like: == != >= <=) { QString look = QString(c).append(getChar()); int type = translator->look2type(look); if (type != Token::Unknown) return new Token(type, look, startRow, startCol, row, col); ungetChar(); } // catch known tokens of a single character (as last...) if (cType != Token::Unknown) return new Token(cType, static_cast(c), startRow, startCol, row, col); // this does not neglect calls to functions with a name of length one (checked it) return new Token(Token::Error, static_cast(c), startRow, startCol, row, col); } QChar Tokenizer::getChar() { if (at >= inputString.size()) { atEnd = true; // //qDebug() << "Tokenizer::getChar() returns: a ZERO CHAR " << " @ " << at - 1; return QChar(); } QChar c(inputString.at(at)); at++; if (isBreak(c)) { row++; prevCol = col; col = 1; } else { col++; } // //qDebug() << "Tokenizer::getChar() returns: " << c << " (" << c.category() << ") " << " @ " << at - 1; return c; } void Tokenizer::ungetChar() { if (at <= 0) return; // do nothing when trying to go before the first character at--; if (atEnd) atEnd = false; QChar c(inputString.at(at)); if (isBreak(c)) { row--; col = prevCol; } else { col--; } } bool Tokenizer::isWordChar(const QChar& c) { // this method exists because some languages have non-letter category characters // mixed with their letter character to make words (like hindi) // NOTE: this has to be extended then languages give problems, // just add a category in the following test return (c.isLetter() || c.isMark()); } bool Tokenizer::isBreak(const QChar& c) { return (c == '\x0a' || c == '\n'); // c.category() == QChar::Other_Control // one of these also contains the tab (\t) // c.category() == QChar::Separator_Line // c.category() == QChar::Separator_Paragraph } bool Tokenizer::isSpace(const QChar& c) { return (c.category() == QChar::Separator_Space || c == ' ' || isTab(c)); } bool Tokenizer::isTab(const QChar& c) { return (c == '\x09' || c == '\t'); } diff --git a/src/interpreter/translator.cpp b/src/interpreter/translator.cpp index 9d469be..e772cd0 100644 --- a/src/interpreter/translator.cpp +++ b/src/interpreter/translator.cpp @@ -1,775 +1,775 @@ /* Copyright (C) 2003-2006 Cies Breijs This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "translator.h" #include #include "token.h" Translator* Translator::m_instance = nullptr; // initialize pointer Translator* Translator::instance() { if (m_instance == nullptr) m_instance = new Translator; // create sole instance if its the first call return m_instance; // address of sole instance } Translator::Translator() : localizer(QStringList() << DEFAULT_LANGUAGE_CODE) { } Translator::~Translator() { delete m_instance; m_instance = nullptr; } int Translator::look2type(QString& look) { if (look2typeMap.contains(look)) return look2typeMap[look]; return Token::Unknown; } int Translator::look2type(QChar& look) { if (look2typeMap.contains(static_cast(look))) return look2typeMap[static_cast(look)]; return Token::Unknown; } QList Translator::type2look(int type) { return look2typeMap.keys(type); } QHash > Translator::token2stringsMap() { QHash > resultMap; QList tokenList = look2typeMap.values(); foreach (int token, tokenList) resultMap.insert(token, look2typeMap.keys(token)); return resultMap; } bool Translator::setLanguage(const QString &lang_code) { // FIXME default to GUI language? return false when language not available? localizer = QStringList() << lang_code << DEFAULT_LANGUAGE_CODE; setDictionary(); setExamples(); return true; } void Translator::setDictionary() { look2typeMap.clear(); default2localizedMap.clear(); QString localizedCommandLook; //BEGIN GENERATED translator_cpp CODE /* The code between the line that start with "//BEGIN GENERATED" and "//END GENERATED" * is generated by "generate.rb" according to the definitions specified in * "definitions.rb". Please make all changes in the "definitions.rb" file, since all * all change you make here will be overwritten the next time "generate.rb" is run. * Thanks for looking at the code! */ - look2typeMap["$"] = Token::VariablePrefix; + look2typeMap[QStringLiteral("$")] = Token::VariablePrefix; localizedCommandLook = ki18nc( "You are about to translate the 'True' COMMAND, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "true").toString(localizer); - default2localizedMap["true"] = localizedCommandLook; + default2localizedMap[QStringLiteral("true")] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::True; localizedCommandLook = ki18nc( "You are about to translate the 'False' COMMAND, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "false").toString(localizer); - default2localizedMap["false"] = localizedCommandLook; + default2localizedMap[QStringLiteral("false")] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::False; - look2typeMap["#"] = Token::Comment; + look2typeMap[QStringLiteral("#")] = Token::Comment; - look2typeMap["\""] = Token::StringDelimiter; + look2typeMap[QStringLiteral("\"")] = Token::StringDelimiter; - look2typeMap["{"] = Token::ScopeOpen; + look2typeMap[QStringLiteral("{")] = Token::ScopeOpen; - look2typeMap["}"] = Token::ScopeClose; + look2typeMap[QStringLiteral("}")] = Token::ScopeClose; - look2typeMap["("] = Token::ParenthesisOpen; + look2typeMap[QStringLiteral("(")] = Token::ParenthesisOpen; - look2typeMap[")"] = Token::ParenthesisClose; + look2typeMap[QStringLiteral(")")] = Token::ParenthesisClose; localizedCommandLook = ki18nc( "You are about to translate the 'ArgumentSeparator' COMMAND, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", ",").toString(localizer); - default2localizedMap[","] = localizedCommandLook; + default2localizedMap[QStringLiteral(",")] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::ArgumentSeparator; localizedCommandLook = ki18nc( "You are about to translate the 'DecimalSeparator' COMMAND, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", ".").toString(localizer); - default2localizedMap["."] = localizedCommandLook; + default2localizedMap[QStringLiteral(".")] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::DecimalSeparator; localizedCommandLook = ki18nc( "You are about to translate the 'Exit' COMMAND, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "exit").toString(localizer); - default2localizedMap["exit"] = localizedCommandLook; + default2localizedMap[QStringLiteral("exit")] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::Exit; localizedCommandLook = ki18nc( "You are about to translate the 'If' COMMAND, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "if").toString(localizer); - default2localizedMap["if"] = localizedCommandLook; + default2localizedMap[QStringLiteral("if")] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::If; localizedCommandLook = ki18nc( "You are about to translate the 'Else' COMMAND, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "else").toString(localizer); - default2localizedMap["else"] = localizedCommandLook; + default2localizedMap[QStringLiteral("else")] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::Else; localizedCommandLook = ki18nc( "You are about to translate the 'Repeat' COMMAND, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "repeat").toString(localizer); - default2localizedMap["repeat"] = localizedCommandLook; + default2localizedMap[QStringLiteral("repeat")] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::Repeat; localizedCommandLook = ki18nc( "You are about to translate the 'While' COMMAND, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "while").toString(localizer); - default2localizedMap["while"] = localizedCommandLook; + default2localizedMap[QStringLiteral("while")] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::While; localizedCommandLook = ki18nc( "You are about to translate the 'For' COMMAND, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "for").toString(localizer); - default2localizedMap["for"] = localizedCommandLook; + default2localizedMap[QStringLiteral("for")] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::For; localizedCommandLook = ki18nc( "You are about to translate the 'To' COMMAND, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "to").toString(localizer); - default2localizedMap["to"] = localizedCommandLook; + default2localizedMap[QStringLiteral("to")] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::To; localizedCommandLook = ki18nc( "You are about to translate the 'Step' COMMAND, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "step").toString(localizer); - default2localizedMap["step"] = localizedCommandLook; + default2localizedMap[QStringLiteral("step")] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::Step; localizedCommandLook = ki18nc( "You are about to translate the 'Break' COMMAND, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "break").toString(localizer); - default2localizedMap["break"] = localizedCommandLook; + default2localizedMap[QStringLiteral("break")] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::Break; localizedCommandLook = ki18nc( "You are about to translate the 'Return' COMMAND, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "return").toString(localizer); - default2localizedMap["return"] = localizedCommandLook; + default2localizedMap[QStringLiteral("return")] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::Return; localizedCommandLook = ki18nc( "You are about to translate the 'Wait' COMMAND, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "wait").toString(localizer); - default2localizedMap["wait"] = localizedCommandLook; + default2localizedMap[QStringLiteral("wait")] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::Wait; localizedCommandLook = ki18nc( "You are about to translate the 'Assert' COMMAND, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "assert").toString(localizer); - default2localizedMap["assert"] = localizedCommandLook; + default2localizedMap[QStringLiteral("assert")] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::Assert; localizedCommandLook = ki18nc( "You are about to translate the 'And' COMMAND, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "and").toString(localizer); - default2localizedMap["and"] = localizedCommandLook; + default2localizedMap[QStringLiteral("and")] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::And; localizedCommandLook = ki18nc( "You are about to translate the 'Or' COMMAND, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "or").toString(localizer); - default2localizedMap["or"] = localizedCommandLook; + default2localizedMap[QStringLiteral("or")] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::Or; localizedCommandLook = ki18nc( "You are about to translate the 'Not' COMMAND, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "not").toString(localizer); - default2localizedMap["not"] = localizedCommandLook; + default2localizedMap[QStringLiteral("not")] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::Not; - look2typeMap["=="] = Token::Equals; + look2typeMap[QStringLiteral("==")] = Token::Equals; - look2typeMap["!="] = Token::NotEquals; + look2typeMap[QStringLiteral("!=")] = Token::NotEquals; - look2typeMap[">"] = Token::GreaterThan; + look2typeMap[QStringLiteral(">")] = Token::GreaterThan; - look2typeMap["<"] = Token::LessThan; + look2typeMap[QStringLiteral("<")] = Token::LessThan; - look2typeMap[">="] = Token::GreaterOrEquals; + look2typeMap[QStringLiteral(">=")] = Token::GreaterOrEquals; - look2typeMap["<="] = Token::LessOrEquals; + look2typeMap[QStringLiteral("<=")] = Token::LessOrEquals; - look2typeMap["+"] = Token::Addition; + look2typeMap[QStringLiteral("+")] = Token::Addition; - look2typeMap["-"] = Token::Substracton; + look2typeMap[QStringLiteral("-")] = Token::Substracton; - look2typeMap["*"] = Token::Multiplication; + look2typeMap[QStringLiteral("*")] = Token::Multiplication; - look2typeMap["/"] = Token::Division; + look2typeMap[QStringLiteral("/")] = Token::Division; - look2typeMap["^"] = Token::Power; + look2typeMap[QStringLiteral("^")] = Token::Power; - look2typeMap["="] = Token::Assign; + look2typeMap[QStringLiteral("=")] = Token::Assign; localizedCommandLook = ki18nc( "You are about to translate the 'Learn' COMMAND, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "learn").toString(localizer); - default2localizedMap["learn"] = localizedCommandLook; + default2localizedMap[QStringLiteral("learn")] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::Learn; localizedCommandLook = ki18nc( "You are about to translate the 'Reset' COMMAND, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "reset").toString(localizer); - default2localizedMap["reset"] = localizedCommandLook; + default2localizedMap[QStringLiteral("reset")] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::Reset; localizedCommandLook = ki18nc( "You are about to translate the 'Clear' COMMAND, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "clear").toString(localizer); - default2localizedMap["clear"] = localizedCommandLook; + default2localizedMap[QStringLiteral("clear")] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::Clear; localizedCommandLook = ki18nc( "You are about to translate the 'Clear' COMMAND ALIAS, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "ccl").toString(localizer); - default2localizedMap["ccl"] = localizedCommandLook; + default2localizedMap[QStringLiteral("ccl")] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::Clear; localizedCommandLook = ki18nc( "You are about to translate the 'Center' COMMAND, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "center").toString(localizer); - default2localizedMap["center"] = localizedCommandLook; + default2localizedMap[QStringLiteral("center")] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::Center; localizedCommandLook = ki18nc( "You are about to translate the 'Go' COMMAND, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "go").toString(localizer); - default2localizedMap["go"] = localizedCommandLook; + default2localizedMap[QStringLiteral("go")] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::Go; localizedCommandLook = ki18nc( "You are about to translate the 'GoX' COMMAND, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "gox").toString(localizer); - default2localizedMap["gox"] = localizedCommandLook; + default2localizedMap[QStringLiteral("gox")] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::GoX; localizedCommandLook = ki18nc( "You are about to translate the 'GoX' COMMAND ALIAS, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "gx").toString(localizer); - default2localizedMap["gx"] = localizedCommandLook; + default2localizedMap[QStringLiteral("gx")] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::GoX; localizedCommandLook = ki18nc( "You are about to translate the 'GoY' COMMAND, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "goy").toString(localizer); - default2localizedMap["goy"] = localizedCommandLook; + default2localizedMap[QStringLiteral("goy")] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::GoY; localizedCommandLook = ki18nc( "You are about to translate the 'GoY' COMMAND ALIAS, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "gy").toString(localizer); - default2localizedMap["gy"] = localizedCommandLook; + default2localizedMap[QStringLiteral("gy")] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::GoY; localizedCommandLook = ki18nc( "You are about to translate the 'Forward' COMMAND, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "forward").toString(localizer); - default2localizedMap["forward"] = localizedCommandLook; + default2localizedMap[QStringLiteral("forward")] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::Forward; localizedCommandLook = ki18nc( "You are about to translate the 'Forward' COMMAND ALIAS, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "fw").toString(localizer); - default2localizedMap["fw"] = localizedCommandLook; + default2localizedMap[QStringLiteral("fw")] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::Forward; localizedCommandLook = ki18nc( "You are about to translate the 'Backward' COMMAND, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "backward").toString(localizer); - default2localizedMap["backward"] = localizedCommandLook; + default2localizedMap[QStringLiteral("backward")] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::Backward; localizedCommandLook = ki18nc( "You are about to translate the 'Backward' COMMAND ALIAS, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "bw").toString(localizer); - default2localizedMap["bw"] = localizedCommandLook; + default2localizedMap[QStringLiteral("bw")] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::Backward; localizedCommandLook = ki18nc( "You are about to translate the 'Direction' COMMAND, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "direction").toString(localizer); - default2localizedMap["direction"] = localizedCommandLook; + default2localizedMap[QStringLiteral("direction")] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::Direction; localizedCommandLook = ki18nc( "You are about to translate the 'Direction' COMMAND ALIAS, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "dir").toString(localizer); - default2localizedMap["dir"] = localizedCommandLook; + default2localizedMap[QStringLiteral("dir")] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::Direction; localizedCommandLook = ki18nc( "You are about to translate the 'TurnLeft' COMMAND, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "turnleft").toString(localizer); - default2localizedMap["turnleft"] = localizedCommandLook; + default2localizedMap[QStringLiteral("turnleft")] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::TurnLeft; localizedCommandLook = ki18nc( "You are about to translate the 'TurnLeft' COMMAND ALIAS, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "tl").toString(localizer); - default2localizedMap["tl"] = localizedCommandLook; + default2localizedMap[QStringLiteral("tl")] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::TurnLeft; localizedCommandLook = ki18nc( "You are about to translate the 'TurnRight' COMMAND, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "turnright").toString(localizer); - default2localizedMap["turnright"] = localizedCommandLook; + default2localizedMap[QStringLiteral("turnright")] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::TurnRight; localizedCommandLook = ki18nc( "You are about to translate the 'TurnRight' COMMAND ALIAS, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "tr").toString(localizer); - default2localizedMap["tr"] = localizedCommandLook; + default2localizedMap[QStringLiteral("tr")] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::TurnRight; localizedCommandLook = ki18nc( "You are about to translate the 'PenWidth' COMMAND, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "penwidth").toString(localizer); - default2localizedMap["penwidth"] = localizedCommandLook; + default2localizedMap[QStringLiteral("penwidth")] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::PenWidth; localizedCommandLook = ki18nc( "You are about to translate the 'PenWidth' COMMAND ALIAS, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "pw").toString(localizer); - default2localizedMap["pw"] = localizedCommandLook; + default2localizedMap[QStringLiteral("pw")] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::PenWidth; localizedCommandLook = ki18nc( "You are about to translate the 'PenUp' COMMAND, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "penup").toString(localizer); - default2localizedMap["penup"] = localizedCommandLook; + default2localizedMap[QStringLiteral("penup")] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::PenUp; localizedCommandLook = ki18nc( "You are about to translate the 'PenUp' COMMAND ALIAS, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "pu").toString(localizer); - default2localizedMap["pu"] = localizedCommandLook; + default2localizedMap[QStringLiteral("pu")] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::PenUp; localizedCommandLook = ki18nc( "You are about to translate the 'PenDown' COMMAND, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "pendown").toString(localizer); - default2localizedMap["pendown"] = localizedCommandLook; + default2localizedMap[QStringLiteral("pendown")] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::PenDown; localizedCommandLook = ki18nc( "You are about to translate the 'PenDown' COMMAND ALIAS, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "pd").toString(localizer); - default2localizedMap["pd"] = localizedCommandLook; + default2localizedMap[QStringLiteral("pd")] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::PenDown; localizedCommandLook = ki18nc( "You are about to translate the 'PenColor' COMMAND, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "pencolor").toString(localizer); - default2localizedMap["pencolor"] = localizedCommandLook; + default2localizedMap[QStringLiteral("pencolor")] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::PenColor; localizedCommandLook = ki18nc( "You are about to translate the 'PenColor' COMMAND ALIAS, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "pc").toString(localizer); - default2localizedMap["pc"] = localizedCommandLook; + default2localizedMap[QStringLiteral("pc")] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::PenColor; localizedCommandLook = ki18nc( "You are about to translate the 'CanvasColor' COMMAND, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "canvascolor").toString(localizer); - default2localizedMap["canvascolor"] = localizedCommandLook; + default2localizedMap[QStringLiteral("canvascolor")] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::CanvasColor; localizedCommandLook = ki18nc( "You are about to translate the 'CanvasColor' COMMAND ALIAS, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "cc").toString(localizer); - default2localizedMap["cc"] = localizedCommandLook; + default2localizedMap[QStringLiteral("cc")] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::CanvasColor; localizedCommandLook = ki18nc( "You are about to translate the 'CanvasSize' COMMAND, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "canvassize").toString(localizer); - default2localizedMap["canvassize"] = localizedCommandLook; + default2localizedMap[QStringLiteral("canvassize")] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::CanvasSize; localizedCommandLook = ki18nc( "You are about to translate the 'CanvasSize' COMMAND ALIAS, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "cs").toString(localizer); - default2localizedMap["cs"] = localizedCommandLook; + default2localizedMap[QStringLiteral("cs")] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::CanvasSize; localizedCommandLook = ki18nc( "You are about to translate the 'SpriteShow' COMMAND, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "spriteshow").toString(localizer); - default2localizedMap["spriteshow"] = localizedCommandLook; + default2localizedMap[QStringLiteral("spriteshow")] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::SpriteShow; localizedCommandLook = ki18nc( "You are about to translate the 'SpriteShow' COMMAND ALIAS, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "ss").toString(localizer); - default2localizedMap["ss"] = localizedCommandLook; + default2localizedMap[QStringLiteral("ss")] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::SpriteShow; localizedCommandLook = ki18nc( "You are about to translate the 'SpriteHide' COMMAND, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "spritehide").toString(localizer); - default2localizedMap["spritehide"] = localizedCommandLook; + default2localizedMap[QStringLiteral("spritehide")] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::SpriteHide; localizedCommandLook = ki18nc( "You are about to translate the 'SpriteHide' COMMAND ALIAS, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "sh").toString(localizer); - default2localizedMap["sh"] = localizedCommandLook; + default2localizedMap[QStringLiteral("sh")] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::SpriteHide; localizedCommandLook = ki18nc( "You are about to translate the 'Print' COMMAND, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "print").toString(localizer); - default2localizedMap["print"] = localizedCommandLook; + default2localizedMap[QStringLiteral("print")] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::Print; localizedCommandLook = ki18nc( "You are about to translate the 'FontSize' COMMAND, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "fontsize").toString(localizer); - default2localizedMap["fontsize"] = localizedCommandLook; + default2localizedMap[QStringLiteral("fontsize")] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::FontSize; localizedCommandLook = ki18nc( "You are about to translate the 'Random' COMMAND, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "random").toString(localizer); - default2localizedMap["random"] = localizedCommandLook; + default2localizedMap[QStringLiteral("random")] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::Random; localizedCommandLook = ki18nc( "You are about to translate the 'Random' COMMAND ALIAS, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "rnd").toString(localizer); - default2localizedMap["rnd"] = localizedCommandLook; + default2localizedMap[QStringLiteral("rnd")] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::Random; localizedCommandLook = ki18nc( "You are about to translate the 'GetX' COMMAND, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "getx").toString(localizer); - default2localizedMap["getx"] = localizedCommandLook; + default2localizedMap[QStringLiteral("getx")] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::GetX; localizedCommandLook = ki18nc( "You are about to translate the 'GetY' COMMAND, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "gety").toString(localizer); - default2localizedMap["gety"] = localizedCommandLook; + default2localizedMap[QStringLiteral("gety")] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::GetY; localizedCommandLook = ki18nc( "You are about to translate the 'Message' COMMAND, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "message").toString(localizer); - default2localizedMap["message"] = localizedCommandLook; + default2localizedMap[QStringLiteral("message")] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::Message; localizedCommandLook = ki18nc( "You are about to translate the 'Ask' COMMAND, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "ask").toString(localizer); - default2localizedMap["ask"] = localizedCommandLook; + default2localizedMap[QStringLiteral("ask")] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::Ask; localizedCommandLook = ki18nc( "You are about to translate the 'Pi' COMMAND, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "pi").toString(localizer); - default2localizedMap["pi"] = localizedCommandLook; + default2localizedMap[QStringLiteral("pi")] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::Pi; localizedCommandLook = ki18nc( "You are about to translate the 'Tan' COMMAND, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "tan").toString(localizer); - default2localizedMap["tan"] = localizedCommandLook; + default2localizedMap[QStringLiteral("tan")] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::Tan; localizedCommandLook = ki18nc( "You are about to translate the 'Sin' COMMAND, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "sin").toString(localizer); - default2localizedMap["sin"] = localizedCommandLook; + default2localizedMap[QStringLiteral("sin")] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::Sin; localizedCommandLook = ki18nc( "You are about to translate the 'Cos' COMMAND, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "cos").toString(localizer); - default2localizedMap["cos"] = localizedCommandLook; + default2localizedMap[QStringLiteral("cos")] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::Cos; localizedCommandLook = ki18nc( "You are about to translate the 'ArcTan' COMMAND, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "arctan").toString(localizer); - default2localizedMap["arctan"] = localizedCommandLook; + default2localizedMap[QStringLiteral("arctan")] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::ArcTan; localizedCommandLook = ki18nc( "You are about to translate the 'ArcSin' COMMAND, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "arcsin").toString(localizer); - default2localizedMap["arcsin"] = localizedCommandLook; + default2localizedMap[QStringLiteral("arcsin")] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::ArcSin; localizedCommandLook = ki18nc( "You are about to translate the 'ArcCos' COMMAND, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "arccos").toString(localizer); - default2localizedMap["arccos"] = localizedCommandLook; + default2localizedMap[QStringLiteral("arccos")] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::ArcCos; localizedCommandLook = ki18nc( "You are about to translate the 'Sqrt' COMMAND, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "sqrt").toString(localizer); - default2localizedMap["sqrt"] = localizedCommandLook; + default2localizedMap[QStringLiteral("sqrt")] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::Sqrt; localizedCommandLook = ki18nc( "You are about to translate the 'Round' COMMAND, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "round").toString(localizer); - default2localizedMap["round"] = localizedCommandLook; + default2localizedMap[QStringLiteral("round")] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::Round; localizedCommandLook = ki18nc( "You are about to translate the 'GetDirection' COMMAND, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "getdirection").toString(localizer); - default2localizedMap["getdirection"] = localizedCommandLook; + default2localizedMap[QStringLiteral("getdirection")] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::GetDirection; localizedCommandLook = ki18nc( "You are about to translate the 'Mod' COMMAND, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "mod").toString(localizer); - default2localizedMap["mod"] = localizedCommandLook; + default2localizedMap[QStringLiteral("mod")] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::Mod; //END GENERATED translator_cpp CODE } void Translator::setExamples() { examples.clear(); QString exampleName; exampleName = ki18nc( "This is an EXAMPLE NAME in KTurtle." "Please see http://edu.kde.org/kturtle/translator.php to learn know how to properly translate it.", "triangle").toString(localizer); examples[exampleName] = localizeScript(QString( "@(reset)\n" "@(repeat) 3 {\n" " @(forward) 100\n" " @(turnleft) 120\n" "}\n" )); exampleName = ki18nc( "This is an EXAMPLE NAME in KTurtle." "Please see http://edu.kde.org/kturtle/translator.php to learn know how to properly translate it.", "curly").toString(localizer); examples[exampleName] = localizeScript(QString( "@(reset)\n" "@(penup)\n" "@(forward) 50\n" "@(pendown)\n" "\n" "@(repeat) 4 {\n" " @(for) $x = 1 @(to) 100 {\n" " @(forward) 10\n" " @(turnright) 100 - $x\n" " }\n" "}\n" )); exampleName = ki18nc( "This is an EXAMPLE NAME in KTurtle." "Please see http://edu.kde.org/kturtle/translator.php to learn know how to properly translate it.", "arrow").toString(localizer); examples[exampleName] = localizeScript(QString( "@(reset)\n" "\n" "@(canvassize) 200@(,) 200\n" "@(canvascolor) 0@(,) 0@(,) 0\n" "@(pencolor) 255@(,) 0@(,) 0\n" "@(penwidth) 5\n" "\n" "@(go) 20@(,)20\n" "@(direction) 135\n" "\n" "@(forward) 200\n" "@(turnleft) 135\n" "@(forward) 100\n" "@(turnleft) 135\n" "@(forward) 141\n" "@(turnleft) 135\n" "@(forward) 100\n" "@(turnleft) 45\n" "\n" "@(go) 40@(,) 100" )); exampleName = ki18nc( "This is an EXAMPLE NAME in KTurtle." "Please see http://edu.kde.org/kturtle/translator.php to learn know how to properly translate it.", "flower").toString(localizer); examples[exampleName] = localizeScript(QString( "@(reset)\n" "@(canvascolor) 255@(,) 55@(,) 140\n" "@(pencolor) 160@(,) 0@(,) 255\n" "@(penwidth) 3\n" "\n" "@(repeat) 8 {\n" " @(repeat) 4 {\n" " @(forward) 20\n" " @(turnright) 30\n" " }\n" " @(repeat) 7 {\n" " @(forward) 10\n" " @(turnright) 15\n" " }\n" " @(repeat) 9 {\n" " @(forward) 3\n" " @(turnright) 10\n" " }\n" "}\n" "\n" "@(go) 145@(,) 145\n" "@(direction) 0" )); } QString Translator::localizeScript(const QString& untranslatedScript) { QString result = untranslatedScript; Translator* translator = Translator::instance(); QRegExp rx("@\\(.*\\)"); rx.setMinimal(true); // make it not greedy int pos = 0; while ((pos = rx.indexIn(result, pos)) != -1) { QString original = result.mid(pos, rx.matchedLength()); original = original.mid(2, original.length() - 3); result = result.replace(pos, rx.matchedLength(), translator->default2localized(original)); } return result; } diff --git a/src/interpreter/treenode.cpp b/src/interpreter/treenode.cpp index d103c07..9f43a2a 100644 --- a/src/interpreter/treenode.cpp +++ b/src/interpreter/treenode.cpp @@ -1,134 +1,134 @@ /* Copyright (C) 2003-2006 Cies Breijs This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "treenode.h" #include TreeNode::~TreeNode() { if (childList != nullptr) { // this should work here: qDeleteAll(*childList); childList->clear(); // but this is nicer (and probably less optimal): // while (!list.isEmpty()) delete list.takeFirst(); } delete _value; delete _token; } void TreeNode::init(TreeNode* parent, Token* token) { setParent(parent); setToken(token); childList = nullptr; currentChildIndex = -1; _value = nullptr; } void TreeNode::appendChild(TreeNode* newChild) { if (childList == nullptr) childList = new ChildList(); newChild->setParent(this); childList->append(newChild); // // // QString out = QString("TreeNode::appendChild(): \"%5\" [%6] @ (%1,%2)-(%3,%4) to parent '%7'") // // // .arg(newChild->token()->startRow()) // // // .arg(newChild->token()->startCol()) // // // .arg(newChild->token()->endRow()) // // // .arg(newChild->token()->endCol()) // // // .arg(newChild->token()->look()) // // // .arg(newChild->token()->type()) // // // .arg(_token->look()); // //qDebug() << "TreeNode::appendChild():" << newChild->token()->look() << " on line" << newChild->token()->startRow() << "to parent" << _token->look(); } TreeNode* TreeNode::child(int i) { if (childList == nullptr) return nullptr; if (0 <= i && i < childList->size()) return childList->at(i); return nullptr; } TreeNode* TreeNode::firstChild() { if (childList == nullptr || childList->isEmpty()) return nullptr; currentChildIndex = 0; return childList->first(); } TreeNode* TreeNode::nextChild() { if (childList == nullptr) return nullptr; currentChildIndex++; return child(currentChildIndex); } int TreeNode::findChildIndex(TreeNode* child) { return childList->indexOf(child); } TreeNode* TreeNode::nextSibling() { if (_parent == nullptr) return nullptr; return _parent->child(_parent->findChildIndex(this)+1); } QString TreeNode::toString() { - QString str = ""; + QString str = QLatin1String(""); showTree(str); return str; } // recursively walk through tree and show node names with indentation void TreeNode::showTree(QString& str, int indent) { if (childList == nullptr) return; indent++; TreeNode* node; for (int i = 0; i < childList->size(); i++) { node = childList->at(i); node->show(str, indent); node->showTree(str, indent); } } void TreeNode::show(QString& str, int indent) const { - QString indentString = ""; - for (int i = 0; i < indent; i++) indentString += "> "; - str += indentString + _token->look() + QString(" @ (%1, %2)-(%3, %4)\n") + QString indentString = QLatin1String(""); + for (int i = 0; i < indent; i++) indentString += QLatin1String("> "); + str += indentString + _token->look() + QStringLiteral(" @ (%1, %2)-(%3, %4)\n") .arg(_token->startRow()) .arg(_token->startCol()) .arg(_token->endRow()) .arg(_token->endCol()); } diff --git a/src/interpreter/value.cpp b/src/interpreter/value.cpp index feed7ab..e89b1ed 100644 --- a/src/interpreter/value.cpp +++ b/src/interpreter/value.cpp @@ -1,317 +1,317 @@ /* Copyright (C) 2003-2006 Cies Breijs This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "value.h" #include //#include #include "translator.h" // for the boolean (true and false) to string translation Value::Value() { init(); } Value::Value(Value* n) : m_type(n->type()), m_bool(n->boolean()), m_double(n->number()), m_string(n->string()) { } void Value::setType(int newType) // maybe someday we have to do some type casting logic here { if (m_type == newType) { return; // don't change values when type is not changing } else { switch (newType) { case Value::Bool: init(); m_type = newType; break; case Value::Number: init(); m_type = newType; break; case Value::String: init(); m_type = newType; break; case Value::Empty: init(); break; } } } bool Value::boolean() const { switch (m_type) { case Value::Bool: return m_bool; case Value::Empty: return false; case Value::Number: return (m_double==0 ? false : true); } return true; // numbers and strings } void Value::setBool(bool b) { m_type = Value::Bool; m_bool = b; } double Value::number() const { switch (m_type) { case Value::Bool: return (m_bool ? 1 : 0); case Value::Number: return m_double; case Value::String: bool ok = true; double num = m_string.toDouble(&ok); if (ok) return num; } return 0; // Value::String, Value::Empty } void Value::setNumber(double d) { m_type = Value::Number; m_double = d; } bool Value::setNumber(const QString &s) { m_type = Value::Number; bool ok = true; double num = s.toDouble(&ok); if (ok) { m_double = num; return true; } m_double = 0; return false; } QString Value::string() const { if (m_type == Value::Bool) { if (m_bool) - return QString(Translator::instance()->default2localized("true")); + return QString(Translator::instance()->default2localized(QStringLiteral("true"))); else - return QString(Translator::instance()->default2localized("false")); + return QString(Translator::instance()->default2localized(QStringLiteral("false"))); } else if (m_type == Value::Number) { QString s; s.setNum(m_double); return s; } return m_string; // Value::String, Value::Empty } void Value::setString(double d) { m_type = Value::String; m_double = d; m_string.setNum(d); } void Value::setString(const QString &s) { m_type = Value::String; m_string = s; } Value& Value::operator=(Value* n) { switch (n->type()) { case Value::Bool: setBool(n->boolean()); break; case Value::Number: setNumber(n->number()); break; case Value::String: setString(n->string()); break; case Value::Empty: init(); break; default: init(); break; } return *this; } Value& Value::operator=(const QString& s) { setString(s); return *this; } Value& Value::operator=(double n) { setNumber(n); return *this; } Value& Value::operator+(Value* n) { if (m_type == Value::Number && n->type() == Value::Number) { m_double += n->number(); } else { m_type = Value::String; m_string = string() + n->string(); } return *this; } Value& Value::operator-(Value* n) { if (m_type == Value::Number && n->type() == Value::Number) { m_double -= n->number(); } else { //qDebug() << "cannot subtract strings" << endl; } return *this; } Value& Value::operator*(Value* n) { if (m_type == Value::Number && n->type() == Value::Number) { m_double *= n->number(); } else { //qDebug() << "cannot multiply strings" << endl; } return *this; } Value& Value::operator/(Value* n) { if (m_type == Value::Number && n->type() == Value::Number) { m_double /= n->number(); } else { //qDebug() << "cannot divide strings" << endl; } return *this; } bool Value::operator==(Value* n) const { if (m_type == Value::Bool && n->type() == Value::Bool) return m_bool == n->boolean(); if (m_type == Value::Number && n->type() == Value::Number) return m_double == n->number(); if (m_type == Value::String && n->type() == Value::String) return m_string == n->string(); if (m_type == Value::Empty && n->type() == Value::Empty) return true; return false; } bool Value::operator!=(Value* n) const { if (m_type == Value::Bool && n->type() == Value::Bool) return m_bool != n->boolean(); if (m_type == Value::Number && n->type() == Value::Number) return m_double != n->number(); if (m_type == Value::String && n->type() == Value::String) return m_string != n->string(); // if (m_type == Value::Empty && n->type() == Value::Empty) return false; return false; } bool Value::operator<(Value* n) const { if (m_type == Value::Bool && n->type() == Value::Bool) return m_bool < n->boolean(); if (m_type == Value::Number && n->type() == Value::Number) return m_double < n->number(); if (m_type == Value::String && n->type() == Value::String) return m_string.length() < n->string().length(); // if (m_type == Value::Empty && n->type() == Value::Empty) return false; return false; } bool Value::operator<=(Value* n) const { if (m_type == Value::Bool && n->type() == Value::Bool) return m_bool <= n->boolean(); if (m_type == Value::Number && n->type() == Value::Number) return m_double <= n->number(); if (m_type == Value::String && n->type() == Value::String) return m_string.length() <= n->string().length(); if (m_type == Value::Empty && n->type() == Value::Empty) return true; return false; } bool Value::operator>(Value* n) const { if (m_type == Value::Bool && n->type() == Value::Bool) return m_bool > n->boolean(); if (m_type == Value::Number && n->type() == Value::Number) return m_double > n->number(); if (m_type == Value::String && n->type() == Value::String) return m_string.length() > n->string().length(); // if (m_type == Value::Empty && n->type() == Value::Empty) return false; return false; } bool Value::operator>=(Value* n) const { if (m_type == Value::Bool && n->type() == Value::Bool) return m_bool >= n->boolean(); if (m_type == Value::Number && n->type() == Value::Number) return m_double >= n->number(); if (m_type == Value::String && n->type() == Value::String) return m_string.length() >= n->string().length(); if (m_type == Value::Empty && n->type() == Value::Empty) return true; return false; } // private void Value::init() { m_type = Value::Empty; // init'ed values are empty by default m_bool = false; m_double = 0; - m_string = ""; + m_string = QLatin1String(""); } diff --git a/src/main.cpp b/src/main.cpp index 7eba081..9b6c416 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,228 +1,228 @@ /* Copyright (C) 2003-2006 Cies Breijs This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #include #include #include #include #include #include #include #include #include "mainwindow.h" // for gui mode #include "interpreter/interpreter.h" // for non gui mode #include "interpreter/echoer.h" #include "interpreter/tokenizer.h" #include "kturtle_version.h" static const char description[] = I18N_NOOP("KTurtle is an educational programming environment that aims to make learning how to program as easy as possible. To achieve this KTurtle makes all programming tools available from the user interface. The programming language used is TurtleScript which allows its commands to be translated."); static const char copyright[] = "(c) 2003-2009 Cies Breijs"; static const char website[] = "http://edu.kde.org/kturtle"; int main(int argc, char* argv[]) { KLocalizedString::setApplicationDomain("kturtle"); QApplication app(argc, argv); app.setAttribute(Qt::AA_UseHighDpiPixmaps, true); KCrash::initialize(); /* for migration*/ QStringList configFiles; - configFiles << QLatin1String("kturtlerc"); - Kdelibs4ConfigMigrator migrator(QLatin1String("kturtle")); + configFiles << QStringLiteral("kturtlerc"); + Kdelibs4ConfigMigrator migrator(QStringLiteral("kturtle")); migrator.setConfigFiles(configFiles); migrator.setUiFiles(QStringList() << QStringLiteral("kturtleui.rc")); migrator.migrate(); - KAboutData aboutData("kturtle", ki18n("KTurtle").toString(), KTURTLE_VERSION_STRING); + KAboutData aboutData(QStringLiteral("kturtle"), ki18n("KTurtle").toString(), KTURTLE_VERSION_STRING); aboutData.setLicense(KAboutLicense::GPL); aboutData.setHomepage(ki18n(website).toString()); aboutData.setShortDescription(ki18n(description).toString()); aboutData.setCopyrightStatement(ki18n(copyright).toString()); - aboutData.addAuthor(ki18n("Cies Breijs").toString(), ki18n("Initiator and core developer").toString(), "cies@kde.nl"); - aboutData.addAuthor(ki18n("Niels Slot").toString(), ki18n("Core developer").toString(), "nielsslot@gmail.com"); - aboutData.addAuthor(ki18n("Mauricio Piacentini").toString(), ki18n("Core developer").toString(), "piacentini@kde.org"); + aboutData.addAuthor(ki18n("Cies Breijs").toString(), ki18n("Initiator and core developer").toString(), QStringLiteral("cies@kde.nl")); + aboutData.addAuthor(ki18n("Niels Slot").toString(), ki18n("Core developer").toString(), QStringLiteral("nielsslot@gmail.com")); + aboutData.addAuthor(ki18n("Mauricio Piacentini").toString(), ki18n("Core developer").toString(), QStringLiteral("piacentini@kde.org")); QCommandLineParser parser; KAboutData::setApplicationData(aboutData); parser.addVersionOption(); parser.addHelpOption(); aboutData.setupCommandLine(&parser); - parser.addOption(QCommandLineOption(QStringList() << QLatin1String("i") << QLatin1String("input"), i18n("File or URL to open (in the GUI mode)"), QLatin1String("URL or file"))); - parser.addOption(QCommandLineOption(QStringList() << QLatin1String("d") << QLatin1String("dbus"), i18n("Starts KTurtle in D-Bus mode (without a GUI), good for automated unit test scripts"))); - parser.addOption(QCommandLineOption(QStringList() << QLatin1String("t") << QLatin1String("test"), i18n("Starts KTurtle in testing mode (without a GUI), directly runs the specified local file"), QLatin1String("file"))); - parser.addOption(QCommandLineOption(QStringList() << QLatin1String("l") << QLatin1String("lang"), i18n("Specifies the localization language by a language code, defaults to \"en_US\" (only works in testing mode)"), QLatin1String("code"))); + parser.addOption(QCommandLineOption(QStringList() << QStringLiteral("i") << QStringLiteral("input"), i18n("File or URL to open (in the GUI mode)"), QStringLiteral("URL or file"))); + parser.addOption(QCommandLineOption(QStringList() << QStringLiteral("d") << QStringLiteral("dbus"), i18n("Starts KTurtle in D-Bus mode (without a GUI), good for automated unit test scripts"))); + parser.addOption(QCommandLineOption(QStringList() << QStringLiteral("t") << QStringLiteral("test"), i18n("Starts KTurtle in testing mode (without a GUI), directly runs the specified local file"), QStringLiteral("file"))); + parser.addOption(QCommandLineOption(QStringList() << QStringLiteral("l") << QStringLiteral("lang"), i18n("Specifies the localization language by a language code, defaults to \"en_US\" (only works in testing mode)"), QStringLiteral("code"))); // parser.addOption(QCommandLineOption(QStringList() << QLatin1String("k") << QLatin1String("tokenize"), i18n("Only tokenizes the turtle code (only works in testing mode)"))); - parser.addOption(QCommandLineOption(QStringList() << QLatin1String("p") << QLatin1String("parse"), i18n("Translates turtle code to embeddable C++ example strings (for developers only)"), QLatin1String("file"))); + parser.addOption(QCommandLineOption(QStringList() << QStringLiteral("p") << QStringLiteral("parse"), i18n("Translates turtle code to embeddable C++ example strings (for developers only)"), QStringLiteral("file"))); parser.process(app); aboutData.processCommandLine(&parser); - if (!parser.isSet("test") && !parser.isSet("parse") && !parser.isSet("dbus")) { + if (!parser.isSet(QStringLiteral("test")) && !parser.isSet(QStringLiteral("parse")) && !parser.isSet(QStringLiteral("dbus"))) { ///////////////// run in GUI mode ///////////////// if (app.isSessionRestored()) { RESTORE(MainWindow); } else { MainWindow* mainWindow = new MainWindow(); mainWindow->show(); - if (parser.isSet("input")) mainWindow->open(parser.value("input")); + if (parser.isSet(QStringLiteral("input"))) mainWindow->open(parser.value(QStringLiteral("input"))); } // free some memory return app.exec(); // the mainwindow has WDestructiveClose flag; it will destroy itself. - } else if (parser.isSet("dbus")) { + } else if (parser.isSet(QStringLiteral("dbus"))) { ///////////////// run in DBUS mode ///////////////// Translator::instance()->setLanguage(); new Interpreter(nullptr, true); return app.exec(); - } else if (parser.isSet("parse")) { + } else if (parser.isSet(QStringLiteral("parse"))) { ///////////////// run in example PARSING mode ///////////////// - QFile inputFile(parser.value("parse")); + QFile inputFile(parser.value(QStringLiteral("parse"))); if (!inputFile.open(QIODevice::ReadOnly | QIODevice::Text)) { std::cout << "Could not open file: " << qPrintable(parser.value("parse")) << std::endl; std::cout << "Exiting..." << std::endl; return 1; } Translator::instance()->setLanguage(); Tokenizer tokenizer; tokenizer.initialize(inputFile.readAll()); inputFile.close(); const QStringList defaultLooks(Translator::instance()->allDefaultLooks()); QString result; Token* t; while ((t = tokenizer.getToken())->type() != Token::EndOfInput) { if (defaultLooks.contains(t->look())) - result.append(QString("@(%1)").arg(t->look())); + result.append(QStringLiteral("@(%1)").arg(t->look())); else result.append(t->look()); if (t->type() == Token::EndOfLine) result.append('\n'); } foreach (const QString &line, result.split('\n')) std::cout << qPrintable(QString("\"%1\"").arg(line)) << std::endl; std::cout << std::endl; } else { ///////////////// run without a gui ///////////////// std::cout << "KTurtle's interpreter in command line mode (version " << KTURTLE_VERSION_STRING << ")" << std::endl; std::cout << copyright << std::endl << std::endl; - QString fileString = parser.value("test"); + QString fileString = parser.value(QStringLiteral("test")); QFile inputFile(fileString); if (!inputFile.open(QIODevice::ReadOnly | QIODevice::Text)) { std::cout << "Could not open input file: " << qPrintable(parser.value("test")) << std::endl; std::cout << "Exitting..." << std::endl; return 1; } QTextStream in(&inputFile); // check for our magic identifier QString s; s = in.readLine(); if (s != KTURTLE_MAGIC_1_0) { std::cout << "The file you try to open is not a valid KTurtle script, or is incompatible with this version of KTurtle.\n"; return 1; } - if (parser.isSet("lang")) { - if (Translator::instance()->setLanguage(parser.value("lang"))) { - std::cout << "Set localization to: " << parser.value("lang").data() << std::endl; + if (parser.isSet(QStringLiteral("lang"))) { + if (Translator::instance()->setLanguage(parser.value(QStringLiteral("lang")))) { + std::cout << "Set localization to: " << parser.value(QStringLiteral("lang")).data() << std::endl; } else { - std::cout << "Could not set localization to:" << parser.value("lang").data() << std::endl; + std::cout << "Could not set localization to:" << parser.value(QStringLiteral("lang")).data() << std::endl; std::cout << "Exitting...\n"; return 1; } } else { Translator::instance()->setLanguage(); std::cout << "Using the default (en_US) localization." << std::endl; } QString localizedScript; localizedScript = Translator::instance()->localizeScript(in.readAll()); // /* if (parser.isSet("tokenize")) { // std::cout << "Tokenizing...\n" << std::endl; // QString code = inputFile.readAll(); // // for (int i = 0; i < code.length(); i++) //qDebug() << code.at(i); // Tokenizer tokenizer; // tokenizer.initialize(code); // Token* t; // while ((t = tokenizer.getToken())->type() != Token::EndOfInput) { // std::cout << "TOK> " // << qPrintable(QString("\"%1\"").arg(t->look()).leftJustified(15)) // << qPrintable(QString("[%1]").arg(QString::number(t->type())).rightJustified(5)) // << qPrintable(QString(" @ (%1,%2)").arg(t->startRow()).arg(t->startCol())) // << qPrintable(QString(" - (%1,%2)").arg(t->endRow()).arg(t->endCol())) // << std::endl; // } // return 0; // }*/ // free some memory // init the interpreter Interpreter* interpreter = new Interpreter(nullptr, true); // set testing to true interpreter->initialize(localizedScript); // install the echoer (new Echoer())->connectAllSlots(interpreter->getExecuter()); // the actual execution (limited to a certain amount of iterations to break endless loops) static const int MAX_ITERATION_STEPS = 20000; int i; for (i = 0; interpreter->state() != Interpreter::Finished && interpreter->state() != Interpreter::Aborted && interpreter->getErrorList()->isEmpty() && i < MAX_ITERATION_STEPS; i++) interpreter->interpret(); if (i == MAX_ITERATION_STEPS) std::cout << "ERR> Iterated more than " << MAX_ITERATION_STEPS << " steps... Execution terminated." << std::endl; } return 0; } diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 4a03cd0..9a3546c 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -1,1093 +1,1093 @@ /* Copyright (C) 2003-2009 Cies Breijs This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "mainwindow.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "interpreter/errormsg.h" #include "interpreter/translator.h" static const int MARGIN_SIZE = 3; // defaultly styled margins look shitty static const char* const GHNS_TARGET = "kturtle/examples"; MainWindow::MainWindow() { setupDockWindows(); // the setup order matters setupActions(); setupCanvas(); setupInterpreter(); setupEditor(); setupStatusBar(); iterationTimer = new QTimer(this); connect(iterationTimer, &QTimer::timeout, this, &MainWindow::iterate); connect(editor, &Editor::contentChanged, inspector, &Inspector::disable); connect(editor, &Editor::contentChanged, errorDialog, &ErrorDialog::disable); connect(errorDialog, &ErrorDialog::currentlySelectedError, editor, &Editor::markCurrentError); colorPicker = nullptr; statusBar()->showMessage(i18nc("@info:status the application is ready for commands", "Ready")); updateContentName(); // also sets the window caption to 'untitled' setRunSpeed(1); // full speed with highlighting abort(); // sets the run-states for the actions right setupGUI(); // after all is set up: readConfig(); updateLanguagesMenu(); currentlyRunningConsole = false; } MainWindow::~MainWindow() { delete editor; KSharedConfig::openConfig()->sync(); } void MainWindow::closeEvent(QCloseEvent *event) { if (editor->maybeSave()) { event->accept(); writeConfig(); } else { event->ignore(); } } void MainWindow::filePrintDialog() { QPrinter printer; QPointer printDialog = new QPrintDialog(&printer, this); if (printDialog->exec()) { QPainter painter; painter.begin(&printer); editor->document()->drawContents(&painter); painter.end(); } delete printDialog; } void MainWindow::canvasPrintDialog() { QPrinter printer; QPointer printDialog = new QPrintDialog(&printer, this); if (printDialog->exec()) { QPainter painter; painter.begin(&printer); canvas->scene()->render(&painter); painter.end(); } delete printDialog; } void MainWindow::showDirectionDialog() { directionDialog = new DirectionDialog(canvas->turtleAngle(), this); connect(directionDialog, &DirectionDialog::pasteText, editor, &Editor::insertPlainText); } void MainWindow::showColorPicker() { if (!colorPicker) { colorPicker = new ColorPicker(this); connect(colorPicker, &ColorPicker::pasteText, editor, &Editor::insertPlainText); } colorPicker->show(); } void MainWindow::contextHelp() { KHelpClient::invokeHelp(contextHelpAnchor); } /*void MainWindow::whatsThis() { QWhatsThis::enterWhatsThisMode(); }*/ void MainWindow::documentWasModified() { //TODO remove this function or make it do something // setWindowModified(textEdit->document()->isModified()); } void MainWindow::setRunSpeed(int speed) { switch (speed) { case 0: dedicatedSpeedAct->setChecked(true); break; case 1: fullSpeedAct->setChecked(true); break; case 2: slowSpeedAct->setChecked(true); break; case 3: slowerSpeedAct->setChecked(true); break; case 4: slowestSpeedAct->setChecked(true); break; case 5: stepSpeedAct->setChecked(true); break; } //TODO runOptionBox->setCurrentIndex(speed); runSpeed = speed; } void MainWindow::setupActions() { QAction * a; KActionCollection* ac = actionCollection(); // WHAT IS THIS? // Similar to a status tip, but not the same. // A status tip is displayed on hover, a whatisthis is displayed when // an item is clicked on it whatisthis mode (cies doesn't like whatis mode for every little widget) // (he thinks whatis is to give the translators even more work) // File menu actions - a = actionCollection()->addAction(KStandardAction::New, "file_new", editor, SLOT(newFile())); + a = actionCollection()->addAction(KStandardAction::New, QStringLiteral("file_new"), editor, SLOT(newFile())); a->setStatusTip(i18n("Create a new file")); a->setWhatsThis(i18n("New File: Create a new file")); - a = actionCollection()->addAction(KStandardAction::Open, "file_open", editor, SLOT(openFile())); + a = actionCollection()->addAction(KStandardAction::Open, QStringLiteral("file_open"), editor, SLOT(openFile())); a->setStatusTip(i18n("Open an existing file")); a->setWhatsThis(i18n("Open File: Open an existing file")); //TODO: Is this correct? -- It doesn't seem to be working - recentFilesAction = dynamic_cast(actionCollection()->addAction(KStandardAction::OpenRecent, "file_recent", editor, SLOT(openFile(QUrl)))); + recentFilesAction = dynamic_cast(actionCollection()->addAction(KStandardAction::OpenRecent, QStringLiteral("file_recent"), editor, SLOT(openFile(QUrl)))); recentFilesAction->setStatusTip(i18n("Open a recently used file")); recentFilesAction->setWhatsThis(i18n("Open Recent File: Open a recently used file")); - a = new QAction(QIcon::fromTheme("get-hot-new-stuff"), i18n("Get more examples..."), this); - actionCollection()->addAction("get_new_examples", a); + a = new QAction(QIcon::fromTheme(QStringLiteral("get-hot-new-stuff")), i18n("Get more examples..."), this); + actionCollection()->addAction(QStringLiteral("get_new_examples"), a); a->setText(i18n("Get more examples...")); connect(a, &QAction::triggered, this, &MainWindow::getNewExampleDialog); - a = actionCollection()->addAction(KStandardAction::Save, "file_save", editor, SLOT(saveFile())); + a = actionCollection()->addAction(KStandardAction::Save, QStringLiteral("file_save"), editor, SLOT(saveFile())); a->setStatusTip(i18n("Save the current file to disk")); a->setWhatsThis(i18n("Save File: Save the current file to disk")); connect(editor->document(), &QTextDocument::modificationChanged, a, &QAction::setEnabled); - a = actionCollection()->addAction(KStandardAction::SaveAs, "file_save_as", editor, SLOT(saveFileAs())); + a = actionCollection()->addAction(KStandardAction::SaveAs, QStringLiteral("file_save_as"), editor, SLOT(saveFileAs())); a->setStatusTip(i18n("Save the current file under a different name")); a->setWhatsThis(i18n("Save File As: Save the current file under a different name")); - exportToHtmlAct = actionCollection()->addAction("file_export_to_html"); + exportToHtmlAct = actionCollection()->addAction(QStringLiteral("file_export_to_html")); exportToHtmlAct->setText(i18n("Export to &HTML...")); exportToHtmlAct->setStatusTip(i18n("Export the contents of the editor as HTML")); exportToHtmlAct->setWhatsThis(i18n("Export to HTML: Export the contents of the editor as HTML")); connect(exportToHtmlAct, &QAction::triggered, this, &MainWindow::exportToHtml); - a = actionCollection()->addAction(KStandardAction::Print, "file_print", this, SLOT(filePrintDialog())); + a = actionCollection()->addAction(KStandardAction::Print, QStringLiteral("file_print"), this, SLOT(filePrintDialog())); a->setStatusTip(i18n("Print the code")); a->setWhatsThis(i18n("Print: Print the code")); - a = actionCollection()->addAction(KStandardAction::Quit, "file_quit", this, SLOT(close())); + a = actionCollection()->addAction(KStandardAction::Quit, QStringLiteral("file_quit"), this, SLOT(close())); a->setStatusTip(i18n("Quit KTurtle")); a->setWhatsThis(i18n("Quit: Quit KTurtle")); // Edit menu actions a = KStandardAction::undo(editor->view(), SLOT(undo()), ac); a->setStatusTip(i18n("Undo a change in the editor")); a->setWhatsThis(i18n("Undo: Undo a change in the editor")); a->setEnabled(false); connect(editor->view(), &QTextEdit::undoAvailable, a, &QAction::setEnabled); a = KStandardAction::redo(editor->view(), SLOT(redo()), ac); a->setStatusTip(i18n("Redo a previously undone change in the editor")); a->setWhatsThis(i18n("Redo: Redo a previously undone change in the editor")); a->setEnabled(false); connect(editor->view(), &QTextEdit::redoAvailable, a, &QAction::setEnabled); a = KStandardAction::cut(editor->view(), SLOT(cut()), ac); a->setStatusTip(i18n("Cut the selected text to the clipboard")); a->setWhatsThis(i18n("Cut: Cut the selected text to the clipboard")); a->setEnabled(false); connect(editor->view(), &QTextEdit::copyAvailable, a, &QAction::setEnabled); a = KStandardAction::copy(editor->view(), SLOT(copy()), ac); a->setStatusTip(i18n("Copy the selected text to the clipboard")); a->setWhatsThis(i18n("Copy: Copy the selected text to the clipboard")); a->setEnabled(false); connect(editor->view(), &QTextEdit::copyAvailable, a, &QAction::setEnabled); a = KStandardAction::paste(editor->view(), SLOT(paste()), ac); a->setStatusTip(i18n("Paste the clipboard's content into the current selection")); a->setWhatsThis(i18n("Paste: Paste the clipboard's content into the current selection")); a = KStandardAction::selectAll(editor->view(), SLOT(selectAll()), ac); a->setStatusTip(i18n("Select all the code in the editor")); a->setWhatsThis(i18n("Select All: Select all the code in the editor")); a->setEnabled(true); a = new QAction(i18n("Overwrite Mode"), this); - actionCollection()->addAction("overwrite", a ); + actionCollection()->addAction(QStringLiteral("overwrite"), a ); a->setStatusTip(i18n("Toggle between the 'insert' and 'overwrite' mode")); a->setWhatsThis(i18n("Overwrite Mode: Toggle between the 'insert' and 'overwrite' mode")); actionCollection()->setDefaultShortcut(a, QKeySequence(Qt::Key_Insert)); a->setCheckable(true); a->setChecked(false); connect(a, &QAction::toggled, this, &MainWindow::toggleOverwriteMode); a = KStandardAction::find(editor, SLOT(find()), ac); a->setStatusTip(i18n("Search through the code in the editor")); a->setWhatsThis(i18n("Find: Search through the code in the editor")); a = KStandardAction::findNext(editor, SLOT(findNext()), ac); a->setStatusTip(i18n("Continue searching through the code in the editor")); a->setWhatsThis(i18n("Find Next: Continue searching through the code in the editor")); a = KStandardAction::findPrev(editor, SLOT(findPrev()), ac); a->setStatusTip(i18n("Continue searching backwards through the code in the editor")); a->setWhatsThis(i18n("Find Previous: Continue searching backwards through the code in the editor")); //TODO: Implement search/replace //a = KStandardAction::replace(editor, SLOT(replace()), ac); //a->setStatusTip(i18n("Search and replace")); //a->setWhatsThis(i18n("Replace: Replace text in the editor")); // Canvas menu action - exportToPngAct = actionCollection()->addAction("canvas_export_to_png"); + exportToPngAct = actionCollection()->addAction(QStringLiteral("canvas_export_to_png")); exportToPngAct->setText(i18n("Export to &Image (PNG)...")); exportToPngAct->setStatusTip(i18n("Export the current canvas to a PNG raster image")); exportToPngAct->setWhatsThis(i18n("Export to PNG: Export the current canvas to a PNG raster image")); connect(exportToPngAct, &QAction::triggered, this, &MainWindow::exportToPng); - exportToSvgAct = actionCollection()->addAction("canvas_export_to_svg"); + exportToSvgAct = actionCollection()->addAction(QStringLiteral("canvas_export_to_svg")); exportToSvgAct->setText(i18n("Export to &Drawing (SVG)...")); exportToSvgAct->setStatusTip(i18n("Export the current canvas to Scalable Vector Graphics")); exportToSvgAct->setWhatsThis(i18n("Export to SVG: Export the current canvas to Scalable Vector Graphics")); connect(exportToSvgAct, &QAction::triggered, this, &MainWindow::exportToSvg); - printCanvasAct = new QAction(QIcon::fromTheme("document-print"), i18n("&Print Canvas..."), this); - actionCollection()->addAction("canvas_print", printCanvasAct); + printCanvasAct = new QAction(QIcon::fromTheme(QStringLiteral("document-print")), i18n("&Print Canvas..."), this); + actionCollection()->addAction(QStringLiteral("canvas_print"), printCanvasAct); printCanvasAct->setStatusTip(i18n("Print the canvas")); printCanvasAct->setWhatsThis(i18n("Print: Print the canvas")); connect(printCanvasAct, &QAction::triggered, this, &MainWindow::canvasPrintDialog); // Run menu actions - runAct = new QAction(QIcon::fromTheme("media-playback-start"), i18n("&Run"), this); - actionCollection()->addAction("run", runAct); + runAct = new QAction(QIcon::fromTheme(QStringLiteral("media-playback-start")), i18n("&Run"), this); + actionCollection()->addAction(QStringLiteral("run"), runAct); actionCollection()->setDefaultShortcut(runAct, QKeySequence(Qt::Key_F5)); runAct->setStatusTip(i18n("Execute the program")); runAct->setWhatsThis(i18n("Run: Execute the program")); connect(runAct, &QAction::triggered, this, &MainWindow::run); - pauseAct = new QAction(QIcon::fromTheme("media-playback-pause"), i18n("&Pause"), this); - actionCollection()->addAction("pause", pauseAct); + pauseAct = new QAction(QIcon::fromTheme(QStringLiteral("media-playback-pause")), i18n("&Pause"), this); + actionCollection()->addAction(QStringLiteral("pause"), pauseAct); pauseAct->setCheckable(true); actionCollection()->setDefaultShortcut(pauseAct, QKeySequence(Qt::Key_F6)); pauseAct->setStatusTip(i18n("Pause execution")); pauseAct->setWhatsThis(i18n("Pause: Pause execution")); connect(pauseAct, &QAction::triggered, this, &MainWindow::pause); - abortAct = new QAction(QIcon::fromTheme("process-stop"), i18n("&Abort"), this); - actionCollection()->addAction("abort", abortAct); + abortAct = new QAction(QIcon::fromTheme(QStringLiteral("process-stop")), i18n("&Abort"), this); + actionCollection()->addAction(QStringLiteral("abort"), abortAct); actionCollection()->setDefaultShortcut(abortAct, QKeySequence(Qt::Key_F7)); abortAct->setStatusTip(i18n("Stop executing program")); abortAct->setWhatsThis(i18n("Abort: Stop executing program")); connect(abortAct, &QAction::triggered, this, &MainWindow::abort); // new QAction(i18n("&Indent"), "format-indent-more", CTRL+Key_I, this, SLOT(slotIndent()), ac, "edit_indent"); // new QAction(i18n("&Unindent"), "format-indent-less", CTRL+SHIFT+Key_I, this, SLOT(slotUnIndent()), ac, "edit_unindent"); // new QAction(i18n("Cl&ean Indentation"), 0, 0, this, SLOT(slotCleanIndent()), ac, "edit_cleanIndent"); // new QAction(i18n("Co&mment"), 0, CTRL+Key_D, this, SLOT(slotComment()), ac, "edit_comment"); // new QAction(i18n("Unc&omment"), 0, CTRL+SHIFT+Key_D, this, SLOT(slotUnComment()), ac, "edit_uncomment"); // Tools menu actions a = new QAction(i18n("&Direction Chooser..."), this); - actionCollection()->addAction("direction_chooser", a); + actionCollection()->addAction(QStringLiteral("direction_chooser"), a); a->setStatusTip(i18n("Shows the direction chooser dialog")); a->setWhatsThis(i18n("Direction Chooser: Show the direction chooser dialog")); connect(a, &QAction::triggered, this, &MainWindow::showDirectionDialog); a = new QAction(i18n("&Color Picker..."), this); - actionCollection()->addAction("color_picker", a); + actionCollection()->addAction(QStringLiteral("color_picker"), a); a->setStatusTip(i18n("Shows the color picker dialog")); a->setWhatsThis(i18n("Color Picker: Show the color picker dialog")); connect(a, &QAction::triggered, this, &MainWindow::showColorPicker); // Settings menu action a = new QAction(i18n("Show &Editor"), this); - actionCollection()->addAction("show_editor", a); + actionCollection()->addAction(QStringLiteral("show_editor"), a); a->setStatusTip(i18n("Show or hide the Code Editor")); a->setWhatsThis(i18n("Show Code Editor: Show or hide the Code Editor")); actionCollection()->setDefaultShortcut(a, QKeySequence(Qt::CTRL + Qt::Key_E)); a->setCheckable(true); a->setChecked(true); connect(a, &QAction::toggled, editorDock, &LocalDockWidget::setVisible); connect(editorDock, &LocalDockWidget::visibilityChanged, a, &QAction::setChecked); a = new QAction(i18n("Show &Inspector"), this); - actionCollection()->addAction("show_inspector", a); + actionCollection()->addAction(QStringLiteral("show_inspector"), a); a->setStatusTip(i18n("Show or hide the Inspector")); a->setWhatsThis(i18n("Show Inspector: Show or hide the Inspector")); actionCollection()->setDefaultShortcut(a, QKeySequence(Qt::CTRL + Qt::Key_I)); a->setCheckable(true); a->setChecked(true); connect(a, &QAction::toggled, inspectorDock, &LocalDockWidget::setVisible); connect(inspectorDock, &LocalDockWidget::visibilityChanged, a, &QAction::setChecked); a = new QAction(i18n("Show E&rrors"), this); - actionCollection()->addAction("show_errors", a); + actionCollection()->addAction(QStringLiteral("show_errors"), a); a->setStatusTip(i18n("Show or hide the Errors tab")); a->setWhatsThis(i18n("Show Errors: Show or hide the Errors tab")); a->setCheckable(true); a->setChecked(false); connect(a, &QAction::toggled, this, &MainWindow::showErrorDialog); // a = new QAction(i18n("Show &Console"), this); // actionCollection()->addAction("show_console", a); // a->setStatusTip(i18n("Show or hide the interactive Console tab")); // a->setWhatsThis(i18n("Show Console: Show or hide the interactive Console tab")); // a->setCheckable(true); // a->setChecked(false); // connect(a, SIGNAL(toggled(bool)), consoleDock, SLOT(setVisible(bool))); // connect(consoleDock, SIGNAL(visibilityChanged(bool)), a, SLOT(setChecked(bool))); a = new QAction(i18n("Show &Line Numbers"), this); - actionCollection()->addAction("line_numbers", a); + actionCollection()->addAction(QStringLiteral("line_numbers"), a); a->setStatusTip(i18n("Turn the line numbers on/off in the editor")); a->setWhatsThis(i18n("Show Line Numbers: Turn the line numbers on/off in the editor")); actionCollection()->setDefaultShortcut(a, QKeySequence(Qt::Key_F11)); a->setCheckable(true); a->setChecked(true); connect(a, &QAction::toggled, editor, &Editor::toggleLineNumbers); // Help menu actions - contextHelpAct = ac->addAction("context_help"); - contextHelpAct->setText(""); - contextHelpAct->setIcon(QIcon::fromTheme("help-about")); + contextHelpAct = ac->addAction(QStringLiteral("context_help")); + contextHelpAct->setText(QLatin1String("")); + contextHelpAct->setIcon(QIcon::fromTheme(QStringLiteral("help-about"))); actionCollection()->setDefaultShortcut(contextHelpAct, QKeySequence(Qt::Key_F2)); contextHelpAct->setStatusTip(i18n("Get help on the command under the cursor")); contextHelpAct->setWhatsThis(i18n("Context Help: Get help on the command under the cursor")); connect(contextHelpAct, &QAction::triggered, this, &MainWindow::contextHelp); updateContextHelpAction(); - a = actionCollection()->addAction(KStandardAction::HelpContents, "help_contents", this, SLOT(appHelpActivated())); + a = actionCollection()->addAction(KStandardAction::HelpContents, QStringLiteral("help_contents"), this, SLOT(appHelpActivated())); a->setStatusTip(i18n("Help")); a->setWhatsThis(i18n("Help: Open manual for KTurtle")); // Menuless actions console = new Console(this); console->setText(i18n("Console")); actionCollection()->setDefaultShortcut(console, QKeySequence(Qt::Key_F4)); - actionCollection()->addAction("console", console); + actionCollection()->addAction(QStringLiteral("console"), console); connect(console, &Console::execute, this, &MainWindow::execute); - executeConsoleAct = actionCollection()->addAction("execute_console"); - executeConsoleAct->setIcon(QIcon::fromTheme("go-jump-locationbar")); + executeConsoleAct = actionCollection()->addAction(QStringLiteral("execute_console")); + executeConsoleAct->setIcon(QIcon::fromTheme(QStringLiteral("go-jump-locationbar"))); executeConsoleAct->setText(i18n("Execute")); connect(executeConsoleAct, &QAction::triggered, console, &Console::executeActionTriggered); executeConsoleAct->setWhatsThis(i18n("Execute: Executes the current line in the console")); // The run speed action group QActionGroup* runSpeedGroup = new QActionGroup(this); // The run action collection, this is used in the toolbar to create a dropdown menu on the run button - KToolBarPopupAction* runSpeedAction = new KToolBarPopupAction(QIcon::fromTheme("media-playback-start"), i18n("&Run"), this); + KToolBarPopupAction* runSpeedAction = new KToolBarPopupAction(QIcon::fromTheme(QStringLiteral("media-playback-start")), i18n("&Run"), this); connect(runSpeedAction, &KToolBarPopupAction::triggered, this, &MainWindow::run); QMenu* runSpeedActionMenu = runSpeedAction->menu(); - actionCollection()->addAction("run_speed", runSpeedAction); + actionCollection()->addAction(QStringLiteral("run_speed"), runSpeedAction); runSpeedActionMenu->setStatusTip(i18n("Execute the program, or use the drop down menu to select the run speed")); runSpeedActionMenu->setWhatsThis(i18n("Run: Execute the program, or use the drop down menu to select the run speed")); connect(runSpeedActionMenu, &QMenu::triggered, this, &MainWindow::run); dedicatedSpeedAct = new QAction(i18nc("@option:radio", "Full Speed (&no highlighting and inspector)"), this); - actionCollection()->addAction("dedicated_speed", dedicatedSpeedAct); + actionCollection()->addAction(QStringLiteral("dedicated_speed"), dedicatedSpeedAct); dedicatedSpeedAct->setCheckable(true); dedicatedSpeedAct->setStatusTip(i18n("Run the program at full speed, with highlighting and inspector disabled")); dedicatedSpeedAct->setWhatsThis(i18n("Full Speed: Run the program at full speed, with highlighting and inspector disabled")); connect(dedicatedSpeedAct, &QAction::triggered, this, &MainWindow::setDedicatedSpeed); runSpeedGroup->addAction(dedicatedSpeedAct); runSpeedActionMenu->addAction(dedicatedSpeedAct); fullSpeedAct = new QAction(i18nc("@option:radio", "&Full Speed"), this); - actionCollection()->addAction("full_speed", fullSpeedAct); + actionCollection()->addAction(QStringLiteral("full_speed"), fullSpeedAct); fullSpeedAct->setCheckable(true); fullSpeedAct->setChecked(true); fullSpeedAct->setStatusTip(i18n("Run the program at full speed")); fullSpeedAct->setWhatsThis(i18n("Full Speed: Run the program at full speed")); connect(fullSpeedAct, &QAction::triggered, this, &MainWindow::setFullSpeed); runSpeedGroup->addAction(fullSpeedAct); runSpeedActionMenu->addAction(fullSpeedAct); slowSpeedAct = new QAction(i18nc("@option:radio choose the slow speed", "&Slow"), this); - actionCollection()->addAction("slow_speed", slowSpeedAct); + actionCollection()->addAction(QStringLiteral("slow_speed"), slowSpeedAct); slowSpeedAct->setCheckable(true); slowSpeedAct->setStatusTip(i18n("Run the program at a slow speed")); slowSpeedAct->setWhatsThis(i18n("Slow Speed: Run the program at a slow speed")); connect(slowSpeedAct, &QAction::triggered, this, &MainWindow::setSlowSpeed); runSpeedGroup->addAction(slowSpeedAct); runSpeedActionMenu->addAction(slowSpeedAct); slowerSpeedAct = new QAction(i18nc("@option:radio", "S&lower"), this); - actionCollection()->addAction("slower_speed", slowerSpeedAct); + actionCollection()->addAction(QStringLiteral("slower_speed"), slowerSpeedAct); slowerSpeedAct->setCheckable(true); slowerSpeedAct->setStatusTip(i18n("Run the program at a slower speed")); slowerSpeedAct->setWhatsThis(i18n("Slower Speed: Run the program at a slower speed")); connect(slowerSpeedAct, &QAction::triggered, this, &MainWindow::setSlowerSpeed); runSpeedGroup->addAction(slowerSpeedAct); runSpeedActionMenu->addAction(slowerSpeedAct); slowestSpeedAct = new QAction(i18nc("@option:radio", "Sl&owest"), this); - actionCollection()->addAction("slowest_speed", slowestSpeedAct); + actionCollection()->addAction(QStringLiteral("slowest_speed"), slowestSpeedAct); slowestSpeedAct->setCheckable(true); slowestSpeedAct->setStatusTip(i18n("Run the program at the slowest speed")); slowestSpeedAct->setWhatsThis(i18n("Slowest Speed: Run the program at the slowest speed")); connect(slowestSpeedAct, &QAction::triggered, this, &MainWindow::setSlowestSpeed); runSpeedGroup->addAction(slowestSpeedAct); runSpeedActionMenu->addAction(slowestSpeedAct); stepSpeedAct = new QAction(i18nc("@option:radio", "S&tep-by-Step"), this); - actionCollection()->addAction("step_speed", stepSpeedAct); + actionCollection()->addAction(QStringLiteral("step_speed"), stepSpeedAct); stepSpeedAct->setCheckable(true); stepSpeedAct->setStatusTip(i18n("Run the program one step at a time")); stepSpeedAct->setWhatsThis(i18n("Step Speed: Run the program one step at a time")); connect(stepSpeedAct, &QAction::triggered, this, &MainWindow::setStepSpeed); runSpeedGroup->addAction(stepSpeedAct); runSpeedActionMenu->addAction(stepSpeedAct); } void MainWindow::setupCanvas() { // put the canvas in a layout as the central widget of the mainwindow QWidget* centralWidget = new QWidget(this); QHBoxLayout* centralLayout = new QHBoxLayout(centralWidget); centralLayout->setMargin(0); // MARGIN_SIZE); canvasTabWidget = new QTabWidget(this); canvasTab = new QWidget(); QHBoxLayout* canvasLayout = new QHBoxLayout(canvasTab); canvas = new Canvas(this); canvas->setFocusPolicy(Qt::NoFocus); canvas->setRenderHint(QPainter::Antialiasing); canvas->setWhatsThis(i18n("Canvas: This is where the turtle moves and draws when the program is running")); canvasLayout->addWidget(canvas); canvasLayout->setMargin(0); canvasTabWidget->insertTab(0, canvasTab, i18n("&Canvas")); QWidget* errorTab = new QWidget(); QHBoxLayout* errorLayout = new QHBoxLayout(errorTab); errorDialog = new ErrorDialog(this); errorLayout->addWidget(errorDialog); canvasTabWidget->insertTab(1, errorTab, i18n("E&rrors")); // a widget stach with 2 layers: 1st with only a canvas, 2nd with the canvas/error tabs stackedWidget = new QStackedWidget; stackedWidget->insertWidget(0, canvasTab); stackedWidget->insertWidget(1, canvasTabWidget); centralLayout->addWidget(stackedWidget); setCentralWidget(centralWidget); } void MainWindow::showErrorDialog(bool show) { if (show) { // show the canvas and errors in a tab widget, focussing on the errors stackedWidget->setCurrentIndex(1); canvasTabWidget->insertTab(0, canvasTab, i18n("&Canvas")); canvasTabWidget->setCurrentIndex(1); - actionCollection()->action("show_errors")->setChecked(true); + actionCollection()->action(QStringLiteral("show_errors"))->setChecked(true); } else { // show the canvas only stackedWidget->insertWidget(0, canvasTab); stackedWidget->setCurrentIndex(0); - actionCollection()->action("show_errors")->setChecked(false); + actionCollection()->action(QStringLiteral("show_errors"))->setChecked(false); } } void MainWindow::setupDockWindows() { editorDock = new LocalDockWidget(i18n("&Editor"), this); - editorDock->setObjectName("editor"); + editorDock->setObjectName(QStringLiteral("editor")); QWidget* editorWrapWidget = new QWidget(editorDock); QHBoxLayout* editorDockLayout = new QHBoxLayout(editorWrapWidget); editorDockLayout->setMargin(MARGIN_SIZE); editorWrapWidget->setLayout(editorDockLayout); // dock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea); editor = new Editor(editorWrapWidget); // create this here to prevent crashes editorDockLayout->addWidget(editor); editorDock->setWidget(editorWrapWidget); // editorDock->setFeatures(QDockWidget::DockWidgetMovable|QDockWidget::DockWidgetFloatable); addDockWidget(Qt::LeftDockWidgetArea, editorDock); editor->show(); editor->setFocus(); editor->setWhatsThis(i18n("Editor: Write your KTurtle commands here")); // Creating the debug window inspectorDock = new LocalDockWidget(i18n("&Inspector"), this); - inspectorDock->setObjectName("inspector"); + inspectorDock->setObjectName(QStringLiteral("inspector")); QWidget* inspectorWrapWidget = new QWidget(inspectorDock); QHBoxLayout* inspectorDockLayout = new QHBoxLayout(inspectorWrapWidget); inspectorDockLayout->setMargin(MARGIN_SIZE); inspectorWrapWidget->setLayout(inspectorDockLayout); inspector = new Inspector(inspectorWrapWidget); inspectorDockLayout->addWidget(inspector); inspectorDock->setWidget(inspectorWrapWidget); addDockWidget(Qt::RightDockWidgetArea, inspectorDock); inspector->setWhatsThis(i18n("Inspector: See information about variables and functions when the program runs")); } void MainWindow::setupEditor() { // editor->setTranslator(Translator::instance()); connect(editor, &Editor::modificationChanged, this, &MainWindow::updateModificationState); connect(editor, &Editor::contentNameChanged, this, &MainWindow::updateContentName); connect(editor, &Editor::fileOpened, this, &MainWindow::addToRecentFilesList); connect(editor, &Editor::fileSaved, this, &MainWindow::addToRecentFilesList); connect(editor, &Editor::cursorPositionChanged, this, &MainWindow::updateOnCursorPositionChange); } void MainWindow::setupInterpreter() { interpreter = new Interpreter(this, false); connect(interpreter, &Interpreter::finished, this, &MainWindow::abort); Executer* executer = interpreter->getExecuter(); // the code to connect the executer with the canvas is auto generated: #include "interpreter/gui_connect.inc" connect(interpreter, &Interpreter::treeUpdated, inspector, &Inspector::updateTree); toggleGuiFeedback(true); } void MainWindow::toggleGuiFeedback(bool b) { Executer* executer = interpreter->getExecuter(); if (b) { connect(executer, &Executer::currentlyExecuting, editor, &Editor::markCurrentWord); connect(executer, &Executer::currentlyExecuting, inspector, &Inspector::markTreeNode); connect(executer, &Executer::variableTableUpdated, inspector, &Inspector::updateVariable); connect(executer, &Executer::functionTableUpdated, inspector, &Inspector::updateFunction); } else { disconnect(executer, &Executer::currentlyExecuting, editor, &Editor::markCurrentWord); disconnect(executer, &Executer::currentlyExecuting, inspector, &Inspector::markTreeNode); - disconnect(executer, SIGNAL(variableTableUpdated(QString,Value)), - inspector, SLOT(updateVariable(QString,Value))); - disconnect(executer, SIGNAL(functionTableUpdated(QString,QStringList)), - inspector, SLOT(updateFunction(QString,QStringList))); + disconnect(executer, &Executer::variableTableUpdated, + inspector, &Inspector::updateVariable); + disconnect(executer, &Executer::functionTableUpdated, + inspector, &Inspector::updateFunction); editor->removeMarkings(); } } void MainWindow::setupStatusBar() { statusBarLanguageLabel = new QLabel(statusBar()); statusBar()->addPermanentWidget(statusBarLanguageLabel, 0); statusBarLanguageLabel->setAlignment(Qt::AlignRight); statusBarPositionLabel = new QLabel(statusBar()); statusBar()->addPermanentWidget(statusBarPositionLabel, 0); statusBarPositionLabel->setAlignment(Qt::AlignRight); statusBarOverwriteModeLabel = new QLabel(statusBar()); statusBar()->addPermanentWidget(statusBarOverwriteModeLabel, 0); statusBarOverwriteModeLabel->setAlignment(Qt::AlignRight); statusBarFileNameLabel = new QLabel(statusBar()); statusBar()->addPermanentWidget(statusBarFileNameLabel, 0); statusBarFileNameLabel->setAlignment(Qt::AlignRight); toggleOverwriteMode(false); updateOnCursorPositionChange(); } void MainWindow::saveNewToolbarConfig() { // this destroys our actions lists ... KXmlGuiWindow::saveNewToolbarConfig(); // ... so plug them again updateLanguagesMenu(); updateExamplesMenu(); } void MainWindow::updateLanguagesMenu() { QList languageList; QActionGroup* languageGroup = new QActionGroup(this); connect(languageGroup, &QActionGroup::triggered, this, &MainWindow::setLanguage); QAction* a; // sort the dictionaries using an algorithm found in the qt docs: QMap map; QSet dictionaries = KLocalizedString::availableApplicationTranslations(); foreach (const QString &lang_code, dictionaries) map.insert(codeToFullName(lang_code), lang_code); // populate the menu: foreach (const QString &lang_code, map) { a = new QAction(codeToFullName(lang_code), actionCollection()); a->setData(lang_code); a->setStatusTip(i18n("Switch to the %1 dictionary", codeToFullName(lang_code))); a->setCheckable(true); if (lang_code == currentLanguageCode) { a->setChecked(true); } //languageMenu->addAction(a); languageGroup->addAction(a); languageList.append(a); } - unplugActionList ("languages_actionlist"); - plugActionList ("languages_actionlist", languageList); + unplugActionList (QStringLiteral("languages_actionlist")); + plugActionList (QStringLiteral("languages_actionlist"), languageList); } void MainWindow::updateExamplesMenu() { QAction * newExample; QString actionName; QList exampleList; QActionGroup* exampleGroup = new QActionGroup (this); foreach (const QString &exampleName, Translator::instance()->exampleNames()) { newExample = new QAction (exampleName, this); newExample->setData(exampleName); exampleGroup->addAction (newExample); connect(newExample, &QAction::triggered, this, &MainWindow::openExample); exampleList.append (newExample); } QStringList allExamples; const QStringList exampleDirs = QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, GHNS_TARGET, QStandardPaths::LocateDirectory); foreach (const QString &dir, exampleDirs) { - const QStringList fileNames = QDir(dir).entryList(QStringList() << "*.turtle", QDir::Files); + const QStringList fileNames = QDir(dir).entryList(QStringList() << QStringLiteral("*.turtle"), QDir::Files); foreach (const QString &fileName, fileNames) { allExamples.append(dir + '/' + fileName); } } if(allExamples.size()>0) { newExample = new QAction(this); newExample->setSeparator(true); exampleGroup->addAction(newExample); exampleList.append(newExample); } foreach(const QString& exampleFilename, allExamples) { QFileInfo fileInfo(exampleFilename); newExample = new QAction (fileInfo.baseName(), this); newExample->setData(exampleFilename); exampleGroup->addAction (newExample); exampleList.append (newExample); connect(newExample, &QAction::triggered, this, &MainWindow::openDownloadedExample); } - unplugActionList ("examples_actionlist"); - plugActionList ("examples_actionlist", exampleList); + unplugActionList (QStringLiteral("examples_actionlist")); + plugActionList (QStringLiteral("examples_actionlist"), exampleList); } void MainWindow::addToRecentFilesList(const QUrl &url) { recentFilesAction->addUrl(url); } void MainWindow::openExample() { QAction* action = qobject_cast(sender()); QString exampleName = action->data().toString(); editor->openExample(Translator::instance()->example(exampleName), exampleName); } void MainWindow::openDownloadedExample() { QAction* action = qobject_cast(sender()); QString exampleFilename = action->data().toString(); editor->openFile(QUrl::fromLocalFile(exampleFilename)); } void MainWindow::toggleOverwriteMode(bool b) { statusBarOverwriteModeLabel->setText(b ? i18n(" OVR ") : i18n(" INS ")); editor->setOverwriteMode(b); } void MainWindow::updateContextHelpAction(const QString& s, const QString& anchor) { //qDebug() << QString("%1 (help anchor: %2)").arg(s).arg(anchor); contextHelpAnchor = anchor; contextHelpString = s.isEmpty() ? i18n("") : s; contextHelpAct->setText(i18n("Help on: %1", contextHelpString)); } void MainWindow::updateOnCursorPositionChange() { statusBarPositionLabel->setText(i18n(" Line: %1 Column: %2 ", editor->row(), editor->col())); Token* cursorToken = editor->currentToken(); QString desc; if (cursorToken) { QString look = cursorToken->look(); int cat = cursorToken->category(); delete cursorToken; cursorToken = nullptr; KLocalizedString layout = ki18n("\"%1\" <%2>"); switch (cat) { // not showing the look (only the name): - case Token::VariableCategory: updateContextHelpAction(i18n(""), "variable"); return; - case Token::NumberCategory: updateContextHelpAction(i18n(""), "number"); return; - case Token::CommentCategory: updateContextHelpAction(i18n(""), "comment"); return; - case Token::StringCategory: updateContextHelpAction(i18n(""), "string"); return; + case Token::VariableCategory: updateContextHelpAction(i18n(""), QStringLiteral("variable")); return; + case Token::NumberCategory: updateContextHelpAction(i18n(""), QStringLiteral("number")); return; + case Token::CommentCategory: updateContextHelpAction(i18n(""), QStringLiteral("comment")); return; + case Token::StringCategory: updateContextHelpAction(i18n(""), QStringLiteral("string")); return; // only showing the look: - case Token::LearnCommandCategory: updateContextHelpAction(look, "learn"); return; - case Token::TrueFalseCategory: updateContextHelpAction(look, "boolean"); return; + case Token::LearnCommandCategory: updateContextHelpAction(look, QStringLiteral("learn")); return; + case Token::TrueFalseCategory: updateContextHelpAction(look, QStringLiteral("boolean")); return; // showing the look and the name: case Token::ScopeCategory: - updateContextHelpAction(layout.subs(look).subs(i18n("scope")).toString(), "scope"); return; + updateContextHelpAction(layout.subs(look).subs(i18n("scope")).toString(), QStringLiteral("scope")); return; case Token::AssignmentCategory: - updateContextHelpAction(layout.subs(look).subs(i18n("assignment")).toString(), "assignment"); return; + updateContextHelpAction(layout.subs(look).subs(i18n("assignment")).toString(), QStringLiteral("assignment")); return; case Token::ParenthesisCategory: - updateContextHelpAction(layout.subs(look).subs(i18n("parenthesis")).toString(), "parenthesis"); return; + updateContextHelpAction(layout.subs(look).subs(i18n("parenthesis")).toString(), QStringLiteral("parenthesis")); return; case Token::MathOperatorCategory: - updateContextHelpAction(layout.subs(look).subs(i18n("mathematical operator")).toString(), "math-operator"); return; + updateContextHelpAction(layout.subs(look).subs(i18n("mathematical operator")).toString(), QStringLiteral("math-operator")); return; case Token::ExpressionCategory: - updateContextHelpAction(layout.subs(look).subs(i18n("expression")).toString(), "expression"); return; + updateContextHelpAction(layout.subs(look).subs(i18n("expression")).toString(), QStringLiteral("expression")); return; case Token::BooleanOperatorCategory: - updateContextHelpAction(layout.subs(look).subs(i18n("boolean operator")).toString(), "boolean-operator"); return; + updateContextHelpAction(layout.subs(look).subs(i18n("boolean operator")).toString(), QStringLiteral("boolean-operator")); return; case Token::FunctionCallCategory: - updateContextHelpAction(layout.subs(look).subs(i18n("learned command")).toString(), "learned-command"); return; + updateContextHelpAction(layout.subs(look).subs(i18n("learned command")).toString(), QStringLiteral("learned-command")); return; case Token::ArgumentSeparatorCategory: - updateContextHelpAction(layout.subs(look).subs(i18n("argument separator")).toString(), "argument-separator"); return; + updateContextHelpAction(layout.subs(look).subs(i18n("argument separator")).toString(), QStringLiteral("argument-separator")); return; // showing the look and the name, and linking to the help through their default look (en_US): case Token::CommandCategory: updateContextHelpAction(layout.subs(look).subs(i18n("command")).toString(), Translator::instance()->defaultLook(look)); return; case Token::ControllerCommandCategory: updateContextHelpAction(layout.subs(look).subs(i18n("controller command")).toString(), Translator::instance()->defaultLook(look)); return; } } updateContextHelpAction(); // display the 'nothing under cursor thing' } void MainWindow::setLanguage(QAction *action) { if (setCurrentLanguage(action->data().toString())) action->setChecked(true); } bool MainWindow::setCurrentLanguage(const QString &lang_code) // 2 or 5 digit code (en, en_US, nl, pt_BR) { bool result = false; //qDebug() << "MainWindow::setCurrentLanguage: " << lang_code; if (Translator::instance()->setLanguage(lang_code)) { currentLanguageCode = lang_code; statusBarLanguageLabel->setText(' ' + codeToFullName(lang_code) + ' '); updateExamplesMenu(); editor->rehighlight(); result = true; } else { KMessageBox::error(this, i18n("Could not change the language to %1.", codeToFullName(lang_code))); } return result; } QString MainWindow::codeToFullName(const QString& lang_code) { - return QString(lang_code == "en_US" ? + return QString(lang_code == QLatin1String("en_US") ? i18n("English [built in]") : i18n("%1 (%2)", QLocale(lang_code.left(2)).nativeLanguageName(), lang_code) ); } void MainWindow::run() { if (interpreter->state() == Interpreter::Uninitialized || interpreter->state() == Interpreter::Finished || interpreter->state() == Interpreter::Aborted) { // reset inspector and interpreter editor->removeMarkings(); inspector->clear(); errorDialog->clear(); showErrorDialog(false); interpreter->initialize(editor->content()); } editor->disable(); console->disable(); executeConsoleAct->setEnabled(false); toggleGuiFeedback(runSpeed != 0); // start parsing (always in full speed) iterationTimer->setSingleShot(false); iterationTimer->start(0); } QString MainWindow::execute(const QString &operation) { disconnect(interpreter, &Interpreter::finished, this, &MainWindow::abort); disconnect(interpreter, &Interpreter::treeUpdated, inspector, &Inspector::updateTree); Executer* executer = interpreter->getExecuter(); disconnect(executer, &Executer::currentlyExecuting, editor, &Editor::markCurrentWord); disconnect(executer, &Executer::currentlyExecuting, inspector, &Inspector::markTreeNode); - disconnect(executer, SIGNAL(variableTableUpdated(QString,Value)), - inspector, SLOT(updateVariable(QString,Value))); - disconnect(executer, SIGNAL(functionTableUpdated(QString,QStringList)), - inspector, SLOT(updateFunction(QString,QStringList))); + disconnect(executer, &Executer::variableTableUpdated, + inspector, &Inspector::updateVariable); + disconnect(executer, &Executer::functionTableUpdated, + inspector, &Inspector::updateFunction); if (interpreter->state() == Interpreter::Uninitialized || interpreter->state() == Interpreter::Finished || interpreter->state() == Interpreter::Aborted) { interpreter->initialize(operation); } runAct->setEnabled(false); pauseAct->setEnabled(false); abortAct->setEnabled(false); currentlyRunningConsole = true; while (!(interpreter->state() == Interpreter::Finished || interpreter->state() == Interpreter::Aborted)) { interpreter->interpret(); } currentlyRunningConsole = false; runAct->setEnabled(true); pauseAct->setEnabled(false); abortAct->setEnabled(false); QString errorMessage; if (interpreter->encounteredErrors()) { ErrorList* errorList = interpreter->getErrorList(); //qDebug() << errorList->first().text(); errorMessage = errorList->first().text(); } connect(interpreter, &Interpreter::finished, this, &MainWindow::abort); connect(interpreter, &Interpreter::treeUpdated, inspector, &Inspector::updateTree); connect(executer, &Executer::currentlyExecuting, editor, &Editor::markCurrentWord); connect(executer, &Executer::currentlyExecuting, inspector, &Inspector::markTreeNode); connect(executer, &Executer::variableTableUpdated, inspector, &Inspector::updateVariable); connect(executer, &Executer::functionTableUpdated, inspector, &Inspector::updateFunction); return errorMessage; } void MainWindow::iterate() { if (interpreter->state() == Interpreter::Finished || interpreter->state() == Interpreter::Aborted) { abort(); return; } runAct->setEnabled(false); pauseAct->setChecked(false); pauseAct->setEnabled(true); abortAct->setEnabled(true); if (interpreter->state() == Interpreter::Executing) { iterationTimer->stop(); iterationTimer->setSingleShot(true); switch (runSpeed) { case 0: iterationTimer->start(0); break; case 1: iterationTimer->start(0); break; case 2: iterationTimer->start(500); break; case 3: iterationTimer->start(1000); break; case 4: iterationTimer->start(3000); break; case 5: iterationTimer->stop(); interpreter->interpret(); pauseAct->setChecked(true); pause(); return; } } interpreter->interpret(); } void MainWindow::pause() { if (pauseAct->isChecked()) { runAct->setEnabled(true); iterationTimer->stop(); return; } iterate(); } void MainWindow::abort() { iterationTimer->stop(); interpreter->abort(); editor->removeMarkings(); inspector->clearAllMarks(); runAct->setEnabled(true); pauseAct->setChecked(false); pauseAct->setEnabled(false); abortAct->setEnabled(false); editor->enable(); console->enable(); executeConsoleAct->setEnabled(true); if (interpreter->encounteredErrors()) { errorDialog->setErrorList(interpreter->getErrorList()); showErrorDialog(true); } } void MainWindow::updateContentName(const QString& str) { QString caption = str.isEmpty() ? i18n("untitled") : str; bool modified = editor->isModified(); setWindowTitle(caption + QLatin1String("[*]")); setWindowModified(modified); - statusBarFileNameLabel->setText(QString(" %1%2 ").arg(caption).arg(modified ? "*" : "")); + statusBarFileNameLabel->setText(QStringLiteral(" %1%2 ").arg(caption).arg(modified ? "*" : "")); } void MainWindow::addToRecentFiles(const QUrl &url) { recentFilesAction->addUrl(url); } void MainWindow::readConfig() { KConfigGroup config(KSharedConfig::openConfig(), "General Options"); // m_paShowStatusBar->setChecked(config->readEntry("ShowStatusBar", QVariant(false)).toBool()); // m_paShowPath->setChecked(config->readEntry("ShowPath", QVariant(false)).toBool()); recentFilesAction->loadEntries(KSharedConfig::openConfig()->group("Recent Files")); QString lang_code(config.readEntry("currentLanguageCode", QVariant(QString())).toString()); - if (lang_code.isEmpty()) lang_code = "en_US"; // null-string are saved as empty-strings + if (lang_code.isEmpty()) lang_code = QStringLiteral("en_US"); // null-string are saved as empty-strings setCurrentLanguage(lang_code); // if(m_paShowStatusBar->isChecked()) // statusBar()->show(); // else // statusBar()->hide(); } void MainWindow::writeConfig() { KConfigGroup config(KSharedConfig::openConfig(), "General Options"); // config.writeEntry("ShowStatusBar",m_paShowStatusBar->isChecked()); // config.writeEntry("ShowPath",m_paShowPath->isChecked()); recentFilesAction->saveEntries(KSharedConfig::openConfig()->group( "Recent Files")); config.writeEntry("currentLanguageCode", currentLanguageCode); config.sync(); } void MainWindow::exportToPng() { // copied from edit code for file selection QUrl url = QFileDialog::getSaveFileUrl(this, i18n("Save as Picture"), QUrl(), - QString("%1 (*.png);;%2 (*)").arg(i18n("PNG Images")).arg(i18n("All files"))); + QStringLiteral("%1 (*.png);;%2 (*)").arg(i18n("PNG Images")).arg(i18n("All files"))); if (url.isEmpty()) return; // get our image from the canvas and save to png QImage pict = canvas->getPicture(); if (url.isLocalFile()) { pict.save(url.toLocalFile(), "PNG"); } else { pict.save(url.path(), "PNG"); } } void MainWindow::exportToSvg() { // copied from edit code for file selection // canvas->saveAsSvg() does not handle QUrl, so only local files are accepted - QString path = QFileDialog::getSaveFileName(this, i18n("Save as SVG"), QString(), QString("%1 (.*svg);;%2 (*)").arg(i18n("Scalable Vector Graphics")).arg(i18n("All files"))); + QString path = QFileDialog::getSaveFileName(this, i18n("Save as SVG"), QString(), QStringLiteral("%1 (.*svg);;%2 (*)").arg(i18n("Scalable Vector Graphics")).arg(i18n("All files"))); if (path.isEmpty()) return; canvas->saveAsSvg(windowTitle(), path); } void MainWindow::exportToHtml() { // copied from edit code for file selection // we do not handle QUrl, so only local files are accepted - QString path = QFileDialog::getSaveFileName(this, i18n("Save code as HTML"), QString(), QString("%1 (*.html);;%2 (*)").arg(i18n("HTML documents")).arg(i18n("All files"))); + QString path = QFileDialog::getSaveFileName(this, i18n("Save code as HTML"), QString(), QStringLiteral("%1 (*.html);;%2 (*)").arg(i18n("HTML documents")).arg(i18n("All files"))); if (path.isEmpty()) return; QSaveFile file(path); if (!file.open(QIODevice::WriteOnly)) return; QTextStream out(&file); out << editor->toHtml(windowTitle(), currentLanguageCode); out.flush(); file.commit(); } // slots for logo functions that need to use the MainWindow class: void MainWindow::slotInputDialog(QString& value) { iterationTimer->stop(); value = QInputDialog::getText(this, i18n("Input"), i18n("Input"), QLineEdit::Normal, value); if(!currentlyRunningConsole) run(); } void MainWindow::slotMessageDialog(const QString& text) { iterationTimer->stop(); KMessageBox::information(this, text, i18n("Message")); if(!currentlyRunningConsole) run(); } void MainWindow::getNewExampleDialog() { QPointer dialog = new KNS3::DownloadDialog(this); dialog->exec(); updateExamplesMenu(); delete dialog; } diff --git a/src/sprite.cpp b/src/sprite.cpp index e2a5b85..2bd0d4f 100644 --- a/src/sprite.cpp +++ b/src/sprite.cpp @@ -1,68 +1,68 @@ /* Copyright (C) 2003-2008 Cies Breijs This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "sprite.h" #include #include const int SPRITE_SIZE = 30; Sprite::Sprite() - : QGraphicsSvgItem(":turtle.svg") + : QGraphicsSvgItem(QStringLiteral(":turtle.svg")) { m_angle = 0; m_speed = 0; setAngle(0); } void Sprite::setSpriteSize(int size) { int w = renderer()->defaultSize().width(); int h = renderer()->defaultSize().height(); if (size <= 0 || w <= 0 || h <= 0) return; qreal s = (static_cast(size)) / ((w > h) ? w : h); setTransform(QTransform::fromScale(s, s), true); } void Sprite::setAngle(double degrees) { resetTransform(); setSpriteSize(SPRITE_SIZE); // Default rotation is done with the top-left corner of the SVG as the rotation point, // but we want to the rotation to be around the SVG's center... // This is why this "translation" is needed before the actual rotation. QTransform transform = QTransform::fromTranslate( renderer()->defaultSize().width() * cos((degrees-135) * M_PI/180) * sqrt(static_cast(2.0))/2, renderer()->defaultSize().height() * sin((degrees-135) * M_PI/180) * sqrt(static_cast(2.0))/2 ); transform.rotate(degrees); setTransform(transform, true); m_angle = degrees; //TODO: Check if the update can be done more efficiently update(); }