File indexing completed on 2024-04-21 03:41:52

0001 /***************************************************************************
0002  *   Copyright (C) 2004-2007 by Albert Astals Cid                          *
0003  *   aacid@kde.org                                                         *
0004  *                                                                         *
0005  *   This program is free software; you can redistribute it and/or modify  *
0006  *   it under the terms of the GNU General Public License as published by  *
0007  *   the Free Software Foundation; either version 2 of the License, or     *
0008  *   (at your option) any later version.                                   *
0009  ***************************************************************************/
0010 
0011 #include "mapasker.h"
0012 
0013 #include <KMessageBox>
0014 #include <KLocalizedString>
0015 
0016 #include <QLabel>
0017 #include <QLayout>
0018 #include <QMouseEvent>
0019 #include <QRandomGenerator>
0020 #include <QScrollBar>
0021 #include <QString>
0022 
0023 #include "map.h"
0024 #include "mapwidget.h"
0025 
0026 #include "settings.h"
0027 
0028 static QString guessWikipediaDomain()
0029 {
0030     QLocale systemLocale = QLocale::system();
0031     QString languageCode;
0032     QLocale::Language systemLanguage = systemLocale.language();
0033     if ( systemLanguage == QLocale::AnyLanguage || systemLanguage == QLocale::C ) {
0034         languageCode = QStringLiteral("en");
0035     } else {
0036         languageCode = systemLocale.name().split(QLatin1Char('_')).first();
0037     }
0038 
0039     return QStringLiteral( "https://%1.wikipedia.org/wiki/" ).arg( languageCode );
0040 }
0041 
0042 mapAsker::mapAsker(QWidget *parent, KGmap *m, QWidget *w, bool asker, uint count) : askWidget(parent, m, w, count, asker), p_asker(asker), p_firstShow(true)
0043 {
0044     QVBoxLayout *lay = new QVBoxLayout(this);
0045     lay -> setContentsMargins(0, 0, 0, 0);
0046     lay -> setSpacing(0);
0047 
0048     p_mapWidget = new mapWidget(this);
0049     p_popupManager.setWidget(p_mapWidget->viewport());
0050     lay -> addWidget(p_mapWidget);
0051 
0052     p_shouldClearPopup = false;
0053 
0054     connect(p_mapWidget, &mapWidget::clicked, this, &mapAsker::handleMapClick);
0055     connect(p_mapWidget, &mapWidget::setMoveActionChecked, this, &mapAsker::setMoveActionChecked);
0056     connect(p_mapWidget, &mapWidget::setZoomActionChecked, this, &mapAsker::setZoomActionChecked);
0057     connect(p_mapWidget, &mapWidget::setMoveActionEnabled, this, &mapAsker::setMoveActionEnabled);
0058 
0059     if (asker)
0060     {
0061         QVBoxLayout *vbl = static_cast<QVBoxLayout*>(w -> layout());
0062         p_next = new QLabel(w);
0063         p_next -> setAlignment(Qt::AlignTop | Qt::AlignHCenter);
0064         p_next -> setWordWrap(true);
0065         p_fill = new QWidget(w);
0066         p_fill -> show();
0067         vbl -> addWidget(p_next);
0068         vbl -> addWidget(p_fill, 1);
0069         nextQuestion();
0070     }
0071     else
0072     {
0073         p_next = nullptr;
0074         p_fill = nullptr;
0075     }
0076 }
0077 
0078 mapAsker::~mapAsker()
0079 {
0080     delete p_next;
0081     delete p_fill;
0082 }
0083 
0084 bool mapAsker::isAsker() const
0085 {
0086     return p_answers;
0087 }
0088 
0089 void mapAsker::mousePressEvent(QMouseEvent*)
0090 {
0091     p_popupManager.clear();
0092 }
0093 
0094 void mapAsker::setMovement(bool b)
0095 {
0096     p_mapWidget -> setMapMove(b);
0097     p_popupManager.clear();
0098 }
0099 
0100 void mapAsker::setZoom(bool b)
0101 {
0102     askWidget::setZoom(b);
0103     p_mapWidget -> setMapZoom(b);
0104     p_popupManager.clear();
0105 }
0106 
0107 void mapAsker::setOriginalZoom()
0108 {
0109     p_mapWidget -> setOriginalImage();
0110     p_popupManager.clear();
0111 }
0112 
0113 void mapAsker::setAutomaticZoom(bool automaticZoom)
0114 {
0115     p_mapWidget -> setAutomaticZoom(automaticZoom);
0116     p_popupManager.clear();
0117 }
0118 
0119 void mapAsker::handleMapClick(QRgb c, const QPoint& p, bool isMoving)
0120 {
0121     if ( kgeographySettings::self() -> tooltipFollowsMouse() && p_asker && isMoving)
0122     {
0123         // Don't do anything if we're click+moving the mouse and are in question mode
0124         return;
0125     }
0126     QRgb colorSeen = c;
0127     QString correctDivision;
0128     QRgb correctRgb;
0129 
0130     if ( p_asker )
0131     {
0132         correctDivision = lastDivisionAsked();
0133         correctRgb = p_map -> getColor(correctDivision).rgb();
0134 
0135         if ( ! p_shuffledColormap.empty() )
0136         {
0137             int i = p_originalColormap.indexOf(correctRgb);
0138             correctRgb = p_shuffledColormap[i];
0139 
0140             i = p_shuffledColormap.indexOf(c);
0141             c = p_originalColormap[i];
0142         }
0143     }
0144     QString aux, cap;
0145     aux = p_map -> getWhatIs(c, !p_asker);
0146     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)));
0147     else if (p_shouldClearPopup)
0148     {
0149         p_popupManager.clear();
0150         p_shouldClearPopup = false;
0151     }
0152     else if (!p_asker)
0153     {
0154         const division *vDivision = p_map -> getDivision(aux);
0155         QString flagFile = vDivision -> getFlagFile();
0156         if (vDivision -> canAsk(division::eCapital)) cap = vDivision -> getCapital();
0157         if (!cap.isEmpty()) cap = i18nc("@item Capital name in map popup", "%1", cap);
0158 
0159         QString wikiLink (guessWikipediaDomain());
0160         wikiLink.append(vDivision -> getName ());
0161         if (!vDivision -> canAsk(division::eClick)) wikiLink = QLatin1String("");
0162 
0163         aux = i18nc("@item Region name in map popup", "%1", vDivision -> getName ());
0164         
0165         if (!flagFile.isEmpty()) p_popupManager.show(aux, wikiLink, cap, p, flagFile);
0166         else if (!cap.isEmpty()) p_popupManager.show(aux, wikiLink, cap , p);
0167         else p_popupManager.show(aux, wikiLink, p);
0168     }
0169     else if (!aux.isEmpty())
0170     {
0171         p_currentAnswer.setCorrectAnswer(QColor(correctRgb));
0172         QVariantList vAnswer;
0173         QColor vColor = QColor(colorSeen);
0174         QRgb vColorRgb = vColor.toRgb().rgb();
0175         vAnswer.append(vColor);
0176         QString vDivisionName;
0177         QRgb origColor;
0178         division * vDivision;
0179         if (kgeographySettings::self()->colorDisguise() == kgeographySettings::EnumColorDisguise::Scramble)
0180         {
0181             int i = p_shuffledColormap.indexOf(vColorRgb);
0182             origColor = p_originalColormap[i];
0183             vDivision = p_map->getDivision(origColor);
0184         }
0185         else
0186         {
0187             vDivision = p_map->getDivision(vColorRgb);
0188         }
0189         vDivisionName = vDivision -> getName();
0190         vAnswer.append(vDivisionName);
0191         p_currentAnswer.setAnswer(vAnswer);
0192         questionAnswered(aux == correctDivision);
0193         nextQuestion();
0194     }
0195 }
0196 
0197 void mapAsker::nextQuestionHook(const division *div)
0198 {
0199     const QString divisionName = div -> getName();
0200     p_next -> setText(i18nc("@info:status", "Please click on:<br/><b>%1</b>", divisionName));
0201     p_currentAnswer.setQuestion(i18nc("@item:intable column Question, %1 is region name", "%1", divisionName));
0202     p_next -> show();
0203     QRgb c = div -> getRGB();
0204     p_currentAnswer.setCorrectAnswer(QColor(c));
0205 }
0206 
0207 QString mapAsker::getQuestionHook() const
0208 {
0209         QString divisionType = p_map->getDivisionsString();
0210         return i18nc("@title", "%1 in Map", divisionType);
0211 }
0212 
0213 void mapAsker::showEvent(QShowEvent *)
0214 {
0215     if (p_firstShow)
0216     {
0217         bool isForAsking = p_next != nullptr;
0218 
0219         QImage image;
0220         image.load(p_map->getMapFile());
0221 
0222         if ( isForAsking
0223           && kgeographySettings::self()->colorDisguise() == kgeographySettings::EnumColorDisguise::Scramble )
0224         {
0225             QVector<QRgb> colormap = image.colorTable();
0226             p_originalColormap = colormap;
0227 
0228             QVector<uchar> swapableIndexes;
0229             const QList<const division*> divisions = p_map->getAllDivisionsOrdered();
0230             for(const division *id : divisions)
0231             {
0232                 if ( id->canAsk(division::eClick) )
0233                 {
0234                     const QRgb rgb = id->getRGB();
0235                     const int colorIdx = colormap.indexOf(rgb);
0236                     swapableIndexes << colorIdx;
0237                 }
0238             }
0239             QVector<uchar> shuffling = swapableIndexes;
0240 
0241             const int n = swapableIndexes.size();
0242             for ( int i = 2; i < n ; ++i )
0243             {
0244                 int o = QRandomGenerator::global()->bounded(i);
0245                 int ci = shuffling[i];
0246                 int co = shuffling[o];
0247                 qSwap(shuffling[i], shuffling[o]);
0248                 qSwap(colormap[ci], colormap[co]);
0249             }
0250             p_shuffledColormap = colormap;
0251             image.setColorTable(colormap);
0252         }
0253 
0254         p_mapWidget -> init(image);
0255         p_firstShow = false;
0256     }
0257 }
0258 
0259 QSize mapAsker::mapSize() const
0260 {
0261     return p_mapWidget -> mapSize();
0262 }
0263 
0264 #include "moc_mapasker.cpp"