kwin4.cpp

Go to the documentation of this file.
00001 /***************************************************************************
00002                           kwin4  -  Boardgame for KDE
00003                              -------------------
00004     begin                : Sun Mar 26 12:50:12 CEST 2000
00005     copyright            : (C) |1995-2007 by Martin Heni
00006     email                : kde@heni-online.de
00007  ***************************************************************************/
00008 
00009 /***************************************************************************
00010  *                                                                         *
00011  *   This program is free software; you can redistribute it and/or modify  *
00012  *   it under the terms of the GNU General Public License as published by  *
00013  *   the Free Software Foundation; either version 2 of the License, or     *
00014  *   (at your option) any later version.                                   *
00015  *                                                                         *
00016  ***************************************************************************/
00017 
00018 // Qt includes 
00019 #include <QRadioButton>
00020 #include <QLayout>
00021 
00022 // KDE includes
00023 #include <kvbox.h>
00024 #include <kstandardgameaction.h>
00025 #include <kmessagebox.h>
00026 #include <kfiledialog.h>
00027 #include <klocale.h>
00028 #include <khelpmenu.h>
00029 #include <kconfig.h>
00030 #include <kdebug.h>
00031 #include <kstandardaction.h>
00032 #include <kaction.h>
00033 #include <kstatusbar.h>
00034 #include <kconfigdialog.h>
00035 #include <kactioncollection.h>
00036 #include <kbuttongroup.h>
00037 #include <kicon.h>
00038 #include <kstandarddirs.h>
00039 #include <kglobal.h>
00040 
00041 // KGame includes
00042 #include <kgamechat.h>
00043 #include <dialogs/kgamedialog.h>
00044 #include <dialogs/kgamedialogconfig.h>
00045 #include <dialogs/kgameconnectdialog.h>
00046 #include <dialogs/kgameerrordialog.h>
00047 #include <dialogs/kgamedebugdialog.h>
00048 
00049 // application specific includes
00050 #include "kwin4.h"
00051 #include "chatdlg.h"
00052 #include "kwin4doc.h"
00053 #include "kwin4view.h"
00054 #include "prefs.h"
00055 #include "ui_settings.h"
00056 #include "ui_statistics.h"
00057 
00058 // Abbreviations
00059 #define ACTION(x)   (actionCollection()->action(x))
00060 #define ID_STATUS_MSG                1003
00061 #define ID_STATUS_MOVER              1002
00062 
00063 
00064 // Configuration file
00065 #include "config-src.h"
00066 
00067 // Construct the main application window
00068 KWin4App::KWin4App(QWidget *parent) 
00069         : KMainWindow(parent), mView(0), mDoc(0), mMyChatDlg(0)
00070 {
00071   #ifdef SRC_DIR
00072   kDebug() << "Found SRC_DIR =" << SRC_DIR << endl;
00073   KGlobal::dirs()->addResourceDir("data",QString(SRC_DIR)+QString("/grafix/"));
00074   QString theme = KStandardDirs::locate("data", "default.rc");
00075   kDebug() << "theme =" << theme << endl;
00076   #endif
00077 
00078   mThemeDirName = KGlobal::dirs()->findResourceDir("data","default.rc");
00079   kDebug() << "THEME DIR IS " << mThemeDirName << endl;
00080 
00081   // Setup application
00082   initGUI();
00083   initStatusBar();
00084   initDocument();
00085 
00086   // Scene
00087   mScene  = new QGraphicsScene(this);
00088 
00089   // Theme
00090   mTheme  = new ThemeManager("default.rc", this);
00091   
00092   // View
00093   mView   = new KWin4View(QSize(800,600),25,mScene,mTheme,this);
00094   mDoc->setView(mView);
00095 
00096   // Players  
00097   mDoc->initPlayers();
00098 
00099   // Adjust GUI
00100   setCentralWidget(mView);
00101   setupGUI();
00102 
00103   // Read global config
00104   mDoc->readConfig(KGlobal::config().data());
00105 
00106   // Check menues
00107   checkMenus();
00108 }
00109 
00110 
00111 // Destruct application
00112 KWin4App::~KWin4App()
00113 {
00114   kDebug() << "~KWin4App()" << endl;
00115   if (mDoc) delete mDoc;
00116   if (mView) delete mView;
00117   if (mScene) delete mScene;
00118   if (mTheme) delete mTheme;
00119   if (mMyChatDlg) delete mMyChatDlg;
00120 
00121 }
00122 
00123 // This method is called from various places
00124 // and signals to check, uncheck and enable
00125 // or disable all menu items.
00126 // The menu parameter can limit this operation
00127 // to one or more of the main menus (File,View,...)
00128 void KWin4App::checkMenus(CheckFlags menu)
00129 {
00130   bool localgame=(!mDoc->isNetwork());
00131   bool isRunning = (mDoc->gameStatus()==KGame::Run);
00132     
00133   // Check file menu  
00134   if (!menu || (menu&CheckFileMenu))
00135   {
00136     changeAction("hint", !(!isRunning && localgame));
00137     changeAction("new_game", !isRunning);
00138     changeAction("save", isRunning);
00139     changeAction("end_game", isRunning);
00140   }
00141 
00142   // Edit menu
00143   if (!menu || (menu&CheckEditMenu))
00144   {
00145     if (!isRunning || !localgame)
00146     {
00147       disableAction("edit_undo");
00148     }
00149     else if (mDoc->getHistoryCnt()==0)
00150     {
00151       disableAction("edit_undo");
00152     }
00153     else if (mDoc->getCurrentMove()<1 )
00154     {
00155       disableAction("edit_undo");
00156     }
00157     else
00158     {
00159       enableAction("edit_undo");
00160     }
00161 
00162     // Show redo
00163     if (!isRunning || !localgame)
00164     {
00165       disableAction("edit_redo");
00166     }
00167     else if (mDoc->getHistoryCnt()==mDoc->getMaxMove())
00168     {
00169       disableAction("edit_redo");
00170     }
00171     else
00172     {
00173       enableAction("edit_redo");
00174     }
00175   }
00176 }
00177 
00178 // Create the actions for the menu. This works together with the xml guirc file
00179 void KWin4App::initGUI()
00180 {
00181   QAction* action;
00182 
00183   action = KStandardGameAction::gameNew(this, SLOT(menuNewGame()), this);
00184   actionCollection()->addAction("new_game", action);
00185   ACTION("new_game")->setToolTip(i18n("Start a new game"));
00186 
00187   action = KStandardGameAction::load(this, SLOT(menuOpenGame()), this);
00188   actionCollection()->addAction("open", action);
00189   ACTION("open")->setToolTip(i18n("Open a saved game..."));
00190 
00191   action = KStandardGameAction::save(this, SLOT(menuSaveGame()), this);
00192   actionCollection()->addAction("save", action);
00193   ACTION("save")->setToolTip(i18n("Save a game..."));
00194 
00195   action = KStandardGameAction::end(this, SLOT(endGame()), this);
00196   actionCollection()->addAction("end_game", action);
00197   ACTION("end_game")->setToolTip(i18n("Ending the current game..."));
00198   ACTION("end_game")->setWhatsThis(i18n("Aborts a currently played game. No winner will be declared."));
00199 
00200   action = actionCollection()->addAction("network_conf");
00201   action->setText(i18n("&Network Configuration..."));
00202   connect(action, SIGNAL(triggered(bool) ), SLOT(configureNetwork()));
00203 
00204   action = actionCollection()->addAction("network_chat");
00205   action->setText(i18n("Network Chat..."));
00206   connect(action, SIGNAL(triggered(bool) ), SLOT(configureChat()));
00207 
00208   if (global_debug>0) 
00209   {
00210     action = actionCollection()->addAction("file_debug");
00211     action->setText(i18n("Debug KGame"));
00212     connect(action, SIGNAL(triggered(bool) ), SLOT(debugKGame()));
00213   }
00214 
00215   action = actionCollection()->addAction("statistics");
00216   action->setIcon(KIcon("flag"));
00217   action->setText(i18n("&Show Statistics"));
00218   connect(action, SIGNAL(triggered(bool)), SLOT(showStatistics()));
00219   ACTION("statistics")->setToolTip(i18n("Show statistics."));
00220 
00221   action = KStandardGameAction::hint(this, SLOT(askForHint()), this);
00222   actionCollection()->addAction("hint", action);
00223   ACTION("hint")->setToolTip(i18n("Shows a hint on how to move."));
00224 
00225   action = KStandardGameAction::quit(this, SLOT(close()), this);
00226   actionCollection()->addAction("game_exit", action);
00227   ACTION("game_exit")->setToolTip(i18n("Quits the program."));
00228 
00229   action = KStandardGameAction::undo(this, SLOT(undoMove()), this);
00230   actionCollection()->addAction("edit_undo", action);
00231   ACTION("edit_undo")->setToolTip(i18n("Undo last move."));
00232 
00233   action = KStandardGameAction::redo(this, SLOT(redoMove()), this);
00234   actionCollection()->addAction("edit_redo", action);
00235   ACTION("edit_redo")->setToolTip(i18n("Redo last move."));
00236 
00237   actionCollection()->addAction(KStandardAction::Preferences, this, SLOT(configureSettings()));
00238 
00239   // TODO: The actions need to work with translated theme names. How?
00240   QDir dir(mThemeDirName);
00241   QStringList filters;
00242   filters.append("*.rc");
00243   QStringList rcFiles = dir.entryList(filters);
00244   kDebug() << "Theme dir = " << mThemeDirName << endl;
00245   kDebug() << "Available theme files="<<rcFiles<<endl;
00246  
00247   action = actionCollection()->addAction("theme", new KSelectAction(i18n("Theme"), this));
00248   ((KSelectAction*)action)->setItems(rcFiles);
00249   connect( action, SIGNAL(triggered(const QString&)), SLOT(changeTheme(const QString&)) );
00250 }
00251 
00252 
00253 // Change the theme of the game
00254 void KWin4App::changeTheme(const QString& name)
00255 {
00256   QString theme = name;
00257   theme.replace("&","");
00258   mTheme->updateTheme(theme);
00259   // TODO: Write Preferences
00260 }
00261 
00262 
00263 // Create the status bar with the message part, the player part.
00264 void KWin4App::initStatusBar()
00265 {
00266   statusBar()->insertPermanentItem(i18n("This leaves space for the mover"),ID_STATUS_MOVER,0);
00267   statusBar()->insertItem(i18n("Ready"), ID_STATUS_MSG);
00268 
00269   displayStatusbarMover("");
00270   displayStatusMessage(i18n("Welcome to Four Wins"));
00271 }
00272 
00273 
00274 // Set up the document, i.e. the KGame object
00275 // and connect all signals emitted by it
00276 void KWin4App::initDocument()
00277 {
00278   mDoc = new KWin4Doc(this);
00279   
00280   // KGame signals
00281   connect(mDoc,SIGNAL(signalGameOver(int, KPlayer*,KGame*)),
00282          this,SLOT(slotGameOver(int, KPlayer*,KGame *)));
00283   connect(mDoc,SIGNAL(signalNextPlayer(int)),
00284          this,SLOT(moveDone(int)));
00285   connect(mDoc,SIGNAL(signalClientLeftGame(int, int,KGame*)),
00286          this,SLOT(networkBroken(int, int, KGame*)));
00287   connect(mDoc,SIGNAL(signalGameRun()),
00288          this,SLOT(gameRun()));
00289 }
00290 
00291 
00292 // Enable or disable an action
00293 void KWin4App::changeAction(const char* action, bool enable)
00294 {
00295   if (!action)
00296   {  
00297     return;
00298   }  
00299 
00300   QAction* act=actionCollection()->action(action);
00301   if (act)
00302   {
00303     act->setEnabled(enable);
00304   }
00305 }
00306 
00307 
00308 // Store the current game 
00309 void KWin4App::saveProperties(KConfigGroup& /*cfg*/)
00310 {
00311   QString filename = KStandardDirs::locateLocal("appdata", "current_game");
00312   mDoc->save(filename);
00313 }
00314 
00315 // Load current game back
00316 void KWin4App::readProperties(const KConfigGroup& /*cfg*/)
00317 {
00318   QString filename = KStandardDirs::locateLocal("appdata", "current_game");
00319   if(QFile::exists(filename))
00320   {
00321     mDoc->load(filename);
00322   }
00323 }
00324 
00325 
00326 // Load a game menu
00327 void KWin4App::menuOpenGame()
00328 {
00329   QString dir(":<kwin4>");
00330   QString filter("*");
00331   QString file("/tmp/kwin.save");
00332   if (global_debug < 10)
00333     file=KFileDialog::getOpenFileName(dir,filter,this);
00334   mDoc->load(file,true);
00335   checkMenus();
00336 }
00337 
00338 // Save game menu
00339 void KWin4App::menuSaveGame()
00340 {
00341   QString dir(":<kwin4>");
00342   QString filter("*");
00343   QString file("/tmp/kwin.save");
00344   if (global_debug < 10)
00345     file=KFileDialog::getSaveFileName(dir,filter,this);
00346   mDoc->save(file);
00347 }
00348 
00349 
00350 // Start a new game menu
00351 void KWin4App::menuNewGame()
00352 {
00353   // End the intro if it is running
00354   mDoc->setGameStatus(KWin4Doc::End);
00355   // Init the board and Clear the old game out
00356   mDoc->setGameStatus(KWin4Doc::Init);
00357   // Run it
00358   mDoc->setGameStatus(KWin4Doc::Run);
00359   // Display game status
00360   displayStatusMessage(i18n("Game running..."));
00361 }
00362 
00363 
00364 // Slot: Noticed that a new game started...update menus
00365 void KWin4App::gameRun()
00366 {
00367   updateStatusNames();
00368   checkMenus(All);
00369 }
00370 
00371 
00372 // Abort a running game
00373 void KWin4App::endGame()
00374 {
00375   mDoc->setGameStatus(KWin4Doc::Abort);
00376 }
00377 
00378 
00379 // Menu to ask for a game hint
00380 void KWin4App::askForHint()
00381 {
00382   if (mDoc) mDoc->calculateHint();
00383 }
00384 
00385 
00386 // Show statistics dialog
00387 void KWin4App::showStatistics()
00388 {
00389   QDialog dlg(this);
00390   Ui::Statistics ui;
00391   ui.setupUi(&dlg);
00392 
00393   ui.p1_name->setText(mDoc->getName(Yellow));
00394   ui.p1_won->display(mDoc->getStatistic(Yellow, TWin));
00395   ui.p1_drawn->display(mDoc->getStatistic(Yellow, TRemis));
00396   ui.p1_lost->display(mDoc->getStatistic(Yellow, TLost));
00397   ui.p1_aborted->display(mDoc->getStatistic(Yellow, TBrk));
00398   ui.p1_sum->display(mDoc->getStatistic(Yellow, TSum));
00399 
00400   ui.p2_name->setText(mDoc->getName(Red));
00401   ui.p2_won->display(mDoc->getStatistic(Red, TWin));
00402   ui.p2_drawn->display(mDoc->getStatistic(Red, TRemis));
00403   ui.p2_lost->display(mDoc->getStatistic(Red, TLost));
00404   ui.p2_aborted->display(mDoc->getStatistic(Red, TBrk));
00405   ui.p2_sum->display(mDoc->getStatistic(Red, TSum));
00406 
00407   if(dlg.exec() == QDialog::Rejected)
00408   {
00409     mDoc->resetStatistic();
00410   }
00411 }
00412 
00413 
00414 // Undo menu call
00415 void KWin4App::undoMove()
00416 {
00417   mDoc->undoMove();
00418   // Undo twice if computer is moving to keep player as input
00419   if (mDoc->playedBy(mDoc->getCurrentPlayer())==KGameIO::ProcessIO)
00420   {
00421     mDoc->undoMove();
00422   }
00423 
00424   // Refresh menus
00425   updateStatusNames();
00426   checkMenus(CheckEditMenu);
00427 }
00428 
00429 // Redo menu call
00430 void KWin4App::redoMove()
00431 {
00432   mDoc->redoMove();
00433   // Redo twice if computer is moving to keep player as input
00434   if (mDoc->playedBy(mDoc->getCurrentPlayer())==KGameIO::ProcessIO)
00435   {
00436     mDoc->redoMove();
00437   }
00438   updateStatusNames();
00439   checkMenus(CheckEditMenu);
00440 }
00441 
00442 
00443 // Set the given text into the statusbar change status message permanently
00444 void KWin4App::displayStatusMessage(const QString &text)
00445 {
00446   statusBar()->clearMessage();
00447   statusBar()->changeItem(text, ID_STATUS_MSG);
00448 }
00449 
00450 
00451 // Set the string in the statusbar window for
00452 // the player currently moving change status mover permanently
00453 void KWin4App::displayStatusbarMover(const QString& text)
00454 {
00455   statusBar()->clearMessage();
00456   statusBar()->changeItem(text, ID_STATUS_MOVER);
00457 }
00458 
00459 
00460 // Ends the current game.
00461 // Called by the gameover signal
00462 void KWin4App::EndGame(TABLE mode)
00463 {
00464   mDoc->endGame(mode);
00465   mDoc->switchStartPlayer();
00466   updateStatusNames();
00467   checkMenus();
00468 }
00469 
00470 
00471 // Set the names in the mover field
00472 void KWin4App::updateStatusNames()
00473 {
00474   QString msg;
00475   if (!(mDoc->gameStatus()==KGame::Run))
00476     msg=i18n("No game  ");
00477   else if (mDoc->getCurrentPlayer()==Yellow)
00478     msg=i18n(" %1 - Yellow ", mDoc->getName(Yellow));
00479   else if (mDoc->getCurrentPlayer())
00480     msg=i18n(" %1 - Red ", mDoc->getName(Red));
00481   else
00482     msg=i18n("Nobody  ");
00483   displayStatusbarMover(msg);
00484 }
00485 
00486 // Notification that the network connection is lost.
00487 void KWin4App::networkBroken(int /*id*/, int oldstatus ,KGame * /*game */)
00488 {
00489   kDebug(12010) <<  "KWin4App::networkBroken("<<oldstatus<<")" << endl;
00490   
00491   // Set all input devices back to default
00492   if (mDoc->playedBy(Yellow)==0)
00493     mDoc->setPlayedBy(Yellow,KGameIO::MouseIO);
00494   if (mDoc->playedBy(Red)==0)
00495     mDoc->setPlayedBy(Red,KGameIO::MouseIO);
00496 
00497   kDebug(12010) << "CurrrentPlayer=" << mDoc->getCurrentPlayer() << endl;
00498   kDebug(12010) << "   " <<  mDoc->getPlayer(mDoc->getCurrentPlayer()) << endl;
00499   
00500   // Activate input device
00501   mDoc->getPlayer(mDoc->getCurrentPlayer())->setTurn(true,true);
00502 
00503   // Issue message
00504   KMessageBox::information(this,i18n("The network game ended!\n"));
00505     
00506   // Restore status  
00507   mDoc->setGameStatus(oldstatus);
00508 }
00509 
00510 
00511 // A move is done. Update status display.
00512 void KWin4App::moveDone(int playerNumber)
00513 {
00514   checkMenus(CheckEditMenu);
00515   updateStatusNames();
00516   displayStatusMessage(i18n("Game running..."));
00517 }
00518 
00519 // The game is over or aborted. Set status and display it.
00520 void KWin4App::slotGameOver(int status, KPlayer* p, KGame* /*me*/)
00521 {
00522   kDebug() << "KWin4App::slotGameOver" << endl;
00523   if (status==-1) // remis
00524   {
00525     EndGame(TRemis);
00526     displayStatusMessage(i18n("The game is drawn. Please restart next round."));
00527   }
00528   else if (status==1) // One of the players won
00529   {
00530     if (p->userId()==Yellow)
00531       EndGame(TWin);
00532     else
00533       EndGame(TLost);
00534     QString msg=i18n("%1 won the game. Please restart next round.", mDoc->getName(((COLOUR)p->userId())));
00535     displayStatusMessage(msg);
00536   }
00537   else if (status==2) // Abort
00538   {
00539     EndGame(TBrk);
00540     QString  m=i18n(" Game aborted. Please restart next round.");
00541     displayStatusMessage(m);
00542   }
00543   else
00544   {
00545     kError() << "Gameover with status " << status << ". This is unexpected and a serious problem" << endl;
00546   }
00547   checkMenus(CheckEditMenu);
00548 }
00549 
00550 
00551 // Show the network configuration dialog
00552 void KWin4App::configureNetwork()
00553 {
00554   if (mDoc->gameStatus()==KWin4Doc::Intro) 
00555   {
00556     mDoc->setGameStatus(KWin4Doc::Pause);
00557   }
00558 
00559   QString host = Prefs::host();
00560   int port=Prefs::port();
00561 
00562   // just for testing - should be non-modal
00563   KGameDialog dlg(mDoc, 0, i18n("Network Configuration"), this,
00564       KGameDialog::NetworkConfig, 20000, true);
00565   dlg.networkConfig()->setDefaultNetworkInfo(host, port);
00566   dlg.networkConfig()->setDiscoveryInfo("_kwin4._tcp",Prefs::gamename());
00567 
00568   KVBox *box=dlg.configPage(KGameDialog::NetworkConfig);
00569   QVBoxLayout *l=(QVBoxLayout *)(box->layout());
00570 
00571   mColorGroup=new KButtonGroup(box);
00572   connect(mColorGroup, SIGNAL(clicked(int)), this, SLOT(remoteChanged(int)));
00573   connect(dlg.networkConfig(), SIGNAL(signalServerTypeChanged(int)), this, SLOT(serverTypeChanged(int)));
00574 
00575   new QRadioButton(i18n("Yellow should be played by remote"), mColorGroup);
00576   new QRadioButton(i18n("Red should be played by remote"), mColorGroup);
00577   l->addWidget(mColorGroup);
00578   mColorGroup->setSelected(0);
00579   remoteChanged(0);
00580 
00581   dlg.exec();// note: we don't have to check for the result - maybe a bug
00582 }
00583 
00584 // Can't get rid of this function in KGame's current state.
00585 // Can't pass a int signal to a bool slot, so this must be here
00586 void KWin4App::serverTypeChanged(int t)
00587 {
00588   mColorGroup->setDisabled(t);
00589 }
00590 
00591 
00592 // The remote player in the network dialog has changed. Adapt priorities.
00593 void KWin4App::remoteChanged(int button)
00594 {
00595   if (button==0)
00596   {
00597     mDoc->getPlayer(Yellow)->setNetworkPriority(0);
00598     mDoc->getPlayer(Red)->setNetworkPriority(10);
00599   }
00600   else
00601   {
00602     mDoc->getPlayer(Yellow)->setNetworkPriority(10);
00603     mDoc->getPlayer(Red)->setNetworkPriority(0);
00604   }
00605 }
00606 
00607 
00608 // Show the chat dialog.
00609 void KWin4App::configureChat()
00610 {
00611   if (!mMyChatDlg)
00612   {
00613     mMyChatDlg=new ChatDlg(mDoc,this);
00614     KWin4Player *p=mDoc->getPlayer(Yellow);
00615     if (!p->isVirtual())
00616       mMyChatDlg->setPlayer(mDoc->getPlayer(Yellow));
00617     else
00618       mMyChatDlg->setPlayer(mDoc->getPlayer(Red));
00619     connect(mDoc,SIGNAL(signalChatChanged(KWin4Player *)),
00620             mMyChatDlg,SLOT(setPlayer(KWin4Player *)));
00621   }
00622 
00623   if (mMyChatDlg->isHidden())
00624     mMyChatDlg->show();
00625   else
00626     mMyChatDlg->hide();
00627 }
00628 
00629 
00630 // Show the KGame debug window.
00631 void KWin4App::debugKGame()
00632 {
00633   KGameDebugDialog* debugWindow = new KGameDebugDialog(mDoc, this);
00634   debugWindow->show();
00635 }
00636 
00637 
00638 // Show Configure dialog.
00639 void KWin4App::configureSettings()
00640 {
00641   if(KConfigDialog::showDialog("settings"))
00642   {
00643     return;
00644   }
00645 
00646   KConfigDialog* dialog = new KConfigDialog(this, "settings", Prefs::self(), KPageDialog::Plain);
00647   Ui::Settings ui;
00648   QWidget* frame = new QWidget(dialog);
00649   ui.setupUi(frame);
00650   dialog->addPage(frame, i18n("General"), "package_settings");
00651   connect(dialog, SIGNAL(settingsChanged(const QString &)), mDoc, SLOT(loadSettings()));
00652   dialog->show();
00653 }
00654 
00655 #include "kwin4.moc"

Generated on Sun Mar 4 10:56:43 2007 for KWin4 by  doxygen 1.4.6