File indexing completed on 2024-09-15 12:05:57
0001 // Copyright (c) 2002-2004 Rob Kaper <cap@capsi.com> 0002 // 0003 // This program is free software; you can redistribute it and/or 0004 // modify it under the terms of the GNU General Public License 0005 // version 2 as published by the Free Software Foundation. 0006 // 0007 // This program is distributed in the hope that it will be useful, 0008 // but WITHOUT ANY WARRANTY; without even the implied warranty of 0009 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0010 // General Public License for more details. 0011 // 0012 // You should have received a copy of the GNU General Public License 0013 // along with this program; see the file COPYING. If not, write to 0014 // the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 0015 // Boston, MA 02110-1301, USA. 0016 0017 #include <QLineEdit> 0018 #include <qmenu.h> 0019 #include <QVBoxLayout> 0020 #include <QGridLayout> 0021 #include <QCloseEvent> 0022 #include <QApplication> 0023 #include <QScrollArea> 0024 #include <QTextDocument> 0025 #include <QCommandLineParser> 0026 #include <QLocale> 0027 #include <QStatusBar> 0028 0029 #include <kaboutapplicationdialog.h> 0030 #include <kactioncollection.h> 0031 #include <klocalizedstring.h> 0032 #include <kmessagebox.h> 0033 #include <knotifyconfigwidget.h> 0034 #include <knotification.h> 0035 #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) 0036 #include <kgamestandardaction.h> 0037 #else 0038 #include <kstandardgameaction.h> 0039 #endif 0040 #include <kstandardaction.h> 0041 #include <kiconloader.h> 0042 #include <kaboutdata.h> 0043 0044 #include <atlantic_core.h> 0045 #include <auction.h> 0046 #include <estate.h> 0047 #include <player.h> 0048 #include <trade.h> 0049 #include "atlantik.h" 0050 0051 #include <atlantik_network.h> 0052 0053 #include <board.h> 0054 #include <trade_widget.h> 0055 #include <portfolioview.h> 0056 0057 #include "eventlogwidget.h" 0058 #include "version.h" 0059 #include "selectserver_widget.h" 0060 #include "selectgame_widget.h" 0061 #include "selectconfiguration_widget.h" 0062 #include "configdlg.h" 0063 #include "clickablelabel.h" 0064 0065 #include <settings.h> 0066 #include <atlantik_debug.h> 0067 0068 #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) 0069 namespace KStandardGameAction = KGameStandardAction; 0070 #endif 0071 0072 LogTextEdit::LogTextEdit(QWidget *parent) 0073 : QTextEdit(parent) 0074 { 0075 m_clear = KStandardAction::clear( this, SLOT( clear() ), nullptr ); 0076 m_selectAll = KStandardAction::selectAll( this, SLOT( selectAll() ), nullptr ); 0077 m_copy = KStandardAction::copy( this, SLOT( copy() ), nullptr ); 0078 connect(this, SIGNAL(copyAvailable(bool)), m_copy, SLOT(setEnabled(bool))); 0079 m_copy->setEnabled(false); 0080 } 0081 0082 LogTextEdit::~LogTextEdit() 0083 { 0084 delete m_clear; 0085 delete m_selectAll; 0086 delete m_copy; 0087 } 0088 0089 void LogTextEdit::contextMenuEvent(QContextMenuEvent *event) 0090 { 0091 QMenu menu(this); 0092 menu.addAction(m_clear); 0093 menu.addSeparator(); 0094 menu.addAction(m_copy); 0095 menu.addAction(m_selectAll); 0096 menu.exec(event->globalPos()); 0097 } 0098 0099 Atlantik::Atlantik(QCommandLineParser *parser) 0100 : KXmlGuiWindow() 0101 , m_cliParser(parser) 0102 , m_atlantikNetwork(nullptr) 0103 , m_board(nullptr) 0104 , m_selectServer(nullptr) 0105 , m_selectGame(nullptr) 0106 , m_selectConfiguration(nullptr) 0107 , m_runningGame(false) 0108 , m_reconnecting(false) 0109 , m_tokenTheme(TokenTheme::defaultTheme()) 0110 { 0111 // Read application configuration 0112 readConfig(); 0113 0114 // Toolbar: Game 0115 m_showEventLog = actionCollection()->addAction(QStringLiteral("showeventlog")); 0116 m_showEventLog->setText(i18n("Show Event &Log...")); 0117 connect(m_showEventLog, SIGNAL(triggered(bool)), this, SLOT(showEventLog())); 0118 m_reconnect = actionCollection()->addAction(QStringLiteral("reconnect")); 0119 m_reconnect->setText(i18n("&Reconnect (After Crash)")); 0120 connect(m_reconnect, SIGNAL(triggered()), this, SLOT(slotReconnect())); 0121 m_reconnect->setEnabled(false); 0122 m_leaveGame = actionCollection()->addAction(QStringLiteral("leave_game")); 0123 m_leaveGame->setText(i18n("&Leave Game")); 0124 connect(m_leaveGame, SIGNAL(triggered()), this, SLOT(slotLeaveGame())); 0125 m_leaveGame->setEnabled(false); 0126 (void) KStandardGameAction::quit(qApp, SLOT(closeAllWindows()), actionCollection()); 0127 0128 // Toolbar: Settings 0129 (void) KStandardAction::preferences(this, SLOT(slotConfigure()), actionCollection()); 0130 (void) KStandardAction::configureNotifications(this, SLOT(configureNotifications()), actionCollection()); 0131 0132 // Game and network core 0133 m_atlanticCore = new AtlanticCore(this); 0134 m_atlanticCore->setObjectName(QStringLiteral("atlanticCore")); 0135 connect(m_atlanticCore, SIGNAL(createGUI(Player *)), this, SLOT(newPlayer(Player *))); 0136 connect(m_atlanticCore, SIGNAL(removeGUI(Player *)), this, SLOT(removeGUI(Player *))); 0137 connect(m_atlanticCore, SIGNAL(createGUI(Trade *)), this, SLOT(newTrade(Trade *))); 0138 connect(m_atlanticCore, SIGNAL(removeGUI(Trade *)), this, SLOT(removeGUI(Trade *))); 0139 0140 m_eventLog = new EventLog(this); 0141 0142 initNetworkObject(); 0143 0144 // Menu,toolbar: Move 0145 m_roll = KStandardGameAction::roll(this, SIGNAL(rollDice()), actionCollection()); 0146 m_roll->setEnabled(false); 0147 0148 m_buyEstate = actionCollection()->addAction(QStringLiteral("atlantik_buy_estate")); 0149 m_buyEstate->setText(i18n("&Buy")); 0150 KActionCollection::setDefaultShortcut(m_buyEstate, QKeySequence(Qt::CTRL | Qt::Key_B)); 0151 m_buyEstate->setIcon(KDE::icon(QStringLiteral("atlantik_buy_estate"))); 0152 connect (m_buyEstate,SIGNAL(triggered()), this, SIGNAL(buyEstate())); 0153 m_buyEstate->setEnabled(false); 0154 0155 m_auctionEstate = actionCollection()->addAction(QStringLiteral("auction")); 0156 m_auctionEstate->setText(i18n("&Auction")); 0157 KActionCollection::setDefaultShortcut(m_auctionEstate, QKeySequence(Qt::CTRL | Qt::Key_A)); 0158 m_auctionEstate->setIcon(KDE::icon(QStringLiteral("auction"))); 0159 connect(m_auctionEstate,SIGNAL(triggered()),this, SIGNAL(auctionEstate())); 0160 m_auctionEstate->setEnabled(false); 0161 0162 0163 m_endTurn = KStandardGameAction::endTurn(this, SIGNAL(endTurn()), actionCollection()); 0164 m_endTurn->setEnabled(false); 0165 0166 m_jailCard = actionCollection()->addAction(QStringLiteral("move_jailcard")); 0167 m_jailCard->setText(i18n("Use Card to Leave Jail")); 0168 connect(m_jailCard, SIGNAL(triggered()),this, SIGNAL(jailCard())); 0169 m_jailCard->setEnabled(false); 0170 0171 m_jailPay = actionCollection()->addAction(QStringLiteral("jail_pay")); 0172 m_jailPay->setText(i18n("&Pay to Leave Jail")); 0173 KActionCollection::setDefaultShortcut(m_jailPay, QKeySequence(Qt::CTRL | Qt::Key_P)); 0174 m_jailPay->setIcon(KDE::icon(QStringLiteral("jail_pay"))); 0175 connect(m_jailPay, SIGNAL(triggered()),this, SIGNAL(jailPay())); 0176 m_jailPay->setEnabled(false); 0177 0178 m_jailRoll = actionCollection()->addAction(QStringLiteral("move_jailroll")); 0179 m_jailRoll->setText(i18n("Roll to Leave &Jail")); 0180 KActionCollection::setDefaultShortcut(m_jailRoll, QKeySequence(Qt::CTRL | Qt::Key_J)); 0181 connect(m_jailRoll, SIGNAL(triggered()), this, SIGNAL(jailRoll())); 0182 m_jailRoll->setEnabled(false); 0183 0184 // Mix code and XML into GUI 0185 setupGUI(); 0186 m_sbVersion = new ClickableLabel(); 0187 m_sbVersion->setText(QString::fromLatin1("Atlantik " ATLANTIK_VERSION_STRING)); 0188 connect(m_sbVersion, SIGNAL(clicked()), this, SLOT(showAboutDialog())); 0189 statusBar()->addWidget(m_sbVersion, 0); 0190 m_sbStatus = new ClickableLabel(); 0191 connect(m_sbStatus, SIGNAL(clicked()), this, SLOT(showEventLog())); 0192 statusBar()->addWidget(m_sbStatus, 1); 0193 0194 // Main widget, containing all others 0195 m_mainWidget = new QWidget(this); 0196 m_mainWidget->setObjectName(QStringLiteral("main")); 0197 m_mainWidget->show(); 0198 m_mainLayout = new QGridLayout(m_mainWidget); 0199 setCentralWidget(m_mainWidget); 0200 0201 // Vertical view area for portfolios. 0202 m_portfolioScroll = new QScrollArea(m_mainWidget); 0203 m_portfolioScroll->setObjectName(QStringLiteral("pfScroll")); 0204 m_mainLayout->addWidget( m_portfolioScroll, 0, 0 ); 0205 m_portfolioScroll->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); 0206 m_portfolioScroll->setWidgetResizable(true); 0207 m_portfolioScroll->setFixedHeight( 200 ); 0208 m_portfolioScroll->hide(); 0209 0210 m_portfolioWidget = new QWidget(); 0211 m_portfolioWidget->setObjectName(QStringLiteral("pfWidget")); 0212 m_portfolioScroll->setWidget(m_portfolioWidget); 0213 m_portfolioWidget->show(); 0214 0215 m_portfolioLayout = new QVBoxLayout(m_portfolioWidget); 0216 m_portfolioLayout->setContentsMargins(0, 0, 0, 0); 0217 0218 // Nice label 0219 // m_portfolioLabel = new QLabel(i18n("Players"), m_portfolioWidget, "pfLabel"); 0220 // m_portfolioLayout->addWidget(m_portfolioLabel); 0221 // m_portfolioLabel->show(); 0222 0223 // Text view for chat and status messages from server. 0224 m_serverMsgs = new LogTextEdit(m_mainWidget); 0225 m_serverMsgs->setObjectName(QLatin1String("serverMsgs")); 0226 m_serverMsgs->setReadOnly(true); 0227 m_serverMsgs->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); 0228 m_serverMsgs->setMinimumWidth(200); 0229 m_serverMsgs->setUndoRedoEnabled(false); 0230 m_mainLayout->addWidget(m_serverMsgs, 1, 0); 0231 0232 // LineEdit to enter commands and chat messages. 0233 m_input = new QLineEdit(m_mainWidget); 0234 m_input->setObjectName(QStringLiteral("input")); 0235 m_mainLayout->addWidget(m_input, 2, 0); 0236 0237 m_serverMsgs->setFocusProxy(m_input); 0238 0239 connect(m_input, SIGNAL(returnPressed()), this, SLOT(slotSendMsg())); 0240 0241 // Set stretching where we want it. 0242 m_mainLayout->setRowStretch(1, 1); // make m_board+m_serverMsgs stretch vertically, not the rest 0243 m_mainLayout->setColumnStretch(1, 1); // make m_board stretch horizontally, not the rest 0244 0245 // Check command-line args to see if we need to connect or show the metaserver window 0246 QString host = m_cliParser ? m_cliParser->value(QStringLiteral("host")) : QString(); 0247 QString port = m_cliParser ? m_cliParser->value(QStringLiteral("port")) : QString(); 0248 if (!host.isEmpty() && !port.isEmpty()) 0249 m_atlantikNetwork->serverConnect(host, port.toInt()); 0250 else 0251 showSelectServer(); 0252 0253 // Connection cookie 0254 m_reconnectCookie.reset(ConnectionCookie::read()); 0255 m_reconnect->setEnabled(m_reconnectCookie != nullptr); 0256 } 0257 0258 void Atlantik::readConfig() 0259 { 0260 // Read configuration settings 0261 0262 // General configuration 0263 m_config.chatTimestamps = Settings::chatTimeStamps(); 0264 0265 // Personalization configuration 0266 m_config.playerName = Settings::playerName(); 0267 m_config.playerImage = Settings::playerImage(); 0268 0269 // Board configuration 0270 m_config.indicateUnowned = Settings::indicateUnowned(); 0271 m_config.highlightUnowned = Settings::highlightUnowned(); 0272 m_config.darkenMortgaged = Settings::darkenMortgaged(); 0273 m_config.animateTokens = Settings::animateToken(); 0274 m_config.quartzEffects = Settings::quartzEffects(); 0275 0276 // Meta server configuation 0277 m_config.connectOnStart = Settings::connectOnStart(); 0278 m_config.hideDevelopmentServers = Settings::hideDevelopmentServers(); 0279 0280 // Portfolio colors 0281 m_config.activeColor = Settings::activeBackground(); 0282 m_config.inactiveColor = Settings::inactiveBlend(); 0283 } 0284 0285 void Atlantik::newPlayer(Player *player) 0286 { 0287 initBoard(); 0288 m_board->addToken(player); 0289 addPortfolioView(player); 0290 0291 // Player::changed() is not connected until later this method, so 0292 // we'd better force an update. 0293 playerChanged(player); 0294 0295 connect(player, SIGNAL(changed(Player *)), this, SLOT(playerChanged(Player *))); 0296 connect(player, SIGNAL(gainedTurn()), this, SLOT(gainedTurn())); 0297 connect(player, SIGNAL(changed(Player *)), m_board, SLOT(playerChanged(Player *))); 0298 0299 if (!player->isSelf()) 0300 KNotification::event(QStringLiteral("newplayer"), i18n("New player joined.")); 0301 } 0302 0303 void Atlantik::newEstate(Estate *estate) 0304 { 0305 initBoard(); 0306 m_board->addEstateView(estate, m_config.indicateUnowned, m_config.highlightUnowned, m_config.darkenMortgaged, m_config.quartzEffects); 0307 } 0308 0309 void Atlantik::newTrade(Trade *trade) 0310 { 0311 TradeDisplay *tradeDisplay = new TradeDisplay(trade, m_atlanticCore); 0312 tradeDisplay->setObjectName(QStringLiteral("tradeDisplay")); 0313 m_tradeGUIMap.insert(trade, tradeDisplay); 0314 tradeDisplay->show(); 0315 } 0316 0317 void Atlantik::newAuction(Auction *auction) 0318 { 0319 initBoard(); 0320 m_board->addAuctionWidget(auction); 0321 } 0322 0323 void Atlantik::removeGUI(Player *player) 0324 { 0325 // Find and remove portfolioview 0326 PortfolioView *portfolioView = findPortfolioView(player); 0327 if (portfolioView) 0328 { 0329 m_portfolioViews.removeOne(portfolioView); 0330 delete portfolioView; 0331 } 0332 0333 if (m_board) 0334 m_board->removeToken(player); 0335 } 0336 0337 void Atlantik::removeGUI(Trade *trade) 0338 { 0339 delete m_tradeGUIMap.take(trade); 0340 } 0341 0342 void Atlantik::showSelectServer() 0343 { 0344 if (m_selectServer) 0345 return; 0346 0347 m_selectServer = new SelectServer(m_config.hideDevelopmentServers, m_mainWidget ); 0348 m_selectServer->setObjectName(QStringLiteral("selectServer")); 0349 m_mainLayout->addWidget(m_selectServer, 0, 1, 3, 1); 0350 m_selectServer->show(); 0351 0352 if (m_selectGame) 0353 { 0354 delete m_selectGame; 0355 m_selectGame = nullptr; 0356 } 0357 0358 m_atlanticCore->reset(true); 0359 initNetworkObject(); 0360 0361 m_reconnect->setEnabled(false); 0362 m_reconnecting = false; 0363 m_leaveGame->setEnabled(false); 0364 0365 connect(m_selectServer, SIGNAL(serverConnect(QString, int)), m_atlantikNetwork, SLOT(serverConnect(QString, int))); 0366 connect(m_selectServer, SIGNAL(msgStatus(const QString &)), this, SLOT(slotMsgStatus(const QString &))); 0367 0368 if (m_config.connectOnStart) 0369 m_selectServer->reloadServerList(); 0370 } 0371 0372 void Atlantik::showSelectGame() 0373 { 0374 if (m_selectGame) 0375 return; 0376 0377 m_selectGame = new SelectGame(m_atlanticCore, m_mainWidget); 0378 m_atlanticCore->emitGames(); 0379 m_leaveGame->setEnabled(false); 0380 0381 m_mainLayout->addWidget(m_selectGame, 0, 1, 3, 1); 0382 m_selectGame->show(); 0383 0384 // Reset core and GUI 0385 if (m_board) 0386 { 0387 m_board->hide(); 0388 m_board->reset(); 0389 // delete m_board; 0390 // m_board = nullptr; 0391 0392 // m_portfolioViews.clear(); 0393 m_atlanticCore->reset(); 0394 } 0395 0396 if (m_selectServer) 0397 { 0398 delete m_selectServer; 0399 m_selectServer = nullptr; 0400 } 0401 if (m_selectConfiguration) 0402 { 0403 delete m_selectConfiguration; 0404 m_selectConfiguration = nullptr; 0405 } 0406 0407 connect(m_selectGame, SIGNAL(joinGame(int)), m_atlantikNetwork, SLOT(joinGame(int))); 0408 connect(m_selectGame, SIGNAL(watchGame(int)), m_atlantikNetwork, SLOT(watchGame(int))); 0409 connect(m_selectGame, SIGNAL(newGame(const QString &)), m_atlantikNetwork, SLOT(newGame(const QString &))); 0410 connect(m_selectGame, SIGNAL(leaveServer()), this, SLOT(showSelectServer())); 0411 connect(m_selectGame, SIGNAL(msgStatus(const QString &)), this, SLOT(slotMsgStatus(const QString &))); 0412 } 0413 0414 void Atlantik::showSelectConfiguration() 0415 { 0416 if (m_selectConfiguration) 0417 return; 0418 0419 if (m_selectGame) 0420 { 0421 delete m_selectGame; 0422 m_selectGame = nullptr; 0423 } 0424 0425 m_selectConfiguration = new SelectConfiguration(m_atlanticCore, m_mainWidget ); 0426 m_selectConfiguration->setObjectName(QStringLiteral("selectConfiguration")); 0427 m_mainLayout->addWidget(m_selectConfiguration, 0, 1, 3, 1); 0428 m_selectConfiguration->show(); 0429 m_leaveGame->setEnabled(true); 0430 0431 connect(m_atlantikNetwork, SIGNAL(gameOption(QString, QString, QString, QString, QString)), m_selectConfiguration, SLOT(gameOption(QString, QString, QString, QString, QString))); 0432 connect(m_atlantikNetwork, SIGNAL(gameInit()), m_selectConfiguration, SLOT(initGame())); 0433 connect(m_selectConfiguration, SIGNAL(startGame()), m_atlantikNetwork, SLOT(startGame())); 0434 connect(m_selectConfiguration, SIGNAL(leaveGame()), m_atlantikNetwork, SLOT(leaveGame())); 0435 connect(m_selectConfiguration, SIGNAL(changeOption(int, const QString &)), m_atlantikNetwork, SLOT(changeOption(int, const QString &))); 0436 connect(m_selectConfiguration, SIGNAL(buttonCommand(QString)), m_atlantikNetwork, SLOT(writeData(QString))); 0437 connect(m_selectConfiguration, SIGNAL(iconSelected(const QString &)), m_atlantikNetwork, SLOT(setImage(const QString &))); 0438 connect(m_selectConfiguration, SIGNAL(statusMessage(const QString &)), this, SLOT(slotMsgStatus(const QString &))); 0439 } 0440 0441 void Atlantik::initBoard() 0442 { 0443 if (m_board) 0444 return; 0445 0446 m_board = new AtlantikBoard(m_atlanticCore, 40, AtlantikBoard::Play, m_mainWidget); 0447 m_board->setObjectName(QStringLiteral("board")); 0448 m_board->setViewProperties(m_config.indicateUnowned, m_config.highlightUnowned, m_config.darkenMortgaged, m_config.quartzEffects, m_config.animateTokens); 0449 m_board->setTokenTheme(m_tokenTheme); 0450 0451 connect(m_atlantikNetwork, SIGNAL(displayDetails(QString, bool, bool, Estate *)), m_board, SLOT(insertDetails(QString, bool, bool, Estate *))); 0452 connect(m_atlantikNetwork, SIGNAL(displayText(QString, bool, bool)), m_board, SLOT(insertText(QString, bool, bool))); 0453 connect(m_atlantikNetwork, SIGNAL(addCommandButton(QString, QString, bool)), m_board, SLOT(displayButton(QString, QString, bool))); 0454 connect(m_atlantikNetwork, SIGNAL(addCloseButton()), m_board, SLOT(addCloseButton())); 0455 connect(m_board, SIGNAL(tokenConfirmation(Estate *)), m_atlantikNetwork, SLOT(tokenConfirmation(Estate *))); 0456 connect(m_board, SIGNAL(buttonCommand(QString)), m_atlantikNetwork, SLOT(writeData(QString))); 0457 } 0458 0459 void Atlantik::showBoard() 0460 { 0461 if (m_selectGame) 0462 { 0463 delete m_selectGame; 0464 m_selectGame = nullptr; 0465 } 0466 0467 if (m_selectConfiguration) 0468 { 0469 delete m_selectConfiguration; 0470 m_selectConfiguration = nullptr; 0471 } 0472 0473 if (!m_board) 0474 initBoard(); 0475 0476 m_runningGame = true; 0477 m_leaveGame->setEnabled(true); 0478 0479 m_mainLayout->addWidget(m_board, 0, 1, 3, 1); 0480 m_board->displayDefault(); 0481 m_board->show(); 0482 0483 foreach (PortfolioView *portfolioView, m_portfolioViews) 0484 if (!portfolioView->player()->isSpectator()) 0485 portfolioView->buildPortfolio(); 0486 } 0487 0488 void Atlantik::freezeBoard() 0489 { 0490 if (!m_board) 0491 showBoard(); 0492 0493 m_runningGame = false; 0494 m_leaveGame->setEnabled(false); 0495 // TODO: m_board->freeze(); 0496 } 0497 0498 void Atlantik::slotNetworkConnected() 0499 { 0500 } 0501 0502 0503 0504 void Atlantik::slotNetworkError(QAbstractSocket::SocketError errnum) 0505 { 0506 switch (errnum) { 0507 case QAbstractSocket::ConnectionRefusedError: 0508 appendMsg(i18n("Error connecting: connection refused by host."), ErrorMsg); 0509 break; 0510 case QAbstractSocket::HostNotFoundError: 0511 appendMsg(i18n("Error connecting: host not found."), ErrorMsg); 0512 break; 0513 default: 0514 appendMsg(i18n("Error connecting: error %1.", QString::number(errnum)), ErrorMsg); 0515 break; 0516 } 0517 0518 // Re-init network object 0519 initNetworkObject(); 0520 } 0521 0522 void Atlantik::slotNetworkDisconnected() 0523 { 0524 // switch( status ) 0525 // { 0526 // case KBufferedIO::involuntary: 0527 // slotMsgStatus( i18n("Connection with server %1:%2 lost.").arg(m_atlantikNetwork->host()).arg(m_atlantikNetwork->port()), QString("connect_no") ); 0528 // showSelectServer(); 0529 // break; 0530 // default: 0531 // if ( !m_atlantikNetwork->host().isEmpty() ) 0532 // slotMsgStatus( i18n("Disconnected from %1:%2.").arg(m_atlantikNetwork->host()).arg(m_atlantikNetwork->port()), QString("connect_no") ); 0533 // break; 0534 // } 0535 } 0536 0537 void Atlantik::slotConfigure() 0538 { 0539 if (KConfigDialog::showDialog(QStringLiteral("configdialog"))) 0540 return; 0541 0542 ConfigDialog *dialog = new ConfigDialog(m_tokenTheme, this); 0543 connect(dialog, SIGNAL(settingsChanged(QString)), this, SLOT(slotUpdateConfig())); 0544 0545 dialog->show(); 0546 } 0547 0548 void Atlantik::showEventLog() 0549 { 0550 bool created = false; 0551 if (!m_eventLogWidget) 0552 { 0553 m_eventLogWidget = new EventLogWidget(m_eventLog, this); 0554 created = true; 0555 } 0556 m_eventLogWidget->show(); 0557 if (created) 0558 m_eventLogWidget->restoreSettings(); 0559 } 0560 0561 void Atlantik::configureNotifications() 0562 { 0563 KNotifyConfigWidget::configure(this); 0564 } 0565 0566 void Atlantik::slotUpdateConfig() 0567 { 0568 bool optBool, viewConfigChanged = false; 0569 QString optStr; 0570 0571 optBool = Settings::chatTimeStamps(); 0572 if (m_config.chatTimestamps != optBool) 0573 { 0574 m_config.chatTimestamps = optBool; 0575 } 0576 0577 optStr = Settings::playerName(); 0578 if (m_config.playerName != optStr) 0579 { 0580 m_config.playerName = optStr; 0581 if (m_atlantikNetwork->isConnected()) 0582 m_atlantikNetwork->setName(optStr); 0583 } 0584 0585 optStr = Settings::playerImage(); 0586 if (m_config.playerImage != optStr) 0587 { 0588 m_config.playerImage = optStr; 0589 if (m_atlantikNetwork->isConnected()) 0590 m_atlantikNetwork->setImage(optStr); 0591 } 0592 0593 optBool = Settings::indicateUnowned(); 0594 if (m_config.indicateUnowned != optBool) 0595 { 0596 m_config.indicateUnowned = optBool; 0597 viewConfigChanged = true; 0598 } 0599 0600 optBool = Settings::highlightUnowned(); 0601 if (m_config.highlightUnowned != optBool) 0602 { 0603 m_config.highlightUnowned = optBool; 0604 viewConfigChanged = true; 0605 } 0606 0607 optBool = Settings::darkenMortgaged(); 0608 if (m_config.darkenMortgaged != optBool) 0609 { 0610 m_config.darkenMortgaged = optBool; 0611 viewConfigChanged = true; 0612 } 0613 0614 optBool = Settings::animateToken(); 0615 if (m_config.animateTokens != optBool) 0616 { 0617 m_config.animateTokens = optBool; 0618 viewConfigChanged = true; 0619 } 0620 0621 optBool = Settings::quartzEffects(); 0622 if (m_config.quartzEffects != optBool) 0623 { 0624 m_config.quartzEffects = optBool; 0625 viewConfigChanged = true; 0626 } 0627 0628 optBool = Settings::connectOnStart(); 0629 if (m_config.connectOnStart != optBool) 0630 { 0631 m_config.connectOnStart = optBool; 0632 } 0633 0634 optBool = Settings::hideDevelopmentServers(); 0635 if (m_config.hideDevelopmentServers != optBool) 0636 { 0637 m_config.hideDevelopmentServers = optBool; 0638 if (m_selectServer) 0639 m_selectServer->setHideDevelopmentServers(optBool); 0640 } 0641 0642 if (viewConfigChanged && m_board) 0643 m_board->setViewProperties(m_config.indicateUnowned, m_config.highlightUnowned, m_config.darkenMortgaged, m_config.quartzEffects, m_config.animateTokens); 0644 } 0645 0646 void Atlantik::slotSendMsg() 0647 { 0648 if (m_atlantikNetwork->isConnected()) 0649 m_atlantikNetwork->cmdChat(m_input->text()); 0650 m_input->setText(QString()); 0651 } 0652 0653 void Atlantik::slotMsgInfo(const QString &msg) 0654 { 0655 appendMsg(msg, InfoMsg); 0656 } 0657 0658 void Atlantik::slotMsgError(const QString &msg) 0659 { 0660 appendMsg(msg, ErrorMsg); 0661 } 0662 0663 void Atlantik::slotMsgStatus(const QString &message, EventType type) 0664 { 0665 m_sbStatus->setText(message); 0666 m_eventLog->addEvent(message, type); 0667 } 0668 0669 static bool commandForMe(const QList<QStringView> &parts, const QString &playerName) 0670 { 0671 if (parts.size() <= 1) 0672 return true; 0673 0674 foreach (const QStringView &p, parts) 0675 { 0676 if (p == playerName) 0677 return true; 0678 } 0679 0680 return false; 0681 } 0682 0683 void Atlantik::slotMsgChat(const QString &player, const QString &msg) 0684 { 0685 QString res; 0686 if (msg == QLatin1String("/me")) 0687 res = QStringLiteral("* %1").arg(player); 0688 else if (msg.startsWith(QLatin1String("/me "))) 0689 res = QStringLiteral("* %1 %2").arg(player, msg.mid(4)); 0690 else if (msg.startsWith(QLatin1String("[ACTION] "))) 0691 res = QStringLiteral("* %1 %2").arg(player, msg.mid(9)); 0692 else 0693 res = QStringLiteral("<%1> %2").arg(player, msg); 0694 appendMsg(res, ChatMsg); 0695 Player *playerSelf = m_atlanticCore->playerSelf(); 0696 if (!isActiveWindow() && (!playerSelf || playerSelf->name() != player)) 0697 KNotification::event(QStringLiteral("chat"), QStringLiteral("%1: %2").arg(player, msg.toHtmlEscaped())); 0698 if (m_atlantikNetwork->isConnected() && playerSelf && msg.startsWith(QLatin1Char('!'))) 0699 { 0700 const QList<QStringView> parts = QStringView(msg).split(QLatin1Char(' '), Qt::SkipEmptyParts); 0701 Q_ASSERT(!parts.isEmpty()); 0702 if (commandForMe(parts, playerSelf->name())) 0703 { 0704 const QStringView cmd = parts.first(); 0705 if (cmd == QLatin1String("!date")) 0706 m_atlantikNetwork->cmdChat(QLocale::c().toString(QDateTime::currentDateTime(), QLocale::ShortFormat)); 0707 else if (cmd == QLatin1String("!ping")) 0708 m_atlantikNetwork->cmdChat(QStringLiteral("pong")); 0709 else if (cmd == QLatin1String("!version")) 0710 m_atlantikNetwork->cmdChat(QString::fromLatin1("Atlantik " ATLANTIK_VERSION_STRING)); 0711 } 0712 } 0713 } 0714 0715 void Atlantik::appendMsg(const QString &msg, MsgType type) 0716 { 0717 const QString escaped = msg.toHtmlEscaped(); 0718 QString ts; 0719 QString res; 0720 0721 if (m_config.chatTimestamps) 0722 { 0723 const QString timeString = QLocale::system().toString(QTime::currentTime(), QLocale::ShortFormat); 0724 ts = QStringLiteral("[%1] ").arg(timeString); 0725 } 0726 0727 switch (type) 0728 { 0729 case ErrorMsg: 0730 res = QStringLiteral("<font color=\"%1\">%2[%3] %4</font>").arg(QStringLiteral("#ff0000"), ts, i18nc("error message", "Error"), escaped); 0731 break; 0732 case InfoMsg: 0733 res = QStringLiteral("<font color=\"%1\">%2[%3] %4</font>").arg(QStringLiteral("#91640a"), ts, i18nc("informative message", "Info"), escaped); 0734 break; 0735 case ChatMsg: 0736 res = QStringLiteral("<font color=\"%1\">%2</font>%3").arg(QStringLiteral("#709070"), ts, escaped); 0737 break; 0738 } 0739 res += QStringLiteral("<br/>\n"); 0740 0741 m_serverMsgs->insertHtml(res); 0742 } 0743 0744 void Atlantik::playerChanged(Player *player) 0745 { 0746 PortfolioView *portfolioView = findPortfolioView(player); 0747 if (!portfolioView) 0748 portfolioView = addPortfolioView(player); 0749 0750 Player *playerSelf = m_atlanticCore->playerSelf(); 0751 if (player == playerSelf) 0752 { 0753 // We changed ourselves.. 0754 foreach (PortfolioView *portfolioView, m_portfolioViews) 0755 { 0756 // Clear all portfolios if we're not in game 0757 if ( !player->game() ) 0758 portfolioView->clearPortfolio(); 0759 0760 // Show players in our game, hide the rest 0761 Player *pTmp = portfolioView->player(); 0762 if (pTmp->game() == playerSelf->game()) 0763 portfolioView->show(); 0764 else 0765 portfolioView->hide(); 0766 } 0767 if (!player->game()) 0768 showSelectGame(); 0769 else 0770 { 0771 if ( !m_board || m_board->isHidden() ) 0772 showSelectConfiguration(); 0773 } 0774 0775 m_roll->setEnabled(player->canRoll()); 0776 m_buyEstate->setEnabled(player->canBuy()); 0777 m_auctionEstate->setEnabled(player->canAuction()); 0778 0779 // TODO: Should be more finetuned, but monopd doesn't send can_endturn can_payjail can_jailroll yet 0780 m_endTurn->setEnabled(player->hasTurn() && !(player->canRoll() || player->canBuy() || player->inJail())); 0781 m_jailCard->setEnabled(player->canUseCard()); 0782 m_jailPay->setEnabled(player->hasTurn() && player->inJail()); 0783 m_jailRoll->setEnabled(player->hasTurn() && player->inJail()); 0784 } 0785 else 0786 { 0787 // Another player changed, check if we need to show or hide 0788 // his/her portfolioView. 0789 if (playerSelf) 0790 { 0791 if (player->game() == playerSelf->game()) 0792 portfolioView->show(); 0793 else 0794 portfolioView->hide(); 0795 } 0796 else if ( !player->game() ) 0797 portfolioView->hide(); 0798 } 0799 } 0800 0801 void Atlantik::gainedTurn() 0802 { 0803 KNotification::event(QStringLiteral("gainedturn"), i18n("It is your turn now."), QPixmap()); 0804 } 0805 0806 void Atlantik::initNetworkObject() 0807 { 0808 if (m_atlantikNetwork) 0809 { 0810 m_atlantikNetwork->reset(); 0811 return; 0812 } 0813 0814 m_atlantikNetwork = new AtlantikNetwork(m_atlanticCore); 0815 connect(m_atlantikNetwork, SIGNAL(msgInfo(QString)), this, SLOT(slotMsgInfo(QString))); 0816 connect(m_atlantikNetwork, SIGNAL(msgError(QString)), this, SLOT(slotMsgError(QString))); 0817 connect(m_atlantikNetwork, SIGNAL(msgStatus(const QString &, EventType)), this, SLOT(slotMsgStatus(const QString &, EventType))); 0818 connect(m_atlantikNetwork, SIGNAL(msgChat(QString, QString)), this, SLOT(slotMsgChat(QString, QString))); 0819 0820 connect(m_atlantikNetwork, SIGNAL(connectionSuccess()), this, SLOT(slotNetworkConnected())); 0821 connect(m_atlantikNetwork, SIGNAL(connectionFailed(QAbstractSocket::SocketError)), this, SLOT(slotNetworkError(QAbstractSocket::SocketError))); 0822 connect(m_atlantikNetwork, SIGNAL(disconnected()), this, SLOT(slotNetworkDisconnected())); 0823 0824 connect(m_atlantikNetwork, SIGNAL(receivedHandshake()), this, SLOT(sendHandshake())); 0825 0826 connect(m_atlantikNetwork, SIGNAL(gameConfig()), this, SLOT(showSelectConfiguration())); 0827 connect(m_atlantikNetwork, SIGNAL(gameInit()), this, SLOT(initBoard())); 0828 connect(m_atlantikNetwork, SIGNAL(gameRun()), this, SLOT(showBoard())); 0829 connect(m_atlantikNetwork, SIGNAL(gameEnd()), this, SLOT(freezeBoard())); 0830 0831 connect(m_atlantikNetwork, SIGNAL(newEstate(Estate *)), this, SLOT(newEstate(Estate *))); 0832 connect(m_atlantikNetwork, SIGNAL(newAuction(Auction *)), this, SLOT(newAuction(Auction *))); 0833 0834 connect(m_atlantikNetwork, SIGNAL(clientCookie(QString)), this, SLOT(clientCookie(QString))); 0835 connect(m_atlantikNetwork, SIGNAL(networkEvent(const QString &, EventType)), m_eventLog, SLOT(addEvent(const QString &, EventType))); 0836 0837 connect(this, SIGNAL(rollDice()), m_atlantikNetwork, SLOT(rollDice())); 0838 connect(this, SIGNAL(buyEstate()), m_atlantikNetwork, SLOT(buyEstate())); 0839 connect(this, SIGNAL(auctionEstate()), m_atlantikNetwork, SLOT(auctionEstate())); 0840 connect(this, SIGNAL(endTurn()), m_atlantikNetwork, SLOT(endTurn())); 0841 connect(this, SIGNAL(jailCard()), m_atlantikNetwork, SLOT(jailCard())); 0842 connect(this, SIGNAL(jailPay()), m_atlantikNetwork, SLOT(jailPay())); 0843 connect(this, SIGNAL(jailRoll()), m_atlantikNetwork, SLOT(jailRoll())); 0844 connect(this, SIGNAL(reconnect(QString)), m_atlantikNetwork, SLOT(reconnect(QString))); 0845 } 0846 0847 void Atlantik::clientCookie(const QString &cookie) 0848 { 0849 ConnectionCookie *newCookie = nullptr; 0850 0851 if (!cookie.isEmpty() && m_atlantikNetwork) 0852 newCookie = new ConnectionCookie(m_atlantikNetwork->host(), m_atlantikNetwork->port(), cookie); 0853 0854 m_cookie.reset(newCookie); 0855 m_reconnect->setEnabled(false); 0856 } 0857 0858 void Atlantik::sendHandshake() 0859 { 0860 if (m_reconnecting) 0861 { 0862 m_reconnecting = false; 0863 Q_EMIT reconnect(m_reconnectCookie->cookie()); 0864 m_reconnectCookie.reset(); 0865 return; 0866 } 0867 0868 m_atlantikNetwork->setName(m_config.playerName); 0869 m_atlantikNetwork->setImage(m_config.playerImage); 0870 0871 // Check command-line args to see if we need to auto-join 0872 QString game = m_cliParser ? m_cliParser->value(QStringLiteral("game")) : QString(); 0873 qCDebug(ATLANTIK_LOG) << "received Handshake; joining game:" << game.toInt(); 0874 if (!game.isEmpty()) 0875 m_atlantikNetwork->joinGame(game.toInt()); 0876 } 0877 0878 void Atlantik::showAboutDialog() 0879 { 0880 KAboutApplicationDialog dialog(KAboutData::applicationData(), this); 0881 dialog.exec(); 0882 } 0883 0884 PortfolioView *Atlantik::addPortfolioView(Player *player) 0885 { 0886 PortfolioView *portfolioView = new PortfolioView(m_atlanticCore, player, m_config.activeColor, m_config.inactiveColor, m_portfolioWidget); 0887 portfolioView->setTokenTheme(m_tokenTheme); 0888 m_portfolioViews.append(portfolioView); 0889 if ( m_portfolioViews.count() > 0 && m_portfolioScroll->isHidden() ) 0890 m_portfolioScroll->show(); 0891 0892 connect(player, SIGNAL(changed(Player *)), portfolioView, SLOT(playerChanged())); 0893 connect(portfolioView, SIGNAL(newTrade(Player *)), m_atlantikNetwork, SLOT(newTrade(Player *))); 0894 connect(portfolioView, SIGNAL(kickPlayer(Player *)), m_atlantikNetwork, SLOT(kickPlayer(Player *))); 0895 connect(portfolioView, SIGNAL(estateClicked(Estate *)), m_board, SLOT(prependEstateDetails(Estate *))); 0896 0897 m_portfolioLayout->addWidget(portfolioView); 0898 portfolioView->show(); 0899 0900 return portfolioView; 0901 } 0902 0903 PortfolioView *Atlantik::findPortfolioView(Player *player) 0904 { 0905 foreach (PortfolioView *portfolioView, m_portfolioViews) 0906 if (player == portfolioView->player()) 0907 return portfolioView; 0908 0909 return nullptr; 0910 } 0911 0912 void Atlantik::closeEvent(QCloseEvent *e) 0913 { 0914 Game *gameSelf = m_atlanticCore->gameSelf(); 0915 Player *playerSelf = m_atlanticCore->playerSelf(); 0916 0917 int result = KMessageBox::Continue; 0918 if ( gameSelf && !playerSelf->isBankrupt() && m_runningGame && !playerSelf->isSpectator() ) 0919 result = KMessageBox::warningContinueCancel( this, i18n("You are currently part of an active game. Are you sure you want to close Atlantik? If you do, you forfeit the game."), i18n("Close & Forfeit?"), KGuiItem(i18n("Close && Forfeit")) ); 0920 0921 if ( result == KMessageBox::Continue ) 0922 { 0923 if ( m_atlantikNetwork && m_atlantikNetwork->isConnected() ) 0924 { 0925 m_atlantikNetwork->leaveGame(); 0926 m_atlantikNetwork->disconnect(); 0927 } 0928 0929 KXmlGuiWindow::closeEvent(e); 0930 } 0931 else 0932 e->ignore(); 0933 } 0934 0935 void Atlantik::slotReconnect() 0936 { 0937 if (!m_reconnectCookie) 0938 return; 0939 0940 m_atlantikNetwork->serverConnect(m_reconnectCookie->host(), m_reconnectCookie->port()); 0941 m_reconnecting = true; 0942 } 0943 0944 void Atlantik::slotLeaveGame() 0945 { 0946 Game *gameSelf = m_atlanticCore->gameSelf(); 0947 Player *playerSelf = m_atlanticCore->playerSelf(); 0948 0949 if (!gameSelf) 0950 return; 0951 0952 if (!m_runningGame || playerSelf->isBankrupt() || playerSelf->isSpectator() || (KMessageBox::warningContinueCancel(this, i18n("You are currently part of an active game. Are you sure you want to leave it? If you do, you forfeit the game."), i18n("Leave & Forfeit?"), KGuiItem(i18n("Leave && Forfeit"))) == KMessageBox::Continue)) 0953 m_atlantikNetwork->leaveGame(); 0954 } 0955 0956 #include "moc_atlantik.cpp"