File indexing completed on 2024-04-14 14:32:02
0001 // Copyright (c) 2002-2003 Rob Kaper <cap@capsi.com> 0002 // 0003 // This library is free software; you can redistribute it and/or 0004 // modify it under the terms of the GNU Lesser General Public 0005 // License version 2.1 as published by the Free Software Foundation. 0006 // 0007 // This library 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 // Lesser General Public License for more details. 0011 // 0012 // You should have received a copy of the GNU Lesser General Public License 0013 // along with this library; see the file COPYING.LIB. If not, write to 0014 // the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 0015 // Boston, MA 02110-1301, USA. 0016 0017 #include <QGroupBox> 0018 #include <QLabel> 0019 #include <QSpinBox> 0020 #include <QCloseEvent> 0021 #include <QHBoxLayout> 0022 #include <QVBoxLayout> 0023 #include <QTreeWidget> 0024 #include <QHeaderView> 0025 #include <QMenu> 0026 #include <QPushButton> 0027 #include <QApplication> 0028 #include <QStyle> 0029 #include <QComboBox> 0030 0031 #include <klocalizedstring.h> 0032 #include <kiconloader.h> 0033 0034 #include <atlantic_core.h> 0035 #include <player.h> 0036 #include <estate.h> 0037 #include <trade.h> 0038 #include <portfolioestate.h> 0039 #include <card.h> 0040 0041 #include "trade_widget.h" 0042 0043 TradeDisplay::TradeDisplay(Trade *trade, AtlanticCore *atlanticCore, QWidget *parent) 0044 : QDialog(parent, Qt::WindowContextHelpButtonHint) 0045 , m_atlanticCore(atlanticCore) 0046 , m_trade(trade) 0047 , m_contextTradeItem(nullptr) 0048 { 0049 setWindowTitle(i18nc("@title:window", "Trade %1", trade->tradeId())); 0050 0051 QVBoxLayout *listCompBox = new QVBoxLayout(this); 0052 0053 m_updateComponentBox = new QGroupBox(i18n("Add Component"), this); 0054 listCompBox->addWidget(m_updateComponentBox); 0055 0056 QHBoxLayout *updateComponentBoxLayout = new QHBoxLayout(m_updateComponentBox); 0057 0058 m_editTypeCombo = new QComboBox(m_updateComponentBox); 0059 m_editTypeCombo->addItem(i18n("Estate")); 0060 m_editTypeCombo->addItem(i18n("Money")); 0061 m_editTypeCombo->addItem(i18n("Card")); 0062 updateComponentBoxLayout->addWidget(m_editTypeCombo); 0063 0064 connect(m_editTypeCombo, SIGNAL(activated(int)), this, SLOT(setTypeCombo(int))); 0065 0066 m_estateCombo = new QComboBox(m_updateComponentBox); 0067 updateComponentBoxLayout->addWidget(m_estateCombo); 0068 foreach (Estate *estate, m_atlanticCore->estates()) 0069 { 0070 if (estate->isOwned()) 0071 { 0072 m_estateCombo->addItem( PortfolioEstate::drawPixmap(estate), estate->name() ); 0073 m_estateMap[m_estateCombo->count() - 1] = estate; 0074 m_estateRevMap[estate] = m_estateCombo->count() - 1; 0075 } 0076 } 0077 0078 connect(m_estateCombo, SIGNAL(activated(int)), this, SLOT(setEstateCombo(int))); 0079 0080 m_moneyBox = new QSpinBox(m_updateComponentBox); 0081 m_moneyBox->setRange(0, 10000); 0082 m_moneyBox->setSingleStep(1); 0083 updateComponentBoxLayout->addWidget(m_moneyBox); 0084 0085 m_cardCombo = new QComboBox(m_updateComponentBox); 0086 updateComponentBoxLayout->addWidget(m_cardCombo); 0087 foreach (Card *card, m_atlanticCore->cards()) 0088 { 0089 if (card->isOwned()) 0090 { 0091 m_cardCombo->addItem(card->title()); 0092 m_cardMap[m_cardCombo->count() - 1] = card; 0093 m_cardRevMap[card] = m_cardCombo->count() - 1; 0094 } 0095 } 0096 0097 connect(m_cardCombo, SIGNAL(activated(int)), this, SLOT(setCardCombo(int))); 0098 0099 Player *pSelf = m_atlanticCore->playerSelf(); 0100 0101 m_fromLabel = new QLabel(m_updateComponentBox); 0102 m_fromLabel->setText(i18n("From")); 0103 updateComponentBoxLayout->addWidget(m_fromLabel); 0104 m_playerFromCombo = new QComboBox(m_updateComponentBox); 0105 updateComponentBoxLayout->addWidget(m_playerFromCombo); 0106 0107 m_toLabel = new QLabel(m_updateComponentBox); 0108 m_toLabel->setText(i18n("To")); 0109 updateComponentBoxLayout->addWidget(m_toLabel); 0110 m_playerTargetCombo = new QComboBox(m_updateComponentBox); 0111 updateComponentBoxLayout->addWidget(m_playerTargetCombo); 0112 0113 foreach (Player *player, m_atlanticCore->players()) 0114 { 0115 if (player->game() == pSelf->game()) 0116 { 0117 m_playerFromCombo->addItem(player->name()); 0118 m_playerFromMap[m_playerFromCombo->count() - 1] = player; 0119 m_playerFromRevMap[player] = m_playerFromCombo->count() - 1; 0120 0121 m_playerTargetCombo->addItem(player->name()); 0122 m_playerTargetMap[m_playerTargetCombo->count() - 1] = player; 0123 m_playerTargetRevMap[player] = m_playerTargetCombo->count() - 1; 0124 0125 connect(player, SIGNAL(changed(Player *)), this, SLOT(playerChanged(Player *))); 0126 } 0127 } 0128 0129 m_updateButton = new QPushButton(i18n("Update"), m_updateComponentBox); 0130 m_updateButton->setEnabled(false); 0131 updateComponentBoxLayout->addWidget(m_updateButton); 0132 0133 connect(m_updateButton, SIGNAL(clicked()), this, SLOT(updateComponent())); 0134 0135 QHBoxLayout *centralLayout = new QHBoxLayout(); 0136 listCompBox->addLayout(centralLayout); 0137 0138 m_participantsList = new QTreeWidget(this); 0139 m_participantsList->setRootIsDecorated(false); 0140 m_participantsList->header()->setSectionResizeMode(QHeaderView::Stretch); 0141 m_participantsList->setHeaderLabels(QStringList() << i18n("Participants")); 0142 QList<QTreeWidgetItem *> items; 0143 foreach (Player *player, m_trade->participants()) 0144 { 0145 QTreeWidgetItem *item = new QTreeWidgetItem(); 0146 item->setText(0, player->name()); 0147 m_playerListMap.insert(player, item); 0148 items << item; 0149 } 0150 m_participantsList->addTopLevelItems(items); 0151 m_participantsList->setMaximumWidth(175); // FIXME grr 0152 centralLayout->addWidget(m_participantsList); 0153 0154 m_componentList = new QTreeWidget(this); 0155 m_componentList->setObjectName(QStringLiteral("componentList")); 0156 m_componentList->setContextMenuPolicy(Qt::CustomContextMenu); 0157 m_componentList->setRootIsDecorated(false); 0158 m_componentList->header()->setSectionResizeMode(QHeaderView::ResizeToContents); 0159 centralLayout->addWidget(m_componentList, 1); 0160 0161 QStringList headers; 0162 headers << i18n("Player"); 0163 headers << i18n("Gives"); 0164 headers << i18n("Player"); 0165 headers << i18n("Item"); 0166 m_componentList->setHeaderLabels(headers); 0167 0168 connect(m_componentList, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(contextMenu(QPoint))); 0169 connect(m_componentList, SIGNAL(itemClicked(QTreeWidgetItem*,int)), this, SLOT(setCombos(QTreeWidgetItem*))); 0170 0171 QHBoxLayout *actionBox = new QHBoxLayout(); 0172 actionBox->setContentsMargins(0, 0, 0, 0); 0173 listCompBox->addItem(actionBox); 0174 0175 actionBox->addItem(new QSpacerItem(20, 20, QSizePolicy::Expanding, QSizePolicy::Minimum)); 0176 0177 m_rejectButton = new QPushButton(KDE::icon(QStringLiteral("dialog-cancel")), i18n("Reject"), this); 0178 actionBox->addWidget(m_rejectButton); 0179 0180 connect(m_rejectButton, SIGNAL(clicked()), this, SLOT(reject())); 0181 0182 m_acceptButton = new QPushButton(KDE::icon(QStringLiteral("dialog-ok")), i18n("Accept"), this); 0183 // m_acceptButton->setEnabled(false); 0184 actionBox->addWidget(m_acceptButton); 0185 0186 connect(m_acceptButton, SIGNAL(clicked()), this, SLOT(accept())); 0187 0188 m_status = new QLabel(this); 0189 listCompBox->addWidget(m_status); 0190 m_status->setText( i18n( "%1 out of %2 players accept current trade proposal.", m_trade->count( true ), m_trade->count( false ) ) ); 0191 0192 connect(m_trade, SIGNAL(itemAdded(TradeItem *)), this, SLOT(tradeItemAdded(TradeItem *))); 0193 connect(m_trade, SIGNAL(itemRemoved(TradeItem *)), this, SLOT(tradeItemRemoved(TradeItem *))); 0194 connect(m_trade, SIGNAL(changed(Trade *)), this, SLOT(tradeChanged())); 0195 connect(m_trade, SIGNAL(rejected(Player *)), this, SLOT(tradeRejected(Player *))); 0196 connect(m_trade, SIGNAL(playerAdded(Player *)), this, SLOT(slotPlayerAdded(Player *))); 0197 connect(m_trade, SIGNAL(playerRemoved(Player *)), this, SLOT(slotPlayerRemoved(Player *))); 0198 connect(m_trade, SIGNAL(acceptChanged(Player *, bool)), this, SLOT(slotAcceptChanged(Player *, bool))); 0199 connect(this, SIGNAL(updateEstate(Trade *, Estate *, Player *)), m_trade, SIGNAL(updateEstate(Trade *, Estate *, Player *))); 0200 connect(this, SIGNAL(updateMoney(Trade *, unsigned int, Player *, Player *)), m_trade, SIGNAL(updateMoney(Trade *, unsigned int, Player *, Player *))); 0201 connect(this, SIGNAL(updateCard(Trade *, Card *, Player *)), m_trade, SIGNAL(updateCard(Trade *, Card *, Player *))); 0202 connect(this, SIGNAL(reject(Trade *)), m_trade, SIGNAL(reject(Trade *))); 0203 connect(this, SIGNAL(accept(Trade *)), m_trade, SIGNAL(accept(Trade *))); 0204 0205 setTypeCombo(m_editTypeCombo->currentIndex()); 0206 setEstateCombo(m_estateCombo->currentIndex()); 0207 } 0208 0209 void TradeDisplay::closeEvent(QCloseEvent *e) 0210 { 0211 // Don't send network event when trade is already rejected 0212 if (m_trade->isRejected()) 0213 m_atlanticCore->removeTrade(m_trade); 0214 else 0215 Q_EMIT reject(m_trade); 0216 0217 e->accept(); 0218 } 0219 0220 void TradeDisplay::tradeItemAdded(TradeItem *tradeItem) 0221 { 0222 QTreeWidgetItem *item = new QTreeWidgetItem(); 0223 item->setText(0, tradeItem->from() ? tradeItem->from()->name() : QStringLiteral("?")); 0224 item->setText(1, i18nc("gives is transitive ;)", "gives")); 0225 item->setText(2, tradeItem->to() ? tradeItem->to()->name() : QStringLiteral("?")); 0226 item->setText(3, tradeItem->text()); 0227 connect(tradeItem, SIGNAL(changed(TradeItem *)), this, SLOT(tradeItemChanged(TradeItem *))); 0228 0229 const QIcon userIcon = KDE::icon(QStringLiteral("user-identity")); 0230 item->setIcon(0, userIcon); 0231 item->setIcon(2, userIcon); 0232 0233 if (TradeEstate *tradeEstate = dynamic_cast<TradeEstate*>(tradeItem)) 0234 item->setIcon(3, PortfolioEstate::drawPixmap(tradeEstate->estate())); 0235 // else if (TradeMoney *tradeMoney = dynamic_cast<TradeMoney*>(tradeItem)) 0236 // item->setIcon(3, PortfolioEstate::pixMap(tradeEstate->estate())); 0237 0238 m_componentList->addTopLevelItem(item); 0239 0240 m_componentMap[tradeItem] = item; 0241 m_componentRevMap[item] = tradeItem; 0242 } 0243 0244 void TradeDisplay::tradeItemRemoved(TradeItem *t) 0245 { 0246 QTreeWidgetItem *item = m_componentMap.take(t); 0247 m_componentRevMap.remove(item); 0248 delete item; 0249 } 0250 0251 void TradeDisplay::tradeItemChanged(TradeItem *t) 0252 { 0253 QTreeWidgetItem *item = m_componentMap.value(t, nullptr); 0254 if (item) 0255 { 0256 const QIcon userIcon = KDE::icon(QStringLiteral("user-identity")); 0257 item->setText(0, t->from() ? t->from()->name() : QStringLiteral("?")); 0258 item->setIcon(0, userIcon); 0259 item->setText(2, t->to() ? t->to()->name() : QStringLiteral("?")); 0260 item->setIcon(2, userIcon); 0261 item->setText(3, t->text()); 0262 } 0263 } 0264 0265 void TradeDisplay::tradeChanged() 0266 { 0267 // TODO: add notification whether playerSelf has accepted or not and 0268 // enable/disable accept button based on that 0269 m_status->setText( i18n( "%1 out of %2 players accept current trade proposal.", m_trade->count( true ), m_trade->count( false ) ) ); 0270 } 0271 0272 void TradeDisplay::playerChanged(Player *player) 0273 { 0274 m_playerFromCombo->setItemText(m_playerFromRevMap[player], player->name()); 0275 m_playerTargetCombo->setItemText(m_playerTargetRevMap[player], player->name()); 0276 0277 foreach (TradeItem *item, m_componentRevMap) 0278 tradeItemChanged(item); 0279 } 0280 0281 void TradeDisplay::tradeRejected(Player *player) 0282 { 0283 if (player) 0284 { 0285 m_status->setText(i18n("Trade proposal was rejected by %1.", player->name())); 0286 QTreeWidgetItem *item = m_playerListMap.value(player, nullptr); 0287 if (item) 0288 item->setIcon(0, KDE::icon(QStringLiteral("dialog-cancel"))); 0289 } else 0290 m_status->setText(i18n("Trade proposal was rejected.")); 0291 0292 // Disable GUI elements 0293 m_updateButton->setEnabled(false); 0294 m_componentList->setEnabled(false); 0295 m_rejectButton->setEnabled(false); 0296 m_acceptButton->setEnabled(false); 0297 0298 // TODO: add/enable close button 0299 } 0300 0301 void TradeDisplay::slotPlayerAdded(Player *player) 0302 { 0303 QTreeWidgetItem *item = m_playerListMap.value(player, nullptr); 0304 if (item) 0305 return; 0306 0307 item = new QTreeWidgetItem(); 0308 item->setText(0, player->name()); 0309 m_playerListMap.insert(player, item); 0310 m_participantsList->addTopLevelItem(item); 0311 tradeChanged(); 0312 } 0313 0314 void TradeDisplay::slotPlayerRemoved(Player *player) 0315 { 0316 QTreeWidgetItem *item = m_playerListMap.take(player); 0317 if (!item) 0318 return; 0319 0320 delete item; 0321 tradeChanged(); 0322 } 0323 0324 void TradeDisplay::slotAcceptChanged(Player *player, bool accept) 0325 { 0326 slotPlayerAdded(player); 0327 QTreeWidgetItem *item = m_playerListMap.value(player, nullptr); 0328 Q_ASSERT(item); // slotPlayerAdded made sure there's an item for player 0329 item->setIcon(0, accept ? KDE::icon(QStringLiteral("dialog-ok")) : QIcon()); 0330 } 0331 0332 void TradeDisplay::setTypeCombo(int index) 0333 { 0334 switch (index) 0335 { 0336 case 0: 0337 // Editing estate component 0338 0339 m_estateCombo->show(); 0340 m_estateCombo->setMaximumWidth(9999); 0341 0342 m_moneyBox->hide(); 0343 m_moneyBox->setMaximumWidth(0); 0344 0345 m_cardCombo->hide(); 0346 m_cardCombo->setMaximumWidth(0); 0347 0348 setEstateCombo(m_estateCombo->currentIndex()); // also updates playerfromCombo 0349 m_playerFromCombo->setEnabled(false); 0350 0351 m_updateButton->setEnabled( m_estateCombo->count() > 0 ); 0352 0353 break; 0354 0355 case 1: 0356 // Editing money component 0357 0358 m_estateCombo->hide(); 0359 m_estateCombo->setMaximumWidth(0); 0360 0361 m_moneyBox->show(); 0362 m_moneyBox->setMaximumWidth(9999); 0363 0364 m_cardCombo->hide(); 0365 m_cardCombo->setMaximumWidth(0); 0366 0367 m_playerFromCombo->setEnabled(true); 0368 0369 m_updateButton->setEnabled(true); 0370 0371 break; 0372 0373 case 2: 0374 // Editing card component 0375 0376 m_estateCombo->hide(); 0377 m_estateCombo->setMaximumWidth(0); 0378 0379 m_moneyBox->hide(); 0380 m_moneyBox->setMaximumWidth(0); 0381 0382 m_cardCombo->show(); 0383 m_cardCombo->setMaximumWidth(9999); 0384 0385 setCardCombo(m_cardCombo->currentIndex()); // also updates playerFromCombo 0386 m_playerFromCombo->setEnabled(false); 0387 0388 m_updateButton->setEnabled(m_cardCombo->count() > 0); 0389 0390 break; 0391 } 0392 } 0393 0394 void TradeDisplay::setEstateCombo(int index) 0395 { 0396 if (m_estateCombo->currentIndex() != index) 0397 m_estateCombo->setCurrentIndex(index); 0398 0399 if (Estate *estate = m_estateMap.value(index, nullptr)) 0400 m_playerFromCombo->setCurrentIndex( m_playerFromRevMap[estate->owner()] ); 0401 } 0402 0403 void TradeDisplay::setCardCombo(int index) 0404 { 0405 if (m_cardCombo->currentIndex() != index) 0406 m_cardCombo->setCurrentIndex(index); 0407 0408 if (Card *card = m_cardMap.value(index, nullptr)) 0409 m_playerFromCombo->setCurrentIndex(m_playerFromRevMap[card->owner()]); 0410 } 0411 0412 void TradeDisplay::setCombos(QTreeWidgetItem *i) 0413 { 0414 TradeItem *item = m_componentRevMap[i]; 0415 if (TradeEstate *tradeEstate = dynamic_cast<TradeEstate*>(item)) 0416 { 0417 setTypeCombo(0); 0418 setEstateCombo( m_estateRevMap[tradeEstate->estate()] ); // also updates playerFromCombo 0419 m_playerTargetCombo->setCurrentIndex( m_playerTargetRevMap[tradeEstate->to()] ); 0420 } 0421 else if (TradeMoney *tradeMoney = dynamic_cast<TradeMoney*>(item)) 0422 { 0423 setTypeCombo(1); 0424 m_moneyBox->setValue( tradeMoney->money() ); 0425 m_playerFromCombo->setCurrentIndex( m_playerFromRevMap[tradeMoney->from()] ); 0426 m_playerTargetCombo->setCurrentIndex( m_playerTargetRevMap[tradeMoney->to()] ); 0427 } 0428 else if (TradeCard *tradeCard = dynamic_cast<TradeCard*>(item)) 0429 { 0430 setTypeCombo(2); 0431 setCardCombo(m_cardRevMap[tradeCard->card()]); // also updates playerFromCombo 0432 m_playerTargetCombo->setCurrentIndex(m_playerTargetRevMap[tradeCard->to()]); 0433 } 0434 } 0435 0436 void TradeDisplay::updateComponent() 0437 { 0438 Estate *estate; 0439 Player *pFrom, *pTarget; 0440 Card *card; 0441 0442 switch (m_editTypeCombo->currentIndex()) 0443 { 0444 case 0: 0445 // Updating estate component 0446 estate = m_estateMap[m_estateCombo->currentIndex()]; 0447 pTarget = m_playerTargetMap[m_playerTargetCombo->currentIndex()]; 0448 0449 if (estate && pTarget) 0450 Q_EMIT updateEstate(m_trade, estate, pTarget); 0451 0452 break; 0453 0454 case 1: 0455 // Updating money component 0456 pFrom = m_playerFromMap[m_playerFromCombo->currentIndex()]; 0457 pTarget = m_playerTargetMap[m_playerTargetCombo->currentIndex()]; 0458 0459 if (pFrom && pTarget) 0460 Q_EMIT updateMoney(m_trade, m_moneyBox->value(), pFrom, pTarget); 0461 0462 break; 0463 0464 case 2: 0465 // Updating card component 0466 card = m_cardMap[m_cardCombo->currentIndex()]; 0467 pTarget = m_playerTargetMap[m_playerTargetCombo->currentIndex()]; 0468 0469 if (card && pTarget) 0470 Q_EMIT updateCard(m_trade, card, pTarget); 0471 0472 break; 0473 } 0474 } 0475 0476 void TradeDisplay::reject() 0477 { 0478 Q_EMIT reject(m_trade); 0479 } 0480 0481 void TradeDisplay::accept() 0482 { 0483 Q_EMIT accept(m_trade); 0484 } 0485 0486 void TradeDisplay::contextMenu(const QPoint &pos) 0487 { 0488 QTreeWidgetItem* item = m_componentList->itemAt(pos); 0489 if (!item) 0490 return; 0491 0492 m_contextTradeItem = m_componentRevMap[item]; 0493 0494 QMenu *rmbMenu = new QMenu(this); 0495 QAction *act = rmbMenu->addAction(i18n("Remove From Trade")); 0496 connect(act, SIGNAL(triggered()), this, SLOT(contextMenuClickedRemove())); 0497 0498 rmbMenu->exec(m_componentList->viewport()->mapToGlobal(pos)); 0499 } 0500 0501 void TradeDisplay::contextMenuClickedRemove() 0502 { 0503 if (!m_contextTradeItem) 0504 return; 0505 0506 if (TradeEstate *tradeEstate = dynamic_cast<TradeEstate*>(m_contextTradeItem)) 0507 Q_EMIT updateEstate(m_trade, tradeEstate->estate(), nullptr); 0508 else if (TradeMoney *tradeMoney = dynamic_cast<TradeMoney*>(m_contextTradeItem)) 0509 Q_EMIT updateMoney(m_trade, 0, tradeMoney->from(), tradeMoney->to()); 0510 else if (TradeCard *tradeCard = dynamic_cast<TradeCard*>(m_contextTradeItem)) 0511 Q_EMIT updateCard(m_trade, tradeCard->card(), nullptr); 0512 0513 m_contextTradeItem = nullptr; 0514 } 0515 0516 #include "moc_trade_widget.cpp"