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 "kgeography.h" 0012 0013 #include <KConfigDialog> 0014 #include <KMessageBox> 0015 #include <KStandardAction> 0016 #include <KToggleAction> 0017 #include <KToolBar> 0018 #include <KActionCollection> 0019 #include <KLocalizedString> 0020 0021 #include <QMenuBar> 0022 #include <QFile> 0023 #include <QLabel> 0024 #include <QLayout> 0025 #include <QSize> 0026 #include <QTimer> 0027 #include <QPushButton> 0028 0029 #include "answersdialog.h" 0030 #include "capitaldivisionasker.h" 0031 #include "divisioncapitalasker.h" 0032 #include "divisionflagasker.h" 0033 #include "flagdivisionasker.h" 0034 #include "settings.h" 0035 #include "mapasker.h" 0036 #include "mapchooser.h" 0037 #include "mapparser.h" 0038 #include "map.h" 0039 #include "placeasker.h" 0040 #include "integerinputdialog.h" 0041 #include "ui_kgeographyoptions.h" 0042 0043 kgeography::kgeography() : KXmlGuiWindow(), p_firstShow(true), p_mustShowResultsDialog(false) 0044 { 0045 p_map = nullptr; 0046 p_askWidget = nullptr; 0047 0048 p_bigWidget = new QWidget(this); 0049 QHBoxLayout *bigWidgetLayout = new QHBoxLayout(p_bigWidget); 0050 bigWidgetLayout -> setSpacing(0); 0051 bigWidgetLayout -> setContentsMargins(0, 0, 0, 0); 0052 0053 QWidget *leftWidget = new QWidget(p_bigWidget); 0054 QVBoxLayout *leftWidgetLayout = new QVBoxLayout(leftWidget); 0055 0056 p_currentMap = new QLabel(leftWidget); 0057 p_currentMap -> setAlignment(Qt::AlignCenter); 0058 p_consult = new QPushButton(i18n("E&xplore Map"), leftWidget); 0059 p_consult->setWhatsThis(i18n("In this section left click on any part of the map to learn about the divisions" )); 0060 QLabel * testYourselfLabel = new QLabel( i18n("Test Yourself:"), this ); 0061 testYourselfLabel->setAlignment( Qt::AlignHCenter ); 0062 p_askMap = new QPushButton(i18n("&Location of Regions"), leftWidget); 0063 p_askMap->setWhatsThis(i18n("In this challenge you are given a division name on the left under the menu and you must find it on the map and click on it")); 0064 p_askPlaceMap = new QPushButton(i18n("&Place Regions in the Map"), leftWidget); 0065 p_askPlaceMap->setWhatsThis(i18n("In this challenge you are given the shape of a region and you must place it on the map")); 0066 p_askCapitalDivisions = new QPushButton(i18n("&Regions by Capital"), leftWidget); 0067 p_askCapitalDivisions->setWhatsThis(i18n("In this quiz you have to guess the division name given its capital")); 0068 p_askDivisionCapitals = new QPushButton(i18n("&Capitals of Regions"), leftWidget); 0069 p_askDivisionCapitals->setWhatsThis(i18n("In this quiz you have to guess the capital of a given division name")); 0070 p_askFlagDivisions = new QPushButton(i18n("Re&gions by Flag"), leftWidget); 0071 p_askFlagDivisions->setWhatsThis(i18n("In this quiz you have to guess the division name given its flag")); 0072 p_askDivisionFlags = new QPushButton(i18n("&Flags of Regions"), leftWidget); 0073 p_askDivisionFlags->setWhatsThis(i18n("In this quiz you have to guess the flag of a division given its name")); 0074 p_underLeftWidget = new QWidget(leftWidget); 0075 // where the number of answers will be shown 0076 m_underLeftWidgetLayout = new QVBoxLayout(p_underLeftWidget); 0077 m_underLeftWidgetLayout->setContentsMargins(0, 0, 0, 0); 0078 0079 leftWidgetLayout -> addWidget(p_currentMap); 0080 leftWidgetLayout -> addWidget(p_consult); 0081 leftWidgetLayout -> addSpacing(10); 0082 leftWidgetLayout -> addWidget(testYourselfLabel); 0083 leftWidgetLayout -> addWidget(p_askMap); 0084 leftWidgetLayout -> addWidget(p_askPlaceMap); 0085 leftWidgetLayout -> addWidget(p_askCapitalDivisions); 0086 leftWidgetLayout -> addWidget(p_askDivisionCapitals); 0087 leftWidgetLayout -> addWidget(p_askFlagDivisions); 0088 leftWidgetLayout -> addWidget(p_askDivisionFlags); 0089 leftWidgetLayout -> addWidget(p_underLeftWidget); 0090 0091 // Make p_underLeftWidget as thin as possible, and always be shown in the same place 0092 QWidget* p_underUnderLeftWidget = new QWidget(leftWidget); 0093 QVBoxLayout *underUnderLeftWidgetLayout = new QVBoxLayout(p_underUnderLeftWidget); 0094 underUnderLeftWidgetLayout -> addStretch(1); 0095 leftWidgetLayout -> addWidget(p_underUnderLeftWidget); 0096 0097 bigWidgetLayout -> addWidget(leftWidget); 0098 setCentralWidget(p_bigWidget); 0099 0100 connect(p_consult, &QPushButton::clicked, this, &kgeography::consult); 0101 connect(p_askMap, &QPushButton::clicked, this, &kgeography::askMap); 0102 connect(p_askPlaceMap, &QPushButton::clicked, this, &kgeography::askPlaceMap); 0103 connect(p_askCapitalDivisions, &QPushButton::clicked, this, &kgeography::askCapitalDivisions); 0104 connect(p_askDivisionCapitals, &QPushButton::clicked, this, &kgeography::askDivisionCapitals); 0105 connect(p_askFlagDivisions, &QPushButton::clicked, this, &kgeography::askFlagDivisions); 0106 connect(p_askDivisionFlags, &QPushButton::clicked, this, &kgeography::askDivisionFlags); 0107 0108 QAction *a = KStandardAction::open(this, SLOT(openMap()), actionCollection()); 0109 a -> setText(i18n("&Open Map...")); 0110 0111 a = KStandardAction::quit(this, SLOT(close()), actionCollection()); 0112 0113 p_zoom = actionCollection()->add<KToggleAction>( QStringLiteral("zoom_select") ); 0114 p_zoom -> setText(i18n("&Zoom") ); 0115 p_zoom -> setIcon( QIcon::fromTheme(QStringLiteral("zoom-in")) ); 0116 p_zoom -> setEnabled(false); 0117 0118 p_zoomOriginal = actionCollection()->addAction( QStringLiteral("zoom_original") ); 0119 p_zoomOriginal -> setText( i18n("&Original Size") ); 0120 p_zoomOriginal -> setIcon( QIcon::fromTheme(QStringLiteral("zoom-original")) ); 0121 p_zoomOriginal -> setEnabled(false); 0122 0123 p_zoomAutomatic = actionCollection()->add<KToggleAction>( QStringLiteral("zoom_automatic") ); 0124 p_zoomAutomatic -> setText( i18n("&Automatic Zoom") ); 0125 p_zoomAutomatic -> setIcon( QIcon::fromTheme(QStringLiteral("zoom-fit-best")) ); 0126 p_zoomAutomatic -> setEnabled(false); 0127 0128 p_move = actionCollection()->add<KToggleAction>( QStringLiteral("move") ); 0129 p_move->setText( i18n("&Move") ); 0130 p_move->setIcon( QIcon::fromTheme(QStringLiteral("transform-move")) ); 0131 p_move -> setEnabled(false); 0132 0133 a = actionCollection()->addAction( QStringLiteral("disclaimer") ); 0134 a->setText( i18n("Disclaimer") ); 0135 connect(a, &QAction::triggered, this, &kgeography::disclaimer); 0136 0137 p_showAuthor = actionCollection()->addAction( QStringLiteral("author") ); 0138 p_showAuthor->setText( i18n("Map author") ); 0139 p_showAuthor->setEnabled(false); 0140 connect(p_showAuthor, &QAction::triggered, this, &kgeography::showMapAuthor); 0141 0142 KStandardAction::preferences(this, SLOT(showPreferencesDialog()), actionCollection()); 0143 0144 setupGUI(Keys | ToolBar | Save | Create); 0145 0146 show(); 0147 } 0148 0149 kgeography::~kgeography() 0150 { 0151 delete p_askWidget; 0152 delete p_map; 0153 } 0154 0155 void kgeography::showPreferencesDialog() 0156 { 0157 if ( KConfigDialog::showDialog( QStringLiteral("settings") ) ) 0158 return; 0159 0160 // KConfigDialog didn't find an instance of this dialog, so lets 0161 // create it : 0162 KConfigDialog* dialog = new KConfigDialog(this, QStringLiteral("settings"), 0163 kgeographySettings::self()); 0164 // FIXME: Waiting for the answer from Kévin about what to do with it 0165 // dialog->setHelp("configuration", "kgeography"); 0166 QWidget *w = new QWidget(); 0167 Ui::Options confWdg; 0168 confWdg.setupUi(w); 0169 0170 dialog->addPage(w, i18n("General"), QStringLiteral("kgeography") ); 0171 0172 // User edited the configuration - update your local copies of the 0173 // configuration data 0174 connect(dialog, &KConfigDialog::settingsChanged, this, &kgeography::updateConfiguration); 0175 0176 dialog->show(); 0177 } 0178 0179 void kgeography::updateConfiguration() 0180 { 0181 boxAsker *aBoxAsker = dynamic_cast<boxAsker*>(p_askWidget); 0182 if ( aBoxAsker != nullptr ) { 0183 aBoxAsker->updateLayout(); 0184 } 0185 } 0186 0187 void kgeography::showEvent(QShowEvent *) 0188 { 0189 if (p_firstShow) 0190 { 0191 QString file = kgeographySettings::self() -> lastMap(); 0192 0193 if (QFile::exists(file)) 0194 { 0195 mapReader reader; 0196 KGmap *kgmap = reader.parseMap(file); 0197 if (kgmap) 0198 { 0199 setMap(kgmap); 0200 } 0201 else 0202 { 0203 KMessageBox::error(this, i18n("Could not open last used map. Error parsing %1: %2", file, reader.getError())); 0204 openMap(); 0205 } 0206 } 0207 else openMap(); 0208 0209 if (!p_map) 0210 { 0211 p_currentMap -> setText(i18n("There is no current map")); 0212 p_consult -> setEnabled(false); 0213 p_askMap -> setEnabled(false); 0214 p_askPlaceMap -> setEnabled(false); 0215 p_askFlagDivisions -> setEnabled(false); 0216 p_askDivisionFlags -> setEnabled(false); 0217 p_askCapitalDivisions -> setEnabled(false); 0218 p_askDivisionCapitals -> setEnabled(false); 0219 } 0220 // if anyone can explain why with the slot works and now without 0221 // i'll be glad to learn 0222 QTimer::singleShot(0, this, &kgeography::resizeMainWindow); 0223 // resizeMainWindow(); 0224 0225 p_firstShow = false; 0226 } 0227 } 0228 0229 void kgeography::openMap() 0230 { 0231 mapChooser mp(this); 0232 if (mp.exec() == mapChooser::Accepted) 0233 { 0234 showResultsDialog(); 0235 setMap(mp.getMap()); 0236 // if anyone can explain why with the slot works and now without 0237 // i'll be glad to learn 0238 QTimer::singleShot(0, this, &kgeography::resizeMainWindow); 0239 // resizeMainWindow(); 0240 } 0241 } 0242 0243 void kgeography::consult() 0244 { 0245 // No need to create another map viewer if we are already in it 0246 mapAsker *ma = dynamic_cast<mapAsker*>(p_askWidget); 0247 if (ma && !ma -> isAsker()) return; 0248 0249 showResultsDialog(); 0250 removeOldAskWidget(); 0251 p_askWidget = new mapAsker(p_bigWidget, p_map, p_underLeftWidget, false); 0252 p_zoom -> setEnabled(true); 0253 p_zoomOriginal -> setEnabled(true); 0254 p_zoomAutomatic -> setEnabled(true); 0255 putAskWidget(); 0256 } 0257 0258 int kgeography::askQuestionNumber(int upto, bool *rOK) 0259 { 0260 int i; 0261 bool ok; 0262 i = IntegerInputDialog::GetInteger(this, i18n("Number of Questions"), 0263 i18n("How many questions do you want? (1 to %1)", upto), 0264 1, upto, upto, &ok); 0265 if ( rOK != nullptr ) *rOK = ok; 0266 return i; 0267 } 0268 0269 void kgeography::askCapitalDivisions() 0270 { 0271 int i; 0272 bool ok; 0273 showResultsDialog(); 0274 i = askQuestionNumber(p_map -> count(division::eCapital), &ok); 0275 if (ok) 0276 { 0277 removeOldAskWidget(); 0278 p_askWidget = new capitalDivisionAsker(p_bigWidget, p_map, p_underLeftWidget, i); 0279 putAskWidget(); 0280 p_mustShowResultsDialog = true; 0281 } 0282 else consult(); 0283 } 0284 0285 void kgeography::askDivisionCapitals() 0286 { 0287 int i; 0288 bool ok; 0289 showResultsDialog(); 0290 i = askQuestionNumber(p_map -> count(division::eCapital), &ok); 0291 if (ok) 0292 { 0293 removeOldAskWidget(); 0294 p_askWidget = new divisionCapitalAsker(p_bigWidget, p_map, p_underLeftWidget, i); 0295 putAskWidget(); 0296 p_mustShowResultsDialog = true; 0297 } 0298 else consult(); 0299 } 0300 0301 void kgeography::askMap() 0302 { 0303 int i; 0304 bool ok; 0305 showResultsDialog(); 0306 i = askQuestionNumber(p_map -> count(division::eClick), &ok); 0307 if (ok) 0308 { 0309 removeOldAskWidget(); 0310 p_askWidget = new mapAsker(p_bigWidget, p_map, p_underLeftWidget, true, i); 0311 p_zoom -> setEnabled(true); 0312 p_zoomOriginal -> setEnabled(true); 0313 p_zoomAutomatic -> setEnabled(true); 0314 putAskWidget(); 0315 p_mustShowResultsDialog = true; 0316 } 0317 else consult(); 0318 } 0319 0320 void kgeography::askPlaceMap() 0321 { 0322 int i; 0323 bool ok; 0324 showResultsDialog(); 0325 i = askQuestionNumber(p_map -> count(division::eClick), &ok); 0326 if (ok) 0327 { 0328 removeOldAskWidget(); 0329 p_askWidget = new placeAsker(p_bigWidget, p_map, p_underLeftWidget, i); 0330 p_zoom -> setEnabled(true); 0331 p_zoomOriginal -> setEnabled(true); 0332 p_zoomAutomatic -> setEnabled(true); 0333 putAskWidget(); 0334 p_mustShowResultsDialog = true; 0335 } 0336 else consult(); 0337 } 0338 0339 void kgeography::askFlagDivisions() 0340 { 0341 int i; 0342 bool ok; 0343 showResultsDialog(); 0344 i = askQuestionNumber(p_map -> count(division::eFlag), &ok); 0345 if (ok) 0346 { 0347 removeOldAskWidget(); 0348 p_askWidget = new flagDivisionAsker(p_bigWidget, p_map, p_underLeftWidget, i); 0349 putAskWidget(); 0350 p_mustShowResultsDialog = true; 0351 } 0352 else consult(); 0353 } 0354 0355 void kgeography::askDivisionFlags() 0356 { 0357 int i; 0358 bool ok; 0359 showResultsDialog(); 0360 i = askQuestionNumber(p_map -> count(division::eFlag), &ok); 0361 if (ok) 0362 { 0363 removeOldAskWidget(); 0364 p_askWidget = new divisionFlagAsker(p_bigWidget, p_map, p_underLeftWidget, i); 0365 putAskWidget(); 0366 p_mustShowResultsDialog = true; 0367 } 0368 else consult(); 0369 } 0370 0371 void kgeography::removeOldAskWidget() 0372 { 0373 // next lines because setZoom(true) (may have) put cursor at application level 0374 if ( p_askWidget != nullptr ) 0375 p_askWidget->setZoom(false); 0376 delete p_askWidget; 0377 p_askWidget = nullptr; 0378 p_zoom -> setEnabled(false); 0379 p_zoomOriginal -> setEnabled(false); 0380 p_zoomAutomatic -> setEnabled(false); 0381 p_move -> setEnabled(false); 0382 p_zoom -> setChecked(false); 0383 p_move -> setChecked(false); 0384 } 0385 0386 QSize kgeography::getPreferredSize() 0387 { 0388 int ySize = menuBar() -> size().height() + toolBar() -> size().height() + ((mapAsker*) p_askWidget)->mapSize().height(); 0389 int xSize = p_underLeftWidget -> parentWidget()-> size().width() + ((mapAsker*) p_askWidget)->mapSize().width(); 0390 return QSize(xSize + 10, ySize + 10); 0391 } 0392 0393 void kgeography::putAskWidget() 0394 { 0395 static_cast<QBoxLayout*>(p_bigWidget -> layout()) -> addWidget(p_askWidget, 1); 0396 p_askWidget -> setAutomaticZoom(p_zoomAutomatic -> isChecked()); 0397 p_askWidget -> show(); 0398 connect(p_askWidget, &askWidget::setZoomActionChecked, p_zoom, &KToggleAction::setChecked); 0399 connect(p_zoom, &KToggleAction::toggled, p_askWidget, &askWidget::setZoom); 0400 connect(p_zoomOriginal, &QAction::triggered, p_askWidget, &askWidget::setOriginalZoom); 0401 connect(p_zoomOriginal, &QAction::triggered, p_zoomAutomatic, &QAction::setChecked); 0402 connect(p_zoomAutomatic, &KToggleAction::toggled, this, &kgeography::setAutomaticZoom); 0403 connect(p_askWidget, &askWidget::setMoveActionEnabled, this, &kgeography::setMoveActionEnabled); 0404 connect(p_askWidget, &askWidget::setMoveActionChecked, p_move, &KToggleAction::setChecked); 0405 connect(p_move, &KToggleAction::toggled, p_askWidget, &askWidget::setMovement); 0406 connect(p_askWidget, &askWidget::questionsEnded, this, &kgeography::questionsEnded); 0407 } 0408 0409 void kgeography::setMap(KGmap *m) 0410 { 0411 removeOldAskWidget(); 0412 kgeographySettings *set = kgeographySettings::self(); 0413 set -> setLastMap(m -> getFile()); 0414 set -> save(); 0415 delete p_map; 0416 p_map = m; 0417 p_showAuthor->setEnabled(m); 0418 0419 QString mapName = p_map -> getName(); 0420 QString divisionType = p_map->getDivisionsString(); 0421 0422 p_askMap->setText(i18n("&Location of %1", divisionType)); 0423 p_askPlaceMap->setText(i18n("&Place %1 in the Map", divisionType)); 0424 p_askCapitalDivisions->setText(p_map->getCapitalToDivisionTitle()); 0425 p_askDivisionCapitals->setText(p_map->getDivisionToCapitalTitle()); 0426 p_askFlagDivisions->setText(i18n("%1 by Flag", divisionType)); 0427 p_askDivisionFlags->setText(i18n("&Flags of %1", divisionType)); 0428 0429 p_currentMap -> setText(i18n("<qt>Current map:<br /><b>%1</b></qt>", mapName)); 0430 p_consult -> setEnabled(true); 0431 p_askMap -> setEnabled(m -> count(division::eClick) > 0); 0432 p_askPlaceMap -> setEnabled(m -> count(division::eClick) > 0); 0433 // as we always want to let user choose among 4 choices, verify we have the ammunition 0434 p_askFlagDivisions -> setEnabled(m -> count(division::eFlag) > 3); 0435 p_askDivisionFlags -> setEnabled(m -> count(division::eFlag) > 3); 0436 p_askCapitalDivisions -> setEnabled(m -> count(division::eCapital) > 3); 0437 p_askDivisionCapitals -> setEnabled(m -> count(division::eCapital) > 3); 0438 consult(); 0439 0440 // set a maximum width for the under left widget, enabling the labels wordwrap and 0441 // avoiding the move of the map in case of large division names. 0442 int width = qMax(p_askMap->sizeHint().width(), p_askPlaceMap->sizeHint().width()); 0443 width = qMax(width, p_askCapitalDivisions->sizeHint().width()); 0444 width = qMax(width, p_askDivisionCapitals->sizeHint().width()); 0445 width = qMax(width, p_askFlagDivisions->sizeHint().width()); 0446 width = qMax(width, p_askDivisionFlags->sizeHint().width()); 0447 p_underLeftWidget->setMaximumWidth(width); 0448 } 0449 0450 void kgeography::disclaimer() 0451 { 0452 KMessageBox::information(this, i18n("Maps, flags, translations, etc. are as accurate as their respective authors could achieve," 0453 " but KGeography should not be taken as an authoritative source."), i18n("Disclaimer")); 0454 } 0455 0456 void kgeography::showMapAuthor() 0457 { 0458 if (p_map) 0459 { 0460 KMessageBox::information(this, i18n("This map has been created by %1.", p_map->getAuthor()), i18n("Map Author")); 0461 } 0462 } 0463 0464 void kgeography::resizeMainWindow() 0465 { 0466 if (p_askWidget && width() ) resize(getPreferredSize().expandedTo(size())); 0467 } 0468 0469 void kgeography::questionsEnded() 0470 { 0471 showResultsDialog(); 0472 consult(); 0473 } 0474 0475 void kgeography::setAutomaticZoom(bool b) 0476 { 0477 p_zoom->setChecked(false); 0478 p_askWidget->setAutomaticZoom(b); 0479 } 0480 0481 void kgeography::setMoveActionEnabled(bool b) 0482 { 0483 p_move->setEnabled(b); 0484 if (b && p_zoomAutomatic->isChecked()) 0485 { 0486 // we don't want the unchecking to bring us to the original zoom state 0487 p_zoomAutomatic->blockSignals(true); 0488 p_zoomAutomatic->setChecked(false); 0489 p_zoomAutomatic->blockSignals(false); 0490 } 0491 } 0492 0493 void kgeography::showResultsDialog() 0494 { 0495 if (p_mustShowResultsDialog) 0496 { 0497 p_mustShowResultsDialog = false; 0498 int ca = p_askWidget -> correctAnswers(); 0499 QString q = p_askWidget -> getQuestionHook(); 0500 QVector<userAnswer> ua = p_askWidget -> userAnswers(); 0501 0502 answersDialog *ad = new answersDialog(this, ua, q, ca); 0503 ad -> exec(); 0504 delete ad; 0505 } 0506 } 0507 0508 #include "moc_kgeography.cpp"