2 Copyright (c) 2006 Paolo Capriotti <p.capriotti@sns.it>
3 (c) 2006 Maurizio Monge <maurizio.monge@kdemail.net>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
11 #include "mainwindow.h"
12 #include <boost/scoped_ptr.hpp>
14 #include <kstandardaction.h>
15 #include <kactioncollection.h>
19 #include <kfiledialog.h>
20 #include <kio/netaccess.h>
21 #include <kmessagebox.h>
22 #include <QKeySequence>
23 #include <QStackedWidget>
24 #include <QDockWidget>
25 #include <QCloseEvent>
26 #include <QTextStream>
28 #include <ktabwidget.h>
29 #include "chesstable.h"
33 #include "variants/variants.h"
34 #include "variants/xchess/piecetype.h"
35 #include "variants/chess.h"
37 #include "controllers/editgame.h"
38 #include "controllers/editposition.h"
39 #include "movelist_table.h"
40 #include "icsconnection.h"
44 #include "pgnparser.h"
45 #include "pref_highlight.h"
46 #include "pref_clock.h"
47 #include "pref_preferences.h"
50 using namespace boost
;
52 MainWindow::~MainWindow() {
57 MainWindow::MainWindow()
59 setObjectName("kboard_main");
60 m_main
= new KTabWidget(this);
61 setCentralWidget(m_main
);
63 m_movelist_stack
= new QStackedWidget
;
65 connect(m_main
, SIGNAL(currentChanged(int)),
66 this, SLOT(changeTab(int)));
67 connect(m_main
, SIGNAL(closeTab()),
68 this, SLOT(closeTab()));
70 movelist_dock
= new QDockWidget(this);
71 movelist_dock
->setWidget(m_movelist_stack
);
72 movelist_dock
->setWindowTitle(i18n("Move list"));
73 movelist_dock
->setObjectName("move_list");
74 addDockWidget(Qt::LeftDockWidgetArea
, movelist_dock
, Qt::Vertical
);
75 movelist_dock
->show();
77 ChessTable
* board
= new ChessTable
;
81 console_dock
= new QDockWidget(this);
82 console
= new Console(0, i18n("FICS Connection"));
83 console_dock
->setWidget(console
);
84 console_dock
->setFocusProxy(console
);
85 console_dock
->setWindowTitle(i18n("Console"));
86 console_dock
->setObjectName("console");
87 addDockWidget(Qt::BottomDockWidgetArea
, console_dock
, Qt::Horizontal
);
88 console_dock
->setWindowFlags(console_dock
->windowFlags() & ~Qt::WindowStaysOnTopHint
);
91 connect(board
, SIGNAL(error(ErrorCode
)), this, SLOT(displayErrorMessage(ErrorCode
)));
92 connect(board
->clock(), SIGNAL(labelClicked(int)), &ui(), SLOT(setTurn(int)));
94 // start in edit game mode
95 newGame("chess", AbstractPosition::Ptr());
99 updatePromotionType();
102 ChessTable
* MainWindow::table() {
103 return qobject_cast
<ChessTable
*>(m_main
->currentWidget());
106 KAction
* MainWindow::addPromotionAction(const QString
& name
, const QString
& text
, const char* uiSlot
) {
107 KAction
* temp
= new KAction(KIcon(name
), text
, this);
108 temp
->setCheckable(true);
109 connect(temp
, SIGNAL(triggered(bool)), &ui(), uiSlot
);
110 m_promote_group
->addAction(temp
);
111 actionCollection()->addAction(name
, temp
);
115 KAction
* MainWindow::installRegularAction(const QString
& name
, const KIcon
& icon
, const QString
& text
, QObject
* obj
, const char* slot
) {
116 KAction
* temp
= new KAction(icon
, text
, this);
117 actionCollection()->addAction(name
, temp
);
118 connect(temp
, SIGNAL(triggered(bool)), obj
, slot
);
122 void MainWindow::setupActions() {
123 // (void) new KAction(i18n("&New game..."), CTRL+Key_N, this, SLOT(newGame()), actionCollection(), "new");
126 KStandardAction::openNew(this, SLOT(newGame()), actionCollection());
127 KStandardAction::open(this, SLOT(loadGame()), actionCollection());
128 KStandardAction::quit(this, SLOT(quit()), actionCollection());
130 m_promote_group
= new QActionGroup(this);
132 m_promote_queen
= addPromotionAction("promoteQueen", i18n("Promote to &queen"), SLOT(promoteToQueen()));
133 m_promote_rook
= addPromotionAction("promoteRook", i18n("Promote to &Rook"), SLOT(promoteToRook()));
134 m_promote_bishop
= addPromotionAction("promoteBishop", i18n("Promote to &Bishop"), SLOT(promoteToBishop()));
135 m_promote_knight
= addPromotionAction("promoteKnight", i18n("Promote to K&night"), SLOT(promoteToKnight()));
137 m_do_promotion
= installRegularAction("doPromotion", KIcon("favorites"),
138 i18n("Do &promotion"), &ui(),
139 SLOT(setDoPromotion(bool)));
140 m_do_promotion
->setCheckable(true);
142 installRegularAction("back", KIcon("back"), i18n("&Back"), &ui(), SLOT(back()));
143 installRegularAction("forward", KIcon("forward"), i18n("&Forward"), &ui(), SLOT(forward()));
144 installRegularAction("begin", KIcon("start"), i18n("Be&gin"), &ui(), SLOT(gotoFirst()));
145 installRegularAction("end", KIcon("finish"), i18n("&End"), &ui(), SLOT(gotoLast()));
146 installRegularAction("connect", KIcon("connect_creating"), i18n("&Connect"), this, SLOT(icsConnect()));
147 installRegularAction("disconnect", KIcon("connect_no"), i18n("&Disconnect"), this, SLOT(icsDisconnect()));
149 KStandardAction::undo(&ui(), SLOT(undo()), actionCollection());
150 KStandardAction::redo(&ui(), SLOT(redo()), actionCollection());
152 installRegularAction("pgnCopy", KIcon("copy"), i18n("Copy PGN"), this, SLOT(pgnCopy()));
153 installRegularAction("pgnPaste", KIcon("paste"), i18n("Paste PGN"), this, SLOT(pgnPaste()));
154 installRegularAction("editPosition", KIcon("edit"), i18n("&Edit position"), this, SLOT(editPosition()));
155 installRegularAction("clearBoard", KIcon("editdelete"), i18n("&Clear board"), &ui(), SLOT(clearBoard()));
156 installRegularAction("setStartingPosition", KIcon("contents"), i18n("&Set starting position"),
157 &ui(), SLOT(setStartingPosition()));
158 installRegularAction("copyPosition", KIcon(), i18n("&Copy position"), &ui(), SLOT(copyPosition()));
159 installRegularAction("pastePosition", KIcon(), i18n("&Paste position"), &ui(), SLOT(pastePosition()));
160 installRegularAction("flip", KIcon("rotate"), i18n("&Flip view"), this, SLOT(flipView()));
161 installRegularAction("toggleConsole", KIcon("openterm"), i18n("Toggle &console"), this, SLOT(toggleConsole()));
162 installRegularAction("toggleMoveList", KIcon("view_text"), i18n("Toggle &move list"), this, SLOT(toggleMoveList()));
163 installRegularAction("configure", KIcon("configure"), i18n("&Configure KBoard..."), this, SLOT(preferences()));
166 void MainWindow::updatePromotionType() {
167 // TODO: I'm removing this code because it causes a crash
168 // and I don't want to investigate further, since the promotion
169 // stuff needs to be changed completely.
171 int ptype
= m_ui
.promotionType();
173 m_promote_group
->setEnabled(false);
175 m_promote_group
->setEnabled(true);
178 m_promote_queen
->setChecked(true);
181 m_promote_rook
->setChecked(true);
184 m_promote_bishop
->setChecked(true);
187 m_promote_knight
->setChecked(true);
190 m_promote_group
->setEnabled(false);
194 std::cout
<< "do promotion: " << m_ui
.doPromotion() << std::endl
;
195 m_do_promotion
->setChecked(m_ui
.doPromotion());
199 void MainWindow::readSettings() { }
200 void MainWindow::writeSettings() { }
202 void MainWindow::closeEvent(QCloseEvent
* e
) {
209 void MainWindow::keyPressEvent(QKeyEvent
* event
) {
210 if (event
->key() == Qt::Key_F5
) {
211 ui().createCtrlAction();
215 void MainWindow::keyReleaseEvent(QKeyEvent
* event
) {
216 if (event
->key() == Qt::Key_F5
) {
217 ui().destroyCtrlAction();
221 void MainWindow::changeTab(int index
) {
222 m_ui
.setCurrentTab(m_main
->currentWidget());
223 m_movelist_stack
->setCurrentIndex(index
);
224 updatePromotionType();
227 void MainWindow::closeTab() {
228 if (m_main
->count() > 1) {
229 ChessTable
* old_board
= table();
230 m_ui
.removeController(old_board
);
231 m_movelist_stack
->removeWidget(
232 m_movelist_stack
->widget(m_main
->currentIndex()));
233 m_main
->removeTab(m_main
->currentIndex());
237 if (m_main
->count() <= 1) {
238 m_main
->setTabBarHidden(true);
241 // update ui controller (just in case...)
242 m_ui
.setCurrentTab(m_main
->currentWidget());
246 void MainWindow::createTab(ChessTable
* board
, const shared_ptr
<Controller
>& controller
,
247 const QString
& caption
, int index
) {
249 index
= m_main
->addTab(board
, caption
);
251 m_main
->insertTab(index
, board
, caption
);
253 m_main
->setCurrentIndex(index
);
254 m_ui
.addController(board
, controller
);
255 m_ui
.setCurrentTab(board
);
256 m_movelist_stack
->addWidget(board
->moveListTable());
257 m_movelist_stack
->setCurrentIndex(index
);
258 if (m_main
->count() > 1) m_main
->setTabBarHidden(false);
262 void MainWindow::cleanupGame(const QString
& what
, const QString
& result
) {
269 void MainWindow::cleanupGame() {
275 bool MainWindow::newGame(const QString
& variantName
, AbstractPosition::Ptr startingPos
) {
276 VariantInfo
* variant
= Variant::variant(variantName
);
278 ChessTable
* board
= new ChessTable
;
279 shared_ptr
<Controller
> controller(new EditGameController(
280 board
, variant
, startingPos
));
281 createTab(board
, controller
,
282 QString("Editing %1 game").arg(variantName
.toLower()));
289 void MainWindow::editPosition() {
290 shared_ptr
<Controller
> controller(new EditPositionController(table(), ChessVariant::info()));
291 m_main
->setTabText(m_main
->currentIndex(), "Editing chess position");
292 ui().setController(controller
);
295 void MainWindow::setupGame(const GameInfo
* gameInfo
, const PositionInfo
& style12
) {
296 QString variantCode
= gameInfo
->variant();
297 VariantInfo
* variant
= Variant::variant(variantCode
);
298 shared_ptr
<EditGameController
> controller(new EditGameController(
300 Q_ASSERT(style12
.relation
== PositionInfo::NotMyMove
||
301 style12
.relation
== PositionInfo::MyMove
);
304 int side
= (style12
.relation
== PositionInfo::MyMove
^ style12
.turn
== 0) ? 0 : 1;
306 if (controller
->addICSPlayer(side
, style12
.gameNumber
, m_connection
)) {
307 ui().setController(controller
);
308 table()->setPlayers(gameInfo
->white(), gameInfo
->black());
309 m_main
->setTabText(m_main
->currentIndex(),
310 QString("FICS Game - %1 vs %2").arg(style12
.whitePlayer
)
311 .arg(style12
.blackPlayer
));
315 void MainWindow::setupExaminedGame(const GameInfo
* /*gameInfo*/, const PositionInfo
& style12
) {
316 shared_ptr
<EditGameController
> controller(new EditGameController(
317 table(), ChessVariant::info()));
318 if (controller
->setExaminationMode(style12
.gameNumber
, m_connection
)) {
319 table()->setPlayers(Player(style12
.whitePlayer
, -1),
320 Player(style12
.blackPlayer
, -1));
321 ui().setController(controller
);
322 m_main
->setTabText(m_main
->currentIndex(),
323 QString("Examining - %1 vs %2").arg(style12
.whitePlayer
)
324 .arg(style12
.blackPlayer
));
329 void MainWindow::setupObservedGame(const GameInfo
* g
, const PositionInfo
& style12
) {
330 std::auto_ptr
<ChessTable
> board(new ChessTable
);
332 shared_ptr
<EditGameController
> controller(new EditGameController(
333 board
.get(), Variant::variant(g
->variant())));
334 if (controller
->setObserveMode(style12
.gameNumber
, m_connection
)) {
335 board
->setPlayers(Player(style12
.whitePlayer
, -1),
336 Player(style12
.blackPlayer
, -1));
337 // ui().setController(controller);
338 //std::cout << "adding tab" << std::endl;
339 createTab(board
.get(), controller
,
340 QString("Observing - %1 vs %2").arg(style12
.whitePlayer
)
341 .arg(style12
.blackPlayer
));
346 void MainWindow::setupPGN(const QString
& s
) {
349 std::map
<QString
, QString
>::const_iterator var
= pgn
.m_tags
.find("Variant");
350 VariantInfo
*variant
;
352 if(var
== pgn
.m_tags
.end())
353 variant
= Variant::variant("Chess");
354 else if(!(variant
= Variant::variant(var
->second
))) {
355 std::cout
<< " --> MainWindow::setupPGN: Error, no such variant " << var
->second
<< std::endl
;
359 shared_ptr
<EditGameController
> controller(new EditGameController(
361 ui().setController(controller
);
362 controller
->loadPGN(pgn
);
364 // table()->setPlayers(gameInfo->white(), gameInfo->black());
365 // m_main->setTabText(m_main->currentIndex(),
366 // QString("FICS Game - %1 vs %2").arg(style12.whitePlayer)
367 // .arg(style12.blackPlayer));
370 bool MainWindow::openFile(const QString
& filename
) {
371 QFileInfo
info(filename
);
374 KMessageBox::sorry(this, i18n("You have specified a folder"), i18n("Error"));
378 if(!info
.exists() || !info
.isFile()) {
379 KMessageBox::sorry(this, i18n("The specified file does not exist"), i18n("Error"));
383 QFile
file(filename
);
385 if(!file
.open(QIODevice::ReadOnly
)) {
386 KMessageBox::sorry(this, i18n("You do not have read permission to this file."), i18n("Error"));
390 QTextStream
stream(&file
);
392 codec
= QTextCodec::codecForLocale();
393 stream
.setCodec(codec
);
395 setupPGN(stream
.readAll());
396 //ui().pgnPaste(stream.readAll());
400 void MainWindow::loadGame() {
401 KUrl url
= KFileDialog::getOpenUrl(KUrl(), "*.pgn", this, i18n("Open PGN file"));
407 if (KIO::NetAccess::download(url
, tmp_file
, this)) {
409 KIO::NetAccess::removeTempFile(tmp_file
);
412 KMessageBox::error(this, KIO::NetAccess::lastErrorString());
415 void MainWindow::createConnection(const QString
& username
, const QString
& password
,
416 const QString
& host
, quint16 port
,
417 const QString
& timeseal
, const QString
& timeseal_cmd
) {
418 m_connection
= shared_ptr
<ICSConnection
>(new ICSConnection
);
420 connect(m_connection
.get(), SIGNAL(established()), this, SLOT(onEstablishConnection()));
421 connect(m_connection
.get(), SIGNAL(hostLookup()), this, SLOT(onHostLookup()));
422 connect(m_connection
.get(), SIGNAL(hostFound()), this, SLOT(onHostFound()));
424 connect(m_connection
.get(), SIGNAL(receivedLine(QString
, int)), console
, SLOT(displayText(QString
, int)));
425 connect(m_connection
.get(), SIGNAL(receivedText(QString
, int)), console
, SLOT(displayText(QString
, int)));
427 connect(console
, SIGNAL(receivedInput(const QString
&)), m_connection
.get(), SLOT(sendText(const QString
&)));
428 connect(console
, SIGNAL(notify()), this, SLOT(flash()));
430 connect(m_connection
.get(), SIGNAL(loginPrompt()), this, SLOT(sendLogin()));
431 connect(m_connection
.get(), SIGNAL(registeredNickname()), this, SLOT(sendBlankPassword()));
432 connect(m_connection
.get(), SIGNAL(prompt()), this, SLOT(prompt()));
435 connect(m_connection
.get(), SIGNAL(creatingExaminedGame(const GameInfo
*, const PositionInfo
&)),
436 this, SLOT(setupExaminedGame(const GameInfo
*, const PositionInfo
&)));
437 connect(m_connection
.get(), SIGNAL(endingExaminedGame(int)), this, SLOT(cleanupGame()));
439 connect(m_connection
.get(), SIGNAL(creatingObservedGame(const GameInfo
*, const PositionInfo
&)),
440 this, SLOT(setupObservedGame(const GameInfo
*, const PositionInfo
&)));
441 connect(m_connection
.get(), SIGNAL(endingObservedGame(int)), this, SLOT(cleanupGame()));
444 connect(m_connection
.get(), SIGNAL(creatingGame(const GameInfo
*, const PositionInfo
&)),
445 this, SLOT(setupGame(const GameInfo
*, const PositionInfo
&)));
446 connect(m_connection
.get(), SIGNAL(endingGame(const QString
&, const QString
&)),
447 this, SLOT(cleanupGame(const QString
&, const QString
&)));
448 connect(m_connection
.get(), SIGNAL(notification()), this, SLOT(flash()));
450 m_connection
->establish(host
.toAscii().constData(), port
, timeseal
, timeseal_cmd
);
453 // send username / password combination
454 if (!username
.isEmpty()) {
455 m_connection
->sendText(username
);
456 m_connection
->sendText(password
);
459 quickConnectDialog
.reset();
462 void MainWindow::icsConnect() {
463 quickConnectDialog
= shared_ptr
<QConnect
>(new QConnect(this));
464 connect(quickConnectDialog
.get(),
465 SIGNAL(acceptConnection(const QString
&,
472 SLOT(createConnection(const QString
&,
478 quickConnectDialog
->show();
481 void MainWindow::destroyConnection() {
482 m_connection
.reset();
485 void MainWindow::icsDisconnect() {
491 void MainWindow::testConnect() {
492 Settings s_ics
= settings
.group("ics");
493 if (s_ics
["username"]) {
494 QString username
= s_ics
["username"].value
<QString
>();
495 QString password
= (s_ics
["password"] | "");
496 QString host
= (s_ics
["icsHost"] | "freechess.org");
497 quint16 port
= (s_ics
["icsPort"] | 5000);
498 createConnection(username
, password
, host
, port
, QString(), QString() );
504 void MainWindow::onEstablishConnection() {
505 // std::cout << "connection established" << std::endl;
508 void MainWindow::onConnectionError(int ) {
509 // std::cout << "connection error (" << code << ")" << std::endl;
512 void MainWindow::onHostLookup() {
513 // std::cout << "hostLookup..." << std::flush;
516 void MainWindow::onHostFound() {
517 // std::cout << "found" << std::endl;
521 void MainWindow::sendLogin() {
522 // std::cout << "sending username" << std::endl;
523 // connection->sendText(connection->username());
526 void MainWindow::sendBlankPassword() {
527 std::cout
<< "sending blank password" << std::endl
;
528 m_connection
->sendText("");
531 void MainWindow::prompt() {
532 if (!m_connection
->initialized()) {
533 m_connection
->startup();
534 m_connection
->setInitialized();
538 void MainWindow::newGame() {
539 AbstractPosition::Ptr pos
= ui().position();
540 scoped_ptr
<NewGame
> dialog(new NewGame(this, pos
));
541 if (dialog
->exec() == QDialog::Accepted
) {
542 if(dialog
->isCustom()) {
543 VariantInfo
*vi
= Variant::variant(dialog
->variant());
544 std::cout
<< "vi[" << dialog
->variant() << "] = " << vi
<< std::endl
;
545 pos
= vi
->createCustomPosition(dialog
->customOptions());
548 else if (!dialog
->playFromCurrent())
549 pos
= AbstractPosition::Ptr();
550 if (!newGame(dialog
->variant(), pos
))
551 QMessageBox::information(this, tr("Error"), tr("Variant not implemented, yet"));
555 void MainWindow::quit() {
559 void MainWindow::flipView() {
563 void MainWindow::toggleConsole() {
564 if (console_dock
->isVisible())
565 console_dock
->hide();
567 console_dock
->show();
568 console_dock
->setFocus(Qt::MouseFocusReason
569 /*Qt::ActiveWindowFocusReason*/ /*Qt::OtherFocusReason*/);
573 void MainWindow::toggleMoveList() {
574 if (movelist_dock
->isVisible())
575 movelist_dock
->hide();
577 movelist_dock
->show();
578 movelist_dock
->setFocus(Qt::OtherFocusReason
);
583 void MainWindow::displayMessage(const QString
& msg
) {
584 Q_UNUSED(msg
); // TODO
585 // statusBar()->message(msg, 2000);
588 void MainWindow::displayErrorMessage(ErrorCode code
) {
591 displayMessage(tr("Illegal move"));
596 void MainWindow::flash() {
597 if( !isAncestorOf(QApplication::focusWidget()) )
602 void MainWindow::prefHighlight() {
603 PrefHighlight dialog
;
604 int result
= dialog
.exec();
605 if (result
== QDialog::Accepted
) {
611 void MainWindow::prefClock() {
613 int result
= dialog
.exec();
614 if (result
== QDialog::Accepted
) {
616 table()->clock()->reload();
620 void MainWindow::preferences() {
622 int result
= dialog
.exec();
623 if (result
== QDialog::Accepted
)
629 #include "mainwindow.moc"