File indexing completed on 2024-04-28 05:38:15

0001 /***************************************************************************
0002  *     Copyright (C) 2009 by Renaud Guezennec                             *
0003  *   https://rolisteam.org/contact                   *
0004  *                                                                         *
0005  *   This program is free software; you can redistribute it and/or modify     *
0006  *   it under the terms of the GNU General Public License as published by  *
0007  *   the Free Software Foundation; either version 2 of the License, or     *
0008  *   (at your option) any later version.                                   *
0009  *                                                                         *
0010  *   This program is distributed in the hope that it will be useful,       *
0011  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
0012  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
0013  *   GNU General Public License for more details.                          *
0014  *                                                                         *
0015  *   You should have received a copy of the GNU General Public License     *
0016  *   along with this program; if not, write to the                         *
0017  *   Free Software Foundation, Inc.,                                       *
0018  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
0019  ***************************************************************************/
0020 
0021 #include "userlistview.h"
0022 
0023 #include <QColorDialog>
0024 #include <QDebug>
0025 #include <QDrag>
0026 #include <QHeaderView>
0027 #include <QMenu>
0028 #include <QMouseEvent>
0029 #include <QPainter>
0030 #include <memory>
0031 
0032 #include "controller/view_controller/imageselectorcontroller.h"
0033 #include "rwidgets/dialogs/imageselectordialog.h"
0034 #include "userlistview.h"
0035 #include "worker/iohelper.h"
0036 #include "worker/utilshelper.h"
0037 
0038 #include "controller/playercontroller.h"
0039 #include "data/character.h"
0040 #include "data/rolisteammimedata.h"
0041 #include "model/characterstatemodel.h"
0042 #include "model/playermodel.h"
0043 #include "preferences/preferencesmanager.h"
0044 #include <QInputDialog>
0045 
0046 UserListView::UserListView(QWidget* parent) : QTreeView(parent)
0047 {
0048     setHeaderHidden(true);
0049 
0050     // set action
0051     m_addAvatarAct= std::make_unique<QAction>(tr("Set Avatar..."), this);
0052     m_removeAvatarAct= std::make_unique<QAction>(tr("Remove..."), this);
0053     m_changeName= std::make_unique<QAction>(tr("Edit name"), this);
0054     m_changeColor= std::make_unique<QAction>(tr("Change color…"), this);
0055 
0056     connect(m_addAvatarAct.get(), &QAction::triggered, this, &UserListView::addAvatar);
0057     connect(m_removeAvatarAct.get(), &QAction::triggered, this, &UserListView::deleteAvatar);
0058     connect(m_changeName.get(), &QAction::triggered, this, [this]() { edit(currentIndex()); });
0059     connect(m_changeColor.get(), &QAction::triggered, this, &UserListView::editCurrentItemColor);
0060 
0061     setIconSize(QSize(64, 64));
0062 
0063     std::vector<std::tuple<QString, QString, Type>> propertyList
0064         = {{"healthPoints", tr("Health Points"), Integer},    {"maxHP", tr("Health Points Maximum"), Integer},
0065            {"minHP", tr("Health Points Minimum"), Integer},   {"distancePerTurn", tr("Distance per turn"), Real},
0066            {"initCommand", tr("Initiative Command"), String}, {"hasInitiative", tr("Has initiative"), Boolean},
0067            {"lifeColor", tr("Life bar color"), Color}};
0068 
0069     for(auto propertyName : propertyList)
0070     {
0071         auto act= new QAction(std::get<1>(propertyName), this);
0072         std::pair<QString, Type> pair(std::get<0>(propertyName), std::get<2>(propertyName));
0073         if(std::get<2>(propertyName) == Boolean)
0074             act->setCheckable(true);
0075 
0076         QVariant var;
0077         var.setValue(pair);
0078         act->setData(var);
0079         connect(act, &QAction::triggered, this, &UserListView::setPropertyValue);
0080         m_propertyActions.push_back(act);
0081     }
0082 }
0083 
0084 void UserListView::setPlayerController(PlayerController* ctrl)
0085 {
0086     m_ctrl= ctrl;
0087 }
0088 
0089 void UserListView::setState()
0090 {
0091     auto act= qobject_cast<QAction*>(sender());
0092     if(nullptr == act)
0093         return;
0094 
0095     auto index= currentIndex();
0096     auto stateId= act->data().toString();
0097     /*auto state= Character::getStateFromIndex(stateIdx);
0098     auto person= static_cast<Person*>(index.internalPointer());
0099     auto tmpPlayer= dynamic_cast<Character*>(person);
0100 
0101     if(nullptr == tmpPlayer || nullptr == state)
0102         return;*/
0103 
0104     model()->setData(index, stateId, PlayerModel::CharacterStateIdRole);
0105 
0106     // tmpPlayer->setStateId(stateId);
0107 }
0108 
0109 void UserListView::setPropertyValue()
0110 {
0111     auto act= qobject_cast<QAction*>(sender());
0112     if(nullptr == act)
0113         return;
0114 
0115     auto index= currentIndex();
0116     QVariant value= act->data();
0117     auto pair= value.value<std::pair<QString, Type>>();
0118     auto person= static_cast<Person*>(index.internalPointer());
0119     auto tmpperso= dynamic_cast<Character*>(person);
0120 
0121     if(nullptr == tmpperso)
0122         return;
0123 
0124     auto formerVal= tmpperso->property(pair.first.toLocal8Bit());
0125     QVariant var;
0126     bool ok;
0127 
0128     switch(pair.second)
0129     {
0130     case Boolean:
0131         var= !formerVal.toBool();
0132         ok= true;
0133         break;
0134     case Integer:
0135         var= QInputDialog::getInt(this, tr("Get value for %1 property").arg(pair.first), tr("Value:"),
0136                                   formerVal.toInt(), -2147483647, 2147483647, 1, &ok);
0137         break;
0138     case Real:
0139         var= QInputDialog::getDouble(this, tr("Get value for %1 property").arg(pair.first), tr("Value:"),
0140                                      formerVal.toDouble(), -2147483647, 2147483647, 1, &ok);
0141         break;
0142     case String:
0143         var= QInputDialog::getText(this, tr("Get value for %1 property").arg(pair.first), tr("Value:"),
0144                                    QLineEdit::Normal, formerVal.toString(), &ok);
0145         break;
0146     case Color:
0147         var= QColorDialog::getColor(formerVal.value<QColor>(), this);
0148         ok= true;
0149         break;
0150     }
0151 
0152     if(!ok)
0153         return;
0154 
0155     tmpperso->setProperty(pair.first.toLocal8Bit(), var);
0156 }
0157 
0158 void UserListView::mouseDoubleClickEvent(QMouseEvent* event)
0159 {
0160     QModelIndex tmp= indexAt(event->pos());
0161     int indentationValue= indentation();
0162     int icon= 0;
0163     if(iconSize().isValid())
0164         icon= iconSize().width();
0165     else
0166         icon= indentationValue;
0167 
0168     if(tmp.isValid())
0169     {
0170         event->pos();
0171         int depth= 1;
0172         while(tmp.parent().isValid())
0173         {
0174             depth++;
0175             tmp= tmp.parent();
0176         }
0177         if((depth * indentationValue < event->pos().x()) && ((depth)*indentationValue + icon >= event->pos().x()))
0178         {
0179             editCurrentItemColor();
0180         }
0181         else
0182             QTreeView::mouseDoubleClickEvent(event);
0183     }
0184     else
0185         QTreeView::mouseDoubleClickEvent(event);
0186 }
0187 
0188 void UserListView::contextMenuEvent(QContextMenuEvent* e)
0189 {
0190     QModelIndex index= indexAt(e->pos());
0191     if(!index.isValid())
0192         return;
0193 
0194     setCurrentIndex(index);
0195 
0196     auto tmpperso= index.data(PlayerModel::PersonPtrRole).value<Person*>();
0197 
0198     auto flags= index.flags();
0199 
0200     if(!(flags & Qt::ItemIsEditable) || tmpperso == nullptr)
0201         return;
0202 
0203     auto uuid= tmpperso->uuid();
0204     auto charact= dynamic_cast<Character*>(tmpperso);
0205     QMenu popMenu(this);
0206 
0207     /*if(nullptr != charact)
0208     {
0209         auto initCmd= charact->getInitCommand();
0210         if(!initCmd.isEmpty())
0211         {
0212             //auto act= popMenu.addAction(tr("Roll initiative"));
0213             connect(act, &QAction::triggered, this, [this, initCmd, charact]() {
0214                 if(m_diceParser->parseLine(initCmd))
0215                 {
0216                     m_diceParser->start();
0217                     auto valueList= m_diceParser->getSumOfDiceResult();
0218                     if(valueList.isEmpty())
0219                         return;
0220 
0221                     charact->setInitiativeScore(static_cast<int>(valueList.first()))
0222                 }
0223             });
0224         }
0225     }*/
0226 
0227     popMenu.addAction(m_changeName.get());
0228     popMenu.addAction(m_changeColor.get());
0229     popMenu.addSeparator();
0230     popMenu.addAction(m_addAvatarAct.get());
0231     popMenu.addAction(m_removeAvatarAct.get());
0232     popMenu.addSeparator();
0233     if(nullptr != charact)
0234     {
0235         popMenu.addSeparator();
0236         auto menu= popMenu.addMenu(tr("Set Property"));
0237         for(auto pro : m_propertyActions)
0238         {
0239             if(pro->isCheckable())
0240             {
0241                 auto data= pro->data().value<std::pair<QString, Type>>();
0242                 pro->setChecked(tmpperso->property(data.first.toLocal8Bit()).toBool());
0243             }
0244             menu->addAction(pro);
0245         }
0246 
0247         auto stateModel= m_ctrl->characterStateModel();
0248         if(stateModel)
0249         {
0250             auto stateMenu= popMenu.addMenu(tr("State"));
0251             for(int i= 0; i < stateModel->rowCount(); ++i)
0252             {
0253                 auto label= stateModel->index(i, 0).data(CharacterStateModel::LABEL).toString();
0254                 auto id= stateModel->index(i, 0).data(CharacterStateModel::ID).toString();
0255 
0256                 auto act= stateMenu->addAction(label);
0257                 act->setCheckable(true);
0258                 auto stateIdPerson= charact->stateId();
0259                 act->setChecked(id == stateIdPerson);
0260                 act->setData(id);
0261                 connect(act, &QAction::triggered, this, &UserListView::setState);
0262             }
0263 
0264             popMenu.addSeparator();
0265         }
0266         auto actionList= charact->actionList();
0267         if(!actionList.isEmpty())
0268         {
0269             auto actionMenu= popMenu.addMenu(tr("Action"));
0270             for(auto action : actionList)
0271             {
0272                 auto act= actionMenu->addAction(action->name());
0273                 connect(act, &QAction::triggered, this,
0274                         [this, &action, uuid]() { emit runDiceForCharacter(action->command(), uuid); });
0275             }
0276         }
0277 
0278         auto shapeList= charact->shapeList();
0279         if(!shapeList.isEmpty())
0280         {
0281             auto shapeMenu= popMenu.addMenu(tr("Shape"));
0282             for(auto shape : shapeList)
0283             {
0284                 auto act= shapeMenu->addAction(shape->name());
0285                 act->setCheckable(true);
0286                 act->setChecked(charact->currentShape() == shape);
0287                 connect(act, &QAction::triggered, this,
0288                         [&charact, shape]()
0289                         {
0290                             if(charact->currentShape() == shape)
0291                                 charact->setCurrentShape(nullptr);
0292                             else
0293                                 charact->setCurrentShape(shape);
0294                         });
0295             }
0296         }
0297     }
0298     popMenu.exec(e->globalPos());
0299 }
0300 
0301 void UserListView::addAvatar()
0302 {
0303     /// @TODO: Here! options manager is required to get access to the photo directory
0304     PreferencesManager* m_preferencesManager= PreferencesManager::getInstance();
0305     QString directory(".");
0306     if(nullptr != m_preferencesManager)
0307     {
0308         directory= m_preferencesManager->value("imageDirectory", QDir::homePath()).toString();
0309     }
0310     ImageSelectorController ctrl(false, ImageSelectorController::All, ImageSelectorController::Square);
0311     ImageSelectorDialog dialog(&ctrl, this);
0312     if(QDialog::Accepted != dialog.exec())
0313         return;
0314 
0315     QModelIndex index= currentIndex();
0316     auto data= ctrl.finalImageData();
0317     if(!index.isValid() || data.isEmpty())
0318         return;
0319 
0320     Person* tmpperso= static_cast<Person*>(index.internalPointer());
0321     if(tmpperso)
0322         tmpperso->setAvatar(data);
0323 }
0324 
0325 void UserListView::deleteAvatar()
0326 {
0327     QModelIndex index= currentIndex();
0328     if(index.isValid())
0329     {
0330         Person* tmpperso= static_cast<Person*>(index.internalPointer());
0331         if(tmpperso)
0332             tmpperso->setAvatar({});
0333     }
0334 }
0335 void UserListView::editCurrentItemColor()
0336 {
0337     QModelIndex index= currentIndex();
0338 
0339     if(!index.isValid())
0340         return;
0341 
0342     QVariant valueVar= index.data(Qt::DecorationRole);
0343 
0344     QColor color= QColorDialog::getColor(valueVar.value<QColor>(), this);
0345 
0346     if(color.isValid())
0347     {
0348         model()->setData(index, QVariant(color), Qt::DecorationRole);
0349     }
0350 }
0351 
0352 void UserListView::mouseMoveEvent(QMouseEvent* event)
0353 {
0354     QModelIndex tmp= indexAt(event->pos());
0355 
0356     QTreeView::mousePressEvent(event);
0357 
0358     if((event->buttons() == Qt::LeftButton) && (tmp.isValid()))
0359     {
0360         Person* tmpperso= static_cast<Person*>(tmp.internalPointer());
0361         if(nullptr != tmpperso)
0362         {
0363             QDrag* drag= new QDrag(this);
0364             RolisteamMimeData* mimeData= new RolisteamMimeData();
0365 
0366             mimeData->setPerson(tmpperso);
0367             drag->setMimeData(mimeData);
0368             drag->setPixmap(helper::utils::roundCornerImage(IOHelper::dataToPixmap(tmpperso->avatar())));
0369             drag->exec();
0370         }
0371     }
0372 }
0373 /*QPixmap UserListView::generateAvatar(Person* p)
0374 {
0375     int diameter= 80;
0376     QPixmap img(diameter, diameter);
0377     img.fill(Qt::transparent);
0378     QPainter painter(&img);
0379     QBrush brush;
0380     if(p->avatar().isNull())
0381     {
0382         painter.setPen(p->getColor());
0383         brush.setColor(p->getColor());
0384         brush.setStyle(Qt::SolidPattern);
0385     }
0386     else
0387     {
0388         QImage img= IOHelper::dataToImage(p->avatar());
0389         brush.setTextureImage(img.scaled(diameter, diameter));
0390     }
0391 
0392     painter.setBrush(brush);
0393     painter.drawRoundedRect(0, 0, diameter, diameter, diameter / 10, diameter / 10);
0394 
0395     return img;
0396 }*/