/*************************************************************************** * Copyright (C) 2002-2003 Andi Peredri * * andi@ukr.net * * Copyright (C) 2004-2005 Artur Wiebe * * wibix@gmx.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include "pdn.h" #include "toplevel.h" #include "newgamedlg.h" #include "view.h" #include "common.h" #define CFG_THEME_PATH CFG_KEY"ThemePath" #define CFG_FILENAME CFG_KEY"Filename" #define CFG_KEEPDIALOG CFG_KEY"ShowKeepDialog" #define CFG_NOTATION CFG_KEY"Notation" #define CFG_NOT_ABOVE CFG_KEY"NotationAbove" #define CFG_NOT_FONT CFG_KEY"NotationFont" #define CFG_CLEAR_LOG CFG_KEY"ClearLogOnNewRound" myTopLevel::myTopLevel() { setWindowTitle(APPNAME); setWindowIcon(QIcon(":/icons/biglogo.png")); m_newgame = new myNewGameDlg(this); make_central_widget(); make_actions(); restore_settings(); /* * new computer game. */ m_view->newGame(m_newgame->rules(), m_newgame->freePlacement(), m_newgame->name(), m_newgame->isWhite(), m_newgame->opponent(), m_newgame->opponentName(), m_newgame->skill()); if(layout()) layout()->setSizeConstraint(QLayout::SetFixedSize); } void myTopLevel::make_actions() { // game menu actions gameNew = new QAction(QIcon(":/icons/logo.png"), tr("&New..."), this); gameNew->setShortcut(tr("CTRL+N", "File|New")); connect(gameNew, SIGNAL(triggered()), this, SLOT(slot_new_game())); gameNextRound = new QAction(QIcon(":/icons/next.png"), tr("&Next Round"), this); connect(gameNextRound, SIGNAL(triggered()), this, SLOT(slot_next_round())); gameStop = new QAction(QIcon(":/icons/stop.png"), tr("&Stop"), this); connect(gameStop, SIGNAL(triggered()), m_view, SLOT(slotStopGame())); gameOpen = new QAction(QIcon(":/icons/fileopen.png"), tr("&Open..."), this); gameOpen->setShortcut(tr("CTRL+O", "File|Open")); connect(gameOpen, SIGNAL(triggered()), this, SLOT(slot_open_game())); gameSave = new QAction(QIcon(":/icons/filesave.png"), tr("&Save..."), this); gameSave->setShortcut(tr("CTRL+S", "File|Save")); connect(gameSave, SIGNAL(triggered()), this, SLOT(slot_save_game())); QAction* gameQuit = new QAction(QIcon(":/icons/exit.png"), tr("&Quit"), this); gameQuit->setShortcut(tr("CTRL+Q", "File|Quit")); connect(gameQuit, SIGNAL(triggered()), this, SLOT(close())); // QApplication::instance(), SLOT(quit())); // view menu actions viewNotation = new QAction(tr("&Show Notation"), this); viewNotation->setCheckable(true); connect(viewNotation, SIGNAL(toggled(bool)), this, SLOT(slot_notation(bool))); viewNotationAbove = new QAction(tr("Show notation &above men"), this); viewNotationAbove->setCheckable(true); connect(viewNotationAbove, SIGNAL(toggled(bool)), this, SLOT(slot_notation(bool))); // settings menu settingsKeep = new QAction(tr("&Confirm aborting current game"), this); settingsKeep->setCheckable(true); // settingsClearLog = new QAction(tr("Clear &log on new round"), this); settingsClearLog->setCheckable(true); connect(settingsClearLog, SIGNAL(toggled(bool)), m_view, SLOT(slotClearLog(bool))); // QAction* settingsNotationFont = new QAction(tr("&Notation font..."), this); connect(settingsNotationFont, SIGNAL(triggered()), this, SLOT(slot_notation_font())); // help menu actions QAction* helpRules = new QAction(tr("&Rules of Play"), this); helpRules->setShortcut(tr("F1", "Help|Help")); connect(helpRules, SIGNAL(triggered()), this, SLOT(slot_help())); QAction* helpAbout = new QAction(QIcon(":/icons/logo.png"), tr("&About")+" "APPNAME, this); connect(helpAbout, SIGNAL(triggered()), this, SLOT(slot_about())); QAction* helpAboutQt = new QAction(tr("About &Qt"), this); connect(helpAboutQt, SIGNAL(triggered()), qApp, SLOT(aboutQt())); /* * toolbar */ QToolBar* tb = addToolBar(tr("&Toolbar")); tb->setMovable(false); tb->addAction(gameNew); tb->addAction(gameOpen); tb->addAction(gameSave); tb->addSeparator(); tb->addAction(gameNextRound); tb->addAction(gameStop); /* * menus */ QMenu* gameMenu = menuBar()->addMenu(tr("&Game")); gameMenu->addAction(gameNew); gameMenu->addAction(gameOpen); gameMenu->addAction(gameSave); gameMenu->addSeparator(); gameMenu->addAction(gameNextRound); gameMenu->addAction(gameStop); gameMenu->addSeparator(); gameMenu->addAction(gameQuit); viewMenu = menuBar()->addMenu(tr("&View")); viewMenu->addAction(tb->toggleViewAction()); viewMenu->addSeparator(); viewMenu->addAction(viewNotation); viewMenu->addAction(viewNotationAbove); QMenu* settingsMenu = menuBar()->addMenu(tr("&Settings")); settingsMenu->addAction(settingsKeep); settingsMenu->addSeparator(); settingsMenu->addAction(settingsNotationFont); settingsMenu->addSeparator(); settingsMenu->addAction(settingsClearLog); QMenu* helpMenu = menuBar()->addMenu(tr("&Help")); helpMenu->addAction(helpRules); helpMenu->addSeparator(); helpMenu->addAction(helpAbout); helpMenu->addAction(helpAboutQt); /* * THEMES. create a default theme. */ QActionGroup* themes_grp = new QActionGroup(this); themes_grp->setExclusive(true); QAction* default_theme = new QAction(tr(DEFAULT_THEME), themes_grp); default_theme->setCheckable(true); m_themes[default_theme] = DEFAULT_THEME; default_theme->setChecked(true); set_theme(default_theme);//FIXME TODO themes_grp->addAction(default_theme); viewMenu->addSeparator(); viewMenu->addAction(default_theme); read_themes(themes_grp, viewMenu,QDir::homePath()+"/"USER_PATH"/"THEME_DIR); //TODO-hardcoded read_themes(themes_grp, viewMenu, PREFIX"/share/kcheckers/"THEME_DIR); connect(themes_grp, SIGNAL(triggered(QAction*)), this, SLOT(set_theme(QAction*))); } void myTopLevel::read_themes(QActionGroup* menu_grp, QMenu* menu, const QString& path) { QDir sharedir(path); QStringList themes = sharedir.entryList(QDir::Dirs|QDir::Readable); themes.removeAll("."); themes.removeAll(".."); for(QStringList::iterator it=themes.begin(); it!=themes.end(); ++it) { sharedir.cd(*it); QString theme_dir = sharedir.absolutePath(); QString errtext; QStringList files = sharedir.entryList(QDir::Files|QDir::Readable); // all files are there. if(files.count()!=8 || files.indexOf(THEME_TILE1) == -1 || files.indexOf(THEME_TILE2) == -1 || files.indexOf(THEME_FRAME) == -1 || files.indexOf(THEME_MANBLACK) == -1 || files.indexOf(THEME_MANWHITE) == -1 || files.indexOf(THEME_KINGBLACK) == -1 || files.indexOf(THEME_KINGWHITE) == -1 || files.indexOf(THEME_FILE) == -1) { // TODO not translated. errtext += "Wrong number of files. "; } files.removeAll(THEME_FILE); // check pic size. QSize size = QPixmap(theme_dir+"/"+files[0]).size(); if(size.width()>MAX_TILE_SIZE || size.height()>MAX_TILE_SIZE) // TODO not translated. errtext += "Picture(s) too big. "; if(size.width()==0 || size.height()==0) // TODO not translated. errtext += "Width/Height is zero. "; // check pics all the same size. foreach(QString file, files) { if(QPixmap(theme_dir+"/"+file).size() != size) { // TODO not translated. errtext += "Pictures are different in size. "; break; } } if(errtext.length()) { // TODO not translated. qWarning() << endl << "Theme in" << sharedir.absolutePath() << endl << errtext; } else { QString themename = sharedir.dirName(); /*TODO QFile file(theme_dir+"/"+THEME_FILE); if(file.open(QFile::ReadOnly)) { QTextStream ts(&file); if(!ts.atEnd()) themename = ts.readLine(); // try go get locale theme name // TODO QString locale = QString("[%1]=").arg(QTextCodec::locale()); while(!ts.atEnd()) { QString line = ts.readLine(); if(line.startsWith(locale)) { themename = line.mid(locale.length()); break; } } file.close(); } */ // QAction* action = new QAction(themename, this); menu_grp->addAction(action); menu->addAction(action); action->setCheckable(true); m_themes[action] = theme_dir; } sharedir.cdUp(); } } void myTopLevel::restore_settings() { QSettings cfg(APPNAME, APPNAME); QString theme_path = cfg.value(CFG_THEME_PATH, DEFAULT_THEME) .toString(); for(myThemeMap::iterator it = m_themes.begin(); it!=m_themes.end();it++) if(it.value() == theme_path) { it.key()->setChecked(true); set_theme(it.key()); break; } filename = cfg.value(CFG_FILENAME).toString(); viewNotation->setChecked(cfg.value(CFG_NOTATION, false).toBool()); viewNotationAbove->setChecked(cfg.value(CFG_NOT_ABOVE, true).toBool()); slot_notation(true); // here: arg is ignored by the function bool clear_log = cfg.value(CFG_CLEAR_LOG, true).toBool(); settingsClearLog->setChecked(clear_log); m_view->slotClearLog(clear_log); // settingsKeep->setChecked(cfg.value(CFG_KEEPDIALOG, true).toBool()); QFont cfont; if(cfont.fromString(cfg.value(CFG_NOT_FONT, "").toString())) m_view->setNotationFont(cfont); // new game m_newgame->readSettings(&cfg); } void myTopLevel::make_central_widget() { m_view = new myView(this); connect(m_view, SIGNAL(working(bool)), this, SLOT(slot_working(bool))); setCentralWidget(m_view); } void myTopLevel::warning(const QString& text) { QMessageBox::warning(this, tr("Error")+" - "APPNAME, text); } void myTopLevel::information(const QString& caption, const QString& text) { QDialog* dlg = new QDialog(this); dlg->setModal(true); dlg->setWindowTitle(caption+" - "APPNAME); // logo left QLabel* logo = new QLabel(dlg); logo->setPixmap(QPixmap(":/icons/dialog.png")); // text editor QTextEdit* te = new QTextEdit(text, dlg); te->setReadOnly(true); te->setMinimumWidth(m_view->width()-100); te->setMinimumHeight(m_view->height()-200); // close button QPushButton* button = new QPushButton(tr("&Close"), dlg); connect(button, SIGNAL(clicked()), dlg, SLOT(accept())); // Layout. QHBoxLayout* hb = new QHBoxLayout(); hb->addWidget(logo, 0, Qt::AlignTop); hb->addWidget(te, 1); QHBoxLayout* hb_button = new QHBoxLayout(); hb_button->addStretch(); hb_button->addWidget(button); QVBoxLayout* vb = new QVBoxLayout(dlg); vb->addLayout(hb, 1); vb->addSpacing(5); vb->addLayout(hb_button); // go dlg->exec(); delete dlg; } void myTopLevel::slot_save_game() { QString fn = QFileDialog::getSaveFileName(this, tr("Save Game")+" - "APPNAME, filename, "PDN Files (*."EXT")"); if(!fn.isEmpty()) { if(fn.right(3)!=EXT) fn += "."EXT; if(m_view->savePdn(fn)) filename = fn; else warning(tr("Could not save: ")+filename); } } void myTopLevel::slot_open_game() { QString fn = QFileDialog::getOpenFileName(this, tr("Open Game")+" - "APPNAME, filename, "PDN Files (*."EXT")"); if(!fn.isEmpty()) open(fn); } void myTopLevel::open(const QString& fn) { if(m_view->openPdn(fn)) filename = fn; } void myTopLevel::closeEvent(QCloseEvent* e) { if(!keep_game()) { store_settings(); e->accept(); } else { e->ignore(); } } void myTopLevel::store_settings() { QSettings config(APPNAME, APPNAME); for(myThemeMap::iterator it=m_themes.begin(); it!=m_themes.end(); it++) if(it.key()->isChecked()) { config.setValue(CFG_THEME_PATH, it.value()); break; } config.setValue(CFG_FILENAME, filename); config.setValue(CFG_NOTATION, viewNotation->isChecked()); config.setValue(CFG_NOT_ABOVE, viewNotationAbove->isChecked()); config.setValue(CFG_KEEPDIALOG, settingsKeep->isChecked()); config.setValue(CFG_NOT_FONT, m_view->notationFont().toString()); config.setValue(CFG_CLEAR_LOG, settingsClearLog->isChecked()); // new game m_newgame->writeSettings(&config); } void myTopLevel::set_theme(QAction* action) { QString path = m_themes[action]; m_view->setTheme(path); } void myTopLevel::slot_help() { QString text = tr("

In the beginning of game you have 12 checkers (men). " "The men move forward only. The men can capture:" "

    " "
  • by jumping forward only (english rules);" "
  • by jumping forward or backward (russian rules)." "
" "

A man which reaches the far side of the board becomes a king. " "The kings move forward or backward:" "

    " "
  • to one square only (english rules);" "
  • to any number of squares (russian rules)." "
" "

The kings capture by jumping forward or backward. " "Whenever a player is able to make a capture he must do so."); information(tr("Rules of Play"), text); } void myTopLevel::slot_about() { QString text = APPNAME", a board game.
Version "VERSION"

" COPYRIGHT"
" ""HOMEPAGE"

" "Contributors:
"CONTRIBS"

" "This program is distributed under the terms " "of the GNU General Public License."; information(tr("About"), text); } void myTopLevel::slot_new_game() { if(keep_game()) return; if(m_newgame->exec()==QDialog::Accepted) { m_view->newGame(m_newgame->rules(), m_newgame->freePlacement(), m_newgame->name(), m_newgame->isWhite(), m_newgame->opponent(), m_newgame->opponentName(), m_newgame->skill()); } } void myTopLevel::slot_working(bool working) { bool disable = !working; gameNew->setEnabled(disable); gameSave->setEnabled(disable); gameNextRound->setEnabled(disable);// FIXME !m_view->isAborted()); gameOpen->setEnabled(disable); gameStop->setEnabled(!disable); m_view->setEnabled(disable); } bool myTopLevel::keep_game() { if(!settingsKeep->isChecked() || m_view->isAborted()) return false; int answer = QMessageBox::question(this, tr("Abort Game?")+" - "APPNAME, tr("Current game will be lost if you continue.\n" "Do you really want to discard it?"), QMessageBox::Yes, QMessageBox::No); if(answer == QMessageBox::Yes) return false; return true; } void myTopLevel::slot_next_round() { if(!keep_game()) m_view->slotNextRound(); } void myTopLevel::slot_notation_font() { bool ok; QFont font = QFontDialog::getFont(&ok, m_view->notationFont(), this); if(ok) m_view->setNotationFont(font); } void myTopLevel::slot_notation(bool) { m_view->setNotation(viewNotation->isChecked(), viewNotationAbove->isChecked()); }