File indexing completed on 2023-09-24 08:17:47
0001 /* 0002 This file is part of the KDE games lskat program 0003 SPDX-FileCopyrightText: 2006 Martin Heni <kde@heni-online.de> 0004 0005 SPDX-License-Identifier: LGPL-2.0-or-later 0006 */ 0007 0008 #include "mainwindow.h" 0009 0010 // Include files for Qt 0011 #include <QAction> 0012 #include <QDir> 0013 #include <QKeySequence> 0014 #include <QPointer> 0015 #include <QRandomGenerator> 0016 #include <QStatusBar> 0017 #include <QStandardPaths> 0018 0019 // KF includes 0020 #include <kwidgetsaddons_version.h> 0021 #include <KActionCollection> 0022 #include <KConfigGroup> 0023 #include <KMessageBox> 0024 #include <KSharedConfig> 0025 #include <KStandardGameAction> 0026 #include <KLocalizedString> 0027 #include <KSelectAction> 0028 // Application specific includes 0029 #include "lskat_debug.h" 0030 #include "lskatglobal.h" 0031 #include "gameview.h" 0032 #include "abstractengine.h" 0033 #include "engine_two.h" 0034 #include "display_two.h" 0035 #include "config_two.h" 0036 #include "display_intro.h" 0037 #include "deck.h" 0038 #include "player.h" 0039 #include "mouseinput.h" 0040 #include "aiinput.h" 0041 #include "namedialogwidget.h" 0042 #include "fromlibkdegames/kcarddialog.h" 0043 #include "fromlibkdegames/carddeckinfo.h" 0044 0045 // Configuration file 0046 #include <config-src.h> 0047 0048 // Forward declarations 0049 const int ADVANCE_PERIOD = 20; 0050 0051 // Shortcut to access the actions 0052 #define ACTION(x) (actionCollection()->action(x)) 0053 0054 using namespace InputDevice; 0055 0056 // Construct the main application window 0057 Mainwindow::Mainwindow(QWidget *parent) 0058 : KXmlGuiWindow(parent) 0059 { 0060 // Reset stuff 0061 mDeck = nullptr; 0062 mEngine = nullptr; 0063 mDisplay = nullptr; 0064 mView = nullptr; 0065 mLSkatConfig = nullptr; 0066 mCanvas = nullptr; 0067 mTheme = nullptr; 0068 0069 // Read theme files 0070 QStringList themeList; 0071 const QStringList dirs = QStandardPaths::locateAll(QStandardPaths::AppDataLocation, QStringLiteral("grafix"), QStandardPaths::LocateDirectory); 0072 for (const QString& dir : dirs) { 0073 const QStringList fileNames = QDir(dir).entryList(QStringList() << QStringLiteral("*.desktop")); 0074 for (const QString& file : fileNames) { 0075 themeList.append(dir + '/' + file); 0076 } 0077 } 0078 if (themeList.isEmpty()) 0079 { 0080 KMessageBox::error(this, i18n("Installation error: No theme list found.")); 0081 QTimer::singleShot(0, this, &QWidget::close); 0082 return; 0083 } 0084 0085 // Read theme files 0086 for (int i = 0; i < themeList.size(); i++) 0087 { 0088 KConfig themeInfo(themeList.at(i), KConfig::SimpleConfig); 0089 KConfigGroup themeGroup(&themeInfo, "Theme"); 0090 QString name = themeGroup.readEntry("Name", QString()); 0091 QString file = themeGroup.readEntry("File", QString()); 0092 bool isDefault = themeGroup.readEntry("Default", false); 0093 mThemeFiles[name] = file; 0094 if (mThemeDefault.isNull()) mThemeDefault = name; 0095 if (isDefault) mThemeDefault = name; 0096 0097 if (global_debug > 0) qCDebug(LSKAT_LOG) << "Found theme: " << themeList.at(i) << " Name(i18n)=" << name << " File=" << file << " default=" << isDefault; 0098 } 0099 mThemeIndexNo = themeIdxFromName(mThemeDefault); 0100 0101 // Create menus etc 0102 initGUI(); 0103 0104 // The LSkat config 0105 mLSkatConfig = new ConfigTwo(this); 0106 connect(mLSkatConfig, &ConfigTwo::signalInputType, this, &Mainwindow::setInputType); 0107 mLSkatConfig->reset(); 0108 0109 // Read game properties and set default values (after config) 0110 readProperties(); 0111 0112 // TODO: Bugfix: Needs to be here if initGUI is before readProperties 0113 if (global_debug > 0) qCDebug(LSKAT_LOG) << "Setting current theme item to " << mThemeIndexNo; 0114 ((KSelectAction *)ACTION(QLatin1String("theme")))->setCurrentItem(mThemeIndexNo); 0115 0116 // Get the card deck 0117 const quint32 seed = QRandomGenerator::global()->generate(); 0118 if (global_debug > 0) qCDebug(LSKAT_LOG) << "Random seed" << seed; 0119 mDeck = new Deck(seed, this); 0120 0121 // Theme manager 0122 QString themeFile = themefileFromIdx(mThemeIndexNo); 0123 if (global_debug > 0) qCDebug(LSKAT_LOG) << "Load theme" << themeFile << " no=" << mThemeIndexNo; 0124 mTheme = new ThemeManager(mCardTheme, themeFile, this, this->width()); 0125 if (mTheme->checkTheme() != 0) 0126 { 0127 KMessageBox::error(this, i18n("Installation error: Theme file error.")); 0128 QTimer::singleShot(0, this, &QWidget::close); 0129 return; 0130 } 0131 0132 // Overall view 0133 mCanvas = new QGraphicsScene(this); 0134 mView = new GameView(QSize(880, 675), ADVANCE_PERIOD, mCanvas, mTheme, this); 0135 0136 // Create intro 0137 mGameMode = Intro; 0138 mDisplay = new DisplayIntro(mDeck, mCanvas, mTheme, ADVANCE_PERIOD, mView); 0139 setCentralWidget(mView); 0140 connect(mView, &GameView::signalLeftMousePress, this, &Mainwindow::menuNewLSkatGame); 0141 0142 // Create GUI 0143 setupGUI(); 0144 0145 statusBar()->showMessage(i18n("Welcome to Skat! Please start a new game.")); 0146 0147 // Skip intro? 0148 if (global_skip_intro) 0149 { 0150 menuNewLSkatGame(); 0151 } 0152 // Start game automatically in demo mode 0153 else if (global_demo_mode) 0154 { 0155 // Start intro 0156 mDisplay->start(); 0157 QTimer::singleShot(12500, this, &Mainwindow::menuNewLSkatGame); 0158 } 0159 else 0160 { 0161 // Start intro 0162 mDisplay->start(); 0163 } 0164 if (global_debug > 0) qCDebug(LSKAT_LOG) << "Mainwindow setup constructor done"; 0165 } 0166 0167 // Destructor 0168 Mainwindow::~Mainwindow() 0169 { 0170 saveProperties(); 0171 delete mEngine; 0172 delete mDisplay; 0173 delete mLSkatConfig; 0174 delete mDeck; 0175 delete mView; 0176 delete mCanvas; 0177 delete mTheme; 0178 } 0179 0180 // Called by KMainWindow when the last window of the application is 0181 void Mainwindow::closeEvent(QCloseEvent *event) 0182 { 0183 if (mEngine) 0184 { 0185 mEngine->stopGame(); 0186 } 0187 saveProperties(); 0188 KXmlGuiWindow::closeEvent(event); 0189 } 0190 0191 // Retrieve a theme file name from the menu index number 0192 QString Mainwindow::themefileFromIdx(int idx) 0193 { 0194 QStringList list(mThemeFiles.keys()); 0195 list.sort(); 0196 QString themeFile = mThemeFiles[list.at(idx)]; 0197 return themeFile; 0198 } 0199 0200 // Retrieve a theme idx from a theme name 0201 int Mainwindow::themeIdxFromName(const QString &name) 0202 { 0203 QStringList list(mThemeFiles.keys()); 0204 list.sort(); 0205 for (int i = 0; i < list.size(); ++i) 0206 { 0207 if (list[i] == name) return i; 0208 } 0209 qCCritical(LSKAT_LOG) << "Theme index lookup failed for " << name; 0210 return 0; 0211 } 0212 0213 // Save properties 0214 void Mainwindow::saveProperties() 0215 { 0216 KConfig *config = KSharedConfig::openConfig().data(); 0217 0218 // Program data 0219 KConfigGroup cfg = config->group("ProgramData"); 0220 cfg.writeEntry("startplayer", mStartPlayer); 0221 cfg.writeEntry("ThemeIndexNo", mThemeIndexNo); 0222 0223 // LSkat data 0224 mLSkatConfig->save(config); 0225 config->sync(); 0226 } 0227 0228 // Load properties 0229 void Mainwindow::readProperties() 0230 { 0231 KConfig *config = KSharedConfig::openConfig().data(); 0232 0233 // Program data 0234 KConfigGroup cfg = config->group("ProgramData"); 0235 0236 // Theme number 0237 mThemeIndexNo = cfg.readEntry("ThemeIndexNo", themeIdxFromName(mThemeDefault)); 0238 if (mThemeIndexNo >= mThemeFiles.size()) mThemeIndexNo = 0; 0239 0240 // Read card path 0241 mCardTheme = CardDeckInfo::deckName(cfg); 0242 0243 int no = cfg.readEntry("startplayer", 0); 0244 setStartPlayer(no); 0245 mLSkatConfig->load(config); 0246 } 0247 0248 // Create a input with the given type 0249 AbstractInput *Mainwindow::createInput( 0250 InputDeviceType inputType, 0251 AbstractDisplay *display, 0252 AbstractEngine *engine) 0253 { 0254 AbstractInput *input = nullptr; 0255 0256 // Always use AI input in demo mode 0257 if (global_demo_mode) 0258 { 0259 inputType = TypeAiInput; 0260 } 0261 0262 // Create the player input 0263 if (inputType == TypeMouseInput) 0264 { 0265 MouseInput *mouseInput = new MouseInput(this); 0266 connect(mView, &GameView::signalLeftMousePress, 0267 mouseInput, &MouseInput::mousePress); 0268 connect(mouseInput, &MouseInput::signalConvertMousePress, 0269 display, &AbstractDisplay::convertMousePress); 0270 connect(mouseInput, &MouseInput::signalPlayerInput, 0271 engine, &AbstractEngine::playerInput); 0272 input = mouseInput; 0273 if (global_debug > 0) qCDebug(LSKAT_LOG) << "Create MOUSE INPUT"; 0274 } 0275 else if (inputType == TypeAiInput) 0276 { 0277 AiInput *aiInput = new AiInput((EngineTwo *)engine, this); 0278 connect(aiInput, &AiInput::signalPlayerInput, 0279 engine, &AbstractEngine::playerInput); 0280 input = aiInput; 0281 if (global_debug > 0) qCDebug(LSKAT_LOG) << "Create AI INPUT"; 0282 } 0283 else 0284 { 0285 qCCritical(LSKAT_LOG) << "Unsupported input device type" << inputType; 0286 } 0287 0288 return input; 0289 } 0290 0291 // Start a new game 0292 void Mainwindow::startGame() 0293 { 0294 // Enable game action 0295 QLatin1String endName(KStandardGameAction::name(KStandardGameAction::End)); 0296 ACTION(endName)->setEnabled(true); 0297 0298 // Deal cards to player - Shuffle card deck and reset pile 0299 mDeck->shuffle(); 0300 0301 // Draw Trump 0302 Suite trump = mDeck->randomTrump(); 0303 0304 // Loop all players in the game 0305 QHashIterator<int,Player *> it = mLSkatConfig->playerIterator(); 0306 while (it.hasNext()) 0307 { 0308 it.next(); 0309 Player *player = it.value(); 0310 player->setDeck(mDeck); 0311 // Deal cards 0312 player->deal(16); 0313 // Store trump 0314 player->setTrump(trump); 0315 } 0316 0317 // Start display 0318 mDisplay->start(); 0319 0320 // Start the game engine 0321 mEngine->startGame(trump, mStartPlayer); 0322 0323 // Start player for next game 0324 setStartPlayer(1-mStartPlayer); 0325 0326 // statusBar()->clearMessage(); 0327 } 0328 0329 // Here a game over is signalled 0330 void Mainwindow::gameOver(int /*winner*/) 0331 { 0332 QLatin1String endName(KStandardGameAction::name(KStandardGameAction::End)); 0333 ACTION(endName)->setEnabled(false); 0334 statusBar()->showMessage(i18n("Game Over. Please start a new game.")); 0335 0336 // Automatically restart game in demo mode 0337 if (global_demo_mode) 0338 { 0339 QTimer::singleShot(10000, this, &Mainwindow::menuNewLSkatGame); 0340 } 0341 } 0342 0343 // Show next player 0344 void Mainwindow::nextPlayer(Player *player) 0345 { 0346 int no = player->id() + 1; 0347 QString name = player->name(); 0348 statusBar()->showMessage(i18nc("Player name and number", "Next move for %1 (player %2)", name, no)); 0349 } 0350 0351 // Setup the GUI 0352 void Mainwindow::initGUI() 0353 { 0354 QAction *action; 0355 0356 // Start a new game 0357 action = KStandardGameAction::gameNew(this, &Mainwindow::menuNewLSkatGame, actionCollection()); 0358 if (global_demo_mode) action->setEnabled(false); 0359 0360 // Clear all time statistics 0361 action = KStandardGameAction::clearStatistics(this, &Mainwindow::menuClearStatistics, actionCollection()); 0362 action->setWhatsThis(i18n("Clears the all time statistics which is kept in all sessions.")); 0363 if (global_demo_mode) action->setEnabled(false); 0364 0365 // End a game 0366 action = KStandardGameAction::end(this, &Mainwindow::menuEndGame, actionCollection()); 0367 action->setWhatsThis(i18n("Ends a currently played game. No winner will be declared.")); 0368 action->setEnabled(false); 0369 0370 // Quit the program 0371 action = KStandardGameAction::quit(this, &QWidget::close, actionCollection()); 0372 action->setWhatsThis(i18n("Quits the program.")); 0373 0374 // Determine start player 0375 KSelectAction *startPlayerAct = new KSelectAction(i18n("Starting Player"), this); 0376 actionCollection()->addAction(QStringLiteral("startplayer"), startPlayerAct); 0377 connect(startPlayerAct, &KSelectAction::indexTriggered, this, &Mainwindow::menuStartplayer); 0378 startPlayerAct->setToolTip(i18n("Changing starting player...")); 0379 startPlayerAct->setWhatsThis(i18n("Chooses which player begins the next game.")); 0380 QStringList list; 0381 list.clear(); 0382 list.append(i18n("Player &1")); 0383 list.append(i18n("Player &2")); 0384 startPlayerAct->setItems(list); 0385 if (global_demo_mode) startPlayerAct->setEnabled(false); 0386 0387 // Determine who plays player 1 0388 KSelectAction *player1Act = new KSelectAction(i18n("Player &1 Played By"), this); 0389 actionCollection()->addAction(QStringLiteral("player1"), player1Act); 0390 connect(player1Act, &KSelectAction::indexTriggered, this, &Mainwindow::menuPlayer1By); 0391 player1Act->setToolTip(i18n("Changing who plays player 1...")); 0392 player1Act->setWhatsThis(i18n("Changing who plays player 1.")); 0393 list.clear(); 0394 list.append(i18n("&Mouse")); 0395 list.append(i18n("&Computer")); 0396 player1Act->setItems(list); 0397 if (global_demo_mode) player1Act->setEnabled(false); 0398 0399 // Determine who plays player 2 0400 KSelectAction *player2Act = new KSelectAction(i18n("Player &2 Played By"), this); 0401 actionCollection()->addAction(QStringLiteral("player2"), player2Act); 0402 connect(player2Act, &KSelectAction::indexTriggered, this, &Mainwindow::menuPlayer2By); 0403 player2Act->setToolTip(i18n("Changing who plays player 2...")); 0404 player2Act->setWhatsThis(i18n("Changing who plays player 2.")); 0405 player2Act->setItems(list); 0406 if (global_demo_mode) player2Act->setEnabled(false); 0407 0408 // Add all theme files to the menu 0409 QStringList themes(mThemeFiles.keys()); 0410 themes.sort(); 0411 0412 KSelectAction *themeAct = new KSelectAction(i18n("&Theme"), this); 0413 actionCollection()->addAction(QStringLiteral("theme"), themeAct); 0414 themeAct->setItems(themes); 0415 connect(themeAct, &KSelectAction::indexTriggered, this, &Mainwindow::changeTheme); 0416 if (global_debug > 0) qCDebug(LSKAT_LOG) << "Setting current theme item to " << mThemeIndexNo; 0417 themeAct->setCurrentItem(mThemeIndexNo); 0418 themeAct->setToolTip(i18n("Changing theme...")); 0419 themeAct->setWhatsThis(i18n("Changing theme.")); 0420 0421 // Choose card deck 0422 QAction *action1 = actionCollection()->addAction(QStringLiteral("select_carddeck")); 0423 action1->setText(i18n("Select &Card Deck...")); 0424 actionCollection()->setDefaultShortcut(action1, QKeySequence(Qt::Key_F10)); 0425 connect(action1, &QAction::triggered, this, &Mainwindow::menuCardDeck); 0426 action1->setToolTip(i18n("Configure card decks...")); 0427 action1->setWhatsThis(i18n("Choose how the cards should look.")); 0428 0429 // Change player names 0430 action = actionCollection()->addAction(QStringLiteral("change_names")); 0431 action->setText(i18n("&Change Player Names...")); 0432 connect(action, &QAction::triggered, this, &Mainwindow::menuPlayerNames); 0433 if (global_demo_mode) action->setEnabled(false); 0434 } 0435 0436 // Choose start player 0437 void Mainwindow::menuStartplayer() 0438 { 0439 int i = ((KSelectAction *)ACTION(QLatin1String("startplayer")))->currentItem(); 0440 setStartPlayer(i); 0441 } 0442 0443 // Change the theme of the game 0444 void Mainwindow::changeTheme(int idx) 0445 { 0446 mThemeIndexNo = idx; 0447 QString themeFile = themefileFromIdx(idx); 0448 if (global_debug > 0) qCDebug(LSKAT_LOG) << "Select theme " << themeFile; 0449 mTheme->updateTheme(themeFile); 0450 } 0451 0452 // Select input for player 1 0453 void Mainwindow::menuPlayer1By() 0454 { 0455 int i = ((KSelectAction *)ACTION(QLatin1String("player1")))->currentItem(); 0456 mLSkatConfig->setInputType(0, (InputDeviceType)i); 0457 } 0458 0459 // Select input for player 2 0460 void Mainwindow::menuPlayer2By() 0461 { 0462 int i = ((KSelectAction *)ACTION(QLatin1String("player2")))->currentItem(); 0463 mLSkatConfig->setInputType(1, (InputDeviceType)i); 0464 } 0465 0466 // Choose a card deck 0467 void Mainwindow::menuCardDeck() 0468 { 0469 QString front = mCardTheme; 0470 0471 KConfigGroup grp = KSharedConfig::openConfig()->group("ProgramData"); 0472 KCardWidget *cardwidget = new KCardWidget(); 0473 QPointer<KCardDialog> dlg; 0474 0475 cardwidget->readSettings(grp); 0476 dlg = new KCardDialog(cardwidget); 0477 if (dlg->exec() == QDialog::Accepted) 0478 { 0479 // Always store the settings, other things than the deck may have changed 0480 cardwidget->saveSettings(grp); 0481 grp.sync(); 0482 if (global_debug > 0) qCDebug(LSKAT_LOG) << "NEW CARDDECK: " << front; 0483 bool change = false; // Avoid unnecessary changes 0484 if (!cardwidget->deckName().isEmpty() && cardwidget->deckName() != mCardTheme) 0485 { 0486 mCardTheme = cardwidget->deckName(); 0487 change = true; 0488 } 0489 if (change) 0490 { 0491 mTheme->updateCardTheme(mCardTheme); 0492 mView->update(); // Be on the safe side and update 0493 } 0494 } 0495 delete dlg; 0496 } 0497 0498 // Clear all time statistics 0499 void Mainwindow::menuClearStatistics() 0500 { 0501 QString message; 0502 message = i18n("Do you really want to clear the all time " 0503 "statistical data?"); 0504 0505 #if KWIDGETSADDONS_VERSION >= QT_VERSION_CHECK(5, 100, 0) 0506 if (KMessageBox::PrimaryAction == KMessageBox::questionTwoActions(this, 0507 #else 0508 if (KMessageBox::Yes == KMessageBox::questionYesNo(this, 0509 #endif 0510 message, 0511 QString(), 0512 KStandardGuiItem::clear(), 0513 KStandardGuiItem::cancel())) 0514 { 0515 QHashIterator<int,Player *> it = mLSkatConfig->playerIterator(); 0516 while (it.hasNext()) 0517 { 0518 it.next(); 0519 Player *player = it.value(); 0520 player->clear(); 0521 } 0522 } 0523 } 0524 0525 // Abort a game 0526 void Mainwindow::menuEndGame() 0527 { 0528 if (mEngine) 0529 { 0530 mEngine->stopGame(); 0531 } 0532 } 0533 0534 // Start a new game 0535 void Mainwindow::menuNewLSkatGame() 0536 { 0537 disconnect(mView, &GameView::signalLeftMousePress, this, &Mainwindow::menuNewLSkatGame); 0538 0539 Player *p1 = mLSkatConfig->player(0); 0540 Player *p2 = mLSkatConfig->player(1); 0541 0542 // Stop running games 0543 if (mEngine) 0544 { 0545 mEngine->stopGame(); 0546 } 0547 0548 // Get rid of old stuff? 0549 if (true || (mGameMode != LSkat)) // Yes! Fixes bugs 330308 and 228067. 0550 // Jenkins objected to the indentation if the above was simply commented out. 0551 { 0552 // Set new game mode 0553 mGameMode = LSkat; 0554 0555 // Start deleting 0556 delete mDisplay; 0557 delete mEngine; 0558 0559 auto *display = new DisplayTwo(mDeck, mCanvas, mTheme, ADVANCE_PERIOD, mView); 0560 mDisplay = display; 0561 mEngine = new EngineTwo(this, mDeck, (DisplayTwo *)mDisplay); 0562 connect(mEngine, &AbstractEngine::signalGameOver, this, &Mainwindow::gameOver); 0563 connect(mEngine, &AbstractEngine::signalNextPlayer, this, &Mainwindow::nextPlayer); 0564 0565 // Connect player score widget updates 0566 connect(p1, &Player::signalUpdate, display, &DisplayTwo::updatePlayer); 0567 connect(p2, &Player::signalUpdate, display, &DisplayTwo::updatePlayer); 0568 0569 mEngine->addPlayer(0, p1); 0570 mEngine->addPlayer(1, p2); 0571 }// end if 0572 0573 // Create inputs and store in player 0574 AbstractInput *input1 = createInput(mLSkatConfig->inputType(0), mDisplay, mEngine); 0575 p1->setInput(input1); 0576 AbstractInput *input2 = createInput(mLSkatConfig->inputType(1), mDisplay, mEngine); 0577 p2->setInput(input2); 0578 0579 statusBar()->showMessage(i18n("Dealing cards...")); 0580 0581 // Start game 0582 startGame(); 0583 } 0584 0585 // Change the player names in a dialog 0586 void Mainwindow::menuPlayerNames() 0587 { 0588 QPointer<NameDialogWidget> dlg = new NameDialogWidget(this); 0589 for (int i = 0; i < 2; i++) 0590 { 0591 Player *p = mLSkatConfig->player(i); 0592 dlg->setName(i, p->name()); 0593 } 0594 0595 if (dlg->exec() == QDialog::Accepted) 0596 { 0597 for (int i = 0; i < 2; i++) 0598 { 0599 Player *p = mLSkatConfig->player(i); 0600 p->setName(dlg->name(i)); 0601 } 0602 } 0603 0604 delete dlg; 0605 } 0606 0607 // Set the start player. 0608 void Mainwindow::setStartPlayer(int no) 0609 { 0610 mStartPlayer = no; 0611 ((KSelectAction *)ACTION(QLatin1String("startplayer")))->setCurrentItem(mStartPlayer); 0612 } 0613 0614 // Set the input type for a given player number. 0615 void Mainwindow::setInputType(int no, InputDeviceType type) 0616 { 0617 Player *p = nullptr; 0618 // Player 1 0619 if (no == 0) 0620 { 0621 ((KSelectAction *)ACTION(QLatin1String("player1")))->setCurrentItem((int)type); 0622 p = mLSkatConfig->player(0); 0623 } 0624 else if (no == 1) 0625 { 0626 ((KSelectAction *)ACTION(QLatin1String("player2")))->setCurrentItem((int)type); 0627 p = mLSkatConfig->player(1); 0628 } 0629 0630 // Exchange player input at runtime 0631 if (mEngine && p && mDisplay && mEngine->isGameRunning()) 0632 { 0633 AbstractInput *input = createInput(type, mDisplay, mEngine); 0634 p->setInput(input); 0635 } 0636 } 0637 0638 #include "moc_mainwindow.cpp"