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"