File indexing completed on 2024-04-21 15:07: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"