File indexing completed on 2024-04-21 15:08: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 <qpainter.h>
0018 #include <QPixmap>
0019 #include <QMouseEvent>
0020 #include <QFile>
0021 #include <QMultiHash>
0022 #include <QMenu>
0023 #include <QApplication>
0024 #include <QStyle>
0025 #include <QFontDatabase>
0026 #include <QPaintEvent>
0027 
0028 #include <klocalizedstring.h>
0029 
0030 #include <atlantic_core.h>
0031 #include <player.h>
0032 #include <estate.h>
0033 #include <estategroup.h>
0034 #include <portfolioestate.h>
0035 
0036 #include "portfolioview.h"
0037 
0038 #include <algorithm>
0039 
0040 #define PE_DISTW    4
0041 #define PE_DISTH    4
0042 #define PE_SPACE    2
0043 #define PE_MARGINW  5
0044 #define PE_MARGINH  2
0045 #define ICONSIZE    48
0046 
0047 PortfolioView::PortfolioView(AtlanticCore *core, Player *player, QColor activeColor, QColor inactiveColor, QWidget *parent)
0048     : QWidget(parent)
0049     , m_atlanticCore(core)
0050     , m_player(player)
0051     , m_activeColor(activeColor)
0052     , m_inactiveColor(inactiveColor)
0053     , qpixmap(nullptr)
0054     , m_image(nullptr)
0055     , b_recreate(true)
0056 {
0057     QPalette pal = palette();
0058     pal.setColor(backgroundRole(), Qt::white);
0059     setPalette(pal);
0060     setMinimumHeight(ICONSIZE);
0061 
0062     // Init icon
0063     loadIcon();
0064 }
0065 
0066 PortfolioView::~PortfolioView()
0067 {
0068     clearPortfolio();
0069     delete m_image;
0070     delete qpixmap;
0071 }
0072 
0073 Player *PortfolioView::player() const
0074 {
0075     return m_player;
0076 }
0077 
0078 void PortfolioView::buildPortfolio()
0079 {
0080     if ( m_portfolioEstates.count() )
0081         clearPortfolio();
0082 
0083     // Loop through estate groups in order
0084     PortfolioEstate *lastPE = nullptr, *firstPEprevGroup = nullptr;
0085 
0086     int x = 100, y = 25, marginHint = 5, bottom;
0087     bottom = ICONSIZE - PE_HEIGHT - marginHint;
0088 
0089     QMultiHash<EstateGroup *, Estate *> groups;
0090 
0091     foreach (Estate *estate, m_atlanticCore->estates())
0092         groups.insert(estate->estateGroup(), estate);
0093 
0094     if (!groups.isEmpty())
0095         m_portfolioEstates.reserve(groups.count());
0096 
0097     foreach (EstateGroup *estateGroup, m_atlanticCore->estateGroups())
0098     {
0099         {
0100             // New group
0101             lastPE = nullptr;
0102 
0103             QList<Estate *> estates = groups.values(estateGroup);
0104             // QMultiHash/QHash tracks multiple values per key
0105             // in LIFO order
0106             std::reverse(estates.begin(), estates.end());
0107 
0108             // Loop through estates
0109             foreach (Estate *estate, estates)
0110             {
0111                 {
0112                     // Create PE
0113                                         PortfolioEstate *portfolioEstate = new PortfolioEstate(estate, m_player, false, this );
0114                                         portfolioEstate->setObjectName(QStringLiteral("portfolioestate"));
0115                     m_portfolioEstates.append(portfolioEstate);
0116 
0117                     connect(portfolioEstate, SIGNAL(estateClicked(Estate *)), this, SIGNAL(estateClicked(Estate *)));
0118                     if (lastPE)
0119                     {
0120                         x = lastPE->x() + 2;
0121                         y = lastPE->y() + 4;
0122                         if (y > bottom)
0123                             bottom = y;
0124                     }
0125                     else if (firstPEprevGroup)
0126                     {
0127                         x = firstPEprevGroup->x() + PE_WIDTH + 8;
0128                         y = 20 + marginHint;
0129                         firstPEprevGroup = portfolioEstate;
0130                     }
0131                     else
0132                     {
0133                         x = ICONSIZE + marginHint;
0134                         y = 20 + marginHint;
0135                         if (y > bottom)
0136                             bottom = y;
0137                         firstPEprevGroup = portfolioEstate;
0138                     }
0139 
0140                     portfolioEstate->move(x, y);
0141                     portfolioEstate->show();
0142 
0143                     lastPE = portfolioEstate;
0144                 }
0145             }
0146         }
0147     }
0148     setMinimumWidth(x + PE_WIDTH + marginHint);
0149     int minHeight = bottom + PE_HEIGHT + marginHint;
0150     if (minHeight > minimumHeight())
0151         setMinimumHeight(minHeight);
0152 }
0153 
0154 void PortfolioView::clearPortfolio()
0155 {
0156     qDeleteAll(m_portfolioEstates);
0157     m_portfolioEstates.clear();
0158 }
0159 
0160 void PortfolioView::setTokenTheme(const TokenTheme &theme)
0161 {
0162     m_tokenTheme = theme;
0163     loadIcon(true);
0164     b_recreate = true;
0165     update();
0166 }
0167 
0168 void PortfolioView::loadIcon(bool force)
0169 {
0170     if (m_imageName == m_player->image() && !force)
0171         return;
0172     m_imageName = m_player->image();
0173 
0174     delete m_image;
0175     m_image = nullptr;
0176 
0177     if (!m_tokenTheme.isValid())
0178         return;
0179 
0180     QString imageFile;
0181     if (!m_imageName.isEmpty())
0182         imageFile = m_tokenTheme.tokenPath(m_imageName);
0183     if (imageFile.isEmpty())
0184         imageFile = m_tokenTheme.tokenPath(m_tokenTheme.fallbackIcon());
0185 
0186     const QPixmap pix(imageFile);
0187     if (pix.isNull())
0188         return;
0189 
0190     m_image = new QPixmap(pix.scaled(ICONSIZE, ICONSIZE, Qt::KeepAspectRatio));
0191 }
0192 
0193 void PortfolioView::paintEvent(QPaintEvent *e)
0194 {
0195     if (b_recreate)
0196     {
0197         const int spacingHint = QApplication::style()->pixelMetric(QStyle::PM_LayoutHorizontalSpacing);
0198         const QFont generalFont = QFontDatabase::systemFont(QFontDatabase::GeneralFont);
0199         if (!qpixmap || qpixmap->size() != size())
0200         {
0201             delete qpixmap;
0202             qpixmap = new QPixmap(width(), height());
0203         }
0204 
0205         QPainter painter;
0206         painter.begin(qpixmap);
0207 
0208         painter.setPen(Qt::white);
0209         painter.setBrush(Qt::white);
0210         painter.drawRect(rect());
0211 
0212         painter.setPen(m_player->hasTurn() ? m_activeColor : Qt::black);
0213         painter.setBrush(m_player->hasTurn() ? m_activeColor : Qt::black);
0214         painter.drawRect(0, 0, width() - 1, 20 - 1);
0215 
0216         if (m_image)
0217         {
0218             painter.setPen(Qt::black);
0219             painter.setBrush(Qt::white);
0220             painter.drawRect(0, 0, ICONSIZE - 1, ICONSIZE - 1);
0221 
0222             painter.drawPixmap((ICONSIZE - m_image->width()) / 2, (ICONSIZE - m_image->height()) / 2, *m_image);
0223         }
0224 
0225         painter.setPen(Qt::white);
0226         painter.setFont(QFont(generalFont.family(), generalFont.pointSize(), QFont::Bold));
0227         painter.drawText(ICONSIZE + spacingHint, 15, m_player->name());
0228 
0229         if ( m_portfolioEstates.count() )
0230             painter.drawText(width() - 50, 15, QString::number(m_player->money()));
0231         else
0232         {
0233             painter.setPen(Qt::black);
0234             painter.setBrush(Qt::white);
0235 
0236             painter.setFont(generalFont);
0237             painter.drawText(ICONSIZE + spacingHint, 30, m_player->host());
0238         }
0239 
0240         b_recreate = false;
0241     }
0242     QPainter painter(this);
0243     painter.drawPixmap(e->rect(), *qpixmap, e->rect());
0244 }
0245 
0246 void PortfolioView::resizeEvent(QResizeEvent *)
0247 {
0248     b_recreate = true;
0249 }
0250 
0251 void PortfolioView::playerChanged()
0252 {
0253     loadIcon();
0254 
0255     b_recreate = true;
0256     if (m_player->isSpectator())
0257         clearPortfolio();
0258     else if (m_portfolioEstates.isEmpty())
0259         buildPortfolio();
0260     update();
0261 }
0262 
0263 void PortfolioView::contextMenuEvent(QContextMenuEvent *e)
0264 {
0265     Player *playerSelf = m_atlanticCore->playerSelf();
0266 
0267     if (m_player != playerSelf && !playerSelf->isSpectator())
0268     {
0269         QMenu rmbMenu(this);
0270         rmbMenu.setTitle(m_player->name());
0271         QAction *act;
0272 
0273         if ( m_portfolioEstates.count() )
0274         {
0275             // Start trade
0276             act = rmbMenu.addAction(i18n("Request Trade with %1", m_player->name()));
0277             connect(act, SIGNAL(triggered()), this, SLOT(slotMenuActionTrade()));
0278         }
0279         else
0280         {
0281             // Kick player
0282             act = rmbMenu.addAction(i18n("Boot Player %1 to Lounge", m_player->name()));
0283             act->setEnabled(m_atlanticCore->selfIsMaster());
0284             connect(act, SIGNAL(triggered()), this, SLOT(slotMenuActionKick()));
0285         }
0286 
0287         rmbMenu.exec(e->globalPos());
0288     }
0289 }
0290 
0291 void PortfolioView::slotMenuActionTrade()
0292 {
0293     Q_EMIT newTrade(m_player);
0294 }
0295 
0296 void PortfolioView::slotMenuActionKick()
0297 {
0298     Q_EMIT kickPlayer(m_player);
0299 }
0300 
0301 #include "moc_portfolioview.cpp"