diff --git a/src/capitaldivisionasker.cpp b/src/capitaldivisionasker.cpp index ab18212..d9eb8bb 100644 --- a/src/capitaldivisionasker.cpp +++ b/src/capitaldivisionasker.cpp @@ -1,64 +1,66 @@ /*************************************************************************** * Copyright (C) 2004 by Albert Astals Cid * * aacid@kde.org * * * * 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. * ***************************************************************************/ #include "capitaldivisionasker.h" #include #include #include "map.h" capitalDivisionAsker::capitalDivisionAsker(QWidget *parent, KGmap *m, QWidget *w, uint count) : boxAsker(parent, m, w, count) { init(); } bool capitalDivisionAsker::nextBoxAskerQuestionHook(const QString &division, int i, bool isAnswer) { bool b; if (isAnswer) { + const QString divisionName = p_map -> getDivision(division) -> getName(); p_capital = p_map -> getDivisionCapital(division); p_currentAnswer.setQuestion(i18nc("@item:intable column Question, %1 is capital name", "%1", p_capital)); - p_currentAnswer.setCorrectAnswer(i18nc("@option:radio is the capital of...", "%1", i18nc(p_map -> getFileName().toUtf8(), division.toUtf8()))); + p_currentAnswer.setCorrectAnswer(i18nc("@option:radio is the capital of...", "%1", divisionName)); setQuestion(i18nc("@title:group", p_map->getCapitalToDivisionQuestionPattern().toUtf8(), p_capital)); - p_radioButtons[i] -> setText(i18nc("@option:radio is the capital of...", "%1", i18nc(p_map -> getFileName().toUtf8(), division.toUtf8()))); + p_radioButtons[i] -> setText(i18nc("@option:radio is the capital of...", "%1", divisionName)); b = true; } else { // There are crazy countries like Norway where two different divisions // have the same capital, avoid asking // Oslo is the capital of ... // Oslo (true) // Akershus (true) // Buskerud // Hedmark if (p_map -> getDivisionCapital(division) != p_capital) { - p_radioButtons[i] -> setText(i18nc("@option:radio is the capital of...", "%1", i18nc(p_map -> getFileName().toUtf8(), division.toUtf8()))); + const QString divisionName = p_map -> getDivision(division) -> getName(); + p_radioButtons[i] -> setText(i18nc("@option:radio is the capital of...", "%1", divisionName)); b = true; } else b = false; } return b; } void capitalDivisionAsker::setAnswerHook(int userSays) { p_currentAnswer.setAnswer(p_radioButtons[userSays] -> text()); } QString capitalDivisionAsker::getQuestionHook() const { return p_map->getCapitalToDivisionTitle(); } diff --git a/src/divisioncapitalasker.cpp b/src/divisioncapitalasker.cpp index 2eebc0c..bfb4508 100644 --- a/src/divisioncapitalasker.cpp +++ b/src/divisioncapitalasker.cpp @@ -1,81 +1,81 @@ /*************************************************************************** * Copyright (C) 2004 by Albert Astals Cid * * aacid@kde.org * * * * 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. * ***************************************************************************/ #include "divisioncapitalasker.h" #include #include #include #include "map.h" divisionCapitalAsker::divisionCapitalAsker(QWidget *parent, KGmap *m, QWidget *w, uint count) : boxAsker(parent, m, w, count) { init(); } bool divisionCapitalAsker::nextBoxAskerQuestionHook(const QString &division, int i, bool isAnswer) { bool b; if (isAnswer) { - QString divisionName = i18nc(p_map -> getFileName().toUtf8(), division.toUtf8()); + const QString divisionName = p_map -> getDivision(division) -> getName(); setQuestion(i18nc("@title:group", p_map->getDivisionToCapitalQuestionPattern().toUtf8(), divisionName)); - p_currentAnswer.setQuestion(i18nc("@item:intable column Question, %1 is region name", "%1", i18nc(p_map -> getFileName().toUtf8(), division.toUtf8()))); + p_currentAnswer.setQuestion(i18nc("@item:intable column Question, %1 is region name", "%1", divisionName)); p_capital = p_map -> getDivisionCapital(division); p_currentAnswer.setCorrectAnswer(i18nc("@option:radio The capital of is...", "%1", p_capital)); p_radioButtons[i] -> setText(i18nc("@option:radio The capital of is...", "%1", p_capital)); b = true; QStringList falseCapitals = p_map -> getDivisionFalseCapitals(division); int index = 0; while (!falseCapitals.isEmpty() && index < 4) { if (index != i) { int random = (int)((float)falseCapitals.size() * KRandom::random() / (RAND_MAX + 1.0)); QString falseCapital = falseCapitals.at(random); falseCapitals.removeAt(random); p_radioButtons[index] -> setText(i18nc("@option:radio The capital of is...", "%1", i18nc(p_map -> getFileName().toUtf8(), falseCapital.toUtf8()))); } ++index; } } else { QString capital; capital = p_map -> getDivisionCapital(division); // There are crazy countries like Norway where two different divisions // have the same capital, avoid asking // The capital of Akershus is ... // Oslo (true) // Oslo (true) // Lillehammer // Moss if (capital != p_capital) { p_radioButtons[i] -> setText(i18nc("@option:radio The capital of is...", "%1", capital)); b = true; } else b = false; } return b; } void divisionCapitalAsker::setAnswerHook(int userSays) { p_currentAnswer.setAnswer(p_radioButtons[userSays] -> text()); } QString divisionCapitalAsker::getQuestionHook() const { return p_map->getDivisionToCapitalTitle(); } diff --git a/src/divisionflagasker.cpp b/src/divisionflagasker.cpp index ccd0206..c0e2d62 100644 --- a/src/divisionflagasker.cpp +++ b/src/divisionflagasker.cpp @@ -1,57 +1,57 @@ /*************************************************************************** * Copyright (C) 2004 by Albert Astals Cid * * aacid@kde.org * * * * 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. * ***************************************************************************/ #include "divisionflagasker.h" #include #include #include #include "map.h" divisionFlagAsker::divisionFlagAsker(QWidget *parent, KGmap *m, QWidget *w, uint count) : boxAsker(parent, m, w, count) { init(); } bool divisionFlagAsker::nextBoxAskerQuestionHook(const QString &division, int i, bool isAnswer) { QSize pixmapSize(60, 40); QIcon icon(p_map -> getDivisionFlagFile(division)); if (isAnswer) { - QString divisionName = i18nc(p_map -> getFileName().toUtf8(), division.toUtf8()); + const QString divisionName = p_map -> getDivision(division) -> getName(); setQuestion(i18nc("@title:group", "The flag of %1 is...", divisionName)); p_currentAnswer.setCorrectAnswer(icon.pixmap(QSize(60, 40))); - p_currentAnswer.setQuestion(i18nc("@item:intable column Question, %1 is region name", "%1", i18nc(p_map -> getFileName().toUtf8(), division.toUtf8()))); + p_currentAnswer.setQuestion(i18nc("@item:intable column Question, %1 is region name", "%1", divisionName)); } else { // There are some maps like the Pacific one where two divisions have the same flag if (icon.pixmap(pixmapSize).toImage() == p_radioButtons[p_position]->icon().pixmap(pixmapSize).toImage()) return false; } p_radioButtons[i] -> setIcon(icon); p_radioButtons[i] -> show(); p_radioButtons[i] -> setIconSize(pixmapSize); return true; } void divisionFlagAsker::setAnswerHook(int userSays) { QIcon i = p_radioButtons[userSays] -> icon(); p_currentAnswer.setAnswer(i.pixmap(QSize(60, 40))); } QString divisionFlagAsker::getQuestionHook() const { QString divisionType = p_map->getDivisionsString(); return i18nc("@title", "Flag of %1", divisionType); } diff --git a/src/flagdivisionasker.cpp b/src/flagdivisionasker.cpp index 33330bc..2837d53 100644 --- a/src/flagdivisionasker.cpp +++ b/src/flagdivisionasker.cpp @@ -1,80 +1,82 @@ /*************************************************************************** * Copyright (C) 2004-2005 by Albert Astals Cid * * aacid@kde.org * * * * 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. * ***************************************************************************/ #include "flagdivisionasker.h" #include #include #include #include #include #include "map.h" +#include "division.h" class flagWidget : public QWidget { public: flagWidget(QWidget *parent) : QWidget(parent) { } QImage img; protected: void paintEvent(QPaintEvent *) override { QPainter p(this); p.drawImage((width() - img.width()) / 2, 0, img); } }; flagDivisionAsker::flagDivisionAsker(QWidget *parent, KGmap *m, QWidget *w, uint count) : boxAsker(parent, m, w, count) { p_flag = new flagWidget(this); setHeadWidget(p_flag); setQuestion(i18nc("@title:group", "This flag belongs to:")); init(); } bool flagDivisionAsker::nextBoxAskerQuestionHook(const QString &division, int i, bool isAnswer) { + const class division *vDivision = p_map -> getDivision(division); if (isAnswer) { // we put the flag image - QImage image(p_map -> getDivisionFlagFile(division)); + QImage image(vDivision -> getFlagFile()); p_flag -> img = image; p_flag -> setMinimumSize(image.size()); p_flag -> update(); p_currentAnswer.setQuestion(QPixmap::fromImage(image.scaled(image.width()/5, image.height()/5, Qt::IgnoreAspectRatio, Qt::SmoothTransformation))); - p_currentAnswer.setCorrectAnswer(i18nc("@option:radio This flag belongs to:", "%1", i18nc(p_map -> getFileName().toUtf8(), division.toUtf8()))); + p_currentAnswer.setCorrectAnswer(i18nc("@option:radio This flag belongs to:", "%1", vDivision -> getName())); } else { // There are some maps like the Pacific one where two divisions have the same flag - QImage image(p_map -> getDivisionFlagFile(division)); + QImage image(vDivision -> getFlagFile()); if (p_flag -> img == image) return false; } - p_radioButtons[i] -> setText(i18nc("@option:radio This flag belongs to:", "%1", i18nc(p_map -> getFileName().toUtf8(), division.toUtf8()))); + p_radioButtons[i] -> setText(i18nc("@option:radio This flag belongs to:", "%1", vDivision -> getName())); return true; } void flagDivisionAsker::setAnswerHook(int userSays) { p_currentAnswer.setAnswer(p_radioButtons[userSays] -> text()); } QString flagDivisionAsker::getQuestionHook() const { QString divisionType = p_map->getDivisionsString(); return i18nc("@title", "%1 by Flag", divisionType); } diff --git a/src/map.cpp b/src/map.cpp index 5bb723b..b81fba1 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -1,234 +1,234 @@ /*************************************************************************** * Copyright (C) 2004-2007 by Albert Astals Cid * * aacid@kde.org * * * * 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. * ***************************************************************************/ #include "map.h" #include // for RAND_MAX #include #include #include #include #include "division.h" KGmap::KGmap() { p_capitalToDivisionPattern = I18N_NOOP2("@title:group", "%1 is the capital of..."); p_divisionToCapitalPattern = I18N_NOOP2("@title:group", "The capital of %1 is..."); } KGmap::~KGmap() { qDeleteAll(p_divisions); } bool KGmap::addDivision(division *d) { bool b; - if ( ( getDivision(d -> getName()) == NULL && getDivision(d -> getRGB()) == NULL ) || - ( getDivision(d -> getName()) != NULL && getDivision(d -> getRGB()) == NULL && !d->canAsk(division::eClick) && !getDivision(d -> getName())->canAsk(division::eClick) ) ) + if ( ( getDivision(d -> getUntranslatedName()) == NULL && getDivision(d -> getRGB()) == NULL ) || + ( getDivision(d -> getUntranslatedName()) != NULL && getDivision(d -> getRGB()) == NULL && !d->canAsk(division::eClick) && !getDivision(d -> getUntranslatedName())->canAsk(division::eClick) ) ) { p_divisions.append(d); b = true; } else b = false; return b; } void KGmap::setFile(const QString &s) { p_file = s; } bool KGmap::setMapFile(const QString &s) { p_mapFile = s; return QFile::exists(s); } void KGmap::setName(const QString &s) { p_name = s; } void KGmap::setDivisionsString(const QString &s) { p_divisionsString = s; } void KGmap::setAuthor(const QString &s) { p_author = s; } void KGmap::setCapitalToDivisionQuestionPattern(const QString &str) { p_capitalToDivisionPattern = str; } void KGmap::setDivisionToCapitalQuestionPattern(const QString &str) { p_divisionToCapitalPattern = str; } void KGmap::setCapitalToDivisionTitle(const QString &str) { p_capitalToDivisionTitle = str; } void KGmap::setDivisionToCapitalTitle(const QString &str) { p_divisionToCapitalTitle = str; } uint KGmap::count(division::askMode am) const { uint count = 0; foreach(const division *d, p_divisions) { if (d->canAsk(am)) count++; } return count; } QString KGmap::getDivisionFlagFile(const QString &s) const { return getDivision(s) -> getFlagFile(); } QString KGmap::getDivisionCapital(const QString &s) const { return getDivision(s) -> getCapital(); } QStringList KGmap::getDivisionFalseCapitals(const QString &divisionName) const { return getDivision(divisionName) -> getFalseCapitals(); } QString KGmap::getCapitalToDivisionQuestionPattern() const { return p_capitalToDivisionPattern; } QString KGmap::getDivisionToCapitalQuestionPattern() const { return p_divisionToCapitalPattern; } QString KGmap::getCapitalToDivisionTitle() const { return p_capitalToDivisionTitle; } QString KGmap::getDivisionToCapitalTitle() const { return p_divisionToCapitalTitle; } QString KGmap::getFile() const { return p_file; } QString KGmap::getFileName() const { QFileInfo fi(p_file); return fi.fileName(); } QString KGmap::getMapFile() const { return p_mapFile; } QString KGmap::getName() const { return p_name; } QString KGmap::getDivisionsString() const { if (p_divisionsString.isNull()) return i18n("Regions"); else return p_divisionsString; } QString KGmap::getRandomDivision(division::askMode am) const { QList aux; int i = (int)((float)p_divisions.size() * KRandom::random() / (RAND_MAX + 1.0)); if (!p_divisions[i] -> canAsk(am)) return getRandomDivision(am); - else return p_divisions[i] -> getName(); + else return p_divisions[i] -> getUntranslatedName(); } QString KGmap::getWhatIs(QRgb c, bool all) const { // this is only asked from mapasker.cpp hence the division::eClick in canAsk division *d = getDivision(c); if (d == NULL) return QStringLiteral("nothing"); else { - if (all) return d -> getName(); - else if (d -> canAsk(division::eClick)) return d -> getName(); + if (all) return d -> getUntranslatedName(); + else if (d -> canAsk(division::eClick)) return d -> getUntranslatedName(); else return QLatin1String(""); } } QString KGmap::getAuthor() const { return p_author; } QColor KGmap::getColor(const QString &s) const { return QColor(getDivision(s)->getRGB()); } QList KGmap::getIgnoredDivisions(division::askMode am) const { QList ignoredDivisions; foreach (division* div, p_divisions) if (!div->canAsk(am)) ignoredDivisions << div; return ignoredDivisions; } QList KGmap::getAllDivisionsOrdered() const { QList constDivisions; foreach (const division* div, p_divisions) constDivisions << div; return constDivisions; } division *KGmap::getDivision(const QString &divisionName) const { foreach (division* div, p_divisions) { - if (div->getName() == divisionName) return div; + if (div->getUntranslatedName() == divisionName) return div; } return NULL; } division *KGmap::getDivision(QRgb c) const { foreach (division* div, p_divisions) { if (div->getRGB() == c) return div; } return NULL; } bool KGmap::getDivisionCanAsk(const QString &div, division::askMode am) const { return getDivision(div) -> canAsk(am); } diff --git a/src/map.h b/src/map.h index 675536e..ab3982c 100644 --- a/src/map.h +++ b/src/map.h @@ -1,74 +1,73 @@ /*************************************************************************** * Copyright (C) 2004-2007 by Albert Astals Cid * * aacid@kde.org * * * * 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. * ***************************************************************************/ #ifndef MAP_H #define MAP_H #include #include #include "division.h" class KGmap { public: KGmap(); ~KGmap(); bool addDivision(division *d); void setFile(const QString &s); bool setMapFile(const QString &s); void setName(const QString &s); void setDivisionsString(const QString &s); void setAuthor(const QString &s); void setCapitalToDivisionQuestionPattern(const QString &str); void setDivisionToCapitalQuestionPattern(const QString &str); void setCapitalToDivisionTitle(const QString &str); void setDivisionToCapitalTitle(const QString &str); // return the number of askable divisions uint count(division::askMode am) const; QString getDivisionFlagFile(const QString &divisionName) const; QString getDivisionCapital(const QString &divisionName) const; QStringList getDivisionFalseCapitals(const QString &divisionName) const; bool getDivisionCanAsk(const QString &div, division::askMode am) const; QString getFile() const; QString getFileName() const; QString getMapFile() const; QString getName() const; QString getDivisionsString() const; QString getRandomDivision(division::askMode am) const; QString getWhatIs(QRgb c, bool all) const; QString getAuthor() const; QColor getColor(const QString &s) const; QList getIgnoredDivisions(division::askMode am) const; QList getAllDivisionsOrdered() const; QString getCapitalToDivisionQuestionPattern() const; QString getDivisionToCapitalQuestionPattern() const; QString getCapitalToDivisionTitle() const; QString getDivisionToCapitalTitle() const; division *getDivision(QRgb c) const; + division *getDivision(const QString &divisionName) const; private: - division *getDivision(const QString &divisionName) const; - QList p_divisions; QString p_name, p_file, p_mapFile; QString p_divisionsString; QString p_capitalToDivisionPattern; QString p_divisionToCapitalPattern; QString p_capitalToDivisionTitle; QString p_divisionToCapitalTitle; QString p_author; }; #endif diff --git a/src/mapasker.cpp b/src/mapasker.cpp index 0110580..1308995 100644 --- a/src/mapasker.cpp +++ b/src/mapasker.cpp @@ -1,257 +1,258 @@ /*************************************************************************** * Copyright (C) 2004-2007 by Albert Astals Cid * * aacid@kde.org * * * * 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. * ***************************************************************************/ #include "mapasker.h" #include #include #include #include #include #include #include #include "map.h" #include "mapwidget.h" #include "settings.h" static QString guessWikipediaDomain() { QLocale systemLocale = QLocale::system(); QString languageCode; QLocale::Language systemLanguage = systemLocale.language(); if ( systemLanguage == QLocale::AnyLanguage || systemLanguage == QLocale::C ) { languageCode = QStringLiteral("en"); } else { languageCode = systemLocale.name().split('_').first(); } return QStringLiteral( "https://%1.wikipedia.org/wiki/" ).arg( languageCode ); } mapAsker::mapAsker(QWidget *parent, KGmap *m, QWidget *w, bool asker, uint count) : askWidget(parent, m, w, count, asker), p_asker(asker), p_firstShow(true) { QVBoxLayout *lay = new QVBoxLayout(this); lay -> setContentsMargins(0, 0, 0, 0); lay -> setSpacing(0); p_mapWidget = new mapWidget(this); p_popupManager.setWidget(p_mapWidget->viewport()); lay -> addWidget(p_mapWidget); p_shouldClearPopup = false; connect(p_mapWidget, &mapWidget::clicked, this, &mapAsker::handleMapClick); connect(p_mapWidget, &mapWidget::setMoveActionChecked, this, &mapAsker::setMoveActionChecked); connect(p_mapWidget, &mapWidget::setZoomActionChecked, this, &mapAsker::setZoomActionChecked); connect(p_mapWidget, &mapWidget::setMoveActionEnabled, this, &mapAsker::setMoveActionEnabled); if (asker) { QVBoxLayout *vbl = static_cast(w -> layout()); p_next = new QLabel(w); p_next -> setAlignment(Qt::AlignTop | Qt::AlignHCenter); p_next -> setWordWrap(true); p_fill = new QWidget(w); p_fill -> show(); vbl -> addWidget(p_next); vbl -> addWidget(p_fill, 1); nextQuestion(); } else { p_next = 0; p_fill = 0; } } mapAsker::~mapAsker() { delete p_next; delete p_fill; } bool mapAsker::isAsker() const { return p_answers; } void mapAsker::mousePressEvent(QMouseEvent*) { p_popupManager.clear(); } void mapAsker::setMovement(bool b) { p_mapWidget -> setMapMove(b); p_popupManager.clear(); } void mapAsker::setZoom(bool b) { askWidget::setZoom(b); p_mapWidget -> setMapZoom(b); p_popupManager.clear(); } void mapAsker::setOriginalZoom() { p_mapWidget -> setOriginalImage(); p_popupManager.clear(); } void mapAsker::setAutomaticZoom(bool automaticZoom) { p_mapWidget -> setAutomaticZoom(automaticZoom); p_popupManager.clear(); } void mapAsker::handleMapClick(QRgb c, const QPoint &p) { QRgb colorSeen = c; QString correctDivision; QRgb correctRgb; if ( p_asker ) { correctDivision = lastDivisionAsked(); correctRgb = p_map -> getColor(correctDivision).rgb(); if ( ! p_shuffledColormap.empty() ) { int i = p_originalColormap.indexOf(correctRgb); correctRgb = p_shuffledColormap[i]; i = p_shuffledColormap.indexOf(c); c = p_originalColormap[i]; } } QString aux, cap; aux = p_map -> getWhatIs(c, !p_asker); if (aux == QLatin1String("nothing")) KMessageBox::error(this, i18nc("@info", "You have found a bug in a map. Please contact the author and tell the %1 map has nothing associated to color %2,%3,%4.", p_map -> getFile(), qRed(c), qGreen(c), qBlue(c))); else if (p_shouldClearPopup) { p_popupManager.clear(); p_shouldClearPopup = false; } else if (!p_asker) { - QString flagFile = p_map -> getDivisionFlagFile(aux); - if (p_map -> getDivisionCanAsk(aux, division::eCapital)) cap = p_map -> getDivisionCapital(aux); + const division *vDivision = p_map -> getDivision(aux); + QString flagFile = vDivision -> getFlagFile(); + if (vDivision -> canAsk(division::eCapital)) cap = vDivision -> getCapital(); if (!cap.isEmpty()) cap = i18nc("@item Capital name in map popup", "%1", cap); QString wikiLink (guessWikipediaDomain()); - wikiLink.append(i18nc(p_map -> getFileName().toUtf8(), aux.toUtf8())); - if (!p_map -> getDivisionCanAsk(aux, division::eClick)) wikiLink = QLatin1String(""); + wikiLink.append(vDivision -> getName ()); + if (!vDivision -> canAsk(division::eClick)) wikiLink = QLatin1String(""); - aux = i18nc("@item Region name in map popup", "%1", i18nc(p_map -> getFileName().toUtf8(), aux.toUtf8())); + aux = i18nc("@item Region name in map popup", "%1", vDivision -> getName ()); if (!flagFile.isEmpty()) p_popupManager.show(aux, wikiLink, cap, p, flagFile); else if (!cap.isEmpty()) p_popupManager.show(aux, wikiLink, cap , p); else p_popupManager.show(aux, wikiLink, p); } else if (!aux.isEmpty()) { p_currentAnswer.setCorrectAnswer(QColor(correctRgb)); QVariantList vAnswer; QColor vColor = QColor(colorSeen); QRgb vColorRgb = vColor.toRgb().rgb(); vAnswer.append(vColor); QString vDivisionName; QRgb origColor; division * vDivision; if (kgeographySettings::self()->colorDisguise() == kgeographySettings::EnumColorDisguise::Scramble) { int i = p_shuffledColormap.indexOf(vColorRgb); origColor = p_originalColormap[i]; vDivision = p_map->getDivision(origColor); } else { vDivision = p_map->getDivision(vColorRgb); } - vDivisionName = i18nc(p_map -> getFileName().toUtf8(), vDivision->getName().toUtf8()); + vDivisionName = vDivision -> getName(); vAnswer.append(vDivisionName); p_currentAnswer.setAnswer(vAnswer); questionAnswered(aux == correctDivision); nextQuestion(); } } void mapAsker::nextQuestionHook(const QString &division) { - QString divisionName = i18nc(p_map -> getFileName().toUtf8(), division.toUtf8()); + const QString divisionName = p_map -> getDivision(division) -> getName(); p_next -> setText(i18nc("@info:status", "Please click on:
%1", divisionName)); - p_currentAnswer.setQuestion(i18nc("@item:intable column Question, %1 is region name", "%1", i18nc(p_map -> getFileName().toUtf8(), division.toUtf8()))); + p_currentAnswer.setQuestion(i18nc("@item:intable column Question, %1 is region name", "%1", divisionName)); p_next -> show(); QRgb c = p_map -> getColor(division).rgb(); p_currentAnswer.setCorrectAnswer(QColor(c)); } QString mapAsker::getQuestionHook() const { QString divisionType = p_map->getDivisionsString(); return i18nc("@title", "%1 in Map", divisionType); } void mapAsker::showEvent(QShowEvent *) { if (p_firstShow) { bool isForAsking = p_next != NULL; QImage image; image.load(p_map->getMapFile()); if ( isForAsking && kgeographySettings::self()->colorDisguise() == kgeographySettings::EnumColorDisguise::Scramble ) { QVector colormap = image.colorTable(); p_originalColormap = colormap; QVector swapableIndexes; QList divisions = p_map->getAllDivisionsOrdered(); foreach(const division *id, divisions) { if ( id->canAsk(division::eClick) ) { const QRgb rgb = id->getRGB(); const int colorIdx = colormap.indexOf(rgb); swapableIndexes << colorIdx; } } QVector shuffling = swapableIndexes; const int n = swapableIndexes.size(); for ( int i = 2; i < n ; ++i ) { int o = int(float(i) * KRandom::random() / (RAND_MAX + 1.0)); int ci = shuffling[i]; int co = shuffling[o]; qSwap(shuffling[i], shuffling[o]); qSwap(colormap[ci], colormap[co]); } p_shuffledColormap = colormap; image.setColorTable(colormap); } p_mapWidget -> init(image); p_firstShow = false; } } QSize mapAsker::mapSize() const { return p_mapWidget -> mapSize(); } diff --git a/src/mapparser.cpp b/src/mapparser.cpp index 5f3532c..2887028 100644 --- a/src/mapparser.cpp +++ b/src/mapparser.cpp @@ -1,236 +1,236 @@ /*************************************************************************** * Copyright (C) 2004-2007 by Albert Astals Cid * * aacid@kde.org * * * * 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. * ***************************************************************************/ #include "mapparser.h" #include #include #include #include #include "division.h" #include "map.h" mapReader::mapReader() { } KGmap *mapReader::parseMap(const QString &path) { QString baseDir; p_error.clear(); KGmap *kgmap = new KGmap(); kgmap -> setFile(path); baseDir = QFileInfo(path).absolutePath() + '/'; // baseDir = path but without the file name QFile xmlFile(path); if (xmlFile.exists()) { if (xmlFile.open(QIODevice::ReadOnly)) { QDomDocument doc; doc.setContent(xmlFile.readAll()); const QDomElement &root = doc.documentElement(); if (root.tagName() == QLatin1String("map")) { const QByteArray ctxt = kgmap -> getFileName().toUtf8(); // Map name kgmap -> setName(i18nc(ctxt, getElementString(QStringLiteral("name"), root, Mandatory).toUtf8())); // Map image file if (!kgmap -> setMapFile( baseDir + getElementString(QStringLiteral("mapFile"), root, Mandatory) )) { p_error = i18n("The map image file for %1 does not exist", kgmap -> getName()); } // Divisions string QString divisionKindName = getElementString(QStringLiteral("divisionsName"), root, Mandatory); kgmap -> setDivisionsString(i18nc(ctxt, divisionKindName.toUtf8())); QString pat = getElementString(QStringLiteral("capitalToDivisionPattern"), root, Optional); if ( pat.contains('%') ) { kgmap->setCapitalToDivisionQuestionPattern(pat); } else if ( ! pat.isEmpty() ) { QTextStream stream(stderr); stream << "capitalToDivisionPattern element should contain one '%%' in map " << kgmap->getName() << kgmap -> getFile(); } pat = getElementString(QStringLiteral("divisionToCapitalPattern"), root, Optional); if ( pat.contains('%') ) { kgmap->setDivisionToCapitalQuestionPattern(pat); } else if ( ! pat.isEmpty() ) { QTextStream stream(stderr); stream << "divisionToCapitalPattern element should contain one '%%' in map " << kgmap->getName() << kgmap -> getFile(); } QString title = getElementString(QStringLiteral("capitalToDivisionTitle"), root, Optional); if ( ! title.isEmpty() ) { kgmap->setCapitalToDivisionTitle(i18nc("@title", title.toUtf8())); } else { kgmap->setCapitalToDivisionTitle(i18n("%1 by Capital", kgmap -> getDivisionsString())); } title = getElementString(QStringLiteral("divisionToCapitalTitle"), root, Optional); if ( ! title.isEmpty() ) { kgmap->setDivisionToCapitalTitle(i18nc("@title", title.toUtf8())); } else { kgmap->setDivisionToCapitalTitle(i18n("Capitals of %1", kgmap -> getDivisionsString())); } // Author string kgmap -> setAuthor( getElementString(QStringLiteral("author"), root, Mandatory) ); QDomElement divisionTag = root.firstChildElement(QStringLiteral("division")); while (!divisionTag.isNull()) { division *kgdiv = new division(); // division name kgdiv -> setUntranslatedName( getElementString(QStringLiteral("name"), divisionTag, Mandatory) ); - kgdiv -> setName( kgdiv -> getUntranslatedName() ); + kgdiv -> setName(i18nc(ctxt, kgdiv -> getUntranslatedName().toUtf8())); // division capital QString capital = getElementString(QStringLiteral("capital"), divisionTag, Optional); if (!capital.isEmpty()) kgdiv -> setCapital(i18nc(ctxt, capital.toUtf8())); // division flag QString flagFile = getElementString(QStringLiteral("flag"), divisionTag, Optional); if (!flagFile.isNull()) { if (!kgdiv -> setFlagFile( baseDir + "/flags/" + flagFile )) { p_error = i18n("The flag image file for %1 does not exist", kgdiv -> getName()); } } // division ignoreness const QString &ignore = getElementString(QStringLiteral("ignore"), divisionTag, Optional).toLower(); if (!ignore.isNull()) { if (ignore == QLatin1String("yes")) kgdiv -> setCanAsk(division::eNone); else if (ignore == QLatin1String("no")) kgdiv -> setCanAsk(division::eClick | division::eCapital | division::eFlag); else if (ignore == QLatin1String("allowclickmode")) kgdiv -> setCanAsk(division::eClick); else if (ignore == QLatin1String("allowclickflagmode")) kgdiv -> setCanAsk(division::eClick | division::eFlag); else { p_error = i18n("Invalid value in tag %1", QStringLiteral("")); } } // division color const QDomElement &colorTag = getElement(QStringLiteral("color"), divisionTag); kgdiv -> setRGB(getElementString(QStringLiteral("red"), colorTag, Mandatory).toInt(), getElementString(QStringLiteral("green"), colorTag, Mandatory).toInt(), getElementString(QStringLiteral("blue"), colorTag, Mandatory).toInt()); // division false capitals QStringList falseCapitals; const QDomNodeList &falseCapitalTags = divisionTag.elementsByTagName(QStringLiteral("falseCapital")); QDomElement falseCapital; for (int i = 0; i < falseCapitalTags.count(); ++i) { falseCapital = falseCapitalTags.item(i).toElement(); if (!falseCapital.isNull()) falseCapitals << falseCapital.text(); } if (!falseCapitals.isEmpty()) kgdiv->setFalseCapitals(falseCapitals); if (!kgmap -> addDivision(kgdiv)) { p_error = i18n("There is already either a division called %1 or a division with the same colors as %2", kgdiv -> getName(), kgdiv -> getName()); delete kgdiv; } divisionTag = divisionTag.nextSiblingElement(QStringLiteral("division")); } } else { p_error = i18n("The map description file should begin with the %1 tag", QStringLiteral("map")); } xmlFile.close(); } else { p_error = i18n("Could not open %1 for reading.", path); } } else { p_error = i18n("%1 does not exist.", path); } if (p_error.isNull()) return kgmap; else { delete kgmap; return NULL; } } QString mapReader::getError() const { return p_error; } QString mapReader::getElementString(const QString &tagName, const QDomElement &parentTag, eMandatoryness mandatoryness) { QString result; const QDomElement &tag = parentTag.firstChildElement(tagName); if (tag.isNull()) { if (mandatoryness == Mandatory) { p_error = i18n("The map description file should have a %1 tag inside %2", tagName, parentTag.tagName()); } } else { if (tag == parentTag.lastChildElement(tagName)) { result = tag.text(); } else { p_error = i18n("The map description file should have exactly one %1 tag inside %2", tagName, parentTag.tagName()); } } return result; } QDomElement mapReader::getElement(const QString &tagName, const QDomElement &parentTag) { const QDomElement &tag = parentTag.firstChildElement(tagName); if (tag.isNull()) { p_error = i18n("The map description file should have a %1 tag inside %2", tagName, parentTag.tagName()); } else { if (tag != parentTag.lastChildElement(tagName)) { p_error = i18n("The map description file should have exactly one %1 tag inside %2", tagName, parentTag.tagName()); } } return tag; } diff --git a/src/placeasker.cpp b/src/placeasker.cpp index 9b20271..1232d27 100644 --- a/src/placeasker.cpp +++ b/src/placeasker.cpp @@ -1,253 +1,253 @@ /*************************************************************************** * Copyright (C) 2004-2007 by Albert Astals Cid * * aacid@kde.org * * Copyright (C) 2006 by Isaac Clerencia * * isaac@warp.es * * * * 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. * ***************************************************************************/ #include "placeasker.h" #include #include #include #include #include #include #include #include #include "map.h" #include "placemapwidget.h" placeAsker::placeAsker(QWidget *parent, KGmap *m, QWidget *w, uint count) : askWidget(parent, m, w, count, true), p_currentDivisionImage(0) { QVBoxLayout *lay = new QVBoxLayout(this); lay -> setContentsMargins(0, 0, 0, 0); lay -> setSpacing(0); p_mapImage = new QImage(p_map->getMapFile()); p_mapWidget = new placeMapWidget(this); lay -> addWidget(p_mapWidget); connect(p_mapWidget, &placeMapWidget::clicked, this, &placeAsker::handleMapClick); connect(p_mapWidget, &placeMapWidget::setMoveActionChecked, this, &placeAsker::setMoveActionChecked); connect(p_mapWidget, &placeMapWidget::setZoomActionChecked, this, &placeAsker::setZoomActionChecked); connect(p_mapWidget, &placeMapWidget::setMoveActionEnabled, this, &placeAsker::setMoveActionEnabled); QVBoxLayout *vbl = static_cast(w -> layout()); p_next = new QLabel(w); p_next -> setAlignment(Qt::AlignTop | Qt::AlignHCenter); p_next -> setWordWrap(true); p_fill = new QWidget(w); p_fill -> show(); vbl -> addWidget(p_next); vbl -> addWidget(p_fill, 1); p_placedPixelIndices = p_mapWidget -> outerPixelIndices(); // Set the background image before start asking p_mapWidget -> init(p_map, p_mapImage); nextQuestion(); } placeAsker::~placeAsker() { delete p_next; delete p_fill; delete p_mapImage; } bool placeAsker::isAsker() const { return p_answers; } void placeAsker::mousePressEvent(QMouseEvent*) { } void placeAsker::setMovement(bool b) { p_mapWidget -> setMapMove(b); } void placeAsker::setZoom(bool b) { askWidget::setZoom(b); p_mapWidget -> setMapZoom(b); } void placeAsker::setOriginalZoom() { p_mapWidget -> setGameImage(); } void placeAsker::setAutomaticZoom(bool automaticZoom) { p_mapWidget -> setAutomaticZoom(automaticZoom); } void placeAsker::handleMapClick(QRgb c, const QPoint & , const QPointF &mapPoint) { QString aux; aux = p_map -> getWhatIs(c, false); if (aux == QLatin1String("nothing")) KMessageBox::error(this, i18nc("@info", "You have found a bug in a map. Please contact the author and tell the %1 map has nothing associated to color %2,%3,%4.", p_map -> getFile(), qRed(c), qGreen(c), qBlue(c))); else { p_mapWidget->placeDivision(p_currentDivisionRect); p_mapWidget->unsetCursor(); // the image is no longer needed delete p_currentDivisionImage; double distX = p_currentDivisionRect.x() - mapPoint.x(); double distY = p_currentDivisionRect.y() - mapPoint.y(); double distance = sqrt(static_cast(distX * distX + distY * distY)); int indexOfCurrent = p_mapImage -> colorTable().indexOf(p_currentRgb); bool consideredGood = distance < 5.0; // if we consider it good enough don't transmit a may be wrong color if (consideredGood) c = p_currentRgb; if (! consideredGood) { bool hasBorderShown = false; for ( int i = p_placedPixelIndices.size() ; --i >= 0 && !hasBorderShown ; ) { uchar pixelIndex = p_placedPixelIndices[i]; size_t nb = p_mapWidget -> nbBorderPixels(pixelIndex, indexOfCurrent); hasBorderShown = nb > 3; } consideredGood = !hasBorderShown && distance < 16.0; if (consideredGood) c = p_currentRgb; } if (! consideredGood) { QRect definedRect(0, 0, p_mapImage -> width(), p_mapImage -> height()); QPoint v = QPoint(mapPoint.x(), mapPoint.y()) - p_currentDivisionRect.topLeft(); QRect initialRect(p_currentDivisionRect); QRect userRect = initialRect.translated(v); QRect definedRectUser = userRect & definedRect; QPoint definedFirstDiag = definedRectUser.bottomRight() - definedRectUser.topLeft(); QPoint origFirstDiag = userRect.bottomRight() - userRect.topLeft(); QPoint badDiff = origFirstDiag -definedFirstDiag; QPoint diagDiff = origFirstDiag -badDiff; QVector stats(p_mapImage -> colorTable().size()); size_t goodCount = 0; size_t outCount = badDiff.x() * badDiff.y() + badDiff.x() * diagDiff.y() + diagDiff.x() * badDiff.y(); size_t badCount = outCount; for ( int dy = definedFirstDiag.y() -1 ; dy >= 0 ; dy-- ) { for ( int dx = definedFirstDiag.x() -1 ; dx >= 0 ; dx-- ) { int origPixelIndex = p_mapImage -> pixelIndex(initialRect.left() + dx, initialRect.top() + dy); if ( origPixelIndex != indexOfCurrent ) continue; int userPixelIndex = p_mapImage -> pixelIndex(definedRectUser.left() + dx, definedRectUser.top() + dy); if ( userPixelIndex == origPixelIndex ) goodCount++; else { stats[userPixelIndex]++; badCount++; } } } consideredGood = goodCount > 0.5 * (goodCount + badCount); if (consideredGood) c = p_currentRgb; else if (outCount > 0.5 * (goodCount + badCount)) { c = p_map -> getIgnoredDivisions(askMode())[0] -> getRGB(); } else { int indexOfMax = -1; size_t maxCount = 0; for ( int i = stats.size() -1 ; i >= 0 ; i-- ) { if ( stats[i] > maxCount ) { indexOfMax = i; maxCount = stats[i]; } } c = p_mapImage -> colorTable().at(indexOfMax); } } p_placedPixelIndices.append(indexOfCurrent); p_currentAnswer.setAnswer(QColor(c)); questionAnswered(consideredGood); nextQuestion(); } } void placeAsker::nextQuestionHook(const QString &division) { - QString divisionName = i18nc(p_map -> getFileName().toUtf8(), division.toUtf8()); + const QString divisionName = p_map -> getDivision(division) -> getName(); p_next -> setText(i18nc("@info:status", "Please place in the map:
%1", divisionName)); p_next -> show(); - p_currentAnswer.setQuestion(i18nc("@item:intable column Question, %1 is region name", "%1", i18nc(p_map -> getFileName().toUtf8(), division.toUtf8()))); + p_currentAnswer.setQuestion(i18nc("@item:intable column Question, %1 is region name", "%1", divisionName)); QColor color = p_map -> getColor(division); p_currentRgb = color.rgb(); p_currentAnswer.setCorrectAnswer(color); setCurrentDivision(division); p_mapWidget->setCurrentDivisionImage(p_currentDivisionImage); } QString placeAsker::getQuestionHook() const { QString divisionType = p_map->getDivisionsString(); return i18nc("@title", "Place %1 in Map", divisionType); } QSize placeAsker::mapSize() const { return p_mapWidget -> mapSize(); } void placeAsker::setCurrentDivision(const QString& division) { int width = p_mapImage->width(); int height = p_mapImage->height(); int minX = width; int maxX = 0; int minY = height; int maxY = 0; QRgb divColor = p_map->getColor(division).rgb(); //first iteration, detect size required by the image for (int x = 0; x < width; x++) { for (int y = 0; y < height; y++) { if (p_mapImage->pixel(x,y) == divColor) { if (x < minX) minX = x; if (x > maxX) maxX = x; if (y < minY) minY = y; if (y > maxY) maxY = y; } } } p_currentDivisionImage = new QImage(maxX - minX, maxY - minY, QImage::Format_ARGB32); p_currentDivisionRect.setCoords(minX, minY, maxX, maxY); p_currentDivisionImage->fill(Qt::transparent); //second iteration, copy the color to the new image for (int x = minX; x < maxX; x++) { for (int y = minY; y < maxY; y++) { if (p_mapImage->pixel(x,y) == divColor) p_currentDivisionImage->setPixel(x - minX, y - minY, divColor); } } }